--- id: "bug-1438" status: "fixed" status_updated: "2026-09-24" status_note: "" component: "controller" severity: "hang" timestamp: "2026-07-14T09:36:00Z" last_seen: "2026-09-19T09:00:00Z" occurrences: 1 files: ["src/controller/testsuite/test_commit_barrier_rollout.c"] tags: ["job-array-single-wal-record", "wal", "test-helper", "offset-arithmetic", "deadlock", "futex"] related: [] legacy: true --- # bug-1438: test_job_array_submit_appends_exactly_one_wal_entry_and_one_continuation: Expected 11 Was 5 (WAL… ## Description test_job_array_submit_appends_exactly_one_wal_entry_and_one_continuation: Expected 11 Was 5 (WAL type mismatch); subsequent test hung all 3 threads on futex_do_wait ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause jap_read_last_wal_hdr()/jap_read_last_wal_payload() were copied from read_last_wal_hdr() in test_ha_role_lifecycle.c, which computes the header offset as seg_offset - sizeof(hdr). That arithmetic is only correct for zero-payload entries (its only prior caller was a WAL_NOOP test). Every WAL_JOB_ARRAY_SUBMIT entry carries a nonzero capnp payload, so seg_offset - sizeof(hdr) landed inside the payload bytes, not the header -- read garbage decoded as a bogus type (5 == WAL_JOB_STOP). The first array test's TEST_ASSERT_EQUAL_UINT32 failure then longjmp'd out of the test body BEFORE reaching jap_teardown(), leaking that test's persist_t (background WAL-sync thread still running) into the next test's jap_setup() memset -- corrupting a live mutex mid-flight and deadlocking all 3 threads on futex_do_wait in the very next test. ## Fix Replaced the back-computed-offset helpers with jap_read_wal_hdr_at()/jap_read_wal_entry_at(), which take the entry's start offset EXPLICITLY. Callers now snapshot g_jap.seg_offset immediately before each persist_submit_job_array_async() call and pass that snapshot in, instead of trying to infer the header position from the post-append offset. ## Verification _Not recorded (migrated from buglog.json)._ ## References _Not recorded (migrated from buglog.json)._