info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
The real, self-identified 'Dead Souls' object library at its 3.0 point release (December 2009) -- an early snapshot of the same 3.x codebase branch that later became the 3.8.6 generation, several point releases and years earlier, with seven of that later version's nine domains: a default starting area, a town, the example town Ylsrim, an LPC-University-style campus, a cave zone, an examples area, and Praxis. Registration includes an age gate ('Are you 13 years of age or older?') followed by a race pick from eight options -- dwarf, elf, half-elf, half-orc, halfling, human, orc, or poleepkwa -- and, like dsII, the very first account ever created walks through a one-time admin-installation wizard before the mud restarts into its normal login flow. This is the most network-connected mud in the collection: it dials out to a live IMC2 hub and a separate Intermud-3 network on every boot, and even a bare, unattended boot triggers an automatic version-check that fetches the still-live dead-souls.net's release notes over a real HTTP connection.
README
The real, self-identified "Dead Souls" object library at its 3.0 point release -- released 2009-12-30, signed Cratylus @ Dead Souls (see doc/RELEASE_NOTES). A genuinely distinct release from the other four Dead Souls entries already in this collection (dsI, 1996-98 Nightmare-IV-era; dsII, 2006's "Dead Souls II"; ds386/ deadsouls_fluffos, the 2014-era 3.8.6 generation) -- but the CLOSEST of the four to ds386/deadsouls_fluffos by a wide margin: 90.8% of shared files are byte-identical, and secure/daemon/master.lpc differs from ds386's by only 8 trivial lines. Best understood as an early snapshot of the exact same "3.x" codebase branch that later became 3.8.6, captured a few point releases and several years earlier -- see NOTES.md \S1 for the full byte-level comparison against all four siblings.
Source: a ZIP archive from mudbytes.net, a now-dead site. Recovered via
the Wayback Machine
(<https://web.archive.org/web/20190802014424id_/http://mudbytes.net/files/download/2733/>)
since the original site is down. Slug dsIII, number 182, port 40229.
Highlights
- Seven shipped domains:
default,town,Ylsrim,campus(an LPC University area),cave,examples, andPraxis-- a strict subset ofds386's 9 (missing onlyamigaraandlearning, added in later point releases). - A working first-boot admin-installation wizard (
secure/lib/connect.lpc): name/password/gender/display-name/ real-name/email, then shuts the mud down (same asds386) -- a restart is required before logging in as the new admin. - Full ordinary-player registration includes an age gate ("Are you 13 years of age or older?"), then a race-selection step (
list/help RACE/pick RACE-- 8 races: dwarf, elf, half-elf, half-orc, halfling, human, orc, poleepkwa). - Strict English-only name validation (
A-Z a-z ' -only, with an explicit rejection message) -- this archive cannot register a Chinese character name; a real ASCII test account (Qinbing) was used instead for verification, same adapted bar asds386's own testing. - Makes THREE independent real outbound network connections -- confirmed live, more than any other Dead Souls-lineage lib in this collection: 1. IMC2 (
secure/daemon/imc2.lpc, preloaded) -- a real socket to a live IMC2 hub a couple seconds after boot. 2. Intermud-3 (daemon/intermud.lpc, preloaded) -- a second real connection attempt. 3. NEW, and automatic on every single boot with zero player interaction:secure/daemon/autoexec.lpc(itself preloaded) firessecure/cmds/creators/dsversion.lpc's update-check one second after boot, which fetchesdoc/RELEASE_NOTESfresh fromdead-souls.netover a real HTTP connection -- confirmed live on a bare idle boot with no login at all. The fetched content shows dead-souls.net is itself STILL LIVE (release notes through 2020), unlike mudbytes.net (this archive's actual download source, which really is dead). A related creator command,secure/cmds/creators/rss.lpc, has the same eager network behavior and fires merely from being LOADED -- which anlpcc --batchcompile sweep of this lib will do, meaning even a bare compile sweep of this lib makes real outbound network connections, not just a live boot. SeeNOTES.md\S5 for the full detail. Do not sweep this lib into high-frequency automated re-boot OR re-compile loops -- same safety-flagging convention asdsI/dsII/imud/foundation2, extended here to coverlpcc_check.shsweeps too. - The archive's own
secure/cfg/groups.cfg/secure/include/config.halready shipped with the correctADMIN/DEBUG_NAMEplaceholder tokens (unlikedsII's copy, which had the original author's real name hardcoded) -- no hand-fix needed for the admin-installer's group-membership scrubbing here. - Nearly every driver-compat bug found while porting this (
get_root_uid()/get_bb_uid()/creator_file(), thelog_error()-during-compile recursion, a staleruntime_config.hslot-numbering mismatch,OLD_EDvs. the split editor API,__DIR__/__FLUFFOS__macro collisions, a mistypedLIB_REMOTEpath,SetLong()/SetExternalDesc()/SetInternalDesc()declared too narrowly,daemon/books.lpc's array-vs-mapping mismatch, a brokenset_pre_exit_functions()call) turned out to be byte-identical to bugs already found and fixed while portingds386-- ported that fix catalog wholesale rather than rediscovering it. Full list, plus the handful of genuinely new findings (a mixed-encoding curse-word table, severalTYPE array NAME-dialect shapesds386's own sweep didn't need to handle), inNOTES.md\S3-4.
Registration flow
name -> "Do you really wish to be known as <Name>? (y/n)" -> "Are
you 13 years of age or older? (y/n)" -> password (5+ letters) ->
confirm password -> gender (male/female/neutral/none) -> email
(required, validated as user@host) -> race selection (list to see
options, pick <race> to choose) -> news screens (<return> to
continue) -> lands in /domains/default/room/ (the default domain's
start room).
The very first account ever created goes through a separate, one-time admin-installation wizard instead (see above) -- the mud shuts down after that wizard completes, and every account after the restart uses the normal flow described here.
Admin account
- id:
fluffos - password:
Mud@2026 - privilege:
SECURE/ASSIST/ELDER/TEST/INTERMUD/BUILDER/TELNET/EMOTESgroup membership (secure/cfg/groups.cfg), account file undersecure/save/creators/f/fluffos.o
Created through the mud's own first-boot installation wizard; no manual
group-membership fix needed (see Highlights above). Verified live:
score shows the correct character sheet, and update (this project's
canonical ACL/compile-permission smoke test) succeeds with Ok.
Status
Boots clean, zero fatal errors. Verified live with a real driver session
and a raw socket client: the first-boot admin installation wizard
(including the mud's self-shutdown-after-install), a restart, admin
login, a brand-new ordinary character's full registration (including
the age gate and race selection), a distinct reconnect-login code path,
and look/score/update/a clean quit all producing correct output
for both accounts.
2282 of 2291 .lpc files pass a full lpcc_check.sh batch compile
sweep (99.6%); the 9 that don't are all pre-existing non-bugs or
compile-sweep-only eval-cost artifacts (a deliberate author anti-load
trap, two builder-tool scaffolding templates, two confirmed-harmless
isolated-compile warning failures, two confirmed batch-eval-cost
artifacts that pass standalone/live, one genuine but pre-existing and
non-blocking content-side performance bug in the cave domain's orc
NPC race setup, a missing LIB_CAPTURE library component, and a
missing opcprof() efun) -- see NOTES.md \S6 for the full breakdown.
WASM status: playable. Shared WASM driver (secure/sefun/sockets.lpc
already stubbed). Admin login (fluffos / Mud@2026) into Fluffos'
workroom, plus score / quit, verified with scripts/wasm_client.js.
Play: https://mudlibs.fluffos.info/dsIII/
Local run
cd libs/dsIII
~/src/fluffos/build-debug/src/driver config.fluffosGame port: 40229. Note the THREE outbound-network-connection caveats
above (two at every boot, one also from a bare compile sweep) before
repeated/automated boots or lpcc_check.sh runs.
NOTES · 移植与修复记录
Dead Souls 3.0 -- porting notes
Source: a ZIP archive (ds3.0/, 5553 files, WINDOWS_INSTRUCTIONS.txt at
top level) from mudbytes.net, a now-dead site. Recovered via the Wayback
Machine
(<https://web.archive.org/web/20190802014424id_/http://mudbytes.net/files/download/2733/>),
re-verified live (HTTP 200, real ZIP magic bytes, 5553-file/ds3.0/
top-level-dir match) at the start of this session before extracting. The
zip bundles fluffos-2.18-ds07/ (a driver source snapshot), bin/,
win32/, extra/ build/install scaffolding -- all ignored, this project
uses its own driver. The real mudlib root is the zip's lib/ directory
(bin/mudos.cfg's own master file : /secure/daemon/master confirms
it). Slug dsIII, number 182, port 40229.
1. Duplicate check -- distinct release, but the closest sibling by far
This collection already has FOUR Dead Souls entries: dsI (~1996-98,
Nightmare-IV-era, 2 domains), dsII (2006, "Dead Souls II", 4 domains),
and ds386/deadsouls_fluffos (3.8.6, 2014-era, 9 domains, confirmed
identical codebase generation to each other). Before building out a full
pipeline, checked whether "Dead Souls 3.0" repackages any of the four:
- Self-identification:
doc/RELEASE_NOTEShas a dated version history culminating in a---- 3.0 ----entry ("Released 2009-12-30... Driver: added Kalinash's fix for Solaris on 64 bit SPARC... Added commands: anchor, unanchor..."), preceded by2.11a20-2.11a22entries -- a real, self-contained, later point release, not a copy ofdsII(Nov 2006) or a re-save ofds386(2014).README.txt's own title text is a stale "Dead Souls 2... Released December 2005" banner (last touched Jan 2008) that predates this zip's actualRELEASE_NOTEScontents -- a rolling-tarball snapshot where the README just wasn't kept in sync, not evidence this is actually the 2006 "II" release. - Domain count: 7 domains (
campus,cave,default,examples,Praxis,town,Ylsrim) -- more thandsII's 4, and a STRICT SUBSET ofds386/deadsouls_fluffos's 9 (missing onlyamigaraandlearning, both added in later 3.x point releases per their ownRELEASE_NOTESentries).dsIhas only 2. 4598 files underlib/here vs.dsII's 1937,ds386's 4727. secure/daemon/master.ccomparison -- the decisive evidence: 1157 lines here vs.ds386's 1157 (identical length) anddsII's 781/dsI's 749 (a different, much smaller shape entirely). A realdiffagainstds386's raw archive shows only 8 changed lines total -- all tiny game-balance/logging tweaks (adebug_message()string, aget_stack(1)vsget_stack()arg, a clean-up percentage26vs34, an array-size cap500vs1024, an error-counter variable) -- vs.dsII's real, substantive divergence (added globals, a rewrittenload_access()body). Againstdeadsouls_fluffos's raw copy, the same file differs by 223 lines -- meaning this archive's master.lpc is closer tods386's thands386anddeadsouls_fluffosare to EACH OTHER (189 lines apart, two nominally-same-version 3.8.6 copies from different sources).- Whole-tree file-identity check: of the 4555 relative paths shared between this archive and
ds386's raw copy, 4136 (90.8%) are byte-identical; againstdeadsouls_fluffosthe rate is only 63.3% (2874/4542). 43 files exist only here (mostlydomains/campus/adm/*admin scratch tools and cacheddomains/town/virtual/sky/*.ccoordinate-instance files); 172 exist only inds386(new content added in later point releases, including the two newer domains).
This is a genuinely distinct release -- not a byte-identical duplicate,
since 419 of the 4555 shared files differ and 43 are unique here -- but
it sits MUCH closer to ds386/deadsouls_fluffos in the lineage than
dsII ever did: this is best understood as an early-2010s snapshot of
the exact same "3.x" branch that later became 3.8.6, captured about 4-5
years and several point releases earlier. duplicate_of is null in
meta.json, but the whole fix catalog below was ported from ds386's
own NOTES.md wholesale (verified per-file via diff against ds386's
raw archive before applying each fix) rather than rediscovered from
scratch, since nearly every driver-compat bug turned out to be
byte-identical.
2. Conversion
English-language archive (public domain, from mudbytes.net) --
scripts/convert_lib.sh against raw/ds3.0/lib confirmed this:
4562/4598 files already valid UTF-8 (pure ASCII), only 5 lossy
conversions, 28 binary files skipped. 2290 .c files renamed to
.lpc, 603 literal .c" references fixed, 31 local angle-bracket
#includes converted to quotes, 1429 files touched by the
static->nosave sweep.
2.1 One source file was genuinely MIXED-encoding, not GB18030 -- and the lossy conversion broke its string-literal syntax
secure/sefun/translate.lpc's FLUBS array (the same multilingual
"drunk talk" curse-word list ds386/dsII both have) contains:
- Two Finnish words with literal Latin-1 bytes (
"kyrpä","räkä", 0xE4 =ä). - One word that was already valid UTF-8 in the raw archive:
"ХУИТА"(Cyrillic, 5 characters,\xd0\xa5\xd0\xa3\xd0\x98\xd0\xa2\xd0\x90).
A single GB18030 pass mangled BOTH differently: the Cyrillic bytes
(already-correct UTF-8) got mis-decoded as GB18030 multi-byte sequences
into garbage CJK characters, and the Latin-1 ä bytes got silently
dropped as invalid, which ate the closing quote immediately after
kyrp too ("kyrp\xe4" -> "kyrp" was NOT what happened -- the actual
result was "kyrp,"r鋕,"shawtay", a real syntax break: an unterminated
string swallowing the next comma, then an invalid bare identifier
r鋕). This is a genuine, driver-compat-relevant compile failure, not
just cosmetic mojibake -- confirmed by a first driver boot failing
simul_efun's compile entirely (*No program in object
'/secure/sefun/sefun'!). Fixed by hand: re-decoded the Finnish words as
Latin-1 and re-typed the Cyrillic word as literal UTF-8, leaving
everything else in the file (99% pure ASCII) untouched. Also
individually re-decoded with iconv -f ISO-8859-1 -t UTF-8: doc/CREDITS,
doc/help/players/credits (a Lars Pensjö name-with-diacritic), and
domains/town/txt/mystery.txt (a ¯\(°_o)/¯ ASCII-art shrug). One more
lossy file, secure/save/functions.o, turned out to be a stale
function-signature cache (secure/daemon/function.lpc's
RestoreObject()/file_exists() guard handles a missing file
gracefully and rebuilds on demand) -- deleted rather than hand-repaired,
same precedent as ds386's functions.o/books.o cache files.
3. Driver-compat fixes -- ported wholesale from ds386's catalog, verified per-file
Every fix below was checked against ds386's raw archive first (diff
on the specific file) to confirm the bug is byte-identical before
porting ds386's exact fix; all were.
- Missing
get_root_uid()/get_bb_uid()/creator_file()master applies (AGENTS.md section 7.2, and thecreator_file()extension first cataloged onds386): this driver'sPACKAGE_UIDSbuild requires all three; missing entirely. Added byte-identical stub implementations (all constant"root"/"backbone") tosecure/daemon/master.lpc, same placement asds386. log_error()'sload_object(WEB_SESSIONS_D)re-entering the compiler mid-compile (AGENTS.md section 7.60's pattern): same fix asds386-- swapped tofind_object().- A stale
runtime_config.hINT-slot-numbering mismatch (AGENTS.md section 7.89,ds386is the origin case): this lib's ownsecure/include/runtime_config.hcomputedBASE_CONFIG_INT = BASE_CONFIG_STR + 15instead of the canonical driver'sRC_BASE_CONFIG_INT = RC_LAST_CONFIG_STR + 1(=256) -- everyget_config(__MAX_EVAL_COST__)/__MAX_BYTE_TRANSFER__/__MAX_READ_FILE_SIZE__/__MAX_STRING_LENGTH__call (identical symbol set tods386's) would read the wrong config slot. Fixed by dropping in the driver's canonical header, same asds386. OLD_EDvs. this archive's splited_start()/ed_cmd()/query_ed_mode()API:lib/editor.candsecure/cmds/creators/lsed.care BYTE-IDENTICAL tods386's raw copies, andlib/interactive.c/lib/nmsh.cdiffer fromds386's by only one unrelated line (avalid_event()security check added later ininteractive.c) -- sods386's exact rewrites were copied/ported directly rather than re-derived:lib/editor.lpc(full file copied fromds386's fixed version),secure/cmds/creators/lsed.lpc(full file copied, stubs the batch-editor feature as unavailable),lib/interactive.lpc's deaded_cmd(".");ed_cmd("x");ed_cmd("Q");quit-path block removed (redundant underOLD_ED's automaticsave_ed_buffer()on destruct),lib/nmsh.lpc'squery_ed_mode()- gated custom ed-prompt branch collapsed to dead code (if(0){...}, unreachable since the driver prints its own ed prompt directly from C underOLD_ED).#define __DIR__ "..."colliding with the native compiler predefine: 13 files here (domains/{town,default,Ylsrim}/virtual/ *.lpc) still had the old manual#define __DIR__idiom thatds386's OWN copies of these same files had already dropped in a later point release (ds386'stown/default/Ylsrimvirtuals have no__DIR__define at all -- confirms this archive predates whatever point release removed them, consistent with section 1's "same branch, earlier snapshot" finding). Removed all 13; the native__DIR__produces an identical value.secure/cmds/admins/sconv.lpc's#ifndef __FLUFFOS__guarding the wrong symbol (this driver predefines bareFLUFFOS, not__FLUFFOS__): byte-identical raw file tods386's; same one-line fix (__FLUFFOS__->FLUFFOS). Left the other ~9 files using the same guard untouched, matchingds386's "no error, no fix" precedent -- all compiled and ran clean.secure/include/lib.h'sLIB_REMOTEmacro pointing at a nonexistent path (/lib/remotewhen the real file lives atsecure/lib/net/remote.lpc): same bug, same fix asds386.LIB_CAPTURE(/lib/capture, no implementation anywhere in the archive) has the same pre-existing gap asds386-- left unfixed, breaks onlydomains/Ylsrim/broken/jar.lpc(a file literally shelved in abroken/subdirectory in the original archive).- **
SetLong/SetExternalDesc/SetInternalDescdeclaredstring-only when theirGet*()counterparts already supportfunctionp()/arrayp()dynamic-description values** -- 44 real call sites use the function-value form here (more thands386's reported failure count, since this archive'scave/examples/Praxisdomains have their own additional users of the idiom). WidenedSetLong/SetExternalDescinlib/events/look.lpc,SetInternalDesc+InternalDesc's declared type inlib/events/look_in.lpc, andlib/std/room.lpc'sSetLongwrapper, all tomixed/mixed *-- exact same fix and files asds386(its ownlib/include/{room,interactive,door}.hforward declarations were NOT widened either, matchingds386's working, tested precedent that the header prototypes aren't enforced against the concrete override here). - **
daemon/books.lpc'sLoadChapters()/lib/std/book.lpc'seventLoadChapters()declaredmixed *(array) when the real payload is a mapping**: same bug, same 3-declaration fix asds386(daemon/books.lpc,lib/std/book.lpcx2). domains/Praxis/supply2.lpc'sset_pre_exit_functions( ({...}), ({...}) )(a#define-aliasedSetProperty(string, mixed)call given two arrays): byte-identical file tods386's (differs only in whitespace); every sibling room in the same directory already has the identical call commented out. Appliedds386's exact fix (comment out with the same explanatory note).secure/sefun/sockets.lpc'sforeach (array item in finalsocks)-- the samedump_socket_status-in-simul_efunarray-dialect pattern flagged as recurring across sibling libs. Fixed toforeach (mixed *item in finalsocks).
4. TYPE array NAME dialect -- 166 files via an automated fixer, plus 7 hand-caught shapes the fixer's regexes didn't cover
Wrote a quote/comment-masking Python regex fixer (handles single-name
declarators with/without default values, multi-name comma lists, bare
array NAME/array *NAME, and (TYPE array) cast forms) and ran it
across the whole work/ tree: 166 files changed on the first pass
(secure/cmds/admins/admintool.lpc's array *classes;/array
*races;, secure/sefun/sockets.lpc, secure/sefun/sefun.h, and 163
more). Then a full driver boot + a standalone re-grep surfaced 7 more
shapes the regex set didn't anticipate, each fixed individually and
verified there was exactly one instance:
lib/body.lpc:1810:class MagicProtection array GetMagicProtection(){ ... }-- aclass TYPENAME arrayFUNCTION RETURN TYPE, not a variable declaration. The generic fixer's "barearray NAME" rule actually MIS-FIRED here (matched the space beforearrayregardless of the precedingmarriage/MagicProtectiontoken, since its negative lookbehind only checks the single character immediately beforearray) and produced the WRONG result (class MagicProtection mixed *GetMagicProtection()-- inserting a spuriousmixed). Caught and corrected toclass MagicProtection *GetMagicProtection(){ ... }by hand; grepped the whole tree for the sameclass \w+ mixed \*mis-fire pattern and confirmed no other instances.secure/daemon/finger.lpc:23:private class marriage array Marriages;-- sameclass TYPENAME arrayshape, in a variable declaration this time; hit the SAME fixer mis-fire (private class marriage mixed *Marriages;). Corrected toprivate class marriage *Marriages;.lib/guard.lpc:6:private nosave array PendingGuard = ({});-- a barearray NAME = default(no element type, WITH an initializer); the fixer's bare-array rule only matched a terminator of;/,/)immediately after the name, not=. Fixed toprivate nosave mixed *PendingGuard = ({});.lib/std/story.lpc:20,65:array GetTaleKeys();/array GetTaleKeys(){ return keys( Tales ); }-- barearrayas a FUNCTION RETURN TYPE (prototype and implementation). Fixed both tomixed *GetTaleKeys().secure/sefun/sockets.lpc:14:foreach (array item in finalsocks)-- covered in section 3 above, same root pattern asds386's recurringdump_socket_status-class foreach.secure/cmds/players/history.lpc:32:string *arr, tmp = ({});-- the ORIGINAL (pre-conversion) source wasstring array arr, tmp = ({});, a multi-name declarator list WITH a default value on the second name. The fixer's multi-name rule required no=in the matched span, so it never touched this line at all, and it slipped through to a real compile failure (Type mismatch ( string vs mixed * ) when initializing tmp) since a barestring *arr, tmponly stars the FIRST name --tmpstayed scalarstringwhile assigned an array. Fixed tostring *arr, *tmp = ({});(both starred, matching the old dialect's "applies to every name in the list" semantics, same asds386's NOTES.md documents for its ownadmintool.lpcfinds).
All 7 fixes verified individually: a clean re-grep for each pattern
class found zero remaining instances, and a full driver boot + full
lpcc_check.sh batch sweep both came back clean of these specific
error signatures afterward.
5. Live verification
Booted clean (Accepting telnet connections on 0.0.0.0:40229.,
Initializations complete., zero fatal errors, zero uncaught compile
errors in log/debug.log).
Confirmed THREE independent real outbound network side effects at boot -- more than any prior Dead Souls-lineage lib in this collection, and the third one is NEW to this archive specifically:
1. IMC2 (secure/daemon/imc2.lpc, preloaded, DISABLE_IMC2/
DISABLE_INTERMUD both 0 in secure/include/config.h): makes a
real socket_connect() a couple seconds after boot. Confirmed live
(ss -tnp showed ESTABLISHED ... 204.209.44.3:8080).
2. Intermud-3 (daemon/intermud.lpc, preloaded): a second real
connection attempt, confirmed live (ss -tnp showed
SYN-SENT ... 74.207.247.83:5000).
3. NEW: an automatic release-notes HTTP fetch on every single boot,
with zero player interaction required. secure/daemon/autoexec.lpc
is ITSELF preloaded, and its create() schedules eventRun() via
call_out(..., 1) -- one second after preload completes, with a
hasrun guard so it only fires once per boot. eventRun()
unconditionally does
catch( load_object("/secure/cmds/creators/dsversion")->cmd());,
and dsversion.lpc's cmd() immediately opens a real socket to
dead-souls.net (97.107.133.86:80) and fetches /RELEASE_NOTES,
overwriting doc/RELEASE_NOTES_HTTP with the live response.
Confirmed live and reproducible on a bare idle boot with NO login
at all: doc/RELEASE_NOTES_HTTP's mtime changed within ~14 seconds
of driver start with zero connections made, and its content is a
REAL, CURRENT response from a still-live server -- the fetched
response includes release notes up through "3.9, Released
2020-04-08", meaning dead-souls.net itself is not dead (unlike
mudbytes.net, this project's actual archive source). A SEPARATE
creator command, secure/cmds/creators/rss.lpc, has the same
eager-create()-time network behavior (registers RSS feeds from
lpmuds.net/feedburner.com via call_out((: Setup :), 2)) but is
NOT itself preloaded -- it only fires if something actually loads the
file, which an lpcc --batch compile sweep does (merely compiling
secure/cmds/creators/rss.lpc as one of thousands of files in the
sweep triggers its create() and, 2 seconds later, its own real
HTTP/RSS fetches) -- confirmed by doc/RELEASE_NOTES_HTTP and
tmp/imc2.log both getting freshly rewritten after this session's
lpcc_check.sh runs, with no driver boot in between.
This means BOTH a live boot of this lib AND a bare lpcc --batch
compile sweep of this lib can make real, uncontrolled outbound
network connections to third-party servers -- extend the existing
"don't sweep into high-frequency automated re-boot loops" caveat
(already standard for dsI/dsII/imud/foundation2-class libs)
to cover automated/batch COMPILE sweeps of this lib too, not just
driver boots. doc/RELEASE_NOTES_HTTP and tmp/imc2.log were reset
to their originally-shipped/pristine state before every commit in
this session; a future re-test will regenerate fresh copies again on
its own next boot/sweep, which is expected and not a bug.
Tested with a raw Python socket client (scripts/mudclient.py), all
required flows in one continuous session:
1. First-boot admin installation wizard (secure/lib/connect.lpc):
username fluffos -> password/confirm Mud@2026 -> default display
name -> gender male -> blank real name -> [email protected] --
completed successfully; the mud self-shut-down as designed
(connect.real's shutdown() + destruct(master()), matching
dsII/ds386's installer behavior -- a driver restart is required
before the new admin can log in). secure/cfg/groups.cfg and
secure/include/config.h correctly ended up with fluffos in place
of the ADMIN/DEBUG_NAME placeholder tokens -- unlike dsII,
this archive's shipped groups.cfg/config.h already had the
correct placeholder tokens (not a hardcoded original-author name), so
no hand-fix was needed here.
2. Reboot + admin login: fluffos/Mud@2026 -> arrived in
/realms/fluffos/workroom with wizard robe+hat, general/creator/
admin news tiers all paged correctly, who-equivalent (people,
auto-sourced via .profile) showed the admin present, score
produced a correct full character sheet ("You are First Admin
Fluffos (neutral)... a level 1 Human Explorer..."), update (no
argument, current-room form) reported Ok (warnings-only compile,
no errors), quit disconnected cleanly with correct
inventory-removal messages.
3. Ordinary new-player registration (tested with Qinbing, an
ASCII name -- this archive enforces a strict A-Z a-z ' -
name-charset check with an explicit rejection message, so a real
Chinese name is out of scope here by design, same adapted bar as
ds386's own testing): name -> confirm (y) -> age-gate (y,
"Are you 13 years of age or older?") -> password -> confirm -> gender
-> [display-name step skipped, CUSTOM_FORMAT is off by default] ->
email (validated, a blank/malformed first attempt is correctly
rejected and re-prompted) -> [real-name step skipped, REAL_NAME is
off] -> race selection (list/help RACE/pick RACE -- 8 races:
dwarf, elf, half-elf, half-orc, halfling, human, orc, poleepkwa) ->
news pages -> landed in "The start room" (the default domain's
entry point) with a correct ASCII-art room map and an HP/MP/SP status
bar. Re-logged in as the same character on a second connection:
Reconnected. (confirms the reconnect path is a distinct, working
code path from fresh registration, not just registration succeeding
once), score produced correct output, quit clean.
4. update <path> on the 4 lpcc-flagged "eval-cost" failures
(section 6 below) confirmed 3 of the 4 are batch-sweep artifacts, not
real bugs -- see that section for the one (domains/cave/room/
common1) that is a genuine, but pre-existing and non-blocking,
content-side performance bug.
2282 of 2291 .lpc files pass a full lpcc_check.sh batch compile
sweep (99.6%); the 9 that don't are broken down in section 6.
6. Known pre-existing gaps and sweep artifacts (not fixed -- content/archive design or tooling artifacts, not driver-compat)
/obj/stargate:#include this is here on purpose to prevent this from loading-- a deliberate author anti-load trap, same class asds386's identical file./obj/area_roomand/open/prog: builder-tool scaffolding templates never meant to compile standalone in place (area_room.lpcis copied elsewhere by the room-building tool before its relative#includeresolves;open/prog.lpcis written bydaemon/defines.lpcat runtime with a$Splaceholder later substituted) -- same non-bug class asds386's identical files./domains/campus/chamber/elevatorand/realms/template/area/ room/sample_room: fail with ONLY a "Redeclaration of global variable" warning and no further error text -- confirmed harmless by an identically-warned sibling passing clean in the same sweep (domains/campus/chamber/tree.lpcfor the first, any of dozens ofLIB_ROOM-inheriting rooms for the second) -- the same isolated-single-file-compile artifact classds386's NOTES.md documents (AGENTS.md section 10.4)./domains/town/room/shop2and/realms/template/area/room/ sample_room(again): fail with "Eval interrupted... cost limit reached" in the BATCH sweep, but PASS when compiled standalone via a single-filelpcc --batchrun outside the shared-budget batch session -- confirmed afeedback_lpcc_sweep_eval_cost_artifact-class false positive (the wholelpcc_check.shsweep shares one continuous eval-cost counter across thousands of files; a room whosecreate()clones a largeSetInventory()list can tip over the limit purely because of what ran immediately before it in the batch, not because the file itself is slow). Also verifiedshop2live via adminupdate-- no error./domains/cave/room/common1: fails BOTH in the batch sweep AND standalone -- a genuine, pre-existing performance bug, but confirmed present byte-identically indaemon/races.cinds386's own raw archive too (not something this port introduced). Root cause:common1.lpc'screate()->SetInventory()clones anorc_female1NPC ->SetRace("orc")->NewBody()->daemon/races.lpc:534'sSetCharacterLimbs(), which hits "Too long evaluation" (5,000,000 usec) even though the actual per-race data is tiny (13HAND/LIMBlines total for "orc").AddRace()'sLIMB-parsing branch (daemon/races.lpc:365-366) has an actual duplicate-append typo --res["Limbs"] = ({ res["Limbs"]..., limb });immediately followed byres["Limbs"] += ({limb});, appending each limb twice -- present identically inds386's raw copy, i.e. a real original-archive bug, not conversion fallout. Whether that duplicate- append is the actual root cause of the 5-second hang (vs. some other expensive step in the NPC/race/body creation chain) was not fully isolated; per this project's "programming bugs only, and even then verify before applying" discipline, and becausedomains/cave/is NOT preloaded and NOT on the core registration/login/play path this pass verified, this was left as a documented, non-blocking gap rather than speculatively patched. A future deep-play pass into thecavedomain specifically should budget time to actually isolate and fix this (or confirm it's cosmetic/rare enough to leave)./domains/Ylsrim/broken/jar:LIB_CAPTUREhas no implementation anywhere in the archive -- same pre-existing gap asds386(the file is literally shelved in abroken/subdirectory in the original archive)./secure/cmds/admins/opcprof: calls theopcprof()efun, which doesn't exist in this driver build at all -- same asds386, a creator-only diagnostic tool, not on any core path.
7. WASM pass
Measured 2026-09-03 against the shared ~/src/fluffos/build-wasm.
secure/sefun/sockets.lpc was already stubbed (the ds386 sibling
treatment this section originally predicted). No further mudlib-side
compile fix was needed. Verified with scripts/wasm_client.js:
fluffos / Mud@2026 into Fluffos' workroom, score showed
"First Admin Fluffos", clean quit. IMC2/I3/HTTP version-check still
try outbound connects at boot — do not loop-reboot. Shop/combat/death
were not exercised this pass.
深度功能测试 / Deep functional test (round two, AGENTS.md §10.7)
First real *playthrough* pass on this lib (prior sessions only verified
registration + look/score/quit + the admin install wizard, per
section 5 above). Played a full, continuous session as an ordinary new
player on the native driver (build-debug), using a second admin
connection only for a controlled death test at the end. This is also
the first lib in the Dead Souls lineage (dsI/dsII/ds386/
dshakkard/deadsouls_fluffos) to get a §10.7 pass -- none of the
siblings have a "深度功能测试" heading in their own NOTES.md yet, so
the bug found below (and its fix pattern) should be checked against
all of them, not just this archive.
Newbie path: read chapter 1 in handbook (repeated through
"chapter N" for the whole book) is this lib's own onboarding doc.
Chapter 4 spells out the intended early game explicitly: level up on
weak monsters in "the newbie mansion" (reached from the village, past
a newbie-only gate guard and a locked mansion door -- the real way in
for a level-1 character is external: grab the ladder from the
gardener's shack west of the mansion, drop it under the mansion's
open second-floor window, and climb ladder/enter window), sell
loot to a shopkeeper (this archive's actual town vendors are James at
the Healers' Guild and Lars at the pub -- the handbook's own "Otik"
example is stock Dead Souls boilerplate text, not hand-tailored to
this archive's actual NPC names, a content detail, not a bug), bank
with Zoe, and eventually join a class (fighter/mage/cleric/thief) via
a guild NPC once a gating quest (Orcslayer) is done.
Test character: id Qintestds, ASCII name (per this archive's own
strict A-Z a-z ' - name-charset validation, same as ds386's and
this archive's own admin-install testing in section 5 -- a Chinese
name is out of scope here by design), password Abc12345, human
Explorer -- kept (not cleaned up) as a representative playthrough
character, currently a ghost-then-regenerated corpse sitting in "The
start room" at half HP/MP/SP after the controlled death test below.
Save file: work/secure/save/players/q/qintestds.o.
Bug found and fixed
Silver/gold/every other in-game currency silently turns into a
float the first time it passes through ANY currency-exchange
calculation, corrupting the player's Currency mapping permanently --
secure/sefun/economy.lpc's query_base_value()/query_value()/
query_base_rate()/query_player_money(), plus one sibling miss in
lib/teller.lpc's eventExchange() and one in lib/props/value.lpc's
SetBaseCost().
- Symptom: reproduced live buying a 2-silver bottle of water from Lars (the pub keeper) with
buy water from lars. The very next attempt to learn a spell from Herkimer (ask herkimer to teach light) printed:"Light costs 100 silver and you only have 88.000000."-- a raw float leaking into player-facing text instead of a clean integer silver count. Confirmed at the data level too: after asave, the raw player file literally containsCurrency (["silver":88.000000,...])-- not a display bug, the stored balance itself is now a float and stays that way forever (every future addition/subtraction against an already-float mapping value stays a float in this dialect, since a declaredinttype is compile-time only and never coerces an assignment -- see this project's ownreference_lpc_int_cast_is_compile_time_onlyprecedent and thequest_times_percent_operatorcorpus sweep for the identical class of bug in other libs). - Root cause, traced end to end:
lib/std/barkeep.lpc'seventSell()(invoked by everybuy X from <barkeep NPC>) doesx = query_value(ob->GetBaseCost(), query_base_currency(), GetLocalCurrency()); ... who->AddCurrency(GetLocalCurrency(), -x);.query_value()and its helperquery_base_value()(secure/sefun/economy.lpc:59-70before the fix) are both declared to returnint, but their bodies do real floating-point exchange-rate math (amount * rate,baseval / rate, whereratealways comes fromECONOMY_D->__Query(type,"rate"), a value the economy daemon stores and returns as a genuinefloat) and return that float without ever callingto_int()-- unlike their own two sibling functions in the exact same file,currency_mass()andcurrency_value(), which already correctly wrap their return into_int(). Once a float slips intox,AddCurrency(string type, int amount)stores it straight into theCurrencymapping (lib/currency.lpc'sCurrency[type] += amount), permanently changing that currency's runtime type for the rest of the character's life. The bank's currency-exchange command (lib/teller.lpc:227-229,ask zoe to exchange N x for y) has the identical gap on its own separate line --i = val / currency_rate(str2);-- missing ato_int()that the very next line in the same function (charge = to_int(i / (100 / GetExchangeFee()));) already has, so it independently reintroduces the same corruption even witheconomy.lpcfixed.lib/props/value.lpc'sSetBaseCost(string currency, int amount)two-argument form (used pervasively for pricing items, e.g.SetBaseCost("silver", 10)in dozens of files) has the same gap at its own point of origin:Cost = i * rate;with noto_int(), contaminating an item's *listed* price before it ever reaches a vendor transaction. - Fix: added
to_int()around the return value ofquery_base_rate(),query_player_money()(also switched its internal accumulatorxfrom a lyingintto an honestfloatthat only gets truncated at the very end, for clarity),query_base_value(), andquery_value()insecure/sefun/economy.lpc; wrappedlib/teller.lpc'si = val / currency_rate(str2);into_int(); wrappedlib/props/value.lpc'sCost = i * rate;into_int(). Every fix matches theto_int()-wrapping convention already established by sibling functions in the very same files -- this is closing an inconsistency the original code already knew the pattern for, not inventing a new one. - Verified: rebuilt nothing (LPC-only change), ran the
lpc-syntaxformatter on all three touched files (all three §9 blind-spot checks came back clean), rebooted the native driver, reconnected asQintestds. The character's pre-existingsilverbalance is still shown as63.000000in the raw save file after the fix -- expected and left as-is: the fix stops NEW corruption, it cannot retroactively un-float a value already written to a save file (that would need a one-time data migration, out of scope for a programming-bug fix). Proved the fix actually works by exercising a brand-new currency the character had never held: opened a bank account with Zoe and didask zoe to exchange 20 silver for gold(the exact previously-brokeneventExchange()path) -- after asave, the raw player file shows"gold":2with no decimal point, next to the still-float legacy"silver":63.000000in the very same mapping literal, proving the fix closes the corruption at its source.log/debug.logstayed clean (no compile/runtime errors) through the whole sequence. - Sibling libs to check:
ds386,dsI,dsII,dshakkard, anddeadsouls_fluffosshare this same Dead Souls Object Library codebase and, per this archive's own section 1 lineage analysis, are very likely to have byte-identical or near-identical copies ofsecure/sefun/economy.lpc,lib/teller.lpc, andlib/props/value.lpc-- worth a quickdiffcheck and the same three-line fix on all of them the next time any gets a §10.7 pass or economy-focused re-test.
What was tested and confirmed working
- Registration: full flow (name -> confirm -> age gate -> password + confirm -> gender -> email, validated -- a blank/malformed first attempt correctly re-prompts -- -> race pick,
list/pick human) -- landed in "The start room" with the starting Player's Handbook, t-shirt, and jeans,scoreandiboth correct immediately after. - Movement/exploration: the default domain's start room only has a
downexit into thecampusdomain (LPC University, a separate builder-tutorial zone) -- this isSetNoModify(1)-locked, deliberate content structure, not a bug. Walked from there through campus, across "University Square", north along a connecting path into the actualtowndomain (village intersection, Saquivor Road, the mansion), and confirmed door/open doormechanics, aclimb ladder/enter windowalternate-entry puzzle (the mansion's front door is locked and needs a key; the intended level-1 route is external, via a ladder retrieved from the gardener's shack), and a newbie-only gate-guard bypass (PreExit()indomains/town/room/gate.lpc, correctly let a level-1 character "sneak past" with a flavor message). - Combat: no player-reachable safe-sparring dummy exists in this archive (
domains/default/npc/dummy.lpcsits in a creator-onlyarenaroom gated byCanReceive();domains/campus/npc/dummy.lpcis never placed in any room at all -- both are inert example content, not a bug, just not wired up for ordinary players). Fell back to the handbook's own recommended weak target: rats in the mansion kitchen (domains/town/room/mansion_room7.lpc,SetLevel(1),SetMaxHealthPoints(10)). A fullkill ratfight ran cleanly for several dozen exchanges (both sides mostly missing at level 1, unarmed -- slow but correct, matches the handbook's own explanation of skill-based to-hit), correctly updatedmelee attack/melee defenseskill percentages instatfrom use, andignore all+ moving away correctly disengaged without further loss once clear of the room. - Skill/class acquisition, two paths: asked Herkimer (the Mages' Guild guildmaster) directly
to join-- correctly refused pending the Orcslayer quest ("First you must prove yourself worthy...",herkimer.lpc'sJoinGuild()). Asked himto teach light(the organic, no-guild-required spell-purchase path) -- correctly gated on affordability, which is exactly the interaction that surfaced the currency bug above. - Shop/economy: bought a claritin pill (10 silver) from James at the Healers' Guild and a bottle of water (2 silver) from Lars at the pub -- both transactions correctly moved the item and deducted silver,
i/inventory updated immediately. Opened a bank account with Zoe (ask zoe for account, 5-silver minimum deposit) and successfully exchanged currency (ask zoe to exchange 20 silver for gold) -- see the bug section above for what this surfaced and how it was verified fixed. - Death/respawn: no reachable-in-budget wild monster could kill a 420-HP level-1 character in reasonable real time (the rat fight above shows just how low the to-hit rates are at level 1), so this was triggered directly and deliberately via the seeded admin account (
fluffos/Mud@2026) on a second connection:eval object ob = find_player("qintestds"); return ob->eventDie("test smash");against the non-admin test character (never the admin's own body, which would hitlib/creator.lpc's wizard-exempteventDie()override instead and prove nothing). Confirmed the full cycle live: death message + ASCII "YOU ARE DEAD!" art,scorecorrectly showedQintestds the ghost,undeadrace, and reduced max MP while dead;regeneratecorrectly rematerialized the character at roughly half HP/MP/SP, applied the expected XP penalty (50 -> 38,score's "more experience points to advance" figure moved from 450 to 462 accordingly), and dropped the character back at the same default "start room" respawn point.log/debug.logstayed clean through the whole death/regenerate sequence. quit/ debug.log / reconnect after a real gap:quitproduced the correct "Please come back another time!" message and clean worn-item-removal text;log/debug.logshowed zero errors immediately after (this project's own §7.16/§10.7 lesson: a clean-lookingquitmessage does not by itself prove nothing broke server-side -- checked anyway, and it really was clean here). Waited a genuine 90-second wall-clock gap, reconnected with the same login/password, and landed back exactly where the character had quit (First Village Bank, same worn items re-equipped), withscorecorrectly reflecting realistic additional food/drink decay over the elapsed real time.
Minor observation, not fixed (cosmetic, not a programming bug)
domains/town/room/mansion_uhall1.lpc (and likely other rooms using
the same window-as-exit idiom) defines "window" as BOTH a raw
SetExits() key and a SetEnters() entry. The room's own
GenerateObviousExits()-generated text lists "window" as if it were
a plain bare-word direction right alongside down/west/east/south
("Obvious exits: down, west, east, window, south, enter window"), but
typing bare window actually fails ("There is no go window here.")
-- only enter window (or, per verbs/rooms/go.lpc's own help text,
presumably go window) actually works. Root cause: lib/nmsh.lpc's
bare-word-to-"go "-command pre-aliasing only covers the fixed
classic-cardinal-direction set (n/s/e/w/ne/nw/se/sw/u/d/out), never
arbitrary custom exit names, while lib/std/room.lpc's
GenerateObviousExits() blindly implode()s every raw exit key into
the display text regardless of whether it's bare-word-usable. This
looks like it would affect every room in the whole Dead Souls lineage
that names a custom exit outside the cardinal set (not something
introduced by this archive), and it's misleading-but-harmless UI text,
not a crash or wrong efun call -- documented here per the project's own
scope discipline (ERR_THERE_IS_NO is a normal, non-fatal parser
rejection, not a bug signature) rather than "fixed" by guessing at what
the room author actually intended.
Sibling sweep of ds386's round-two eventRevive()/room.lpc/combat.lpc/beggar.lpc bugs (2026-08-27)
ds386's own round-two deep-functional-test pass (this NOTES.md's own
sibling file) found and fixed four bugs and flagged all of them for a
sweep across the whole Dead Souls 3.x lineage: (1) SEVERE
eventRevive() feeding float arithmetic into AddHealthPoints()/
AddMagicPoints()'s int parameters (AGENTS.md §7.121 class), (2) the
MudOS-era replace_program() fold in lib/std/room.lpc's create()
(AGENTS.md §7.141), (3) the Wimpy fraction-vs-percentage bug in
lib/combat.lpc (AGENTS.md §7.124 class), and (4) a minor GiveMap()
reentrancy gap in domains/town/npc/beggar.lpc. Checked all four here:
- Bug #1 (
eventRevive()float corruption): NOT PRESENT, confirmed clean.lib/player.lpc'seventRevive()heals back HP/MP/SP via plain integer division (AddMagicPoints(-(GetMaxMagicPoints()/2)),AddStaminaPoints(-(GetMaxStaminaPoints()/2)),AddHealthPoints(-(GetMaxHealthPoints()/2))) -- this codebase never adopted thePERCENT_MP/PERCENT_HPfloat-#definepercentage schemeds386/dshakkard/deadsouls_fluffosuse here, so there is no float expression feeding theintparameters at all. No fix needed. - Bug #2 (
replace_program()fold inlib/std/room.lpc): PRESENT, fixed identically tods386/dsI. Removed thereplaceable(this_object()) && !GetNoReplace()→inherit_list()→replace_program(tmp[0])fold fromcreate()entirely (pure memory micro-optimization, no functional effect once applied since this driver defersreplace_program()'s effect to a periodic backend sweep, which crashes any closure built on a freshly-loaded room, e.g.eventHearTalk()'sTALK_AREAfilter, for roughly its first 5 minutes).SetNoReplace()/GetNoReplace()left in place as harmless now-unused API. - Bug #3 (
Wimpyfraction-vs-percentage): PRESENT, fixed identically tods386.lib/combat.lpc:65hadWimpy = 0.20;(declaredprivate int Wimpy, so the float literal silently truncated) instead ofWimpy = 20;, plusSetWimpy/GetWimpymistypedfloatinstead ofint. Fixed both. Verified live: booted (~/src/fluffos/build-debug/src/driver config.fluffosfromlibs/dsIII/), logged in as the existing admin account (fluffos/Mud@2026), ranwimpy->Percentage: 20%, a clean integer. - Bug #4 (
GiveMap()reentrancy indomains/town/npc/beggar.lpc): PRESENT, fixed identically tods386. Added the same!present("town map",ob)delivery-time re-check insideGiveMap()that already existed at schedule-time ininit().
Verified live end-to-end: fresh boot compiled clean (zero new
errors in log/debug.log, only the same pre-existing benign warning
classes already catalogued), say hello world worked immediately with
no crash, and wimpy showed the fixed 20%. Killed the test driver by
exact PID when done.
Source pattern for all four checks: ds386/NOTES.md's "Deep
functional test (round two, 2026-08-27)" section.
Sibling sweep: become <class> SetClass -> ChangeClass fix (2026-09-01)
Ported the fix from riftsds (AGENTS.md §7.195/§7.196; commit
11216f003b1) -- see ds386/NOTES.md's identical write-up (same
session, same batch) for the full bug mechanism. Summary: the stock
Dead Souls "Praxis" demo guild-join rooms called SetClass() directly
instead of ChangeClass(), so the multi-class privilege gate
(high_mortalp(), which excludes creators too) always silently
rejected a fresh explorer's first class despite a success message
printing.
Confirmed present here, byte-identical to ds386/riftsds's
pre-fix files: all six domains/Praxis/*_join.lpc files called
SetClass(); secure/include/compat.h was missing the same three
query_name/query_cap_name/query_gender mappings.
Fix applied: six SetClass() -> ChangeClass() edits, three
compat.h accessor lines added -- identical to ds386.
Live-verified with the seeded fluffos admin (Class reset to
"explorer" via eval between attempts, to force the exact
creator-excluded-from-high_mortalp() scenario the bug hits):
become fighter/become cleric/become mage all now print the real
success text and score confirms the genuine class change ("You are
a level 1 Human Fighter"/"Cleric"/"Mage"). become monk/kataan/
rogue do not work, but this is the identical pre-existing,
shared-lineage missing-class-data gap documented in ds386/NOTES.md
(secure/cfg/classes/ here also only ships explorer/fighter/
mage/cleric/thief -- confirmed, same as riftsds and ds386),
not a regression or a miss in this fix.
Committed only the six join-file fixes and the three compat.h
mappings; incidental save-file churn from this session's boot (seeded
fluffos admin's Class field, player list, mudinfo, snoop, preload
saves, RELEASE_NOTES_HTTP refetch) was left uncommitted. Killed the
test driver by exact PID when done.
Shop (2026-09-04 librarian slice)
Otik's general store (/domains/town/room/shop) is live on this 3.0
snapshot — the handbook's "Otik" example is not boilerplate here.
Seeded admin fluffos / Mud@2026 (88 silver on the creator save)
goto'd the store. buy wooden torch from otik completed a paid
sale: Otik said "Here is an old wooden torch for 60 silver!",
inventory showed the torch, money 88→28 silver. Purse math is
integer. Do not use bare buy torch — /domains/town/obj/rayovac.lpc
still carries "torch" in its id list. 拜师 analogue
ask herkimer to join at /domains/town/room/magic_guild is still
Orcslayer-gated ("First you must prove yourself worthy..."), same
as the earlier §10.7 pass; re-confirmed live this slice.
Bug found and fixed (heartbeat hobbled(this_player())):
same shape as deadsouls_fluffos/brassring/dsII.
lib/body.lpc heart_beat called hobbled(this_player()); during
heartbeat this_player() is 0, so disable.lpc did
0->GetMissingLimbs() every 2s. Changed to hobbled(this_object())
and added if(!objectp(ob)) return "No missing limbs."; after the
decls in secure/sefun/disable.lpc. After this boot, look/goto/buy
worked with no idle collapse. Verb-file hobbled(this_player())
checks in go/jump/enter/climb were left alone (those run in command
context). Same one-line fix applied this session to
dshakkard/riftsds/ds386 (dsI has no hobbled()).
深度功能测试(§10.7,2026-10-03)— compile warnings
Method: scripts/lpc_warnings.py dsIII --fix (KB 04 §6.10) over all
2298 .lpc files, then a pristine-tree (scripts/pristine_tree.sh)
live boot: admin login (fluffos/Mud@2026), movement between the
workroom and the sample room, NPC load, and a direct eval
MASTER_D->log_error(...) probe. Clean boot, no crash, no
"insufficient permission" apply-rejection anywhere in the console.
Fixed, mechanically, across ~1390 files: every nosave-function
(the historic static→nosave conversion hitting functions, not
just variables)→protected/dropped-if-called-cross-object, every
unused local variable, every unknown escape sequence. See the commit
log for the itemized breakdown; this is this lib's share of the
corpus-wide warning-is-a-bug policy (AGENTS.md Conventions, 2026-10-03).
Fixed by hand, five distinct arg-count/return-type families (KB 04
§6.10's varargs-on-override pattern; none change call-site behavior
since LPC already tolerates a call with a different arg count than
declared):
domains/default/npc/horse.lpc: dropped two redundant direct inherits (LIB_MOUNT/LIB_DOMESTICATE) already reached throughLIB_SENTIENT→LIB_NPC/LIB_LIVING— the safe, same-file diamond case.lib/std/germ.lpc'seventSuffer()family: base changedvoid→int(its only caller discards the return value); six disease overrides (ecoli/lice/cold/h1n1/flu/fleas) gotvarargs;rage.lpc's barereturn;becamereturn 0;.eventTurnOn()/eventTurnOff()family:varargson five files' overrides (jennybot, turret, rocketpack, wristcomp, drone2) plusgenerator.lpc'seventTurnOn()-only override.create()family (six files): checked each override against the *actual* base it inherits before fixing, since unlike the two families above these don't share one common base. Five getvarargs;secure/lib/net/remote.lpcis the one case where the *base* has more required args than its two overriders (realms/{fluffos,template}/adm/remote.lpc), so the fix lands on the base instead.
Two real bugs found and fixed:
secure/daemon/imc2.lpc'sGetChanInfo()built a copy ofchaninfoand then returned the literal1instead of the copy. Grepped every file for a caller: none exist today, so this is currently unreached, but it's a real bug fixed at the root.scripts/wasm_keep_dirs.txthad zero entries for dsIII. Since git doesn't tracklog/and the WASM site's zip-boot only pre-creates directories listed there, every live site boot has been silently failing everylog_error()write ("Wrong permissions ... No such file or directory") and dumping the raw warning/backtrace text onto the player's screen instead — this is what actually surfaced the "Redeclaration of global variable" spam visibly during this session's own boot test rather than it going to a bedroom-quiet-but-dead log. Ranpython3 scripts/gen_keep_dirs.py --merge dsIII(targeted single-lib mode, no 15-minute corpus rescan) and live-verified the fix: createdwork/log/errorsby hand in the running pristine-tree boot, then confirmed a repeateval MASTER_D->log_error(...)wrote cleanly tolog/errors/fluffoswith no error, both on screen and by reading the file on disk.
One self-caught mistake, documented so the class is on record:
secure/sefun/fuzzymatch.lpc had been "fixed" in an earlier slice by
moving alen/blen/dist inside each function's #ifdef
__FLUFFOS__ guard (this driver never defines __FLUFFOS__, so the
guarded block, and everything only used inside it, is dead on this
build — KB 04 §6.10's documented ifdef-branch caveat). That earlier
pass missed that mixed foo, baz = alen+1; on the next line is
*also* only used inside that same guarded block, and had deleted it
outright instead of moving it in too, leaving a dangling while(baz)
reference in the (currently dead) branch. Caught on a pre-commit
re-read of the diff, not by the compiler (the branch doesn't compile
here, so lpcc never saw it either) — restored the declaration inside
the guard in both affected functions. Grepped the rest of this
session's unused-locals diff for the same shape (a deleted
declaration whose *use* is also inside an #ifdef a few lines below
the deletion point) and found no other instance.
Explicitly deferred, not rushed — a fresh full scan after all of
the above shows 2193 distinct diagnostics remain (2298 files compile,
10 pre-existing/deliberate failures unrelated to this session:
obj/area_room.lpc, obj/stargate.lpc, open/prog.lpc,
secure/cmds/admins/opcprof.lpc — a missing customdefs.h, a
file whose own header says "here on purpose to prevent this from
loading", and an opcprof efun this driver build lacks):
- 1671 "Redeclaration of global variable" warnings across 929 files — two unrelated mixins declaring the same global name; the driver forces the second to
nosaveto avoid a save-key collision. Cosmetic when both sides were alreadynosave; a real miss only when a side that wasn'tnosavesilently loses persistence. Top clusters are theread/touch/smell/listen/lookevent mixins pulled in viastorage.lpc/flask.lpc, andbase_armor.lpc. This needs its own dedicated pass, not a rushed one. - ~190 "inherited from both" diamond-inheritance warnings in the same
storage.lpc/flask.lpc/base_armor.lpc/client.lpcclusters — each is a judgment call about which definition should win, unlike the clean same-filehorse.lpccase already fixed. - ~20 remaining "Number of arguments disagrees"/return-type-mismatch instances beyond the three families already fixed (
GetHelp,eventReleaseObject,SetProtection,CanRelease/pre_north,CanReceive,clean_up,eventCatch,eventReceiveObject,CanGet/GetLong,eventJump,GetExternalDesc,SetCoordinates,eventRead/eventSocketClosed,eventReceiveCommand,CanSell). - A handful of one-off warnings (
Function pointer returning string constant is NOT a function call,Non-void functions must return a value,Types in ?: do not match, a fewPrevious function prototype ... does not match) scattered acrossdomains/Praxis/*,lib/props/save.lpc,daemon/classes.lpc,lib/pager.lpc, and others — each needs its own individual read, not a mechanical fix.
深度功能测试(§10.7,2026-10-03, addendum)— corrections and follow-up
Correction to the 2026-10-03 section above: its sentence "Grepped the rest of this session's
unused-locals diff for the same shape … found no other instance" was wrong. The grep
was by name, not by scope. A scope-aware check (a deleted declaration whose name still
occurs, inside the same function body of the original file, on a line under an
#if/#ifdef) found 23 more: the declaration had been deleted because the driver does
not compile the branch that uses it, which silently breaks the branch for the day it is
compiled. All 23 were restored *inside* their inactive branch (daemon/map.lpc,
domains/Praxis/roots.lpc, lib/body.lpc, lib/cedit.lpc ×2, lib/chamber.lpc,
lib/lvs/position.lpc, secure/cmds/creators/gauge.lpc, secure/daemon/autoexec.lpc,
secure/daemon/imc2.lpc, secure/daemon/master.lpc, secure/lib/net/http.lpc), the
same fix fuzzymatch.lpc needed, and scripts/lpc_warnings.py now refuses to delete such
a local (KB 04 §6.10).
Follow-up fixes (same day): 15 (: "name" :) function pointers in domains/Praxis/*
(a string constant, not a call, in this driver) → (: name :) with a forward prototype;
domains/town/obj/ebutton1/ebutton2 car->SetDoor(1) → SetDoorClosed(1) (KB 06 §7.211);
lib/virtual/virt_land.lpc SetCoordinates(int x, int y, int z) renamed
SetVirtualCoordinates (it clobbered LIB_ROOM::SetCoordinates(mixed) in every virtual
room; the only callers of the 3-int form are in the file itself); return-type/prototype
families (limb.lpc GetSaveString, room.lpc RemoveSearch, eventDeteriorate in
obj/light/obj/whip, oob.lpc eventRead, corpse.lpc SetClass/GetClass);
29 more varargs and 14 bare return; by the tool; secure/cmds/admins/opcprof.lpc now
reports that the opcprof() efun is gone from FluffOS. Oracle against the pre-session
commit (8ef71a2827e): 1385 nosave→protected flips, no other change except the
intended SetCoordinates rename.
Remaining diagnostics: 1671 Redeclaration of global variable (929 files) and 418 inherited
from both, from 46 source files (17 redundant leaf inherits, 8 function overlaps, 4
partial overlaps, 17 name collisions; queued), and the four files that never compiled
(obj/area_room, obj/stargate, open/prog, secure/cmds/admins/opcprof before this
change).
深度功能测试(§10.7,2026-10-03, structural pass)— one file reached through two inherit paths
The last open cluster of the compile-warning pass (KB 06 §7.213 has the mechanism). 1671
Redeclaration of global variable + 418 inherited from both X and Y warnings came from 46
source files; the other ~900 files repeated them. dsIII now prints 5 diagnostics, all in the
three files that never compiled (obj/area_room, obj/stargate, open/prog; type.h's
OBJECT redefinition is open/prog.lpc including it next to compat.h).
Fixes, by kind:
- 16 leaf files inherited something their other inherit already contained (
LIB_READafterLIB_ITEM/LIB_ARMOR,LIB_SMELLafterLIB_BED,LIB_SHOOTinpcannon,LIB_AMBIANCEafterLIB_SHOPinhealer):scripts/lpc_diamonds.py --fix-redundant --applyremoved the line.healerlit lamps now count (the plain ambiance getter had replacedroom.lpc's). - Name collisions between private variables:
npc.lpclost a deadUnique(the real one isLIB_UNIQUENESS's),interactive.lpcan unusedglobaltmp,autosave.lpcrenamesLastSave→LastAutoSave(props/save.lpchas its own),pipe.lpcBurnRate→PipeBurnRate,room.lpccounter→RoomCounterandSearch→DefaultSearch(inventory.lpcandevents/search.lpchave theirs; the room's ownAddSearch/GetSearchkeep using the room's),exits.lpcDir→RoomDir(enter.lpchas one),corpse.lpcClass→LivingClass(damage.lpc's is the weapon class; corpses do not save),donate.lpcOwner→DonateOwner(domesticate.lpchas one),bot_limb.lpclost its copy oflimb.lpc'sstank,base_storage.lpcits unusedmy_save(worn_storage.lpcrenames its own toWornSave),players.lpc/pwatch.lpc/drone.lpc/the door module declared a name twice in one file, and the nine creator modules prefix their scratch globals (globalstr→file_globalstr, ...) the way dsII's do:staff.lpcandglasses.lpcinherit all nine. - Functions defined by two inherits, resolved in the class that inherits both and spelled the way the inherit order had already chosen:
player.lpcCanGet()(living's, whichliving::direct_get_obj()needs; interactive's "is a living being!" never was in effect),chamber.lpc/vehicle.lpcGetDoor/SetDoor/GetEnter/ResolveObjectName(exits') andSetLanguage(read's),eventTurn()of the four activatable/turnable bots (the later inherit,LIB_ACTIVATE/LIB_TURN),GetSave()of the two poles (item::GetSave(), as in dsII),worn_storage.lpcSetSaveRecurse()(persist's, which itscreate()relies on). trainer.lpcinit():base_trainerandsentientboth define it, the later inherit won, sobase_trainer'sinit()— it forgets a student who left in the middle of a lesson — never ran and "I am already training you!" stuck for good. It now calls both. Live, before and after: leave Radagast's room mid-lesson, wait out one tick, come back → before: "I am already training you!" forever; after: "You will have to start your studies anew, Fluffos." and the next lesson starts.- Dummy hybrids (
campus/obj/trashcan,town/obj/riverwater,town/obj/seawater) inheritedLIB_BASE_DUMMYandLIB_STORAGE/LIB_FLASK, i.e. every item mixin twice (100 warnings each). WhatLIB_BASE_DUMMYadds to an item isisDummy()andSetInvis(1); the leaves define those and drop the inherit (and with it the door/knock/scratch verbs ofLIB_ENTER: "knock on river" now gets the parser's refusal, "enter river" says "You can't enter that." instead of "...!"). The eight places that askedinherits(LIB_BASE_DUMMY, ob)(verbs/items/look.lpc×3,room.lpc,flask.lpc×3,sefun/get_object.lpc) askob->isDummy(), which every dummy and hybrid answers. LIB_OOB(secure/lib/net/oob.lpc) inheritedLIB_SOCKETandLIB_CLIENT, bothLIB_DAEMONs (28 warnings, andOOB_Danother 24 because it inheritedLIB_DAEMONnext toLIB_CLIENT). The class now inheritsLIB_CLIENTonly and carries the sixLIB_SOCKETmembers it used (Descriptor,Owner,GetAddress,GetDescriptor,eventCloseSocket,eventSocketClosed,SocketWriteforsocket::eventWrite);OOB_Dcallsclient::create().
Radiance (a bug the oracle exposed, not a warning): container::GetRadiantLight() already adds
GetBaseRadiance(), the object's own glow, but npc.lpc and storage.lpc still added
object::/item::GetRadiantLight() on top, so SetRadiantLight(7) gave 14 for an NPC, chest, bed
or chair and 7 for an item or a player. Both return the container's value now (7); worn_storage
did not count its contents at all (armor's getter won) and returns it too. No shipped object sets a
radiance on those classes. The container formula itself (own glow attenuated by ambient: 0 at
ambient 20 for a 7) is untouched.
Verification. Golden-master oracle (scripts/ds_oracle.py, KB 08 §10.12), 266 + 18 programs
(every lib/ program and 61 leaf files) probed on HEAD and on the working tree: normalised GetSaveString() unchanged everywhere, no getter changed
besides random per-creation stats; function definers change only where the resolution is now
explicit (list above), duplicate variables disappear, the radiance rows above, healer's
lamp-in-room 30→35, and the three hybrids lose the enter/knock/scratch functions. Live on a
pristine tree, HEAD and edited side by side: trashcan (look at/in, get/put, "firmly attached",
knock, open), river and sea (look, fill, drink, "stays in place", jump into sea swims), coffin and
hoverpod (enter/out), pole GetSave(), sign and note read, plasma cannon wear/remove, the
trainer scenario above, the OOB service port (oob-test, oob-begin, oob-file replies are
byte-identical to HEAD) and the OOB client (clone to a local listener: same oob-begin packet, the
socket closes after oob-end), a fresh mortal (13+ prompt, race, start room, score,
inventory) fighting the dodo with damage both ways, and the admin command battery with no
runtime error on the console. The formatter (KB 08 §9) was not run: this tree is not
formatter-clean, it rewrites nearly every line of the 58 touched files.
深度功能测试(§10.7,2026-10-03, addendum 2)— a regression of mine in Praxis stone.lpc, and a corrected claim
Found while verifying the same Praxis files in ds386 (eval new("/domains/Praxis/obj/misc/stone")->GetLong()).
domains/Praxis/obj/misc/stone.lpc: once the(: "long_func" :)pointer became a real pointer (the 15-pointer fix earlier today),look at stoneranlong_func(), which printed its text withmessage()and returned nothing;GetExternalDesc()then added to the0it got back and the player saw a run-time error trace (Left hand side of += is a number (or zero)).long_func()now returns the text (the same fix as ds386). The other 14 pointers' targets were each called once live in ds386 (exit checks,at_desk,la_jail,listen_council, the spider'sdeath_func, ...): none raises an error.- Correction to the structural-pass notes and to the comments in
trashcan/riverwater/seawater:LIB_BASE_DUMMYadded more thanisDummy()and the invisibility. It also bringsLIB_ENTER,LIB_KNOCKandLIB_SCRATCH, and the oracle'sfn -rows for these three objects (about 30direct_*/event*/Set*functions) are that loss, not noise. Nothing in the lib calls them on these fixtures, and the live transcripts showknock on trashcan/knock on river/open river/enter riveranswering "You can't ..." before and after (KB 06 §7.213 kind 5 now says so). The comments in the three files now say it too. - One of the "5 remaining diagnostics" was not a dead file:
secure/include/type.hredefines theOBJECTmacro thatcompat.halready defined ("/lib/std/item"against the bit mask0x10; nothing in the lib uses either), andsocket_err.h/socket.hdo the same withERROR_STRINGS(32 against 33). Each#definenow follows an#undef, which keeps the include-order behaviour the lib always had. dsIII is at 4 diagnostics:obj/area_room.lpc,obj/stargate.lpcandopen/prog.lpc(two errors).
深度功能测试(§10.7,2026-10-04)— Praxis comma-form function pointers
The 30 comma-form pointers in the 21 Praxis files and the target fixes made in ds386 (see its NOTES section of the
same date: SetSearch handlers return their text, the helm asks GetMorality(), test_invis takes the viewer,
look_at_vault/look_at_manhole restored as text) carry over here: scripts/lpc_twin_port.py adopt ds386 dsIII
--pre HEAD --apply (18 files are token twins: 12 byte-identical, 6 spliced into dsIII's own spacing; farm, west_road2 and yard carry dsIII's own code and were edited by hand the same way). All 21 files compile without a diagnostic, and a live spot check (search field,
search mounds, look at mound/manhole/vault/treats, the planning room, a voting hall) answers as in ds386.
深度功能测试(§10.7,2026-10-05)— 主控 author_file()/domain_file()
驱动的 mudlib_stats 包在主控载入时各调用一次 author_file(<主控文件>) 和 domain_file("/"),要求返回字符串。本库这两个 apply 只为 domains / realms 目录下的文件返回名字,其余返回 0,所以每次启动都打印 author_file() in the master file does not work, using root_uid as fallback 和 domain_file() in the master file does not work, using bb_ui as fallback 两行,网页版每位访客的终端里都看得到。secure/daemon/master.lpc 改成与 fluffos 组织维护的 Dead Souls 上游(deadsouls_fluffos)相同的写法:其余文件的域返回 "BACKBONE",作者返回 "NONAME"。域等于 backbone 域时驱动让对象沿用创建者的域,与返回 0 时相同;作者统计(author_stats())多出一行 NONAME,汇总 realms 目录以外的对象(KB 06 §7.222)。用 lpcc config.fluffos /nonexistent.lpc 前后对比,主控载入段只少了这两行。
- 2026-10-14: FluffOS 970d9f09 warns
Float value truncated to int(#1426). 13 sites in 10 files: assignments, initializers and returns now spell the truncationto_int(...)(same value);x op= <float>converted the float before the operation (zeroingxfor a factor below 1) and is nowx = to_int(x op ...):/lib/teller.lpc(total +=),/secure/daemon/players.lpc(seed *=). Changed objects loaded before and after in fresh drivers, no regressions (scripts/lpc_fix_float_trunc.py, KB 04 §6.10).
x != "a" || x != "b" and x == "a" && x == "b": comparison chains of one value that can never differ (2026-10-20, KB 06 7.282)
if (arg != "wan" || arg != "pill") return notify_fail(...) is true whatever arg is, dir == "south" && dir == "north" is never true: the guard under the test never opens, or never closes. The author meant "neither of these" (&&) or "either of these" (||). != chains joined by || became && (only where the statement under the test is a return, a refusal or a guard clause), == chains joined by && became || (scripts/lpc_fix_cmp_chain.py). What it was: prompt / editor messages were never marked MSG_NOWRAP (msg_class == "prompt" && msg_class == "editor"). Changed: /lib/interface.lpc (1).
if (x = CONST): a comparison written as an assignment (2026-10-20, KB 06 7.290)
if (arg = "button" || arg = "pill"), if (!arg || arg = "") return 0;, else if (check = 0 && tempB != ""): = was typed for ==, so the condition is the constant: the branch is always taken for a non-zero number or any string (even "") and never for 0, and the variable is overwritten; the driver does not warn. Every such = became == (scripts/lpc_fix_cond_assign.py, 10 terms). Changed: /cmds/creators/cryptogram.lpc (1), /cmds/creators/rot.lpc (1), /domains/campus/npc/jennybot.lpc (1), /domains/default/weap/grenade.lpc (1), /domains/default/weap/plasma.lpc (1), /domains/default/weap/rpg.lpc (1), /domains/default/weap/torpedo.lpc (1), /lib/lead.lpc (1), /secure/sefun/mappings.lpc (1), /verbs/builders/reload.lpc (1).
A login password over 255 bytes: crypt() raises (2026-10-20, KB 06 7.294)
The driver's crypt() raises (Error in crypt(), check your salt) for a key over 255 bytes, where the old driver hashed any length. A password of 256 bytes or more typed at the login prompt threw an error in the password check and left the connection at a bare > prompt, so the login never completed (the old-password test of password the same); found by the sweep shape of 300 x. /secure/sefun/sefun.lpc now defines a simulated efun crypt(key, salt) of the same name: only an over-long key is cut (to 255 characters, then character by character until sizeof(to_buffer(key)) <= 255: the limit is in bytes, a CJK character takes three) before it is handed to efun::crypt(); every ordinary password hashes as before and the saved hashes are untouched (scripts/lpc_add_sefun.py crypt).
The suffix strip after a directory read (2026-10-20, KB 06 7.296)
After the .c -> .lpc rename the names read with get_dir("*.lpc") were still cut by two characters ($1[0..<3]): baguadao.lpc became baguadao.l, and every path built from it failed to load (stories, battlefields, events, help indexes, player-made item data, summon lists). Now [0..<5] (scripts/lpc_fix_getdir_strip.py). Changed: /daemon/help.lpc (2).
help <topic> on a plain clone, telnet and setreboot without an argument (2026-10-21, KB 06 7.212, 7.336)
help <topic> loads /daemon/help, whose LoadIndices() adds get_dir() results with +: secure/cmds/common, verbs/spells and verbs/undead are directories the archive ships empty and a git clone does not have (git keeps no empty directory; the site recreates them from scripts/wasm_keep_dirs.txt). Booted without them, the first help <topic> printed A runtime error occurred (Bad type argument to +. Had array and int) and the half-built daemon answered every later topic with "no results". Every directory is now read through DirList() (get_dir(pattern) || ({})); help look, help telnet, help races and help commands answer with the four directories removed (PLAY_RMDIRS). The mortal telnet with no argument raised Bad argument 1 to sscanf() Expected: string Got: 0 (the bare-verb sweep: A runtime error occurred), and the usage line it meant to print came from this_object()->help(), a function no object defines: it tests !args || now and prints GetHelp(); the administrators' setreboot called the same missing help() and went on without a return, it prints its syntax and returns now. Changed: /daemon/help.lpc, /secure/cmds/players/telnet.lpc, /secure/cmds/admins/setreboot.lpc.
Creator and administrator commands with no argument, the A* padding (2026-10-21, KB 06 7.336, 7.338)
The creator / administrator verbs had never been run, only compiled. Swept as the seeded administrator (play_sweep_lib.py SLUG --wiz --account fluffos:Mud@2026 --shapes one), seven of them raised on the bare command: areaclone and cryptogram (sscanf(0, ...)), pause (lower_case(0)), html (read_file(0)), encre (player_save_file() runs before the argument is looked at and raises Bad argument 1 to save_file()), resolve and wget (the daemons RESOLV_D->eventResolve(0) and WGET_D->eventGet(0) run sscanf(0, ...) / strsrch(0, ...)). Each tests the argument first and prints its GetHelp(). The A* sefun's find_path() (the creator command astar) died with (s)printf(): Null pad string specified because it pads the map with sprintf("%N'\27's", ""), a pad string that has no display width in FluffOS; it pads with spaces and replaces them, and astar prints its demo route again. The sweep must skip removeraces (it empties the race table: every NPC created afterwards fails in its heart beat). Changed: /secure/cmds/builders/areaclone.lpc, /cmds/creators/cryptogram.lpc, /secure/cmds/admins/pause.lpc, /cmds/creators/html.lpc, /secure/cmds/admins/encre.lpc, /cmds/creators/resolve.lpc, /secure/cmds/creators/wget.lpc, /secure/sefun/astar.lpc.
add_action() registrations of functions nobody defines, second round: objects behind a macro path or that the static scan cannot settle (2026-10-21, KB 06 §7.349)
The first round's static scan could not read objects that inherit through a macro path (a #define ROOM STD_DIR "room/room" whose body starts with another macro) or an inherit it could not resolve, and skipped them as UNSURE; the second round fixed the resolver, rescanned, and asked function_exists() of those objects in a running driver. An add_action("fn", "verb") whose function is defined neither by the object, nor by its headers, nor by its parents, nor by any object derived from it (scripts/lpc_scan_callout_targets.py, descendants checked transitively, then function_exists() in a running driver, scripts/lpc_verify_handlers.py). The driver walks the actor's sentences from the newest one: when that sentence's function does not exist it raises *Function for verb 'drop' not found. and tries no other handler of the verb (an older dead sentence is passed over silently). Removed 3 registrations in 2 files (scripts/lpc_fix_dead_add_action.py), the verbs are left to their other handlers: /secure/obj/machine.lpc (check_it), /secure/obj/memo.lpc (clean_memo, erase_memo). Most frequent: check_it x1, clean_memo x1, erase_memo x1.
Combat probe with the seeded administrator (2026-10-22): clean
scripts/play_combat_probe.py dsIII --account ... --clone ...: the administrator cloned /domains/default/npc/tree, /domains/Praxis/cemetery/mon/ghosta, /domains/Praxis/obj/mon/balrog, /domains/campus/npc/charly, /domains/town/npc/thief, /domains/Ylsrim/npc/balrog into its room and attacked each for 20 s (6 fights read): no driver line and no error text on the screen. (KB 08 §10.16)
new(MISSING)->move() / carry_object(MACRO(..))->wear() chains guarded (2026-10-22, KB 06 §7.73 addendum)
A statement new(PATH)->move(...); / carry_object(ARMOR_D("x"))->wear(); whose path names no file of this archive: new() answers 0 and ->move() on it raises Bad argument 1 to EFUN call_other(). In create() the object never loads, in reset() every spawn below the first missing one is skipped on every reset. 2 statement(s) in 2 file(s) (new) are now { object new_ob = new(PATH); if (new_ob) new_ob->move(...); } (scripts/lpc_guard_carry_object.py --new: the path is resolved with the macros the file itself sees, an ambiguous macro or a virtual-object path is left). Load check of the 2 changed files, HEAD vs tree: 2 load at HEAD, 2 load now (0 newly loading, 0 regress).
Pointers (: name :) to functions the object never defines (2026-10-22, KB 06 §7.355)
A (: name :) in an item_desc / inquiry / chat_msg_combat names a function that neither the object, its headers nor its parents have a body for: it compiles, and the use raises *Undefined lfun pointer called: name (look THING / ask NPC about TOPIC fail on the spot, a combat or idle chat pointer fails inside the NPC's chat() and the rest of that heart beat is skipped). scripts/lpc_scan_callout_targets.py --kinds=lfun. 2 more function(s) stay missing (other 2): the prototype is there and the body is lost, or it was never written, and no sibling lib's copy of the file can be copied as it is (it lacks the function, needs helpers this lib does not have, or has another signature); nothing invented: /secure/lib/net/ftp.lpc:eventCmdPass, /secure/lib/net/h_ftpd.lpc:eventCmdPass.
log/ subdirectories nobody created: the logging write_file() / log_file() raises (2026-10-22, KB 06 §7.358)
The code of this lib writes logs into 3 subdirectories of log/: log/harass (lib/interface.lpc), log/imc2_server (secure/daemon/imc2server/server_log.h), log/secure/log (secure/lib/connect.lpc). Neither the archive, a git clone nor the site pack has them (no local boot wrote into them, so gen_keep_dirs.py never recorded them), and write_file() raises *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory" for a missing directory: the function that logs stops on that line and what came after it (the reward, the flag, the next step) never runs. This lib's log_file() is write_file(LOG_DIR + file, text) and raises the same error for a missing directory (measured). log/harass, log/imc2_server, log/secure/log are now in scripts/wasm_keep_dirs.txt (scripts/lpc_keep_log_dirs.py; the site and the pristine tree create the empty directories from it). Proof (scripts/lpcc_eval.py, an eval object under /adm/daemons or similar writes /log/zzdirprobe/..., fresh processes): the measured table in KB 06 §7.358.
Bare wizard command with a 0 argument (2026-10-27, KB 06 §7.336 Also)
After the permission gate, the command still handed 0 to sscanf / read_file / find_living. lpc_fix_bare_arg.py adds if (!arg) (or help(me) / GetHelp()) before the first use. See this commit for the files touched in this lib.