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>
3.4 KiB
| id | status | status_updated | status_note | component | severity | timestamp | last_seen | occurrences | files | tags | related | legacy | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| bug-1566 | fixed | 2026-09-24 | xceadmin | unknown | 2026-08-17T08:30:00.000Z | 2026-09-19T09:00:00Z | 1 |
|
|
true |
bug-1566: User-reported: ./scripts/xceadmin scheduler record status (from a /xce-deploy-ha deployment)…
Description
User-reported: ./scripts/xceadmin scheduler record status (from a /xce-deploy-ha deployment) failed with 'Error: cannot connect to localhost:9991: [Errno 111] Connection refused' -- the deployment's actual --peers were localhost:9901/9902/9903, not 9991.
Environment
Not recorded (migrated from buglog.json).
Reproduction
Not recorded (migrated from buglog.json).
Root cause
xceadmin's --controller option (config push, and all 3 scheduler record start/stop/status subcommands) defaulted unconditionally to a hardcoded module constant _DEFAULT_CONTROLLER = 'localhost:9991' with no way to override it except typing --controller on every single invocation. /xce-deploy-ha's generated scripts/xceadmin wrapper (added earlier this session) was a bare passthrough (exec python3 -m xceadmin.cli "$@") that never told xceadmin what the actual deployed cluster's real ports were -- so any xceadmin command that didn't explicitly pass --controller silently tried the generic, deployment-agnostic default instead of this specific deployment's real peers, which have nothing to do with 9991 unless the deploy happened to use that exact port by coincidence.
Fix
FIXED (TDD RED->GREEN). Added envvar="XCEADMIN_CONTROLLER" to all 4 --controller click.option() decorators in cli.py (naming matches the existing XCEADMIN_SCHEMA_PATH convention in xcecommon/schema.py) -- click's built-in option-resolution precedence is CLI flag > envvar > default, so an explicit --controller still always wins. Added test_controller_option_falls_back_to_xceadmin_controller_env_var (RED pre-fix: asserted the env var value reaches the command, failed with the hardcoded default instead) and test_controller_flag_overrides_xceadmin_controller_env_var (regression lock for the override guarantee) to test_cli.py. deploy-ha.sh's generated scripts/xceadmin wrapper now exports XCEADMIN_CONTROLLER="${PEER_ARRAY[0]}" (this deployment's own first --peers candidate) before exec'ing xceadmin. GREEN: full xceadmin test suite (261 tests via direct pytest, 258 passed + 3 skipped via the meson-driven build) all pass, no regressions. LIVE VALIDATION: rebuilt via /xce-build xceadmin --incremental (bug-1565's new flag, keeping the already-built controller/worker/scheduler binaries), redeployed with --peers localhost:9901,9902,9903 (matching the user's report exactly), started the cluster + scheduler, ran the user's EXACT command (scripts/xceadmin scheduler record status) in a completely stripped environment (env -i, no nix, no network) with NO --controller flag: correctly reached localhost:9901 (confirmed by the error changing from a raw connection-refused on the wrong port to a real application-level 'scheduler not connected' before the scheduler was started, then a clean 'recording: no' / exit 0 once it was) instead of failing against the wrong hardcoded port.
Verification
Not recorded (migrated from buglog.json).
References
Not recorded (migrated from buglog.json).