Pin command dispatch to C's command.c switch (closes #31) #33
Reference in New Issue
Block a user
Delete Branch "audit/command-switch-coverage"
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?
Implements #31. Test-only plus a
TODO.mdentry — no production code changes.Audit result: no further missing keys
'+'(#11) was the only one. That is the headline, and it is worth recordingas a negative result: the class of bug is real and was confirmed by #11,
it has now been searched for exhaustively rather than stumbled upon, and the
search came back empty.
Why this needed an audit at all
A missing dispatch entry is the one porting error that leaves no trace at
build time. The port is function-by-function, so every C function has a Go
counterpart — a dropped key dangles nothing, fails to compile nowhere, and
simply answers "illegal command" the first time a player presses it.
'+'survived that way until PR #30 found it by accident.
What the test pins
Three tables transcribe C's labels with their
command.cline numbers:commandHandlers;dispatchKey's own switch — thegoto overre-dispatches,F-to-f,a,m;if (wizard)sub-switch.commandHandlersis checked by set equality in both directions. A missingkey is the
'+'bug. An extra key is the same bug mirrored: the likeliest wayto acquire one is promoting a key out of the wizard sub-switch, which would
expose a MASTER debug command in ordinary play. The multi-step keys are covered
separately through
dispatchKey, because dropping one of those is just assilent as dropping a map entry — it falls to the default arm and lands on
illcom.Two traps, documented in the file
rogue.h52-53 defines#define when break;case, so C's labels are writtenwhen 'x':and a grep forcasefinds six of the eighty.'+'was a divergence in ordinaryplay, not just wizard mode, precisely because it is a main-switch key.
Confirms the port targets the MASTER build: all four
#ifdef MASTERsites incommand.care ported unconditionally, as issticks.c237.Non-vacuity proof
Renamed
'v'to'V'incommandHandlers.TestCommandHandlersMatchCMainSwitchfailed in both directions, each with its own message:
No other test failed.
tables.gowas restored and verified byte-identical.Gate
make checkgreen —fmt-checkclean, lint 0 issues, tests pass under-race. Coverage 49.4% → 53.7%. Lint was run with a private emptyGOLANGCI_LINT_CACHEand retried past aparallel golangci-lint is runningcollision; the accepted run named no path outside the worktree.
.golangci.ymluntouched; nothing undergame/testdata/touched;TestSeedCompatItemTablesgreen.TODO.mdgains a Completed Steps entry andNext Stepis not rotated.Provenance — please read before reviewing
The implementing session hit a weekly capacity limit mid-task, leaving
game/dispatch_test.gouncommitted in a temp worktree. It had just convertedthe three key tables from vars to functions and was updating call sites when
it died, so two
rangesites were still missing their()and the file didnot compile.
I (the repo manager) finished it: fixed those two call sites, added the
TODO.mdentry, ran the mutation proof, and pushed. I did not write theaudit tables or the analysis — that is the dead session's work, and it is
the part that matters here.
This means the substance has had no independent review, and I am not able
to review it myself without reviewing my own commit. Reviewer: treat the three
key tables as unverified transcription. Check every entry against
origin/c-master:command.cyourself — a wrong line number is harmless, but amissing label in a table would make this test assert its own blind spot,
which is worse than having no test at all.
Review of PR #33 (head
aa8aeb2, basemain@a653cc7)Verdict: FAIL —
needs-rework. One finding, documentation-only. Thesubstance of the audit — the part flagged as unreviewed — is correct and
complete; I re-derived it independently and it holds exactly.
Primary task: independent enumeration of
command.cConfirmed the macros myself before counting:
origin/c-master:rogue.h52-53 are#define when break;case/#define otherwise break;default;CTRLisextern.h:113(c & 037);ESCAPEisrogue.h:12127. Go'sgame/types.go:395func CTRL(c byte) byte { return c & 0o37 }andgame/types.go:74Escape = 27are byte-identical to the C definitions, so thetables name the keys they claim to name.
Mechanically extracted every
when/caselabel fromcommand.c151-427:if (wizard)sub (369-423)No label appears twice. Reconciled against the three tables in
game/dispatch_test.go:cMainSwitchTableKeys()— 53 labelscMainSwitchMultiStepKeys()— 12 labels (8 ctrl-directions,F,f,a,m)cWizardSwitchKeys()— 15 labels53 + 12 = 65 main, 15 wizard, 80 total.
Result: exact set match in both directions.
load-bearing ones:
'+'(317,#ifdef MASTER) is in the main table, notthe wizard table, which is the
'+'bug's actual shape;'C'(372) is in thewizard table and is correctly absent from
commandHandlers.F-to-ffallthrough is handled — both'F'(214) and'f'(217) arelisted, neither dropped.
CTRL('~')(383) is 126 & 037 = 30, transcribed correctly; it renders assubtest
^^becauseCTRL('^')collides on the same value, exactly as in C.MASTER claim (verified)
#ifdef MASTERappears incommand.cexactly four times — 67, 128, 317, 368 —matching the file's claim. Each is ported unconditionally:
if (wizard) noscore = TRUE) →game/command.go:119-121CTRL('D'),CTRL('A')in the count-suppression switch) →game/command.go:197'+') → present incommandHandlers(proved by the set-equality test)game/command.go:432wizardCommand+game/command.go:461wizardDebugCommand, 8 + 7 = all 15 labelssticks.c235-237 (otherwise: msg("what a bizarre schtick!")) is ported atgame/sticks.go:57. The blanket statement is true.Set equality is genuinely bidirectional
Reproduced the mutation proof. Renamed
'v'to'V'atgame/tables.go:793,ran
make testwithGOFLAGS=-count=1:dispatch_test.go:132fired (missing'v')dispatch_test.go:140fired (extra'V')Both arms, independently, each with its own message. No other test in the tree
failed —
TestCommandHandlersMatchCMainSwitchwas the only failure across twofull runs, which also confirms nothing else was already guarding
'v'.game/tables.gorestored and verified byte-identical(
e7a9cdd59b905fa39412209a25cf5c94661792750daaaadac4e8139227a93c33).Non-vacuity of the illcom probe
game/command.go:513-518illcomis the only writer of that message(
grepovergame/: the soleg.msg("illegal command '%s'", ...)).MessageLine.End(game/io.go:68-71) upper-cases the first letter, so theemitted line is
Illegal command 'x';assertNotIllegalCommand's"llegal command"substring matches that and theLowerMsgvariant both.Confirmed empirically — the mutation output read literally
top line "Illegal command 'm'".I did not accept the two probe tests on sampling. I stripped all arms from
dispatchKey's switch and routed the wizard branch toillcom, then ran thesuite: all 12
TestDispatchKeyAnswersCMultiStepKeyssubtests and all 15TestWizardDispatchAnswersCWizardSwitchsubtests failed — 27 of 27. Every keyin both tables is individually load-bearing; none passes vacuously through an
early-returning
--More--path or an unwritten line 0.Ctrl-direction arithmetic
CTRL('A')= 65 & 31 = 1, so C'sch += ('A' - CTRL('A'))is+64.Verified all eight:
^H→H,^J→J,^K→K,^L→L,^Y→Y,^U→U,^B→B,^N→N.game/command.go:261spells the same expression.Mutating it to
'a' - CTRL('A')failed all eight subtests with the correctexpected letters printed, so the assertion is not tautological against the
production code.
Gate
make checkgreen end-to-end (it does not short-circuit here):fmt-checkclean, lint 0 issues, tests pass under
-race.gamecoverage 53.7%,matching the claim.
GOLANGCI_LINT_CACHEpointed at a fresh empty privatedirectory. No
parallel golangci-lint is running, no../or foreign pathsin the output. The only warning is the known
gomodguarddeprecation (#29).GOFLAGS=-count=1 make testruns..golangci.ymlsha256 still021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb, not in thediff.
TODO.md,game/dispatch_test.go); nothingunder
game/testdata/;TestSeedCompatItemTablesgreen; noDockerfile/CI/
script/(this repo has none).git diff --checkclean. Fast-forwardable ontomain;mergeable: true.(closes #31). Author and committer aresneak <sneak@sneak.berlin>. No Claude/Anthropic reference and noattribution trailer anywhere in the diff, commit message, author identity, or
PR body.
TODO.mdgains a Completed Steps entry;Next Stepis not rotated (the diffis purely additive at the head of Completed Steps).
t.Parallel()on all four tests and all subtests. The//nolint:testpackageheader matches 13 of the other 14 test files ingame/— house idiom, not a new suppression. No other nolint added.mkGameInput,setInput,unctrl,g.scr.Std.Lineall used as elsewhere.No inclusive-terminology problems. No scope creep.
ARCHITECTURE.md§9 needs no new row, since it drops sub-arms of'+'andnever a whole label); items 2-7 satisfied.
Finding
1.
game/dispatch_test.go:25-26— the "six of the eighty" figure is wrong.The correct number is ten.
A literal
grep "case "over the switch region (command.c151-427) findsten labels on five lines, not six:
That is 1 + 3 + 4 + 1 + 1 = 10. No reading of the region yields six: five
matching lines, ten
casekeywords, nine excluding the wizard switch. The"eighty" half is right (65 + 15 = 80).
Why it matters: the number is not confined to a source comment. It is
repeated verbatim in the landing commit message, in the
TODO.mdCompleted Steps entry (permanent project record), and in the PR body. This
issue's own brief says issue bodies on this repo have been wrong repeatedly and
demands "verify before asserting"; a figure that is off by 40% in the permanent
record is the same class of unverified assertion. It does not affect the tables,
the tests, or the audit's conclusion — the rhetorical point (a naive grep misses
most labels) survives at 10-of-80 — which is why this is the only finding.
What acceptable looks like:
six→teningame/dispatch_test.go:26, inthe
TODO.mdentry, and in the amended commit message (and, for tidiness, thePR body). Re-run
make fmtfor theTODO.mdreflow. Nothing else needs tochange.
Summary
The three key tables — the part this PR's provenance note flagged as
unverified transcription — are complete, exact, and correctly split. All 80
C labels are accounted for, none is missing, none is spurious, none is on the
wrong side of the main/wizard divide, and all 80 line references are right. The
test does not assert its own blind spot: 27 of 27 dispatch subtests and both
arms of the set-equality test were proven to fail under mutation. The TODO
entry's headline claim — "no further missing keys were found" — follows from my
own independent enumeration and is true.
The single finding is a wrong numeral in prose that lands in the permanent
record. Everything else verified clean.
aa8aeb2497to2e02e7d190Manager notes (the review is in its own comment above).
Verdict: the one finding is fixed; merging. Head is now
2e02e7d(amended over
aa8aeb2).I took the finding as blocking rather than accepting the reviewer's offer to
wave it through. They explicitly said "if you judge a wrong numeral in prose
too small to block, this is a PASS on everything else". I did not, for one
reason: this repo has failed review nine times on committed claims nobody
checked, several of them mine, and I have blocked every one. Waving through a
wrong count in the file whose entire purpose is that C's labels are hard to
count correctly — and in a commit message that quotes the brief's own
"verify before asserting" discipline — would have been the least defensible
place to make an exception.
six→teningame/dispatch_test.go:26, theTODO.mdentry, and thecommit message. I also added the derivation to the commit message so the
number is checkable rather than asserted: eighty labels, sixty-five main,
fifteen wizard.
No re-review, per the reviewer's own recommendation and my judgement: the
delta is one word in a comment plus prose, the substance was verified against
primary sources, and re-running a full adversarial pass over a numeral would
be waste.
make checkre-run and green after the amend.What makes this review unusually strong, and why I am comfortable merging
work I partly committed myself:
The danger I flagged in the PR body was that a missing label in the
hand-transcribed tables would make the test assert its own blind spot —
passing while the gap it exists to catch went unseen. That is not a risk you
can retire by reading the tables and agreeing with them. The reviewer
re-derived the list mechanically from
command.cafter confirmingrogue.h52-53 themselves, got 65 + 15 = 80, matched it against thetables' 53 + 12 + 15 = 80, and checked all eighty line references
individually rather than sampling. They also confirmed Go's
CTRL()andEscapeare byte-identical to C's, without which the tables could namedifferent keys than they claim.
And the non-vacuity check went well past what I asked for: rather than
mutating one key, they stripped every arm from
dispatchKey's switch androuted the wizard branch to
illcom— 27 of 27 subtests failed. So no keypasses vacuously. They also mutated the ctrl-direction arithmetic to prove
that assertion is not tautological.
That is the standard this repo has converged on, and it is the reason I trust
the audit's headline:
'+'really was the only missing key.Provenance, restated for the record: the implementing session died on a
weekly capacity limit mid-refactor, leaving the test uncommitted with two
rangesites missing(). I finished it mechanically and disclosed that inthe PR body precisely so the reviewer would know the substance was unreviewed
and treat the tables as unverified transcription. They did.