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>
7.8 KiB
| id | status | status_updated | status_note | component | severity | timestamp | last_seen | occurrences | files | tags | related | legacy | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| bug-1579 | wontfix | 2026-09-24 | not a bug: intended host-attrs reset on disconnect; script fixed b673b7c9 |
unknown | unknown | 2026-08-18T09:00:00Z | 2026-09-19T09:00:00Z | 2 |
|
|
|
true |
bug-1579: run-resource-verify.sh's new controller-side check (task 6.2, query_controller_resvals()) reported…
Description
run-resource-verify.sh's new controller-side check (task 6.2, query_controller_resvals()) reported a live MISMATCH for the default resource set's 'cpuf' resource: 'controller check: cpuf -> MISMATCH: injected=9.5 observed=0.000000', even though inject_resources()'s own resupdate call reported 'cpuf=9.5 -> accepted' moments earlier in the same run.
Environment
Not recorded (migrated from buglog.json).
Reproduction
Not recorded (migrated from buglog.json).
Root cause
NOT A BUG -- documented, intentional controller production behavior colliding with this test script's own multi-process session structure. inject_resources() (task 6.1) runs join+resupdate+quit in ONE xce_test process; the 'quit' disconnects the synthetic worker's TCP connection to the controller at the end of that same script. query_controller_resvals() (task 6.2) then runs its resval query in a SEPARATE, LATER xce_test process/session -- by which point the synthetic worker is already gone from the controller's perspective. 'cpuf' is one of worker.c's N_HOST_ATTRS resources (add_hostattrs_resvals(), worker.c:260-287: type/model/cpuf/maxcpus/maxmem/maxswap/maxtmp/ndisks), which mark_worker_unavail() -> apply_worker_dead_mutation() (worker.c:704-716) deliberately RESETS (reset_hostattrs_unknown() then re-applies add_hostattrs_resvals()) whenever a worker is marked dead/disconnected -- correct, intentional production behavior for a REAL worker daemon that has genuinely gone away (you don't want a dead worker still advertising stale cpu capacity for scheduling). Every OTHER default resource (r15m, pg, ls, it, swp, io, tmp, mem -- none of which are in worker.c's N_HOST_ATTRS list) is a generic, non-host-attrs resval that persists correctly across worker disconnect and reported MATCH. Confirmed via live isolation: re-running with the exact same 8 non-cpuf resources reported 8/8 MATCH; re-running the mixed accept/reject scenario (mem=5, not-a-real-resource=1) correctly reported mem MATCH and skipped the rejected resource entirely (no query attempted). design.md's own sequence diagram does not show a worker disconnect between the resupdate leg and the resval-query leg, implying the intended flow keeps the synthetic worker connected throughout verification -- task 6.1's single-shot 'join;resupdate;quit' session structure deviates from that, but only resources that collide with worker.c's host-attrs reset list are affected.
Fix
DEFAULT-SET INSTANCE FIXED (task 6.2 remediation round 2): DEFAULT_RESOURCE_ARGS in run-resource-verify.sh now uses "r1m=9.5" instead of "cpuf=9.5" as the second already-supported regression-coverage name (mem=8.5 kept as-is -- mem is NOT host-attrs, confirmed safe). r1m is confirmed via resval_typeresolve.c's resinfo[] table to be a genuinely pre-existing resource name, and via src/worker/src/resource_sync.c to be a periodic/dynamic load-index resource (not in worker.c's N_HOST_ATTRS list), so it preserves the original 'already-supported name for regression coverage' intent without the disconnect-reset problem. Live-validated: default (no-args) set now reports a clean N/N MATCH with no false cpuf mismatch. Original two options re-evaluated: option (a) -- drop the host-attrs name from the default set -- is what was taken here. Option (b) -- keep the synthetic worker's xce_test session connected across all per-layer checks instead of quitting after inject_resources() -- was investigated live and found NOT to be a simple call-reordering fix: xce_test's REPL has no command path from the worker context back to the client context without first calling leave_ctx() (via ../cmd_up), which performs the exact same disconnect that quit does. Making option (b) work would require either a C-level xce_test change (e.g. a context-preserving command) or a materially riskier bash coprocess restructuring of this script -- both explicitly out of scope for this remediation. The underlying production behavior (add_hostattrs_resvals() / mark_worker_unavail() resetting host-attrs resources on worker disconnect) remains correct and untouched, and this note is preserved for any FUTURE task or user-supplied custom resource=value argument that names a host-attrs resource (type, model, cpuf, maxcpus, maxmem, maxswap, maxtmp, ndisks) -- those still hit this same class of false-MISMATCH if queried after the synthetic worker disconnects.
REAL FIX APPLIED (follow-up session, 2026-08-18): the underlying disconnect-timing gap this workaround left open for any host-attrs name is now actually closed, not just avoided for the default set. run-resource-verify.sh's inject_resources() now inserts a !bash "$SELF_SCRIPT" --internal-controller-check <TOP> <PEERS> <WORKER_HOST> <name...> line (xce_test's !<shell-command> escape, preprocess_and_run(), test.c ~line 950-998 -- a single top-level-REPL-loop call site that works identically in ANY context including worker, with no leave_ctx()/disconnect) BETWEEN resupdate and quit, inside the SAME xce_test worker session. This invokes a new internal_controller_check() function (hidden dispatch at the bottom of the script, before main "$@") that runs a nested client-context xce_test session and queries resval for every requested name WHILE the synthetic worker's connection is still open -- so a host-attrs resource is never reset to baseline before it is checked. Raw observed values are written to logs/controller-check-raw.tsv; query_controller_resvals() (still called at the same point in main(), after inject_resources() returns) now reads that file instead of running its own live query -- a pure sequencing change, the MATCH/MISMATCH comparison logic and TSV formats are byte-for-byte unchanged. DEFAULT_RESOURCE_ARGS restored cpuf=9.5 (dropped the r1m workaround) as live proof: 'controller check: cpuf -> MATCH' now, not the old false MISMATCH. Live-validated (5 separate runs): default 9-resource set incl. cpuf clean 9/9 MATCH at both controller and scheduler layers (~5-7s total runtime); mixed accept/reject with a host-attrs custom name (cpuf=3.25 alongside a rejected unknown resource) correctly MATCHes cpuf and skips the rejected name at both layers; --keep-running and mid-injection SIGTERM (landing WHILE the nested !-escape check was actively running) both verified clean, zero orphaned xce_test processes (full /proc/[0-9]*/cmdline scan, not just pgrep). Option (b) from the original analysis below (keep the session connected) turned out to be achievable after all via this !-escape mechanism, without any C-level xce_test change -- the earlier conclusion that it needed one was specific to trying to move BETWEEN contexts (worker -> client) without disconnecting, which is genuinely not possible; running an entirely separate NESTED xce_test client session via a shell escape while remaining IN the worker context sidesteps that limitation entirely.
Verification
Not recorded (migrated from buglog.json).
References
- Related: bug-1578