Audit C's command switch against commandHandlers for other silently-dropped keys #31
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
'+'(#11) was missing fromcommandHandlersand answered"illegal command '+'" where C answers "sorry". Nobody found it by
auditing — it surfaced incidentally during a survey. Nothing has ever
checked C's command switch against the Go dispatch table, so there is no
reason to believe
'+'was the only one.The port is otherwise function-by-function faithful, which makes a
key-by-key gap especially easy to miss: every function has a counterpart,
so a missing dispatch entry leaves no dangling reference and no compile
error. It fails silently, at runtime, only when a player presses the key.
'+'also showed the failure is subtler than "the key does nothing": it livedin C's main switch rather than the
if (wizard)sub-switch, so thedivergence existed in normal play too, not just wizard mode. An audit needs to
respect that distinction.
Definition of done
command.ccommand switch — both the mainswitch and the
if (wizard)sub-switch — is accounted for, as exactly oneof:
commandHandlers(or the wizard dispatch, matching C'splacement); or
ARCHITECTURE.md§9 as deliberately dropped, with the reason.drift again. The mechanism is yours to choose — a table of expected keys
checked against
commandHandlers, with a comment pointing at the C switch,is probably enough. It must fail if a key is removed from the dispatch
table.
filed as its own issue — do NOT bulk-implement a pile of behaviours in
an audit commit. Report what you found and split.
#ifdef MASTERblocks are handled explicitly: state whether the porttargets the MASTER build or not, and apply that consistently. (
'+'wasinside
#ifdef MASTER, and was ported.)make checkfully green.TODO.mdupdated in the same commit — Completed Steps entry, do notrotate "Next Step".
(closes #N).Implementation requirements
git show origin/c-master:command.cin full. Do NOT check out ormodify
origin/c-masterormodern-rogue.whenmacro — it expands tobreak; case, so case labels do notlook like ordinary C
casestatements. A naive grep forcasewill missthem.
'+'is writtenwhen '+':.wizard mode (or vice versa) is a divergence even if the key "works".
this audit — note it and file separately. This issue is about presence.
wrong repeatedly, including several written by me. If this description is
wrong when you check it, say so and stop.
concurrent sessions and has produced a false green here. Export
GOLANGCI_LINT_CACHEto a fresh empty private directory beforemake lint/make checkand confirm no foreign paths appear in the output.maketargets only. Do NOT modify.golangci.yml. No Dockerfile/CI/script/.game/testdata/.Priority
Medium. No known defect behind it — but
'+'proves the class exists, andthe audit is bounded, one-time, and leaves a regression test behind.
Audit done (read-only); implementation plan
Verified the issue's premises before planning — all three hold:
origin/c-master:rogue.h52-53 really are#define when break;caseand#define otherwise break;default, so agrep 'case 'finds ~6 of ~75 labels.CTRLisextern.h:113,(c & 037);ESCAPEisrogue.h:121,27.command.c151-427 andif (wizard) switch (ch)at 369-423, inside theotherwise:arm.#ifdef MASTERappears exactly 4 times incommand.c— lines 67(
wizardimpliesnoscore), 128 (^D/^Ain the count-suppressionswitch), 317 (
'+'), 368 (the whole wizard sub-switch). All four areported unconditionally, so this port targets the MASTER build, and that
is consistent. Matches
sticks.c:237from #13.Result: no further missing keys.
'+'was the only one.Mechanically extracted every
when/case/otherwiselabel in 151-427 andmatched it against the Go dispatch. 60 main-switch labels, 15 wizard-switch
labels, all accounted for, and all on the correct side of the main/wizard
split. Nothing needs adding to ARCHITECTURE.md §9 — no case label is
dropped. (The one §9 entry that touches this switch, the
passwd()enterarm of
'+', is a sub-arm of a present key, not a missing label.)Cross-check in the other direction also passes: Go's
commandHandlershas nokey C's main switch lacks, and the wizard-only keys (notably
'C') sit inwizardCommand, not incommandHandlers— C's placement.Plan
No behaviour change; the deliverable is the regression test.
game/dispatch_test.gowith three tables transcribed from the Cswitch, each carrying the
command.cline range it came from:cMainSwitchTableKeys— the 48 main-switch labels Go answers fromcommandHandlers;cMainSwitchMultiStepKeys— the 12 whose arms need a re-dispatch(
goto over) or a fallthrough and so live indispatchKey's ownswitch: the 8 ctrl-directions,
F,f,a,m;cWizardSwitchKeys— the 15 sub-switch labels.cMainSwitchTableKeysand the actual keys ofcommandHandlers— both directions, so it fails on a removed key andon a wizard key wrongly promoted into the main table;
cMainSwitchMultiStepKeyskey is claimed bydispatchKeyratherthan falling through to
illcom, asserted on its return value andflags (
runCommandonly sets flags;'a're-dispatchesLastComm;F/f/mgetEscapeat the direction prompt, which makes themside-effect-free while still proving the arm ran);
cWizardSwitchKeyskey is claimed bywizardCommand, checked as"the top line does not read
illegal command", one fresh game per key.Safe against prompts:
testTerm.ReadCharnever blocks or exhausts.the failure, then restoring.
TODO.mdCompleted Steps entry, noNext Steprotation.Nothing to file separately: no missing key, and no key that is present but
behaves differently turned up in the presence pass.