.golangci.yml is the prompts-repo standard verbatim plus one approved
exception (paralleltest, sneak 2026-07-06). Roughly 1,500 findings
fixed:
- autofix sweep (wsl_v5/nlreturn/intrange/modernize formatting), with
the misspell autofix REVERTED where it rewrote authentic C game text
("missle vanishes" stays, with nolint and a comment)
- error handling: errcheck sites get real handling — saveFile now
closes explicitly and removes corrupt saves, scoreboard writes are
documented best-effort, err113 sentinel errors (ErrSaveOutOfDate,
ErrScreenTooSmall); panics allowed for unrecoverable states per
MEMORY.md policy
- gosec: real fixes (ParseInt for SEED, 0600 scorefile) and justified
per-line nolints for provably-bounded conversions (randomMonsterLetter
helper collapses eight rnd(26)+'A' sites)
- API tidying from linters: pointer receivers on flag types
(recvcheck), msg helpers renamed addmsgf/doaddf/Printwf/MvPrintwf
(goprintffuncname), myExit()/findFloor(monst)/mkGameInput(t) drop
always-constant params (unparam), gameEnd carries no status
- gocritic/staticcheck: if-else chains to switches, the pack.c
inventory filter untangled into matchesFilter, main.go split so
defers run before exit (exitAfterDefer, funlen)
- revive doc comments on all exported flag types/consts/methods
Remaining findings are confined to linters pending sneak's exception
decision (mnd, gochecknoglobals, cyclop, nestif, gocognit, exhaustive,
goconst, testpackage); TODO.md records the state. MEMORY.md added at
repo root as the project's agent working notes.
ObjectKind separates what an item is from how it draws: Object.Type
(a byte that doubled as the map character) becomes Kind ObjectKind,
with Glyph() producing the display character and objectKindForGlyph
converting back at the map boundary. KindWand covers the C 'stick'
category. The magic-missile bolt uses KindGold, matching C's literal
o_type='*' trick, with a comment.
PotionKind, ScrollKind, RingKind, WandKind, WeaponKind, ArmorKind and
TrapKind are now iota enums with Stringer (names come from the base
info tables); Object gains typed accessors (obj.RingKind(), ...) and
Launch is typed WeaponKind. beTrapped returns TrapKind. The
getItem/inventory/whatis prompt filters take ObjectKind, with
KindCallable/KindRingOrStick replacing the C CALLABLE/R_OR_S
sentinels; wizard.c's type_name table is subsumed by
ObjectKind.String(). IsRing/IsWearing/initWeapon/doPot signatures are
typed accordingly.
The save format version becomes 5.4.4-go2: the gob field rename would
otherwise silently zero Kind when reading old saves.
No behavior change; full suite green.
rooms.c, passages.c, new_level.c ported in full: room/maze layout,
corridor spanning tree with extra connections, passage numbering flood
fill, trap/stairs/object placement, treasure rooms. Careful RNG-call
ordering throughout keeps generation seed-faithful to C.
Supporting subsystems this depends on, also ported:
- screen.go: curses replaced by in-memory Window cell buffers behind a
Terminal interface (tcell arrives with the UI phase; tests run headless)
- io.go: msg/addmsg/endmsg message-line protocol, status line, step_ok
- pack.c in full (add_pack sorting/stacking walk, get_item, inventory)
- things.c in full (inv_name, new_thing, discovery lists, pagination)
- monsters.c in full; chase.c navigation half (roomin/cansee/see_monst/
find_dest/runto/set_oldch); rings.c, armor.c in full
- weapons.c/sticks.c creation half (init_weapon, fix_stick, num)
- misc.c look() display update, eat, level-up, direction input
- daemons.c callbacks except stomach (needs death()) and the runners
chase driver (combat phase)
- init.c init_player with the starting kit
Tests: level invariants across seeds, determinism, 30-depth sweep.