Skip to content

Commit c6d2296

Browse files
tbitcsoz-agent
andcommitted
fix(zephyr): correct ZRMB header length to 84 bytes and fix determinism test API names
- lib/arbiter_blob.c: ZRMB_HEADER_LEN 80 -> 84 (struct includes crc32 field, 4+2+2+4+4+32+32+4 = 84 bytes). Update CRC comment offset accordingly. - python/arbiter/emit_blob.py: header_len field value 80 -> 84, crc32 pack_into offset 76 -> 80 to match actual struct layout. - tests/unit/test_arbiter_blob/src/main.c: valid_blob[80] -> valid_blob[84], fix header_len/total_len bytes from 0x50 to 0x54, remove hardcoded 80 in null-param tests (use sizeof(valid_blob)), fix bad[] array size to 84. - tests/unit/test_arbiter_determinism/src/main.c: replace all lowercase arbiter_* struct/function names with ARBITER_ prefix to match the public header API. Fix result field names: .mode -> .current_mode, .fired_count -> .requested_action_count. Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent 02374cc commit c6d2296

5 files changed

Lines changed: 74 additions & 61 deletions

File tree

LEDGER.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Change Ledger
22

3+
## 2026-06-01T00:04 — Fix ZRMB header length and CRC offset
4+
- **Author**: Oz
5+
- **Type**: fix
6+
- **REQs affected**: REQ-BUILD-001, REQ-ARCH-006, REQ-ARCH-023
7+
- **Summary**: Corrected the binary blob header length from 80 to 84 bytes
8+
(the actual size of magic/version/flags/lengths/two hashes/crc32), updated
9+
the CRC offset from 76 to 80 in the emitter, and fixed the blob unit test
10+
fixture lengths. This removes Linux `-Werror` array-initializer failures
11+
and aligns runtime loader validation with emitted blobs.
12+
- **Status**: complete
13+
314
## 2026-06-01T00:00 — Fix public/generated header include casing
415
- **Author**: Oz
516
- **Type**: fix

lib/arbiter_blob.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LOG_MODULE_DECLARE(arbiter, CONFIG_ARBITER_LOG_LEVEL);
99

1010
#define ZRMB_MAGIC 0x424D525A /* "ZRMB" little-endian */
1111
#define ZRMB_VERSION 1
12-
#define ZRMB_HEADER_LEN 80 /* magic(4)+ver(2)+flags(2)+hlen(4)+tlen(4)+mhash(32)+shash(32)+crc(4) */
12+
#define ZRMB_HEADER_LEN 84 /* magic(4)+ver(2)+flags(2)+hlen(4)+tlen(4)+mhash(32)+shash(32)+crc(4) */
1313

1414
struct zrmb_header {
1515
uint32_t magic;
@@ -81,7 +81,7 @@ int ARBITER_blob_load(const uint8_t *blob, size_t blob_len,
8181
}
8282

8383
/* Validate CRC over everything except the CRC field itself.
84-
* CRC field is at offset 76 (4 bytes before end of header).
84+
* CRC field is at offset 80 (4 bytes before end of header).
8585
*/
8686
uint32_t crc = compute_crc32(blob, offsetof(struct zrmb_header, crc32));
8787
uint32_t crc_rest = compute_crc32(

python/arbiter/emit_blob.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def emit_blob(model: CanonicalModel) -> bytes:
3232
header += ZRMB_MAGIC
3333
header += struct.pack("<H", ZRMB_VERSION)
3434
header += struct.pack("<H", 0) # flags
35-
header += struct.pack("<I", 80) # header_len
35+
header += struct.pack("<I", 84) # header_len
3636
header += struct.pack("<I", 0) # total_len placeholder
3737
header += model_hash_bytes
3838
header += schema_hash_bytes
@@ -66,6 +66,6 @@ def emit_blob(model: CanonicalModel) -> bytes:
6666
# CRC over everything except the CRC field (last 4 bytes of header)
6767
blob = bytes(header[:-4]) + bytes(sections)
6868
crc = zlib.crc32(blob) & 0xFFFFFFFF
69-
struct.pack_into("<I", header, 76, crc) # crc32
69+
struct.pack_into("<I", header, 80, crc) # crc32
7070

7171
return bytes(header) + bytes(sections)

tests/unit/test_arbiter_blob/src/main.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
extern int ARBITER_blob_load(const uint8_t *blob, size_t blob_len,
88
struct ARBITER_model *model_out);
99

10-
/* Minimal valid ZRMB header (80 bytes) */
11-
static uint8_t valid_blob[80] = {
10+
/* Minimal valid ZRMB header (84 bytes) */
11+
static uint8_t valid_blob[84] = {
1212
'Z', 'R', 'M', 'B', /* magic */
1313
0x01, 0x00, /* version = 1 */
1414
0x00, 0x00, /* flags = 0 */
15-
0x50, 0x00, 0x00, 0x00, /* header_len = 80 */
16-
0x50, 0x00, 0x00, 0x00, /* total_len = 80 */
15+
0x54, 0x00, 0x00, 0x00, /* header_len = 84 */
16+
0x54, 0x00, 0x00, 0x00, /* total_len = 84 */
1717
/* 32 bytes model_hash (zeros) */
1818
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1919
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -37,8 +37,8 @@ ZTEST(ARBITER_blob, test_null_params)
3737
{
3838
struct ARBITER_model model;
3939

40-
zassert_equal(ARBITER_blob_load(NULL, 80, &model), ARBITER_EINVAL);
41-
zassert_equal(ARBITER_blob_load(valid_blob, 80, NULL), ARBITER_EINVAL);
40+
zassert_equal(ARBITER_blob_load(NULL, sizeof(valid_blob), &model), ARBITER_EINVAL);
41+
zassert_equal(ARBITER_blob_load(valid_blob, sizeof(valid_blob), NULL), ARBITER_EINVAL);
4242
}
4343

4444
ZTEST(ARBITER_blob, test_truncated)
@@ -50,7 +50,7 @@ ZTEST(ARBITER_blob, test_truncated)
5050

5151
ZTEST(ARBITER_blob, test_bad_magic)
5252
{
53-
uint8_t bad[80];
53+
uint8_t bad[84];
5454

5555
memcpy(bad, valid_blob, sizeof(bad));
5656
bad[0] = 'X';
@@ -62,7 +62,7 @@ ZTEST(ARBITER_blob, test_bad_magic)
6262

6363
ZTEST(ARBITER_blob, test_bad_version)
6464
{
65-
uint8_t bad[80];
65+
uint8_t bad[84];
6666

6767
memcpy(bad, valid_blob, sizeof(bad));
6868
bad[4] = 99; /* invalid version */

tests/unit/test_arbiter_determinism/src/main.c

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include <string.h>
2525

2626
/* Use a minimal inline model for self-contained testing */
27-
static const struct arbiter_fact_def test_facts[] = {
27+
static const struct ARBITER_fact_def test_facts[] = {
2828
{ .id = 0, .type = ARBITER_FACT_INT32, .range_min = -1000,
2929
.range_max = 1000, .default_value = 0, .stale_after_ms = 0,
3030
.safety_relevant = true, .name = "input" },
@@ -36,26 +36,26 @@ static const struct arbiter_fact_def test_facts[] = {
3636
.safety_relevant = false, .name = "enable" },
3737
};
3838

39-
static const struct arbiter_condition_def test_conditions[] = {
39+
static const struct ARBITER_condition_def test_conditions[] = {
4040
{ .fact_id = 2, .op = ARBITER_OP_EQ, .value = 1,
4141
.group = ARBITER_COND_ALL, .group_index = 0, .next = UINT16_MAX },
4242
};
4343

44-
static const struct arbiter_expr_def test_expressions[] = {
44+
static const struct ARBITER_expr_def test_expressions[] = {
4545
/* output = input * 3 */
4646
{ .target_fact_id = 1, .op = ARBITER_EXPR_SCALE,
4747
.left_fact_id = 0, .left_literal = 0,
4848
.right_fact_id = UINT16_MAX, .right_literal = 3,
4949
.scale = 1 },
5050
};
5151

52-
static const struct arbiter_action_def test_actions[] = {
52+
static const struct ARBITER_action_def test_actions[] = {
5353
{ .id = 0, .type = ARBITER_ACTION_CALLBACK, .target_fact_id = 0,
5454
.target_value = 0, .callback = NULL, .must_complete_within_ms = 0,
5555
.safe_state_action = false, .name = "noop" },
5656
};
5757

58-
static const struct arbiter_rule_def test_rules[] = {
58+
static const struct ARBITER_rule_def test_rules[] = {
5959
{ .id = 0, .rule_class = ARBITER_RULE_INFERENCE,
6060
.condition_start = 0, .condition_count = 1,
6161
.action_start = 0, .action_count = 0,
@@ -67,7 +67,7 @@ static const struct arbiter_rule_def test_rules[] = {
6767

6868
static const char *test_mode_names[] = { "normal" };
6969

70-
static const struct arbiter_model test_model = {
70+
static const struct ARBITER_model test_model = {
7171
.name = "determinism_test",
7272
.model_hash = {0},
7373
.schema_hash = {0},
@@ -93,22 +93,22 @@ static const struct arbiter_model test_model = {
9393

9494
ZTEST(determinism, test_repeat_eval_identical)
9595
{
96-
struct arbiter_ctx ctx;
97-
struct arbiter_snapshot snap_ref, snap_cur;
98-
struct arbiter_result result_ref, result_cur;
96+
struct ARBITER_ctx ctx;
97+
struct ARBITER_snapshot snap_ref, snap_cur;
98+
struct ARBITER_result result_ref, result_cur;
9999

100-
arbiter_init(&ctx, &test_model);
101-
arbiter_set_bool(&ctx, 2, true);
102-
arbiter_set_i32(&ctx, 0, 42);
100+
ARBITER_init(&ctx, &test_model);
101+
ARBITER_set_bool(&ctx, 2, true);
102+
ARBITER_set_i32(&ctx, 0, 42);
103103

104104
/* Reference run */
105-
arbiter_snapshot_begin(&ctx, &snap_ref);
106-
arbiter_eval(&test_model, &snap_ref, &result_ref, NULL);
105+
ARBITER_snapshot_begin(&ctx, &snap_ref);
106+
ARBITER_eval(&test_model, &snap_ref, &result_ref, NULL);
107107

108108
/* Repeat N times and compare */
109109
for (int i = 0; i < REPEAT_COUNT; i++) {
110-
arbiter_snapshot_begin(&ctx, &snap_cur);
111-
arbiter_eval(&test_model, &snap_cur, &result_cur, NULL);
110+
ARBITER_snapshot_begin(&ctx, &snap_cur);
111+
ARBITER_eval(&test_model, &snap_cur, &result_cur, NULL);
112112

113113
/* Byte-identical snapshot values */
114114
zassert_mem_equal(
@@ -117,10 +117,11 @@ ZTEST(determinism, test_repeat_eval_identical)
117117
"Snapshot diverged on iteration %d", i);
118118

119119
/* Identical result */
120-
zassert_equal(result_ref.mode, result_cur.mode,
120+
zassert_equal(result_ref.current_mode, result_cur.current_mode,
121121
"Mode diverged on iteration %d", i);
122-
zassert_equal(result_ref.fired_count, result_cur.fired_count,
123-
"Fired count diverged on iteration %d", i);
122+
zassert_equal(result_ref.requested_action_count,
123+
result_cur.requested_action_count,
124+
"Action count diverged on iteration %d", i);
124125
}
125126
}
126127

@@ -130,29 +131,30 @@ ZTEST(determinism, test_repeat_eval_identical)
130131

131132
ZTEST(determinism, test_fact_order_independence)
132133
{
133-
struct arbiter_ctx ctx_a, ctx_b;
134-
struct arbiter_snapshot snap_a, snap_b;
135-
struct arbiter_result res_a, res_b;
134+
struct ARBITER_ctx ctx_a, ctx_b;
135+
struct ARBITER_snapshot snap_a, snap_b;
136+
struct ARBITER_result res_a, res_b;
136137

137138
/* Context A: set input first, then enable */
138-
arbiter_init(&ctx_a, &test_model);
139-
arbiter_set_i32(&ctx_a, 0, 100);
140-
arbiter_set_bool(&ctx_a, 2, true);
141-
arbiter_snapshot_begin(&ctx_a, &snap_a);
142-
arbiter_eval(&test_model, &snap_a, &res_a, NULL);
139+
ARBITER_init(&ctx_a, &test_model);
140+
ARBITER_set_i32(&ctx_a, 0, 100);
141+
ARBITER_set_bool(&ctx_a, 2, true);
142+
ARBITER_snapshot_begin(&ctx_a, &snap_a);
143+
ARBITER_eval(&test_model, &snap_a, &res_a, NULL);
143144

144145
/* Context B: set enable first, then input */
145-
arbiter_init(&ctx_b, &test_model);
146-
arbiter_set_bool(&ctx_b, 2, true);
147-
arbiter_set_i32(&ctx_b, 0, 100);
148-
arbiter_snapshot_begin(&ctx_b, &snap_b);
149-
arbiter_eval(&test_model, &snap_b, &res_b, NULL);
146+
ARBITER_init(&ctx_b, &test_model);
147+
ARBITER_set_bool(&ctx_b, 2, true);
148+
ARBITER_set_i32(&ctx_b, 0, 100);
149+
ARBITER_snapshot_begin(&ctx_b, &snap_b);
150+
ARBITER_eval(&test_model, &snap_b, &res_b, NULL);
150151

151152
/* Must be identical */
152153
zassert_equal(ctx_a.fact_values[1].value, ctx_b.fact_values[1].value,
153154
"Output differs: order A=%d, order B=%d",
154155
ctx_a.fact_values[1].value, ctx_b.fact_values[1].value);
155-
zassert_equal(res_a.mode, res_b.mode, "Mode differs by write order");
156+
zassert_equal(res_a.current_mode, res_b.current_mode,
157+
"Mode differs by write order");
156158
}
157159

158160
/* ------------------------------------------------------------------ */
@@ -161,21 +163,21 @@ ZTEST(determinism, test_fact_order_independence)
161163

162164
ZTEST(determinism, test_cross_seed_consistency)
163165
{
164-
struct arbiter_ctx ctx;
165-
struct arbiter_snapshot snap;
166-
struct arbiter_result result;
166+
struct ARBITER_ctx ctx;
167+
struct ARBITER_snapshot snap;
168+
struct ARBITER_result result;
167169

168170
/* Test 100 different input values, each repeated 100 times */
169171
for (int32_t input = -50; input < 50; input++) {
170172
int32_t reference_output = 0;
171173

172174
for (int rep = 0; rep < 100; rep++) {
173-
arbiter_init(&ctx, &test_model);
174-
arbiter_set_bool(&ctx, 2, true);
175-
arbiter_set_i32(&ctx, 0, input);
175+
ARBITER_init(&ctx, &test_model);
176+
ARBITER_set_bool(&ctx, 2, true);
177+
ARBITER_set_i32(&ctx, 0, input);
176178

177-
arbiter_snapshot_begin(&ctx, &snap);
178-
arbiter_eval(&test_model, &snap, &result, NULL);
179+
ARBITER_snapshot_begin(&ctx, &snap);
180+
ARBITER_eval(&test_model, &snap, &result, NULL);
179181

180182
int32_t output = ctx.fact_values[1].value;
181183

@@ -205,16 +207,16 @@ ZTEST(determinism, test_reinit_determinism)
205207
int32_t results[100];
206208

207209
for (int i = 0; i < 100; i++) {
208-
struct arbiter_ctx ctx;
209-
struct arbiter_snapshot snap;
210-
struct arbiter_result result;
210+
struct ARBITER_ctx ctx;
211+
struct ARBITER_snapshot snap;
212+
struct ARBITER_result result;
211213

212-
arbiter_init(&ctx, &test_model);
213-
arbiter_set_bool(&ctx, 2, true);
214-
arbiter_set_i32(&ctx, 0, 777);
214+
ARBITER_init(&ctx, &test_model);
215+
ARBITER_set_bool(&ctx, 2, true);
216+
ARBITER_set_i32(&ctx, 0, 777);
215217

216-
arbiter_snapshot_begin(&ctx, &snap);
217-
arbiter_eval(&test_model, &snap, &result, NULL);
218+
ARBITER_snapshot_begin(&ctx, &snap);
219+
ARBITER_eval(&test_model, &snap, &result, NULL);
218220

219221
results[i] = ctx.fact_values[1].value;
220222
}

0 commit comments

Comments
 (0)