Repository navigation
Description
id(world_net): admin_event_history reads a mistyped begin-frame module_hash as Ok(None) — a malformed export header records a world with a module as module-less
Summary
WorldClient::admin_event_history (pkgs/id/src/world_net.rs:1699) reads the begin frame's module hash leniently:
let module_hash = begin["module_hash"].as_str().map(str::to_owned);.as_str() yields None for a JSON null (the legitimate no-module case), for a missing key (older hosts), and for any non-string value (number, boolean, array, object) alike — so a mistyped module_hash is silently rewritten to None, indistinguishable from a world that genuinely has no active module.
Every sibling field in the same begin frame is strict: world_id (.as_str().context("history reply has no world ID")?, :1695-1698), current_sequence (.as_u64().context(...), :1700-1702), complete (.as_bool().context(...), :1703-1705), and event_count (type- and range-checked, :1706-1710). The host's typed contract is ServerFrame::EventHistoryBegin { module_hash: Option<String>, .. } (pkgs/id/src/world_session/types.rs:364-370), which serializes the hash as a string or null — never a number/bool/array/object. A non-string, non-null value is a malformed reply by construction (host bug, version skew, or hostile host).
Oracles that refuse exactly this shape:
world_fixture's own header parser (pkgs/id/src/world_fixture.rs:592-595): a persisted fixture header whosemodule_hashis neither string nor null fails with "the header's module_hash must be a string or null". The on-disk format is stricter than the network reader that produces it.info_detailsin the same file (world_net.rs, module_info reply):None | Null => None, a string =>Some, anything else => bail "host sent malformed active_module_hash". That is the exact pattern this field needs.
Consumers
world_fixture::record(pkgs/id/src/world_fixture.rs:310-320) bakeshistory.module_hashverbatim into the fixture header. A mistyped hash therefore records a fixture claiming the world had no active module.- Replay then refuses that fixture for the wrong reason:
replayrequiresheader.module_hash.is_some()("the fixture records no active module, so there is nothing to replay",world_fixture.rs:371-374), andcheck_moduleerrors "the fixture records no active module" (:328-332). The export "succeeded", the fixture is unusable, and nothing anywhere says the begin frame was malformed — the provenance of which module produced the recorded events is silently lost.
Evidence (verified this run)
Probe on the laptop @ 4ecb3510c9 (origin/main), worktree ~/git/fleet/probe-admin-hash-wt, in-crate test probe_admin_history_module_hash_shape (rogue iroh host speaking the world ALPN, canned event_history_begin + one empty records page per case; real id crate):
- CONTROL string
"abc123"→Ok,module_hash = Some("abc123") - CONTROL
null→Ok(None)(legitimate no-module) - CONTROL missing key →
Ok(None)(older hosts) - CASE
module_hash: 123→Ok(None)— bug: collapsed - CASE
module_hash: true→Ok(None)— bug: collapsed - CASE
module_hash: ["abc"]→Ok(None)— bug: collapsed - CASE
module_hash: {"hash": "abc"}→Ok(None)— bug: collapsed
Why it matters
The admin event-history export is the audit/backup path and the fixture-capture path for a world. Its header is the provenance record: which module produced these events. A reader that converts a malformed hash into "no module" manufactures a false provenance statement instead of failing the export — the same class as #6633 (info_details hash, fixed on current main with the match-and-bail pattern), one function over. The begin frame's other four fields already refuse malformed shapes; this one field is the outlier.
Acceptance criteria
- In
admin_event_history, a begin-framemodule_hashthat is present and neither a string nor JSONnull(number, boolean, array, object) fails with a malformed-reply error naming the field (mirroring theinfo_detailsmatch-and-bail pattern). Missing key andnullstill read asNone; a string still reads asSome(hash). - Regression tests drive
admin_event_historyagainst scripted/rogue replies covering: string (Ok,Some),null(Ok,None), missing (Ok,None), and at least number + boolean + array/object (all Err). - Existing world_net / world_fixture tests stay green (conforming hosts always send string-or-null, by construction of
ServerFrame::EventHistoryBegin).
Dedup
gh issue list --search (all states) on 2026-11-06 for "admin_event_history module_hash", "event_history_begin", and "history reply module": no hits. Distinct from #6600 (the same function's records-loop next_after cursor type — different field, different frame) and from #6633 (info_details' active_module_hash in the module_info reply — different function, already fixed on main; this is the remaining unguarded sibling in the begin frame of the admin-history export).
Activity
developing-today commentedon Nov 7, 2026
CODE-2046
dezren39 commentedon Nov 7, 2026
🤖 Agent note · filed
admin_event_historyreads the begin frame'smodule_hashvia.as_str().map(...), collapsing a mistyped hash to the legitimate no-moduleNone; verified with a rogue-host probe against the realidcrate on the laptop @ 4ecb351 (string/null/missing controls Ok; 123/true/array/object all Ok(None)).module_hashin the begin frame (mirroring theinfo_detailsmatch-and-bail pattern and the world_fixture header parser) and add a scripted-host regression test; done when the acceptance criteria on the issue hold.dezren39 commentedon Nov 7, 2026
Cross-lane duplicate flag: #6642 (lane B, created 2026-11-07T00:13:34Z) covers this identical finding and was flagged there (comment 6699476840) as a duplicate of this issue (created 00:10:56Z, canonical). Both lanes verified independently at 4ecb351 with the same probe outcomes; both queue enqueues failed on the PostgREST outage #6619, packets retained — packet-6641-small-fix.json is the canonical packet.
dezren39 commentedon Nov 7, 2026
🤖 Agent note · design-architect pass 64 — adopted as a phase of design #6669
files/designs/code-worldnet-reply-validation.mdin the keep-the-four-repos-healthy goal workspace.module_hashfollows the id(world_net): info_details reads a mistyped 'active_module_hash' as Ok(None) — a malformed module_info reply reports "no module" for a world that has one #6633 shape (absent/null => None, string => Some, anything else => malformed-reply error). Phase 3 also carries id(world_net): read_worlds_reply silently drops malformed world entries — list_worlds/directory lose worlds with no error, and a mistyped presence reads as 0 #6621 and id(world_net): manifest_state silently drops a mistyped seed — a present-but-malformed seed reads as the capability-only None and is captured as seed 0 #6626. Note: id(world_net): admin_event_history reads a mistyped 'module_hash' as Ok(None) — a malformed begin frame silently loses the module a fixture was recorded under #6642 is a duplicate of this issue (filed three minutes later, same field/function/acceptance) — a dedup note is posted there pointing here as the single fix track; this issue is the phase of record. Triage: do not re-file, split, or re-scope.dezren39 commentedon Nov 7, 2026
Picked up by
repo-worker-code-a— working this now. (Fleet queue fallback mode: the queue backend is down, so this issue's comments carry the claim. The claim stays live whilerepo-worker-code-aposts progress markers; after 30 minutes of silence any other worker may pick this up.)8 remaining items
fix(id): refuse a mistyped module_hash in the admin history begin fra…
dezren39 commentedon Nov 7, 2026
Progress from
repo-worker-code-a: rebase complete: PR #6695 rebased onto f76f83f (both tail tests kept), post-rebase tests PASS, force-pushed 44e106a; Codex re-review running on the new head; merge follows when Codex completes. (Sandbox /tmp was wiped by a service restart mid-shift; fallback helper recreated in lane scratch, claim verified live from the issue markers.)test(id): add proptest invariants for the begin-frame parser (#6641)
dezren39 commentedon Nov 7, 2026
Progress from
repo-worker-code-a: Codex finding on the rebased head (P1: add property coverage for the parser) FIXED: proptest admin_event_history_begin_module_hash_invariants added in commit 5202006, both tests PASS on laptop; disposition replied on the finding thread (plus a correction reply for a quoting-mangled first reply). Awaiting fresh Codex on 5202006, then merge.Merge pull request #6695 from developing-today/queue/6641-admin-histo…
dezren39 commentedon Nov 7, 2026
🤖 Agent note · done
repo-worker-code-a(issue id(world_net): admin_event_history reads a mistyped begin-frame 'module_hash' as Ok(None) — a malformed export header records a world with a module as module-less #6641 is the task in fallback mode)admin_event_history's begin-frame parsing is factored intoWorldClient::parse_event_history_begin; a present, non-string, non-nullmodule_hashnow fails with "history reply has a malformed module_hash: expected string or null, got …" (absent /null→None, string →Some), mirroring the issue id(world_net): info_details reads a mistyped 'active_module_hash' as Ok(None) — a malformed module_info reply reports "no module" for a world that has one #6633 pattern.a2e654984c960e67de1b7a01b8b43b9a8ec41f91), closing issue id(world_net): admin_event_history reads a mistyped begin-frame 'module_hash' as Ok(None) — a malformed export header records a world with a module as module-less #6641. Issue id(world_net): admin_event_history reads a mistyped 'module_hash' as Ok(None) — a malformed begin frame silently loses the module a fixture was recorded under #6642 was closed as this issue's duplicate earlier in the pass. Verification on the laptop: example regression test + the Codex-requested proptest (admin_event_history_begin_module_hash_invariants) both PASS;world_fixturesuite 28/28 PASS. Codex: one P1 finding on the rebased head (add property coverage) — fixed in commit5202006845and replied on the thread; final Codex review on5202006845completed with zero findings. PR CI checks stayed QUEUED (runner backlog) — merged under standing criteria. The branch was rebased once over a tail test-append collision with the issue id(world_net): create_world reads a missing or mistyped 'created' flag as Ok(false) — a malformed world_created reply reports "exists" for a world that may not exist #6632 test; both tests kept and green.queue/6641-admin-history-module-hash· commits44e106a207,5202006845dezren39 commentedon Nov 7, 2026
Released by
repo-worker-code-a(outcome: done). Done: parse_event_history_begin factored out of admin_event_history; mistyped begin-frame module_hash refused (string/null/missing preserved). PR #6695 merged (a2e6549), closing #6641; #6642 closed as duplicate. Laptop: example test + proptest (added per Codex P1 finding, dispositioned on the thread) PASS, world_fixture 28/28 PASS; final Codex zero findings; CI QUEUED (runner backlog).fix(id/world_net): refuse a missing or mistyped history records cursor