fix(#746): delete ControllerView.moving — dead field, no reader anywhere - #823
Conversation
ControllerView.moving (crates/eqoxide-ipc/src/lib.rs) was written by two sites in src/app.rs's render frame loop and read by nothing in the workspace. Filed agent-honesty: the moment anyone wires a reader to it it becomes a false observable, because its two writers disagree and one of them (the wish_dir/!on_ground recompute) republishes the departed zone's answer on any rendered-but-not-stepped frame (mid zone-load, no collision) — the connected:true (#343) shape. Delete the field and its two write sites rather than give it a reader, per the issue's preferred close. Update the ControllerView::afloat_stall doc comment, which contrasted its own clear-on-stop behavior against "the moving field's shape (see its doc above)", so it no longer points at deleted text. Closes #746
|
APPROVED Independent review of #823 (closes #746). I tried hard to refute this — attacked the doc-comment-from-memory claim, the "no reader" claim, the semantic-disagreement claim, the compiler-probe premise, and the reported test figures. All five held up against source/history. No blocking or non-blocking findings. 1. The doc comment written "from memory" — checked against git history, not re-readThe new sentence on I did not take this on faith. Recovered the pre-deletion doc via Then I verified the mechanism against the actual pre-deletion code at
So a body that crosses a zone line airborne ( 2. "No reader anywhere" — tried to break it three ways, all clean
3. Compiler-probe premise — the "did it typecheck the whole workspace" questionCan't independently re-run the author's throwaway single-field-deletion probe (it was discarded), but I ran my own full-workspace build+test from scratch on the remote builder against this exact PR head, which is strictly stronger evidence: a full 4. PR #821 conflict check#821 holds 5. Test figures — independently re-derived on the merged tree, not accepted from the PR bodyPR head ( First run attempt was a false start worth flagging against myself: I backgrounded Full-workspace
This is an exact match to the baseline figures (55=55, 0 non-canonical, 14 all-zero, 1798+0+47+0=1845) — reproduced independently, not copied from the PR body. ConclusionEvery claim I attacked — the doc comment's mechanism, the "no reader" completeness, the semantic-disagreement between the two writers, and the test figures — checked out against source and independently-run evidence rather than the PR's own prose. This is a clean, correctly-scoped dead-field deletion. No blocking or non-blocking findings. |
What
Deletes
ControllerView.moving(crates/eqoxide-ipc/src/lib.rs) and its two write sites insrc/app.rs's render frame loop. Closes #746.Evidence that no reader exists
The field's own doc comment (pre-existing, written for #746) already stated the conclusion, but I
re-derived it independently rather than trust the comment:
grep -n "moving" crates/eqoxide-ipc/src/lib.rs— one declaration (pub moving: bool,), plusdoc-comment prose mentioning "moving" in unrelated contexts (a
desired_azimuthdoc, anEMA "moving average"doc, a test-freeze doc). No reader.grep -rn "ControllerView" --include=*.rs .across the whole tree — every hit is either thetype definition/impl, a doc comment, the
ControllerSharedalias, the one construction site(
ControllerView::default()insrc/main.rs), orsrc/movement.rs's re-export. No structliteral ever names
moving:, and no destructuring pattern (ControllerView { moving, .. })exists anywhere.
grep -n "\.moving" src/app.rs(field access, not the concept) — exactly two hits, bothwrites (
v.moving = false;andv.moving = intent.wish_dir[...] || !self.on_ground;),both through the
Arc<Mutex<ControllerView>>lock guardv. Neither is a read.grep -n "moving" src/app.rs(the broader concept, to catch coincidental matches) turns up ~30hits. I read every one. The overwhelming majority are a different, local
let moving: boolthat feeds
select_player_action(around line 1356) and a structurally identical local in theremote-entity animation path (around line 2626) — these are plain locals computed from
last_moved_at/speed, not reads of theControllerViewfield, andselect_player_action's ownmoving: boolparameter (line ~2482) is likewise unrelated. The rest are prose ("movingaverage", "moving the formula", "moving NPCs", etc.) with nothing to do with this field.
grep -rn "moving" crates/eqoxide-core/src/game_state.rs crates/eqoxide-http/src/observe.rs crates/eqoxide-net/src/action_loop.rs— zero hits that touchControllerView::moving. Nothingmirrors it into
GameState, nothing serializes it, andControllerViewitself derives onlyClone, Copy, Debug, Default— noSerialize, so it is not reachable via the/observeJSONeither. (Contrast
hold/afloat_stall, which are deliberately mirrored intoGameStateandpublished over HTTP — this field had no such path.)
The compiler oracle
Per the task's request, I ran this as an actual measurement, not just a grep. In a separate
throwaway worktree branched from the same
origin/maincommit, I deleted only the fielddeclaration (leaving both
app.rswrite sites untouched) and built the workspace on the remotebuilder (
cargo build --workspace --locked).Result: exactly two compile errors, both
error[E0609]: no field \moving` on type`std::sync::MutexGuard<'_, ControllerView>`
, pointing atsrc/app.rs's twov.moving = ...`lines — the same two lines identified by grep, and nothing else in the workspace failed to
compile. This is the proof the issue asked for: if any reader existed, removing the field would
have broken it too, and none did. Full compiler output:
Note the
available fieldslist itself:hold/afloat_stall(the two fields with definedclear paths) don't even appear there — they're private to the crate, invisible from
app.rs'scall site, which independently confirms they are read only through
ControllerView::publish_disclosures/disclosures, never as raw field access the waymovingwas.
I then discarded that throwaway worktree (
git worktree remove --force, branch deleted; it wasnever committed to
fix-746-moving) and made the real change in this branch: field + bothwriters removed together, so this branch's own build is clean start to finish.
The semantic disagreement between the writers
The two writers computed genuinely different things, which is itself part of the finding — had
anyone read the field, they'd have gotten an inconsistent answer depending on which writer fired
last:
src/app.rs:~1387(camera-init / first-seed arm):v.moving = false;— always false, regardlessof actual state, because nothing has stepped the controller yet.
src/app.rs:~1717(steady-state per-frame publish, gated oncamera_initialized):v.moving = intent.wish_dir[0] != 0.0 || intent.wish_dir[1] != 0.0 || !self.on_ground;— ahorizontal-wish-or-airborne predicate, recomputed unconditionally on every publish even on
rendered frames that did not step the controller (no collision, mid zone-load). That
unconditional recompute of
!self.on_groundis the concrete failure mode described in thefield's pre-existing doc comment and in PR revert(#746): un-publish player.moving — its clear is not continuous, so it lies across a zone load #792's independent review: a character that crosses a
zone line airborne would report a confident
moving: truefor the whole multi-second zone load,because the previous zone's
on_groundstate survives untouched through the gap. That is theconnected: true(connected/last_packet_age_ms are published ONLY by the render loop, which sleeps when the world dies — a dead connection reports connected:true forever #343) shape the issue warns about.Why deletion, not a reader
Per the issue's own framing and the "Options" section, deletion was the preferred close, and I
agree with the reasoning: the second writer has no clear-on-stop (unlike
hold/afloat_stall,which are explicitly cleared via
clear_hold()on the not-stepped path), so any reader wired toit inherits a false-positive window with no defined boundary. Giving it a reader would require
first giving it a real writer with a defined clear path — which is a new feature, not a fix for
this ticket — so I deleted it instead and left a note in the neighboring
afloat_stalldoccomment (which used to contrast itself against "the moving field's shape (see its doc above)")
pointing at the history instead of a doc that no longer exists.
Five-figure test results
Full workspace run on this branch (
cargo test --workspace --locked --no-fail-fastvia theremote builder), stdout/stderr captured separately. Completion was judged by the launching
process actually exiting (polled
kill -0on the PID until it failed), not by theFinished `test` profileline, which prints when the test binaries finish building — thatline does appear in this run's stderr, at line 292 of 347, followed by 55 more lines of test
execution output in stdout after it, confirming it was not mistaken for the completion signal.
Finished `test` profile [unoptimized + debuginfo] target(s) in 11m 02s(stderr; compilesentinel only, reported per the task's instruction, not treated as completion proof)
running [0-9]+ tests?headers vs 55test result:lines — equal (all in stdout;0 of either in stderr)
test result: (ok|FAILED)\. N passed; N failed; N ignored; N measured; N filtered out; finished in T)0 passed; 0 failed; 0 ignored, not a raw0 passedsubstring match, so a
0 passed; N ignoredtarget — there are several — does not count)of the 55
running N testsheader counts (1845 either way)This is an exact match to the
origin/mainbaseline in every figure (55=55, 0 non-canonical,14 all-zero, 1798+0+47+0=1845) — a pure dead-storage removal, as expected: nothing added, nothing
newly exercised, nothing broken.
NOT verified, and not claimed
task brief explicitly says a live run is not required here, and I did not launch one.
(re-adding the field and a reader compiles fine; the property being protected is "no reader
exists", which is what the grep + compiler-oracle steps above established, not something a unit
test can assert about future code).
ControllerViewor
GameState— this PR is scoped to ipc: ControllerView.moving has no reader anywhere — a dead field that becomes a false observable the moment anyone wires it up #746's exact field.