MORE_NEEDED_CAMPAIGN.md
Status: Merged (March 6, 2026)
Operation More Needed has been merged to main. This document is retained as a
historical record of the campaign’s goals, fixes, and methodology. For current
parity work, see PROJECT_PLAN.md and the open GitHub
issues.
Execution Update (March 4, 2026)
MORE_NEEDED implementation and parity-fix work now lands directly on main.
Treat this document as the campaign tracker, but use main as the active
integration branch for day-to-day engineering updates.
Campaign Name
Operation More Needed
Why This Campaign Exists
When NetHack displays --More--, C gameplay pauses until the player presses a key.
The JS port was approximating this — queueing messages, batching output, and
suppressing some prompt events — producing timing and display divergences that
cascaded into hard-to-diagnose parity failures.
This campaign makes --More-- handling explicit throughout:
- Sessions record actual key steps for every
--More--dismissal (no auto-suppression). - JS message/display paths are async so gameplay can pause exactly when C does.
- Event logs capture the truth (
^eventannotations in sessions). - Comparator layers bear the flexibility burden; replay execution stays simple.
The branch name is the mission statement: more is needed — more explicit key steps, more event evidence, more async fidelity, more parity.
Background (What Changed)
This branch was created after Operation Iron Parity was assessed as unsuccessful for near-term parity closure (March 4, 2026). The pivot:
- Many real
--More--prompts had been auto-suppressed in sessions, with compensation logic inreplay_corehiding meaningful gameplay complexity. - An erroneous C-side patch had been changing gameplay behavior during instrumentation; corrected.
- Replay execution simplified: replay keys, capture outputs; no gameplay-aware queueing or squashing logic in replay core.
- Flexible/tolerant handling moved to comparator/reporting code.
- Sessions re-recorded with:
- richer
^eventlogging (monster movement, dog AI, map wipe, engravings, etc.), - corrected PRNG instrumentation behavior,
- explicit space-key steps for
--More--dismissals (record_more_spaces), - refreshed gameplay baselines against current C binary.
- richer
- Async message flow refactors begun:
pline/message paths made async so gameplay can pause exactly at--More--.
- Cursor-position capture/comparison added to the test harness.
Work Completed on This Branch
Concrete fixes already landed:
--More--async chain —plineand message display paths refactored to be async-capable; gameplay pauses correctly when C does.^eventlogging —^distfleeck,^movemon_turn,^wipe,^dog_move,^dog_goal,^dog_invent_decision,^mcalcmove, and others added to C harness and JS runtime for parity comparison.- Session re-recording — all 42-seed gameplay sessions re-recorded with
record_more_spaces=trueand the new event logging baseline. - Group E fix (seed42_items, dog display at step 20) —
--More--dismissal during eating occupation now correctly processes a monster turn in JS. - Group F fix (
interface_nameprompt, ‘A’ command) —handleRemoveAllimplemented indo_wear.js, wired to ‘A’ incmd.js, with correct overlay menu rendering (inverse video on prompt row) inheadless.js. - Group A fix (seed100
^wipere-record) — sessions re-recorded so^wipeonly appears when an engraving actually exists, matching current C behavior. - Cursor channel — cursor position captured per step in C harness and JS
HeadlessDisplay; comparator reports cursor divergences (non-blocking). - Overlay menu prompt rendering —
renderOverlayMenuline 0 renders with inverse video (attr=1) to match Ctty_select_menubehavior. - Engraving visibility fix —
newsym()andrenderDisplayMap()now setengr.erevealed = truewhen a square is visible, matching C display.c:963-964. Previously engravings at visible squares showed as floor tiles until explicitly read or felt. Also fixed statue object naming (“statue of a sewer rat”). Resolved: #215.
Current State (latest gate run)
Session suite: 124 / 150 passing (26 failing).
Fixes landed since last triage:
- seed305 fixed (engraving
erevealed+ statue naming):newsym()andrenderDisplayMap()now setengr.erevealed = truefor any visible square, matching C display.c:963-964 (“even when covered by objects or a monster”). Statue object names now include the monster type (“statue of a sewer rat”). seed305 now passes all channels (RNG 8209/8209, events 3081/3081, screen).
Observed failure taxonomy (all 26 failing sessions triaged):
-
dochugmonster-movement/pet-AI divergence (~14 sessions, dominant): First RNG mismatch is JS atdochug(monmove.js:847)while C is at a completely different callsite —dog_move,do_attack,m_move,dog_invent,mcalcmove,teleport,obj_resists, etc. This single codepath is the #1 blocker. Affected sessions include seed031, seed303, seed304, seed306, seed307, seed308, seed310, seed311, seed325, seed329 and others. -
Level-generation divergence (~7 sessions, Group D wizard seeds): Divergence in dungeon/object placement code:
themeroom_fill,makerooms,makedog,get_location_coord,newobjinsp_lev. Several diverge at step 1 immediately after descending to a new level. Affected: seed321, seed323, seed326, seed327, seed328, seed330, seed331. -
Other gameplay divergences (~4 sessions): Miscellaneous first divergences: seed302 (
getbones— bones-file loading), seed322/seed332/seed333 (combat and makemon paths diverging late in long sessions), seed312 (wipe_engr_atvsmcalcmove). -
Manual-direct message/turn boundary divergence (1 session):
seed033_manual_directcurrently fails as gameplay divergence (rhackvsmcalcmovefirst RNG mismatch) with^mcalcmoveevent disagreement.
Active Workstreams
Team execution lanes (GitHub issues linked):
dochugmonster-movement/pet-AI divergence (primary blocker, ~14 sessions) — #213:- Investigate
dochug(monmove.js:847): why does JS arrive there when C is indog_move,do_attack,m_move, etc. at the same RNG position? - Likely root causes: JS processes extra or wrong monster turns, or takes a different code path for a monster type/situation that C handles differently.
- Fix
dochug/distfleeck/dog_goalordering and decision-path mismatches using^eventtraces. Prioritize fixes that move first divergence later across many sessions simultaneously. - Related: #170 (dog_goal food eval), #8 (pet combat/dog_move sequencing), #11 (pet-position render drift)
- Investigate
- Level-generation divergence in wizard sessions (~7 sessions) — #214:
themeroom_fill,makerooms,makedog,sp_levplacement paths diverge from C when descending to new dungeon levels.- Investigate whether JS level-gen code matches C order for room filling, object placement, and monster initialization in special rooms.
- Related: #165 (room and maze generation parity)
- Screen-only rendering bug (1 session — seed305) — #215:
- RNG and events match fully; screen diverges on tile/symbol rendering.
- Fix the specific display path producing wrong tile (e.g.,
·vs`).
- Manual-direct boundary stabilization (targeted, 1 session) — #216:
- Resolve
seed033_manual_directcommand/turn ordering mismatch (rhack-side RNG in JS vsmcalcmove-side RNG in C). - Use
^mcalcmoveand surrounding--More--/message evidence to confirm correct pause and progression ordering.
- Resolve
- Cursor parity closure (tracked in
docs/CURSOR_PLAN.md):- Complete JS
setCursor/getCursorintegration across display paths. - Add cursor comparison to gameplay session suite.
- Align gameplay/topline/prompt cursor behavior with C.
- Complete JS
- Async message-flow parity (ongoing):
- Propagate async call chains wherever C behavior can block on
--More--. - Eliminate any remaining queueing-era approximations that mask ordering.
- Propagate async call chains wherever C behavior can block on
- Event fidelity (ongoing, supports all lanes):
- Add instrumentation where first-divergence evidence is thin.
- Keep instrumentation behavior-neutral (no gameplay side effects).
Non-Negotiable Rules
- Instrumentation must not change gameplay semantics.
- No suppression or normalization of real
--More--, RNG, screen, typgrid, or cursor differences to improve pass rates artificially. - Replay core remains execution-simple; comparison flexibility belongs in comparator code.
- Session fixtures are evidence artifacts, not hand-tuned outputs.
- Re-recording a session is valid only when the C binary behavior changed; re-recording to match a JS bug is not permitted.
Success Criteria
Operation More Needed is successful when all are true:
- Remaining gameplay failures are reduced to an agreed merge threshold, with first-divergence clusters materially narrowed and documented.
- Cursor channel is captured and compared for gameplay suites.
--More--handling is explicit in sessions and correctly replayed with no suppression-era approximations remaining.- Re-recorded session corpus is stable and trusted as parity evidence.
more-neededis merged intomainwith maintainer sign-off.
Merge Gate
Before merging more-needed into main:
- Keep unit/infra gates green (or explicitly document blockers).
- Demonstrate gameplay parity improvement against the Iron Parity baseline.
- Publish a short merge note summarizing:
- what changed architecturally (async message flow, event logging, session re-recording),
- which parity channels improved (events, screens, colors, cursor),
- remaining known gaps and follow-up issues.