chore(wolf): sync anatomy/cerebrum/memory/hooks/token-ledger bookkeeping

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
Rongsong Shen 2026-08-25 14:13:40 +00:00
parent 3eba7c16bf
commit d1803376d8
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
5 changed files with 1593 additions and 36 deletions

View file

@ -1,7 +1,7 @@
# anatomy.md # anatomy.md
> Auto-maintained by OpenWolf. Last scanned: 2026-08-25T13:04:51.029Z > Auto-maintained by OpenWolf. Last scanned: 2026-08-25T13:49:34.701Z
> Files: 738 tracked | Anatomy hits: 0 | Misses: 0 > Files: 740 tracked | Anatomy hits: 0 | Misses: 0
## ../../../../../../tmp/ ## ../../../../../../tmp/
@ -946,7 +946,7 @@
- `apiserver.c` — include <errno.h> (~5966 tok) - `apiserver.c` — include <errno.h> (~5966 tok)
- `CLAUDE.md` — XCE Controller (~4927 tok) - `CLAUDE.md` — XCE Controller (~4927 tok)
- `cluster.c` — include "config.h" (~24998 tok) - `cluster.c` — include "config.h"; bug-1693 (2026-08-25): new `int schedadmin_signal_disconnect(void)` (thin wrapper around the existing static `schedadmin_signal(-ECONNRESET, NULL)`) lets `sched.c`'s `handle_scheduler_leave()` wake a pending `OPCode_schedAdmin` waiter immediately on scheduler disconnect instead of only at the 5s `SCHEDADMIN_TIMEOUT_MS` deadline; the post-wait dispatch gained a `got_status==-ECONNRESET` branch replying `SchedAdminReply{error="scheduler disconnected"}` (~25702 tok)
- `commit.c` — Declares is (~13741 tok) - `commit.c` — Declares is (~13741 tok)
- `config_repl.c` — define _GNU_SOURCE (~36913 tok) - `config_repl.c` — define _GNU_SOURCE (~36913 tok)
- `config_repl.h` — pragma once (~6952 tok) - `config_repl.h` — pragma once (~6952 tok)
@ -957,10 +957,10 @@
- `ha_convergence.c` — Declares char (~8389 tok) - `ha_convergence.c` — Declares char (~8389 tok)
- `ha.c` — define _GNU_SOURCE (~126128 tok) - `ha.c` — define _GNU_SOURCE (~126128 tok)
- `ha.h` — ifndef HA_H (~34172 tok) - `ha.h` — ifndef HA_H (~34172 tok)
- `job.c` — include <assert.h> (~37749 tok) - `job.c` — include <assert.h>; bug-1693 (2026-08-25): `fetchfile_pending_t` gained a `worker_t* worker` field (set in `on_fetchfile()` before registering); new `void fetchfile_signal_worker_disconnect(worker_t*)` walks `g_fetchfile_list` and wakes every pending waiter proxied to a disconnected worker with `-ECONNRESET`, called from `handle_worker_leave()` (worker.c); `XCE_TESTING`-only `fetchfile_wait_for_test()` seam added for regression coverage (~38719 tok)
- `join.c` — include "config.h" (~2994 tok) - `join.c` — include "config.h" (~2994 tok)
- `main.c` — build-time-versioning task 3.2 (argp_program_version runtime-composed into static `version_buf[128]`, "My name is..." startup INFO reads that buffer) PLUS dirty-content-fingerprint task 3.2 (2026-08-21): new static `version_display_buf[128]` composed via `xce_compose_version_ex()` (adds `STR(VERSION_DIRTY_FINGERPRINT)`) feeds `argp_program_version` instead; `version_buf`'s composition + the startup INFO log are byte-identical/untouched (Req 3.2). Live-verified: `--version` -> `7ebcba6d-cdb7cc7d`, startup log -> `7ebcba6d-dirty` (~5346 tok) - `main.c` — build-time-versioning task 3.2 (argp_program_version runtime-composed into static `version_buf[128]`, "My name is..." startup INFO reads that buffer) PLUS dirty-content-fingerprint task 3.2 (2026-08-21): new static `version_display_buf[128]` composed via `xce_compose_version_ex()` (adds `STR(VERSION_DIRTY_FINGERPRINT)`) feeds `argp_program_version` instead; `version_buf`'s composition + the startup INFO log are byte-identical/untouched (Req 3.2). Live-verified: `--version` -> `7ebcba6d-cdb7cc7d`, startup log -> `7ebcba6d-dirty` (~5346 tok)
- `meson.build` (~3521 tok) - `meson.build` (src/controller/) — bug-1693: added `testsuite/test_fetchfile_disconnect.c` to `controller_unit_test_src` (~3533 tok)
- `misc.c` — include <errno.h> (~1359 tok) - `misc.c` — include <errno.h> (~1359 tok)
- `myapp.c` — define _GNU_SOURCE (~6287 tok) - `myapp.c` — define _GNU_SOURCE (~6287 tok)
- `myconf.c` — define _GNU_SOURCE (~1180 tok) - `myconf.c` — define _GNU_SOURCE (~1180 tok)
@ -971,15 +971,15 @@
- `repl.c` — include <assert.h> (~9240 tok) - `repl.c` — include <assert.h> (~9240 tok)
- `reply.c` — include "config.h" (~590 tok) - `reply.c` — include "config.h" (~590 tok)
- `resources.c` — include <errno.h> (~50 tok) - `resources.c` — include <errno.h> (~50 tok)
- `sched.c` — include <errno.h> (~6080 tok) - `sched.c` — include <errno.h>; bug-1693 (2026-08-25): `handle_scheduler_leave()` now calls `schedadmin_signal_disconnect()` (cluster.c) BEFORE acquiring `c->sched.lock` (calling after would deadlock against the OPCode_schedAdmin dispatch case, which holds that lock for its whole wait) so a mid-wait scheduler disconnect wakes the pending waiter immediately instead of only at the 5s deadline (~6405 tok)
- `slowlane.c` — define _GNU_SOURCE (~2392 tok) - `slowlane.c` — define _GNU_SOURCE (~2392 tok)
- `startup_validation.c` — define _GNU_SOURCE (~1524 tok) - `startup_validation.c` — define _GNU_SOURCE (~1524 tok)
- `task.c` — include <errno.h> (~1376 tok) - `task.c` — include <errno.h> (~1376 tok)
- `worker.c` — include <errno.h> (~8004 tok) - `worker.c` — include <errno.h>; bug-1693 (2026-08-25): `handle_worker_leave()` now calls `fetchfile_signal_worker_disconnect(w)` (job.c) right after nulling `w->ep`, so a mid-wait worker disconnect wakes any `on_fetchfile()` waiter proxied to it immediately instead of only at the 10s deadline (~8298 tok)
## src/controller/include/ ## src/controller/include/
- `cluster.h` — if !defined(_CLUSTER_H_) (~3474 tok) - `cluster.h` — if !defined(_CLUSTER_H_); bug-1693: declares `fetchfile_signal_worker_disconnect(worker_t*)` and `schedadmin_signal_disconnect(void)` (~3400 tok)
- `commit.h` — pragma once (~3894 tok) - `commit.h` — pragma once (~3894 tok)
- `slowlane.h` — pragma once (~1149 tok) - `slowlane.h` — pragma once (~1149 tok)
- `worker.h` — if !defined(_WORKER_H_) (~213 tok) - `worker.h` — if !defined(_WORKER_H_) (~213 tok)
@ -989,7 +989,7 @@
- `clean_failover_preservation.sh` — clean_failover_preservation.sh — ha-term-safety task 5.2 live integration test. (~5327 tok) - `clean_failover_preservation.sh` — clean_failover_preservation.sh — ha-term-safety task 5.2 live integration test. (~5327 tok)
- `configcompare.c` — define _GNU_SOURCE (~2273 tok) - `configcompare.c` — define _GNU_SOURCE (~2273 tok)
- `configcompare.h` — pragma once (~1186 tok) - `configcompare.h` — pragma once (~1186 tok)
- `controller_test.c` — include <argp.h> (~2459 tok) - `controller_test.c` — include <argp.h>; bug-1693: registered `test_fetchfile_disconnect` (extern decl + TEST()) alongside existing `test_sched_admin_dispatch` (~2481 tok)
- `ctrlstatus_fmt.h` — ifndef _CTRLSTATUS_FMT_H_ (~631 tok) - `ctrlstatus_fmt.h` — ifndef _CTRLSTATUS_FMT_H_ (~631 tok)
- `resval_typeresolve.c` — resval_resolve_type(): resource-name -> Value_u_which table lookup (14 known names unchanged) + task 2.1's numeric-default fallback / `-t` type_override for unrecognized names (~499 tok) - `resval_typeresolve.c` — resval_resolve_type(): resource-name -> Value_u_which table lookup (14 known names unchanged) + task 2.1's numeric-default fallback / `-t` type_override for unrecognized names (~499 tok)
- `resval_typeresolve.h` — declares resval_resolve_type()/RESVAL_TYPE_UNKNOWN; task 2.1 fallback now implemented (~676 tok) - `resval_typeresolve.h` — declares resval_resolve_type()/RESVAL_TYPE_UNKNOWN; task 2.1 fallback now implemented (~676 tok)
@ -1020,16 +1020,18 @@
- `test_dispatch_commit.c` — Declares table (~7800 tok) - `test_dispatch_commit.c` — Declares table (~7800 tok)
- `test_dispatch_fail_retry.c` — task 5.2's fail->succeed->fail test (`test_rpc_failure_bound_resets_after_intervening_success`, toggles worker ep broken/working across `dispatch_a_job_test()` calls) proves Req 4.3 counter-reset end-to-end (GREEN). Its job.state==PEND/job.allocs==NULL assertions on the post-success retryable/terminal failures were REMOVED (task 5.2 remediation, 2026-08-23) after kiro-debug (HIGH confidence) found that sub-scenario unreachable via any real caller today -- see bug-1631 for the deferred analysis; the removed-assertion rationale is documented inline in the test (~13000 tok) - `test_dispatch_fail_retry.c` — task 5.2's fail->succeed->fail test (`test_rpc_failure_bound_resets_after_intervening_success`, toggles worker ep broken/working across `dispatch_a_job_test()` calls) proves Req 4.3 counter-reset end-to-end (GREEN). Its job.state==PEND/job.allocs==NULL assertions on the post-success retryable/terminal failures were REMOVED (task 5.2 remediation, 2026-08-23) after kiro-debug (HIGH confidence) found that sub-scenario unreachable via any real caller today -- see bug-1631 for the deferred analysis; the removed-assertion rationale is documented inline in the test (~13000 tok)
- `test_dispatch_fail_terminal.c` — Declares table (~3499 tok) - `test_dispatch_fail_terminal.c` — Declares table (~3499 tok)
- `test_fetchfile_disconnect.c` — bug-1693 regression suite (NEW, 2026-08-25): drives job.c's real `fetchfile_signal_worker_disconnect()`/`fetchfile_wait_for_test()` (XCE_TESTING seam) directly with a plain stack `worker_t` (not the full `on_fetchfile()`/real jobmgr+workermgr chain, out of this fix's scope). Proves a worker disconnect wakes a pending fetchfile wait in <1s with `-ECONNRESET` (not the ~5-10s deadline's `-ETIMEDOUT`), and that a disconnect on a DIFFERENT worker never cross-wakes an unrelated waiter (~2197 tok)
- `test_ha_durability.c` — Declares char (~5643 tok) - `test_ha_durability.c` — Declares char (~5643 tok)
- `test_ha_rdhup_integration.c` — Declares char (~8362 tok) - `test_ha_rdhup_integration.c` — Declares char (~8362 tok)
- `test_job_array_sched_push.c` — job-array-single-wal-record task 5.1: standalone binary (`sched_push_unit_test`) linking real `sched.c`+`dataex.c`+`egress.c` to test `sched_job_new_fun`/`xcesched_push_jobarray`; bug-1693 (2026-08-25): added a one-line link-satisfying `schedadmin_signal_disconnect()` stub (mirrors the file's existing `check_worker_()` stub) since `sched.c`'s `handle_scheduler_leave()` now calls the real one, defined in cluster.c, which this binary doesn't link (~2863 tok)
- `test_job_dispatch_fail_count.c` (~1002 tok) - `test_job_dispatch_fail_count.c` (~1002 tok)
- `test_job_dispatch_fail_count.c` — scheduler-dispatch-commit task 1.3: proves job_t.dispatch_fail_count (xce/types.h wrapper struct, new uint32_t next to submit_lsn) is a plain, directly settable/incrementable/resettable in-memory-only field; bare stack-local job_t, no jobmgr/RTTI, mirrors test_persist_types.c's test_slot_key_t_fields precedent. Data-model only -- no dispatch_a_job_() wiring (~1600 tok) - `test_job_dispatch_fail_count.c` — scheduler-dispatch-commit task 1.3: proves job_t.dispatch_fail_count (xce/types.h wrapper struct, new uint32_t next to submit_lsn) is a plain, directly settable/incrementable/resettable in-memory-only field; bare stack-local job_t, no jobmgr/RTTI, mirrors test_persist_types.c's test_slot_key_t_fields precedent. Data-model only -- no dispatch_a_job_() wiring (~1600 tok)
- `test_job_dispatch.c` — Declares in (~1205 tok) - `test_job_dispatch.c` — Declares in (~1205 tok)
- `test_jobdispatch_no_double_notify.c` — Declares table (~5490 tok) - `test_jobdispatch_no_double_notify.c` — Declares table (~5490 tok)
- `test_repl_apply.c` — include <dirent.h> (~5812 tok) - `test_repl_apply.c` — include <dirent.h> (~5812 tok)
- `test_resval_typeresolve.c` — Declares override (~1118 tok) - `test_resval_typeresolve.c` — Declares override (~1118 tok)
- `test_sched_admin_dispatch.c` (~7510 tok) - `test_sched_admin_dispatch.c` — Unity tests for OPCode_schedAdmin dispatch (cluster.c) via `myreq_handler_for_test`: standby/not-connected/admission-exhausted rejects, success/timeout/rpc-status-only/business-error round trips. bug-1693 (2026-08-25): added `test_schedadmin_disconnect_wakes_immediately`, calling the real `schedadmin_signal_disconnect()` (cluster.c) from a second thread against a real pending wait -- proves a disconnect wakes it in <1s (not the real unshrunk 5s deadline) with a distinguishable `"scheduler disconnected"` SchedAdminReply. Calls `schedadmin_signal_disconnect()` directly rather than `handle_scheduler_leave()` since this binary doesn't link the real sched.c (test_config_repl.c's stub would silently swallow the call -- see cerebrum.md) (~8752 tok)
- `test_sched_worker_change.c` — Declares bug (~3893 tok) - `test_sched_worker_change.c` — bug-1578 regression (sched_worker_change() dangling resvals_to_sched fix); standalone binary (`sched_worker_change_unit_test`) linking real sched.c+dataex.c+egress.c. bug-1693 (2026-08-25): upgraded its link-satisfying `schedadmin_signal_disconnect()` stub into a counting/capturing SPY, and added `test_scheduler_leave_signals_schedadmin_before_clearing_ep` proving the REAL `handle_scheduler_leave()` calls it exactly once and BEFORE nulling `c->sched.ep` (the deadlock-avoidance ordering) -- complements test_sched_admin_dispatch.c's test in controller_unit_test, where cluster.c is real but sched.c is stubbed; together the two prove both halves of the fix for real (~5279 tok)
- `test_term_safety_adapter.c` — define _GNU_SOURCE (~29920 tok) - `test_term_safety_adapter.c` — define _GNU_SOURCE (~29920 tok)
- `test_wal_job_ckpt_fact.c` — bug-1691 regression suite: WAL_JOB_CKPT restart-drop fix for job.ckptinfo (plain char*, xstring-backed via makeString()). 7 tests: apply_committed_entry unconditional-decode (no-state-change is the key test, since on_job_ckpt() never changes state — mirrors bug-1690's RUSAGE divergence) + forward-transition + backward-compat, apply_wal_entry adopt + backward-compat, direct-payload restart replay, and a real on_job_ckpt() production-path restart-replay test (needed `persist_init(..., &c)` not NULL, since CKPT is hook-driven like RUSAGE, not a direct call site like DISPATCH/START/FINISH — persist_start() only registers persist_job_hook_fun when p->cluster != NULL) (~7000 tok) - `test_wal_job_ckpt_fact.c` — bug-1691 regression suite: WAL_JOB_CKPT restart-drop fix for job.ckptinfo (plain char*, xstring-backed via makeString()). 7 tests: apply_committed_entry unconditional-decode (no-state-change is the key test, since on_job_ckpt() never changes state — mirrors bug-1690's RUSAGE divergence) + forward-transition + backward-compat, apply_wal_entry adopt + backward-compat, direct-payload restart replay, and a real on_job_ckpt() production-path restart-replay test (needed `persist_init(..., &c)` not NULL, since CKPT is hook-driven like RUSAGE, not a direct call site like DISPATCH/START/FINISH — persist_start() only registers persist_job_hook_fun when p->cluster != NULL) (~7000 tok)
- `test_wal_job_dispatch_fact.c` — Declares in (~5222 tok) - `test_wal_job_dispatch_fact.c` — Declares in (~5222 tok)

View file

@ -188,3 +188,4 @@
- **A prior task's own test file can pre-emptively flag a specific assertion as "this will need to change once task N.M lands" in its own comment/message string — grep for the LATER task's own number in sibling test files before assuming "task boundary == only my new file changes."** Task 3.1's `test_dispatch_commit.c::test_dc_worker_not_found_leaves_job_pend_and_alloc_uncommitted` asserted `dispatch_fail_count` stayed unchanged with the message "incrementing it is task 3.3's job, not 3.1's" — a deliberate, anticipated staleness, not an accidental regression. Confirmed via the mandated RED (git-stash job.c only, rebuild, run new tests → fail as expected) → GREEN (restore, rebuild) cycle: the GREEN pass surfaced this ONE pre-existing sibling-test failure (seeded counter 2 → now correctly 3), fixed by updating that one assertion + its message, not by touching my own new file. This is explicitly within "test infrastructure under testsuite/ may change" boundary language even when the task brief's boundary section only names the NEW file — a task boundary permitting "test infrastructure" changes covers fixing a sibling test's own foreseen staleness, not just adding new tests. - **A prior task's own test file can pre-emptively flag a specific assertion as "this will need to change once task N.M lands" in its own comment/message string — grep for the LATER task's own number in sibling test files before assuming "task boundary == only my new file changes."** Task 3.1's `test_dispatch_commit.c::test_dc_worker_not_found_leaves_job_pend_and_alloc_uncommitted` asserted `dispatch_fail_count` stayed unchanged with the message "incrementing it is task 3.3's job, not 3.1's" — a deliberate, anticipated staleness, not an accidental regression. Confirmed via the mandated RED (git-stash job.c only, rebuild, run new tests → fail as expected) → GREEN (restore, rebuild) cycle: the GREEN pass surfaced this ONE pre-existing sibling-test failure (seeded counter 2 → now correctly 3), fixed by updating that one assertion + its message, not by touching my own new file. This is explicitly within "test infrastructure under testsuite/ may change" boundary language even when the task brief's boundary section only names the NEW file — a task boundary permitting "test infrastructure" changes covers fixing a sibling test's own foreseen staleness, not just adding new tests.
- **A "mirror the precedent's free-and-replace pattern exactly" instruction (bug-1678/1687/1689's own established shape) can be actively WRONG for a new field if that field's live-mutation path sources any nested pointer from `makeString()` (bug-1690, WAL_JOB_RUSAGE/job.run_usage).** `update_host_runusage()` (misc.c) builds `xce_host_runusage_t.host_name` from `makeString()` — an RTTI-managed, refcounted, HEADER-BEFORE-DATA pointer (confirmed by reading librtti's actual source in the nix store, `RTTI_DATA_TO_OBJ`: `((meta_obj_t*)(((char*)v) - RTTI_OBJ_HEADER_SIZE))`), NOT a plain `malloc()`. `persist_apply_pump_run()` (the LIVE online-apply pump, confirmed via its own doc comment to run continuously on the primary itself, not just boot replay) re-applies every committed fact — including one the SAME process just live-mutated moments earlier via the synchronous "mutate-then-persist" pattern (the SAME pattern bug-1678's `dispatch_a_job_()` uses for `job.allocs`). For DISPATCH this is safe because `job.allocs`'s nested `host` field is genuinely capnp-wire-decoded end-to-end (arrives from the scheduler already deserialized) — `free_JobAlloc_ptr()` on it is always consistent. For RUSAGE it is NOT safe: calling the capnp-generated `free_JobRunusage_ptr()` on the LIVE (xstring-backed) structure would `free()` a non-malloc'd pointer — guaranteed ASAN heap-corruption abort on the very first live report for a new host. **General check before reusing this "free-and-replace at apply time" precedent for any NEW WAL fact type: grep the field's LIVE-mutation call site for `makeString()` (or any other non-malloc allocator) on any pointer the apply seam might later free — if found, replace with a MERGE (overwrite scalars in place, only adopt genuinely-new nested pointers by ownership transfer, never free an existing one) instead of a free-and-replace.** Proved with a real regression test using an actual `makeString()`'d pointer and asserting POINTER IDENTITY survives the merge (not just value equality) — a value-only check would not have caught this class of bug. Also found, but explicitly NOT fixed (separate file/component, out of scope): `job_destroy()` (`src/lib/jobj.c`)'s own existing manual `FREEUP`-based walk over `run_usage` has this exact same latent host_name/xstring mismatch, independent of and pre-dating this fix. - **A "mirror the precedent's free-and-replace pattern exactly" instruction (bug-1678/1687/1689's own established shape) can be actively WRONG for a new field if that field's live-mutation path sources any nested pointer from `makeString()` (bug-1690, WAL_JOB_RUSAGE/job.run_usage).** `update_host_runusage()` (misc.c) builds `xce_host_runusage_t.host_name` from `makeString()` — an RTTI-managed, refcounted, HEADER-BEFORE-DATA pointer (confirmed by reading librtti's actual source in the nix store, `RTTI_DATA_TO_OBJ`: `((meta_obj_t*)(((char*)v) - RTTI_OBJ_HEADER_SIZE))`), NOT a plain `malloc()`. `persist_apply_pump_run()` (the LIVE online-apply pump, confirmed via its own doc comment to run continuously on the primary itself, not just boot replay) re-applies every committed fact — including one the SAME process just live-mutated moments earlier via the synchronous "mutate-then-persist" pattern (the SAME pattern bug-1678's `dispatch_a_job_()` uses for `job.allocs`). For DISPATCH this is safe because `job.allocs`'s nested `host` field is genuinely capnp-wire-decoded end-to-end (arrives from the scheduler already deserialized) — `free_JobAlloc_ptr()` on it is always consistent. For RUSAGE it is NOT safe: calling the capnp-generated `free_JobRunusage_ptr()` on the LIVE (xstring-backed) structure would `free()` a non-malloc'd pointer — guaranteed ASAN heap-corruption abort on the very first live report for a new host. **General check before reusing this "free-and-replace at apply time" precedent for any NEW WAL fact type: grep the field's LIVE-mutation call site for `makeString()` (or any other non-malloc allocator) on any pointer the apply seam might later free — if found, replace with a MERGE (overwrite scalars in place, only adopt genuinely-new nested pointers by ownership transfer, never free an existing one) instead of a free-and-replace.** Proved with a real regression test using an actual `makeString()`'d pointer and asserting POINTER IDENTITY survives the merge (not just value equality) — a value-only check would not have caught this class of bug. Also found, but explicitly NOT fixed (separate file/component, out of scope): `job_destroy()` (`src/lib/jobj.c`)'s own existing manual `FREEUP`-based walk over `run_usage` has this exact same latent host_name/xstring mismatch, independent of and pre-dating this fix.
- **This project's Unity build has `TEST_ASSERT_EQUAL_DOUBLE` silently non-functional (fails every call with "Unity Double Precision Disabled") because `unity_dep = dependency('unity')` is a prebuilt nix package with no `-DUNITY_INCLUDE_DOUBLE`** (Unity's own default is double support OFF unless explicitly opted in; float support is ON by default). Grep any existing test file comparing a C `double` field before assuming `TEST_ASSERT_EQUAL_DOUBLE` works — the established codebase convention (e.g. `test_apply_committed_entry.c`, `test_dispatch_commit.c`, `test_worker_join.c`) is `TEST_ASSERT_EQUAL_FLOAT` even for genuinely-`double`-typed fields (implicit narrow to float; fine for clean/round test fixture values). Caught only by actually running the RED build and reading the real failure message, not by reasoning from Unity's public API alone. - **This project's Unity build has `TEST_ASSERT_EQUAL_DOUBLE` silently non-functional (fails every call with "Unity Double Precision Disabled") because `unity_dep = dependency('unity')` is a prebuilt nix package with no `-DUNITY_INCLUDE_DOUBLE`** (Unity's own default is double support OFF unless explicitly opted in; float support is ON by default). Grep any existing test file comparing a C `double` field before assuming `TEST_ASSERT_EQUAL_DOUBLE` works — the established codebase convention (e.g. `test_apply_committed_entry.c`, `test_dispatch_commit.c`, `test_worker_join.c`) is `TEST_ASSERT_EQUAL_FLOAT` even for genuinely-`double`-typed fields (implicit narrow to float; fine for clean/round test fixture values). Caught only by actually running the RED build and reading the real failure message, not by reasoning from Unity's public API alone.
- **`controller_unit_test` (the main shared meson.build `controller_unit_test_src` binary) does NOT link the real `sched.c`/`dataex.c` at all** (bug-1693, 2026-08-25) — `sched.c`'s own `on_scheduler_join()`/`collect_confvars()` and `dataex.c`'s `notify()` collide at link time with fake local definitions several OTHER files in that same binary already provide (`test_commit_barrier_reply.c`, `test_worker_join.c`), so `test_config_repl.c` instead ships a trivial no-op `handle_scheduler_leave(cluster_t *c) { (void)c; return 0; }` stub purely to satisfy the linker. **Any new/changed behavior added to a real `sched.c` function is therefore SILENTLY UNTESTED by any `controller_unit_test`-based test that calls that function by name** — the call resolves to the stub, not the real implementation, with no compile/link error to flag the mismatch (confirmed empirically: a new regression test asserting sub-second wake timing after calling `handle_scheduler_leave()` passed compilation and linking fine, then failed by taking the full 5s deadline — the stub had silently swallowed the call). `nm '<obj>.o' | grep ' T <symbol>$'` across every `.o` in the target's build dir is the fast way to confirm which TU actually provides a given symbol in a given binary before trusting a test's result. The two standalone binaries that DO link the real `sched.c` (`sched_push_unit_test`, `sched_worker_change_unit_test` — see their own `meson.build` comments for the collision rationale) don't link `cluster.c`, so neither binary alone can exercise a fix that spans both files for real; bug-1693's fix split verification across both (a direct-call test against `cluster.c`'s real new function in `controller_unit_test`, plus a small counting-spy test in `test_sched_worker_change.c` proving `sched.c`'s real caller invokes it) rather than inventing a third binary that links both (would need to duplicate most of `controller_unit_test_src`'s already-large dependency list to satisfy `cluster.c`'s own huge fan-out). General lesson: when a fix spans a function in `sched.c`/`dataex.c` AND a function in any of the ~15 other files real-linked into `controller_unit_test_src`, check with `nm`/grep for a same-name fake stub in a sibling test file in that binary BEFORE trusting a test that calls the `sched.c`/`dataex.c` side by name — it may be exercising a stub, not your change.

View file

@ -123,8 +123,8 @@
"first_read": "2026-08-25T07:27:27.677Z" "first_read": "2026-08-25T07:27:27.677Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c": {
"count": 24, "count": 29,
"tokens": 36630, "tokens": 38640,
"first_read": "2026-08-25T07:27:28.858Z" "first_read": "2026-08-25T07:27:28.858Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/ha.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/ha.c": {
@ -143,8 +143,8 @@
"first_read": "2026-08-25T07:28:07.131Z" "first_read": "2026-08-25T07:28:07.131Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c": {
"count": 7, "count": 10,
"tokens": 24998, "tokens": 25458,
"first_read": "2026-08-25T07:28:24.287Z" "first_read": "2026-08-25T07:28:24.287Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/lib/zarray.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/lib/zarray.c": {
@ -163,8 +163,8 @@
"first_read": "2026-08-25T07:29:10.899Z" "first_read": "2026-08-25T07:29:10.899Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c": {
"count": 2, "count": 3,
"tokens": 6080, "tokens": 6405,
"first_read": "2026-08-25T07:29:20.929Z" "first_read": "2026-08-25T07:29:20.929Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/config_repl.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/config_repl.c": {
@ -328,13 +328,13 @@
"first_read": "2026-08-25T09:29:39.634Z" "first_read": "2026-08-25T09:29:39.634Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/meson.build": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/meson.build": {
"count": 5, "count": 6,
"tokens": 3510, "tokens": 3521,
"first_read": "2026-08-25T09:31:05.167Z" "first_read": "2026-08-25T09:31:05.167Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/controller_test.c": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/controller_test.c": {
"count": 8, "count": 10,
"tokens": 2437, "tokens": 2459,
"first_read": "2026-08-25T09:35:28.617Z" "first_read": "2026-08-25T09:35:28.617Z"
}, },
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/schema/controller.capnp": { "/home/rshen/projects/xce/worktrees/scheduler-framework/src/schema/controller.capnp": {
@ -406,6 +406,26 @@
"count": 2, "count": 2,
"tokens": 0, "tokens": 0,
"first_read": "2026-08-25T12:33:06.428Z" "first_read": "2026-08-25T12:33:06.428Z"
},
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/include/cluster.h": {
"count": 1,
"tokens": 3474,
"first_read": "2026-08-25T13:19:12.092Z"
},
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c": {
"count": 6,
"tokens": 8789,
"first_read": "2026-08-25T13:21:17.170Z"
},
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c": {
"count": 5,
"tokens": 5260,
"first_read": "2026-08-25T13:21:52.146Z"
},
"/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_job_array_sched_push.c": {
"count": 1,
"tokens": 0,
"first_read": "2026-08-25T13:31:53.292Z"
} }
}, },
"files_written": [ "files_written": [
@ -1314,6 +1334,234 @@
"action": "edit", "action": "edit",
"tokens": 535, "tokens": 535,
"at": "2026-08-25T13:04:51.036Z" "at": "2026-08-25T13:04:51.036Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c",
"action": "edit",
"tokens": 792,
"at": "2026-08-25T13:24:45.716Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c",
"action": "edit",
"tokens": 496,
"at": "2026-08-25T13:25:19.968Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/include/cluster.h",
"action": "edit",
"tokens": 212,
"at": "2026-08-25T13:25:31.898Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 418,
"at": "2026-08-25T13:25:45.653Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c",
"action": "edit",
"tokens": 186,
"at": "2026-08-25T13:25:56.526Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c",
"action": "edit",
"tokens": 883,
"at": "2026-08-25T13:26:28.560Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c",
"action": "edit",
"tokens": 136,
"at": "2026-08-25T13:26:50.662Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/worker.c",
"action": "edit",
"tokens": 347,
"at": "2026-08-25T13:27:03.570Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c",
"action": "edit",
"tokens": 1308,
"at": "2026-08-25T13:27:29.850Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_fetchfile_disconnect.c",
"action": "create",
"tokens": 2354,
"at": "2026-08-25T13:28:09.937Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/meson.build",
"action": "edit",
"tokens": 30,
"at": "2026-08-25T13:28:19.494Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/controller_test.c",
"action": "edit",
"tokens": 26,
"at": "2026-08-25T13:28:20.720Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/controller_test.c",
"action": "edit",
"tokens": 21,
"at": "2026-08-25T13:28:21.549Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_job_array_sched_push.c",
"action": "edit",
"tokens": 161,
"at": "2026-08-25T13:32:05.503Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c",
"action": "edit",
"tokens": 161,
"at": "2026-08-25T13:32:16.865Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c",
"action": "edit",
"tokens": 115,
"at": "2026-08-25T13:37:33.072Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 59,
"at": "2026-08-25T13:39:08.420Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 23,
"at": "2026-08-25T13:39:22.303Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 21,
"at": "2026-08-25T13:41:25.427Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 18,
"at": "2026-08-25T13:41:35.604Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c",
"action": "edit",
"tokens": 716,
"at": "2026-08-25T13:42:18.573Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c",
"action": "edit",
"tokens": 40,
"at": "2026-08-25T13:42:39.566Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c",
"action": "edit",
"tokens": 112,
"at": "2026-08-25T13:42:58.962Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_admin_dispatch.c",
"action": "edit",
"tokens": 6,
"at": "2026-08-25T13:43:39.068Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c",
"action": "edit",
"tokens": 410,
"at": "2026-08-25T13:44:12.438Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c",
"action": "edit",
"tokens": 754,
"at": "2026-08-25T13:44:48.403Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c",
"action": "edit",
"tokens": 249,
"at": "2026-08-25T13:45:04.781Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c",
"action": "edit",
"tokens": 459,
"at": "2026-08-25T13:45:16.760Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/testsuite/test_sched_worker_change.c",
"action": "edit",
"tokens": 67,
"at": "2026-08-25T13:45:49.403Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c",
"action": "edit",
"tokens": 42,
"at": "2026-08-25T13:46:55.175Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c",
"action": "edit",
"tokens": 42,
"at": "2026-08-25T13:47:04.558Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c",
"action": "edit",
"tokens": 52,
"at": "2026-08-25T13:47:24.584Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 27,
"at": "2026-08-25T13:47:35.046Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/worker.c",
"action": "edit",
"tokens": 23,
"at": "2026-08-25T13:47:45.420Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/cluster.c",
"action": "edit",
"tokens": 26,
"at": "2026-08-25T13:49:05.945Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/job.c",
"action": "edit",
"tokens": 36,
"at": "2026-08-25T13:49:18.648Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/sched.c",
"action": "edit",
"tokens": 21,
"at": "2026-08-25T13:49:27.546Z"
},
{
"file": "/home/rshen/projects/xce/worktrees/scheduler-framework/src/controller/worker.c",
"action": "edit",
"tokens": 17,
"at": "2026-08-25T13:49:34.709Z"
} }
], ],
"edit_counts": { "edit_counts": {
@ -1338,10 +1586,10 @@
"src/include/persist.h": 2, "src/include/persist.h": 2,
"src/include/wal_types.h": 6, "src/include/wal_types.h": 6,
"src/controller/persist.c": 36, "src/controller/persist.c": 36,
"src/controller/job.c": 10, "src/controller/job.c": 15,
"src/controller/testsuite/test_wal_job_start_fact.c": 1, "src/controller/testsuite/test_wal_job_start_fact.c": 1,
"src/controller/meson.build": 5, "src/controller/meson.build": 6,
"src/controller/testsuite/controller_test.c": 10, "src/controller/testsuite/controller_test.c": 12,
"src/scheduler/testsuite/test_limit_plugin.c": 2, "src/scheduler/testsuite/test_limit_plugin.c": 2,
"src/scheduler/testsuite/meson.build": 4, "src/scheduler/testsuite/meson.build": 4,
"src/scheduler/src/plugins/limit.c": 1, "src/scheduler/src/plugins/limit.c": 1,
@ -1352,11 +1600,19 @@
"src/schema/controller.capnp": 1, "src/schema/controller.capnp": 1,
"src/controller/testsuite/test_wal_job_rusage_fact.c": 4, "src/controller/testsuite/test_wal_job_rusage_fact.c": 4,
"src/controller/testsuite/test_wal_job_ckpt_fact.c": 2, "src/controller/testsuite/test_wal_job_ckpt_fact.c": 2,
"src/controller/testsuite/test_wal_job_preason_fact.c": 2 "src/controller/testsuite/test_wal_job_preason_fact.c": 2,
"src/controller/cluster.c": 5,
"src/controller/include/cluster.h": 1,
"src/controller/sched.c": 7,
"src/controller/worker.c": 3,
"src/controller/testsuite/test_sched_admin_dispatch.c": 6,
"src/controller/testsuite/test_fetchfile_disconnect.c": 1,
"src/controller/testsuite/test_job_array_sched_push.c": 1,
"src/controller/testsuite/test_sched_worker_change.c": 6
}, },
"anatomy_hits": 49, "anatomy_hits": 52,
"anatomy_misses": 32, "anatomy_misses": 33,
"repeated_reads_warned": 226, "repeated_reads_warned": 247,
"cerebrum_warnings": 0, "cerebrum_warnings": 0,
"stop_count": 41 "stop_count": 42
} }

View file

@ -4061,3 +4061,43 @@
| 05:55 | Edited src/controller/testsuite/controller_test.c | 1→2 lines | ~19 | | 05:55 | Edited src/controller/testsuite/controller_test.c | 1→2 lines | ~19 |
| 06:04 | Edited src/controller/testsuite/test_wal_job_preason_fact.c | modified test_wjp_apply_committed_entry_decode_failure_leaves_untouched() | ~499 | | 06:04 | Edited src/controller/testsuite/test_wal_job_preason_fact.c | modified test_wjp_apply_committed_entry_decode_failure_leaves_untouched() | ~499 |
| 13:13 | bug-1692 FIXED: WAL_JOB_PREASON restart-drop of job.pend_reasons (last of 5 field-parity audit gaps) | src/controller/persist.c, src/controller/job.c, src/include/wal_types.h, src/controller/testsuite/test_wal_job_preason_fact.c | GREEN: 1178 Tests 2 Failures (only pre-existing bug-1561), 11/11 new tests pass, 0 ASAN findings | ~145000 | | 13:13 | bug-1692 FIXED: WAL_JOB_PREASON restart-drop of job.pend_reasons (last of 5 field-parity audit gaps) | src/controller/persist.c, src/controller/job.c, src/include/wal_types.h, src/controller/testsuite/test_wal_job_preason_fact.c | GREEN: 1178 Tests 2 Failures (only pre-existing bug-1561), 11/11 new tests pass, 0 ASAN findings | ~145000 |
| 06:15 | Session end: 151 writes across 35 files (persistence.md, SKILL.md, plugin.h, plugin.c, driver.c) | 81 reads | ~840393 tok |
| 06:24 | Edited src/controller/cluster.c | modified requires() | ~740 |
| 06:25 | Edited src/controller/cluster.c | added 1 condition(s) | ~463 |
| 06:25 | Edited src/controller/include/cluster.h | expanded (+9 lines) | ~198 |
| 06:25 | Edited src/controller/sched.c | modified handle_scheduler_leave() | ~390 |
| 06:25 | Edited src/controller/job.c | modified struct() | ~174 |
| 06:26 | Edited src/controller/job.c | added 3 condition(s) | ~824 |
| 06:26 | Edited src/controller/job.c | expanded (+6 lines) | ~127 |
| 06:27 | Edited src/controller/worker.c | expanded (+17 lines) | ~324 |
| 06:27 | Edited src/controller/testsuite/test_sched_admin_dispatch.c | modified SCHEDADMIN_TIMEOUT_MS() | ~1220 |
| 06:28 | Created src/controller/testsuite/test_fetchfile_disconnect.c | — | ~2197 |
| 06:28 | Edited src/controller/meson.build | 2→3 lines | ~28 |
| 06:28 | Edited src/controller/testsuite/controller_test.c | 1→2 lines | ~24 |
| 06:28 | Edited src/controller/testsuite/controller_test.c | 1→2 lines | ~20 |
| 06:32 | Edited src/controller/testsuite/test_job_array_sched_push.c | modified check_worker_() | ~150 |
| 06:32 | Edited src/controller/testsuite/test_sched_worker_change.c | modified check_worker_() | ~150 |
| 06:37 | Edited src/controller/testsuite/test_sched_admin_dispatch.c | 8→11 lines | ~107 |
| 06:39 | Edited src/controller/sched.c | 3→6 lines | ~55 |
| 06:39 | Edited src/controller/sched.c | 4→5 lines | ~22 |
| 06:41 | Edited src/controller/sched.c | 6→3 lines | ~19 |
| 06:41 | Edited src/controller/sched.c | 5→4 lines | ~16 |
| 06:42 | Edited src/controller/testsuite/test_sched_admin_dispatch.c | modified handle_scheduler_leave() | ~668 |
| 06:42 | Edited src/controller/testsuite/test_sched_admin_dispatch.c | 7→4 lines | ~37 |
| 06:42 | Edited src/controller/testsuite/test_sched_admin_dispatch.c | 7→7 lines | ~104 |
| 06:43 | Edited src/controller/testsuite/test_sched_admin_dispatch.c | removed 3 lines | ~6 |
| 06:44 | Edited src/controller/testsuite/test_sched_worker_change.c | modified schedadmin_signal_disconnect() | ~383 |
| 06:44 | Edited src/controller/testsuite/test_sched_worker_change.c | modified test_scheduler_leave_signals_schedadmin_before_clearing_ep() | ~703 |
| 06:45 | Edited src/controller/testsuite/test_sched_worker_change.c | added 1 condition(s) | ~232 |
| 06:45 | Edited src/controller/testsuite/test_sched_worker_change.c | expanded (+11 lines) | ~428 |
| 06:45 | Edited src/controller/testsuite/test_sched_worker_change.c | 4→5 lines | ~63 |
| 06:46 | Edited src/controller/cluster.c | modified schedadmin_signal_disconnect() | ~39 |
| 06:47 | Edited src/controller/cluster.c | modified schedadmin_signal_disconnect() | ~39 |
| 06:47 | Edited src/controller/job.c | modified fetchfile_signal_worker_disconnect() | ~49 |
| 06:47 | Edited src/controller/sched.c | 3→3 lines | ~25 |
| 06:47 | Edited src/controller/worker.c | 4→4 lines | ~22 |
| 06:49 | Edited src/controller/cluster.c | modified schedadmin_signal_disconnect() | ~25 |
| 06:49 | Edited src/controller/job.c | modified fetchfile_signal_worker_disconnect() | ~34 |
| 06:49 | Edited src/controller/sched.c | 3→3 lines | ~19 |
| 06:49 | Edited src/controller/worker.c | 4→4 lines | ~16 |
| 14:10 | bug-1693 FIXED: schedAdmin/fetchfile disconnect-wait Decision Log violations (timeout was sole failure-detection) | src/controller/cluster.c, sched.c, job.c, worker.c, include/cluster.h, testsuite/test_sched_admin_dispatch.c, testsuite/test_fetchfile_disconnect.c (new), testsuite/test_sched_worker_change.c, testsuite/test_job_array_sched_push.c, meson.build, testsuite/controller_test.c | RED confirmed (5001ms/backstop timeout pre-fix, 3 tests) -> GREEN (all <1s post-fix); full suite 1181 Tests 2 Failures (bug-1561 only, pre-existing), 0 new failures | ~95000 |

File diff suppressed because it is too large Load diff