Skip to content

Commit d45bc9c

Browse files
thefallentreeclaude
andcommitted
Remove leftover debug printf leaking internal object path in xianlvqiyuan
adm/daemons/logind.lpc's get_name() had a leftover printf("%O\n", ob) that printed the login object's raw internal path (e.g. /obj/login#2) to every new player, between the Chinese-name prompt and the password prompt. Confirmed live pre/post fix. Two unreferenced duplicate daemon files carry the identical leftover line but are never loaded (LOGIN_D points only at logind) -- left untouched per the dead-code convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VyQCUoTo1Z93Py9aVFHQi1
1 parent bd1412d commit d45bc9c

2 files changed

Lines changed: 225 additions & 1 deletion

File tree

libs/xianlvqiyuan/NOTES.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,228 @@ as remote/untrusted. Retested: fresh registration (id `xlqygate`, name
210210
all correct); fluffos login + `update /adm/daemons/band` still succeeds
211211
(`重新编译 /adm/daemons/band.lpc:成功!`). Zero new runtime errors. Test
212212
char save removed after verification.
213+
214+
## 深度功能测试 / Deep functional test (2026-07-24, AGENTS.md §10.7)
215+
216+
Full checklist pass: read `doc/help/newbie` first (confirms start room
217+
南城客栈, sect-join via `apprentice`/`recruit`, `learn <skill> from
218+
<teacher>`, `wimpy` for safe retreat, and the game's own advice to spar
219+
low-level NPCs rather than a dedicated dummy). Native driver, port
220+
40032, one continuous `scripts/mudclient.py` session per phase,
221+
`debug.log` grepped after every `quit`/reconnect. Registered several
222+
real-Chinese-name characters over the session (`吴垚`/wuyao,
223+
`林清羽`/linqing, `林清月`/linqingm, `王承志`/wangchz, `姚心薇`/yaoxinw,
224+
etc.) — final debug.log byte count is **identical** to the pre-session
225+
baseline (`work/log/debug.log`, 31531 bytes, last real content from a
226+
prior pass) through the entire test: registration ×many, sect join,
227+
organic skill learning, a real fight, a shop purchase attempt, three
228+
`quit`s, two unclean (net-dead) disconnects with both prompt and
229+
delayed reconnect, and one clean-quit-then-wait-then-relogin — **zero
230+
new lines**, i.e. zero runtime errors surfaced anywhere in this pass.
231+
232+
### Bug found and fixed: leftover debug `printf("%O", ob)` leaks the login object's internal path to every registering player
233+
234+
`adm/daemons/logind.lpc`'s `get_name()` (the Chinese-name step of new
235+
registration) had `printf("%O\n", ob);` immediately after the
236+
name-validation block and before `ob->set("name", arg)` — no comment,
237+
serves no functional purpose, clearly a leftover debug statement from
238+
development. `%O` on FluffOS renders an object's identity as its file
239+
path plus clone index (`/obj/login#2`), so **every single new
240+
registration** showed a raw internal object reference between the
241+
Chinese-name prompt and the password prompt:
242+
243+
```
244+
您的中文名字:/obj/login#2
245+
请设定您的密码:
246+
```
247+
248+
Confirmed live pre-fix (multiple registrations, e.g. id `shendep`/`沈德鹏`,
249+
id `wuyao`/`吴垚`) and confirmed gone post-fix (id `yaoxinw`/`姚心薇`: the
250+
Chinese-name prompt now falls straight through to the password prompt
251+
with no stray line). This is a real, if minor, programming defect —
252+
unintentional internal-state disclosure to every new player, not a
253+
design choice (there is no explanatory comment, and every sibling
254+
`get_*` step in the same file is otherwise clean of debug output).
255+
256+
Fix (`adm/daemons/logind.lpc:614`, in `get_name()`): deleted the line.
257+
258+
```lpc
259+
// BEFORE
260+
printf("%O\n", ob);
261+
ob->set("name", arg);
262+
// AFTER
263+
ob->set("name", arg);
264+
```
265+
266+
Two structurally-identical dead copies of the same daemon —
267+
`adm/daemons/login.lpc:606` and `adm/daemons/loggind.lpc:564` (note the
268+
double-g typo'd filename) — carry the exact same leftover `printf`, but
269+
neither file is ever loaded (`LOGIN_D` in `include/globals.h` points
270+
only at `/adm/daemons/logind`, and `grep -rn` confirms no code anywhere
271+
references `/adm/daemons/login` or `/adm/daemons/loggind`). Left
272+
untouched per AGENTS.md's dead-code convention — not on any live path.
273+
274+
**This doesn't match any existing AGENTS.md §7 bug class** (closest is
275+
§7.10/§7.26, but those are about `log_error()`'s own ACL/attribution,
276+
not a stray developer `write`/`printf` shipped into a live prompt
277+
sequence). Draft class for AGENTS.md, offered in the session report
278+
rather than committed here per task instructions.
279+
280+
### Root-caused, not fixed: the "default error message" noise is a real (but practically harmless) race between a 0-delay `call_out` and fast/scripted client input
281+
282+
This lib's NOTES.md (and sibling `xianlvqingyuanzheda`'s) already
283+
documented an unexplained, non-deterministic appearance of the driver's
284+
own `default error message` (`adm/etc/config.xiyou:126`, "你发现事情不
285+
大对了,但是又说不上来。") during registration, with no fix attempted
286+
because no deterministic trigger had been found. This pass pins the
287+
exact mechanism:
288+
289+
`enter_world()` (`adm/daemons/logind.lpc`) moves a brand-new character
290+
into `/d/wiz/init` (the gift-allocation room) synchronously. That
291+
room's `init()` (`d/wiz/init.lpc`) does **not** register its
292+
`input_to("get_input", ...)` synchronously — it schedules
293+
`call_out("get_start0", 0, me)`, and only `get_start0()` (running on
294+
the *next* server tick, not the same call stack) actually calls
295+
`me->command("start")`, which is what ultimately shows the gift menu
296+
and registers the real `input_to`. Between the room-entry text
297+
finishing ("...局面进入请先help whatsnew。") and that call_out actually
298+
firing, the player is briefly a normal command-dispatch target with
299+
**no** matching `add_action` and **no** pending `input_to` — any input
300+
arriving in that window is treated as an unrecognized ordinary command,
301+
producing the driver's generic `default error message` fallback
302+
instead of anything the room intended, and — if a script (not a human)
303+
keeps firing more scripted input immediately afterward — misaligns
304+
every subsequent scripted answer by one, cascading into a real
305+
false-negative test failure (confirmed: a batch of `9`/`y`/`look`/etc.
306+
sent at `--idle 0.4``0.6` reliably desyncs the whole gift-selection
307+
exchange, while the identical batch at `--idle 3.0` never reproduces
308+
it, 1-for-1 across repeated trials).
309+
310+
**Not fixed, and not proposed as a new AGENTS.md class**: this requires
311+
input arriving inside a sub-second window immediately after the room's
312+
banner text — no real human types that fast, and a human who *did* see
313+
the stray "default error message" would simply see the real gift menu
314+
appear a moment later and answer it normally (the call_out reliably
315+
fires within well under a second even under this host's heavy
316+
concurrent-agent load in every trial observed). The mechanism is now
317+
understood and written down here so the next tester of this lib or its
318+
XLQY-family siblings doesn't have to re-derive it, but per §10.7's
319+
scope note this reads as a test-harness-timing artifact with no
320+
demonstrated real-player impact, not a programming defect to change
321+
code for.
322+
323+
### Sect join and organic skill learning — both verified live, no bugs
324+
325+
Followed the newbie doc's own path: `kezhan` (南城客栈, start) → `west`
326+
`north` reaches 十字街头 (`d/city/center.lpc`), where 张果老
327+
(`d/qujing/wuzhuang/npc/zhangguolao.lpc`, a 五庄观 sect teacher) stands
328+
reachable in exactly 2 moves from spawn. `apprentice zhang` correctly
329+
completed the kowtow flow and joined 五庄观 as its 4th generation
330+
disciple (`score` afterward showed `门派:五庄观` / `师承:五庄观张果老`
331+
correctly). `skills zhang` listed his teachable skills; `learn force
332+
from zhang` correctly charged spirit, printed "你的「内功心法」进步
333+
了!", and `skills` afterward showed `内功心法 (force)` newly at level
334+
1 — the full organic teacher-NPC path works end to end. The NPC's own
335+
`attempt_apprentice()` uses `command("recruit " + ob->query("id"))` to
336+
self-accept — this lib's `command_hook` is correctly **not** `private`
337+
(`feature/command.lpc:35`, with a stale `// private nomask...` comment
338+
above it showing this was already fixed in an earlier pass, just never
339+
written up) — so this NPC-issued `command()` call dispatches correctly
340+
(the §8.3a addendum shape that broke `xuanjianlu`/`shiji` does **not**
341+
recur here; already fixed, confirmed live).
342+
343+
### Safe-sparring mechanism exists in source but is unreachable content (not a bug — documented, not touched)
344+
345+
Two byte-identical files, `d/city/obj/muren.lpc` and
346+
`d/obj/misc/muren.lpc` ("木人"/wooden training dummy), implement exactly
347+
the §10.7-checklist "mirror the attacker's own stats in `accept_fight()`"
348+
safe-sparring pattern this project looks for first. Neither file is
349+
referenced from any room's `set("objects", ...)` anywhere in the
350+
tree (`grep -rln "muren"` outside the two files themselves returns
351+
nothing) — genuinely orphaned dev content, not wired into the live map
352+
in this archive snapshot. Several other NPCs that look like they
353+
*should* be teachers reachable near town (`d/city/npc/shubao.lpc`
354+
秦琼, `d/changan/npc/huang.lpc` 黄飞虎, both with full
355+
`recruit_apprentice`/`attempt_apprentice` bodies) are similarly
356+
orphaned — likely-live-elsewhere duplicates of NPCs that DO appear in
357+
reachable rooms under different paths (e.g. `d/jjf/npc/qinqiong.lpc`).
358+
This is a content gap (§13-shaped), not a programming defect — the
359+
newbie doc itself already documents the actual intended safe-practice
360+
method as fighting low-level, similarly-matched NPCs and using
361+
`wimpy`, not a dedicated dummy, so nothing was changed. Followed that
362+
documented path instead (below).
363+
364+
### Combat, wimpy, and a shop purchase — verified live
365+
366+
`wimpy 70` set, then walked to 鞋帽店 (`d/city/zhuque-s3.lpc`
367+
`xiemao.lpc`, `west, south, south, east` from spawn) and `kill yitai`
368+
(二姨太, `d/city/npc/eryi.lpc`, `combat_exp` 1000 — the lowest-`combat_exp`
369+
reachable-and-attackable NPC found within a 4-room BFS of spawn).
370+
Combat played out with real damage messages on both sides; the
371+
character's 气血 dropped into the "受伤"/"似乎非常疲惫" bands and the
372+
`wimpy` auto-flee correctly triggered ("看来该找机会逃跑了..."),
373+
succeeding on the second attempt and returning the character to 朱雀大街
374+
unharmed further — the self-preservation mechanism the newbie doc
375+
promises works as documented. Did not reach death/respawn this pass
376+
(fled before that point, by design) — **death/reincarnation is
377+
therefore unverified live**, noted explicitly rather than assumed
378+
tested. `list` at 南城客栈 and 鞋帽店 both rendered real shop
379+
inventories; `buy huasheng from xiao er` (a fresh character with 0
380+
cash) correctly failed with "你的钱不够。" — the purchase-rejection path
381+
works; a successful purchase was not exercised since no test character
382+
in this pass had any money and grinding for some was out of scope for
383+
this pass's time budget.
384+
385+
### Disconnect/reconnect — no §7.20/§7.21-class bug; this lineage doesn't use void-parking at all
386+
387+
`obj/user.lpc`'s `net_dead()`/`do_net_dead()`/`user_dump()` chain
388+
**never moves the player into a VOID_OB or any holding room** — the
389+
body simply stays in its current room with `set_heart_beat(0)` and a
390+
`netdead` temp flag while disconnected; `NET_DEAD_TIMEOUT` is 600s
391+
before an unrecovered net-dead session force-quits via the same
392+
`QUIT_CMD` a real quit uses (so no separate stale-location save path to
393+
get wrong). `reconnect()` is a plain "resume heartbeat, clear the
394+
netdead flag" function, and `adm/daemons/logind.lpc`'s login flow
395+
genuinely calls `user->reconnect()` (line 872) on the SAME function —
396+
so, unlike the two flavors cataloged in AGENTS.md §7.20, there is
397+
structurally no location-loss path here to hit. Verified live: (1)
398+
disconnected without `quit` mid-session (character in 朱雀大街),
399+
reconnected within ~2s — "重新连线完毕。", `look` showed the same room,
400+
no data loss; (2) disconnected again, waited 25 real seconds (past the
401+
15s `do_net_dead` confirmation mark, so the driver-level `netdead` flag
402+
was genuinely set this time), reconnected — same clean "重新连线完毕。"
403+
and same room; (3) sent a clean `quit` (real flavor-text quit message),
404+
waited 20 real seconds, logged back in via the normal (non-reconnect)
405+
path — landed correctly at the persisted `startroom` (南城客栈, not
406+
wherever the character last stood before quitting, confirming
407+
`valid_startroom` gating works), `score` showed all prior state
408+
(gender, name, sect membership from a different, earlier test
409+
character) intact. `debug.log` stayed byte-identical to the
410+
pre-session baseline through all three cases.
411+
412+
### Not verified live (explicitly)
413+
414+
- **Death/reincarnation**: not reached — the `wimpy`-triggered flee
415+
worked before the test character's HP ran out. Code was not
416+
separately reviewed for correctness beyond what the §7.24-style grep
417+
(`set("startroom"` in death/reincarnation code) below covers.
418+
- **A completed shop purchase**: only the correctly-rejected
419+
insufficient-funds path was exercised (see above).
420+
- Grepped `set("startroom"` lib-wide for the §7.24 shape (death/limbo
421+
code silently overwriting the persistent login-location field). One
422+
hit under `d/death/`: `d/death/block.lpc` ("鸿蒙之外", the "your spirit
423+
has dissolved, use suicide/reborn" limbo room) unconditionally does
424+
`this_player()->set("startroom", "/d/death/block")` in `init()` for
425+
every non-wizard who enters. Read (not live-reproduced, since death
426+
was never reached this pass): unlike §7.24's `zzfy` shape, this room
427+
itself carries `set("valid_startroom", 1)` in its own `create()`
428+
the same "may this room be a permanent home" flag `d/city/kezhan.lpc`
429+
uses for the real start room — so this reads as an intentional
430+
"you're now stuck here as your only reachable location until you
431+
`suicide`/`reborn`" limbo design, not an accidental hijack of a
432+
living player's real chosen home. Neither `cmds/std/suicide.lpc` nor
433+
`cmds/usr/suicide.lpc` touch `startroom` at all, consistent with
434+
"reincarnating starts you over," not "silently changes where your
435+
ORIGINAL character logs in." Flagged as a content/design read, not
436+
fixed, per §10.7's scope note — genuinely unverified live and stated
437+
as such.

libs/xianlvqiyuan/work/adm/daemons/logind.lpc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,6 @@ private void get_name(string arg, object ob)
611611
}
612612
}
613613

614-
printf("%O\n", ob);
615614
ob->set("name", arg);
616615
write("请设定您的密码:");
617616
input_to("new_password", 1, ob);

0 commit comments

Comments
 (0)