info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
A Dead Souls 3.8.x-based game-in-development (self-titled 'The Brass Ring') that ships as a content overlay for Dead Souls rather than a full mudlib on its own. On top of the underlying Dead Souls engine, TBR bundles a full DikuMud Alfa port (domains/diku-alfa/, 1185 files -- Midgaard and its zones) and is actively building its own bespoke fantasy continent, Etnar (the village of Wyr, with NPCs Albert Derby/Waltin Kelley/Caltan Dowini/the Pierce family already in place and a virtual wilderness room system). Character creation includes an age gate, a screen-reader accessibility question, an 8-race pick, and a complete 6/4/4 primary/secondary/minor skill selection across all 28 skills; new characters enter play in Saquivor, the real starting town (distinct from the tutorial start room), from which Etnar's Wyr (The Lounge) and diku-alfa's Temple of Midgaard are both reachable. No outbound network connections at boot -- unlike several sibling Dead-Souls-family libs, this one is safe for high-frequency automated re-boot loops.
README
A Dead Souls 3.8.x-based game-in-development. The village of Saquivor is the starting town; from there, roads lead west past the old church, across a humpbacked bridge, and into a dark forest. Bundled alongside the game's own custom content is a full port of the classic DikuMud Alfa world (the city of Midgaard and its surrounding zones) and the beginnings of a bespoke fantasy continent called Etnar -- the village of Wyr, with the Bramblewood and Vexwood forests and the town of Orgon planned around it.
Source: gh repo clone LashMUD/TheBrassRing. Slug brassring, number
963, port 40265.
Etnar
Etnar is the game's own original setting-in-progress, not carried over
from the base Dead Souls or DikuMud content. The village of Wyr is the
region the author was actively building at the time of this snapshot,
with rooms and NPCs (Albert Derby, Waltin Kelley, Caltan Dowini, the
Pierce family) already in place, plus a virtual (procedurally-served)
room system covering the wider wilderness. The char and q'in
subdirectories are reserved for future regions the game's own
readme.txt describes as "the lands of Q'in and Char."
Status
Boots clean under this project's native FluffOS driver, zero compile
or fatal errors. Verified live with two independent new characters:
full registration (name, age gate, screen-reader question, password,
gender, email, race pick, and a 6/4/4 primary/secondary/minor skill
selection covering all 28 skills) all the way into the game world;
enter town correctly reaching Saquivor's "Village Road Intersection";
Etnar's Wyr village and the bundled DikuMud content both reached and
rendering correctly; look/score/update/quit all producing
correct output; and reconnecting restoring the same character, in the
same room, with the same inventory.
Admin account: fluffos / Mud@2026 (this project's standard
seeded admin, granted by moving its save file into
secure/save/creators/ after a normal registration -- see NOTES.md
section 5).
WASM status: playable. Shared WASM driver. Admin login
(fluffos / Mud@2026) through the news pager into the Temple of
Midgaard, plus hp: 430/430 / quit ("Please come back another
time!"), verified with scripts/wasm_client.js. Play:
https://mudlibs.fluffos.info/brassring/
See NOTES.md for the full porting log, including how this session
reconstructed the game's entire missing security-daemon layer (this
repo never once committed a secure/master.lpc/simul_efun engine of
its own -- it ships as a pure content overlay meant to be dropped onto
an existing Dead Souls 3.9 install) and the real programming bugs found
along the way.
No outbound network connections at boot (IMC2 is disabled by this game's own shipped config, and its Intermud daemon never actually opens a socket) -- unlike several other Dead-Souls-family libs in this collection, this one is safe for high-frequency automated re-boot loops.
Local run
cd libs/brassring
~/src/fluffos/build-debug/src/driver config.fluffosGame port: 40265.
NOTES · 移植与修复记录
The Brass Ring -- porting notes
Source: gh repo clone LashMUD/TheBrassRing (cloned 2026-08-31). Slug
brassring, number 963, port 40265.
1. What this repo actually is: a content-only overlay, not a full mudlib
The repo's own README.md/Setup.txt say it outright: this holds "files
based on the Dead Souls mudlib ... used to develop The Brass Ring mud,"
and the setup instructions are literally "download the dead souls mud
library from http://dead-souls.net ... then replace the files in the
ds3.9/lib directories with the files in this repository." Confirmed by
file counts: the repo ships only 1,717 files total, and per-directory
counts are a small fraction of a real Dead Souls tree (daemon/: 2 vs
ds386's 60; secure/: 26 vs 568; cmds/: 8 vs 150; lib/: 21 vs 318).
Only the files the author actually touched or added were ever
committed.
The hard consequence: secure/daemon/master.lpc,
secure/sefun/sefun.lpc, and the entire rest of the security-daemon
engine layer were never committed to this repo at all -- not
gitignored, genuinely absent from git history (git log --all --
lib/secure/daemon/master.c returns zero commits, and there is no
.gitignore in this repo at all). Without a master.lpc the game
cannot boot under any driver.
Bundled inside the same repo (not a separate clone) is a complete port
of DikuMud Alfa (domains/diku-alfa/, 1,185 files -- the city of
Midgaard and its zones) with a top-level note crediting "the DikuMud to
Dead Souls port." The sibling repo
LashMUD/DikuMud-to-Dead-Souls-Port was checked and found to be the
same content already folded into this repo (confirmed file-for-file on
room/90.zon/rm_9000.c, byte-identical to the truncated file present
here -- see section 6.4) -- it did not need to be cloned separately.
2. Reconstructing the missing security layer, following the ds386/dshakkard precedent
This is the exact situation dshakkard (185, ds-hakkard) and, before
it, the general Dead-Souls-lineage guidance in AGENTS.md section 1.5
already cover: ds386's own raw archive, and its own already
driver-compat-fixed work/ tree, are the correct substitute for a
missing Dead Souls engine layer -- not invented content, since
ds386 (Dead Souls 3.8.6) is confirmed the same lineage TBR is built
on (its Setup.txt says "ds3.9," close enough that dshakkard's own
precedent -- also a 3.8.6-vs-3.9-labelled game -- used the same ds386
substitution successfully).
Procedure actually followed, at whole-tree scale rather than just
secure/:
1. rsync -a --ignore-existing ds386's pristine raw archive
(libs/ds386/raw/ds3.8.6/lib/) onto TheBrassRing's own raw clone
(libs/brassring/raw/lib/). --ignore-existing means TBR's own
1,717 files were never touched; every directory or file TBR didn't
ship (all of secure/daemon, secure/sefun, most of cmds/,
entire top-level directories like estates/, realms/, save/,
www/, etc.) was filled in from ds386's pristine source. Verified
after merge: 573 files under secure/ (568 from ds386 + TBR's own
26, with only overlapping paths -- secure/cfg/preload.cfg, the
secure/include/*.h set, secure/daemon/{autoexec,finger,players},
secure/lib/connect, secure/obj/medtric, secure/sefun/light,
and one each under secure/cmds/admins and secure/cmds/creators
-- correctly kept as TBR's own versions).
2. Ran scripts/convert_lib.sh on the merged raw tree (GB18030->UTF-8
-- a no-op here, this repo was already plain ASCII/UTF-8 --
.c->.lpc rename, static->nosave, literal .c" reference
fixes) to produce libs/brassring/work.
3. Then, critically, went one step further than a plain "copy
ds386's raw" substitution: every file the mechanical rename step
touched that TBR itself never shipped (identified precisely via
git status --porcelain --untracked-files=all inside the raw
clone, since the rsync --ignore-existing step left ds386's added
files untracked in that git working copy -- 4,676 files) was
replaced again, this time with ds386's own already
driver-compat-fixed work/ copy of the same path (after the
.c->.lpc rename). This reuses every hand-fix ds386's own
onboarding already discovered (the get_root_uid()/get_bb_uid()
stubs, the valid_read/valid_write lazy-load reentrancy guard,
etc. -- see AGENTS.md section 7.1/7.2) instead of rediscovering them
from a fresh mechanical-only conversion of ds386's *raw* (unfixed)
source. All 4,676 substitutions matched a real path in ds386's
work/ -- zero misses.
4. TBR's own 1,717 files went through nothing but the ordinary
mechanical convert_lib.sh pass; they needed their own,
TBR-specific fixes on top (section 3 below).
This means secure/daemon/master.lpc, secure/sefun/sefun.lpc,
secure/daemon/players.lpc's non-TBR sibling pieces, and every other
inherited engine file in this lib are not reconstructed from
scratch in the sense of writing new code -- they are ds386's own
real, already-tested Dead Souls 3.8.6 engine, verified to be the
correct substitute the same way dshakkard verified it (every
/secure/* path TBR's own code actually references was checked to
exist in ds386, and TBR's shipped secure/include/config.h and
secure/cfg/* are TBR's own real customized versions, not
substitutions).
3. Genuine programming bugs found and fixed (TBR's own code, or the bundled diku-alfa content)
None of the bugs below live in the reused ds386 engine layer -- that part came pre-fixed. All of them are in content this session actually had to touch: TBR's own custom files, or the bundled DikuMud port.
3.1 array is not a reserved word in this driver build -- pervasive TYPE array NAME old-MudOS dialect (AGENTS.md section 6.3, much larger instance than previously catalogued)
~/src/fluffos/src/compiler/internal/lexer_utils.cc only lexes the
word array as the L_ARRAY token when the driver is built with
ARRAY_RESERVED_WORD defined -- this build isn't, so array is a
plain identifier. Every TYPE array NAME declaration (global, local,
function-return-type, and function-parameter forms alike) is a hard
syntax error here: the parser reads TYPE as the type, array as the
*declared name*, and chokes on whatever follows. AGENTS.md section 6.3
already catalogues this class from isolated single-lib instances; here
it was the single largest driver-compat fix of this session --
found in every layer of TBR's own hand-written code (lib/body.lpc,
lib/combat.lpc, lib/combat_r_o.lpc, lib/living.lpc,
lib/genetics.lpc, lib/base_trainer.lpc, lib/meal.lpc,
lib/props/deterioration.lpc, lib/std/base_armor.lpc,
lib/lvs/abilities.lpc, daemon/help.lpc, daemon/seasons.lpc,
secure/lib/connect.lpc, secure/daemon/finger.lpc,
secure/daemon/players.lpc, secure/cmds/admins/mudconfig.lpc,
secure/obj/medtric.lpc, powers/npc/magic_user.lpc) and in the
bundled diku-alfa content (domains/diku-alfa/etc/{magic_user,
base_trainer}.lpc and 4 cityguard NPCs) and etnar's own bespoke NPCs
(albert_derby.lpc, waltin_kelley.lpc) -- 37 files, ~120 sites.
Because lib/body.lpc and lib/player.lpc (see 3.2) are inherited by
essentially every player/NPC object, this single bug class cascaded
into 1,873 of 3,800 files (49%) failing a full lpcc_check.sh batch
sweep before it was found and fixed -- a textbook instance of
AGENTS.md section 6.4's "one shared root cause, not N bugs."
Fix: mechanical script (fix_type_array.py, not checked in) that
drops the word array and inserts the real TYPE *NAME pointer-array
syntax, adding one * per comma-separated declarator (the classic
"TYPE * a, b; only stars the first name" sub-bug -- section 6.3's
other variant -- would otherwise reappear if only the first name in a
list got starred). Two shapes needed hand-fixing after the script ran:
- **
TYPE array *NAME** (8 sites:powers/npc/magic_user.lpc,waltin_kelley.lpc,caltan_dowini.lpc, bothpierce_pascal*.lpc, bothdiku-alfa/etc/magic_user*.lpc,diku-alfa/room/50.zon/ rm_5039.lpc) -- the author had *already* written the correct*and the redundantarraykeyword doubled it; the script's blind "insert a star" rule producedobject **targets(a pointer to an array of arrays, not what was intended). Fixed by hand: droparrayonly, keep the existing single*. class TYPENAME array NAME(2 sites:lib/body.lpc'sclass MagicProtection array GetMagicProtection(),secure/daemon/finger.lpc'sclass marriage array Marriages) -- the same dialect applied to aclass-typed array, needingclass TYPENAME *NAMEinstead.
3.2 lib/player.lpc: un-starred oldparties -- the exact bug already catalogued on ds386's own raw archive
Setup()'s string oldparties = PARTY_D->GetOldParties(); (missing
the *) is passed to RemoveExtraChannels() and foreached as if it
were an array, causing Bad type for argument 1 of
RemoveExtraChannels ( string * vs string ). This is not a new
discovery -- dshakkard's own meta.json already documents "a real
un-starred string oldparties bug in lib/player.lpc present
byte-identically in ds386's own raw archive" from that session's
TYPE * a, b;-class sweep. TBR's lib/player.c is its own tracked
file (not reused from ds386's already-fixed copy), so it carried the
same pre-existing upstream typo forward unfixed. Confirmed the fix
(ds386/work/lib/player.lpc already has string *oldparties) and
applied the identical one-character change. This bug alone masked a
huge share of the section 3.1 cascade, since player.lpc is inherited
by every player body -- fixing it (after fixing every direct TYPE
array site) is what let the corpus-wide compile-sweep failure rate
drop from 49% to under 1%.
3.3 domains/etnar/wyr/wyr/npc/pierce/pierce_pascal.lpc: missing closing brace drops a whole function
checkPrank() opens 2 extra brace levels (an if block, then a
switch) but only closes 1 before the file moves on to
checkPlacement() -- a hard "unexpected (" parse error at the next
function's own declaration, since the parser is still inside
checkPrank()'s body. Confirmed genuinely missing (not a
convert_lib.sh fallout) by a raw brace count (21 open, 20 close) and
by diffing against the sibling draft file pierce_pascal_1.lpc (a
much later, unfinished rewrite of the same NPC's logic, not currently
inherited/loaded by anything -- left as-is, it's the author's own
in-progress scratch file, not dead weight to clean up). Fixed by adding
the one missing }.
3.4 domains/diku-alfa/room/74.zon/npc/7044_blob_lemure.lpc: SertClass() typo
SertClass("fighter") -- undefined function; should be SetClass().
A plain one-character transposition typo, one instance, in the bundled
diku-alfa content (not TBR's own file). Fixed directly.
3.5 domains/diku-alfa/room/79.zon/meals/6013_water_barrel.lpc: wrong argument type to SetMealType()
SetMealType("water") -- SetMealType() (lib/meal.lpc) takes the
int bitmask constants from include/meal_types.h
(MEAL_FOOD/MEAL_DRINK/etc.), not a string; every sibling meal file
in the same directory (e.g. 7090_waybread.lpc) correctly passes
MEAL_FOOD. Fixed to SetMealType(MEAL_DRINK), matching the object's
actual purpose (a water barrel).
3.6 #define __DIR__ collisions in etnar's and diku-alfa's virtual-room servers -- same class dshakkard already catalogued
16 virtual/server.lpc/virtual/void.lpc files (all 6 etnar
sub-regions -- virtual, char, q'in, wyr/baramblewood,
wyr/orgon, wyr/vexwood, wyr/wyr -- plus diku-alfa/virtual/)
carry a manual #define __DIR__ "/domains/<name>/virtual/" that
collides with this driver's own native __DIR__ predefine ("Illegal
to redefine a predefined value"). AGENTS.md/dshakkard's own notes
already catalogue this exact pattern ("6 bespoke-domain virtual-room
files with the redundant manual #define __DIR__", fixed there by
deleting the line since the driver's own value is already correct).
Same fix applied here, at larger scale (16 files, since both etnar and
the bundled diku-alfa port use the standard Dead Souls virtual-room
template).
4. Config changes for playability (not bugs -- shipped defaults that would have blocked testing)
MUD_IS_LOCKED: TBR ships this1(a personal-development default --secure/lib/connect.lpc'sis_locked()check gates every new connection except creators). Flipped to0so ordinary registration works, matching this project's standard "make the default boot actually playable" policy.ADMIN_EMAIL/DEBUGGER: TBR ships"[email protected]"/"lash"(the original author's placeholders, perSetup.txt's own instruction to change them). Set to a generic placeholder and"fluffos"respectively;DEBUGGERonly gates a couple of debug-message/newbie exclusions, not admin rank (see section 5).
Confirmed no live outbound network connections at boot: TBR's own
secure/include/config.h ships DISABLE_IMC2 1 (verified this
actually gates secure/daemon/imc2.lpc's socket_create()/
socket_connect() calls behind #if DISABLE_IMC2, not just a cosmetic
flag); DISABLE_INTERMUD is 0 but daemon/intermud.lpc makes no
socket calls of its own at all in this codebase (it's a local
chat-channel abstraction only). No RELEASE_NOTES/version-check HTTP
fetch runs automatically either (TBR's own secure/daemon/autoexec.lpc
is much smaller than ds386's and only calls
IMC2_D->UnSetAutoDisabled(), itself a no-op while DISABLE_IMC2 is
set). Unlike ds386/dshakkard/havenmud, this lib is safe for
high-frequency automated re-boot loops.
5. Admin seeding (fluffos / Mud@2026) -- the Dead Souls file-move convention, made easier by a lucky default
Per AGENTS.md section 1.5's Dead-Souls-lineage note: admin-ness here is
a save-file-directory fact (secure/save/creators/<letter>/<name>.o
vs secure/save/players/<letter>/<name>.o), not a rank flag. Procedure
followed exactly as documented on riftsds: registered fluffos
through the completely normal new-player flow (name/age/password/
gender/email/race/skill-selection, AUTO_WIZ left at its shipped 0
so no special creator prompt was needed), then with the driver stopped,
moved secure/save/players/f/fluffos.o to a newly-created
secure/save/creators/f/fluffos.o, then rebooted.
One bonus finding: TBR's own shipped secure/cfg/groups.cfg already
lists fluffos in every ACL group (SECURE, ASSIST, ELDER,
TEST, INTERMUD, BUILDER, TELNET, EMOTES) -- confirmed
byte-identical to ds386's own default groups.cfg, i.e. this is Dead
Souls' own stock placeholder example name, not something this project
seeded. So the file-move above was the *only* step actually needed;
groups.cfg required no edit.
Verified: update /domains/town/room/start succeeds with no ACL
denial as fluffos (creator-only compile permission confirmed
working), and fluffos can goto anywhere in the world (used to
verify the etnar and diku-alfa content -- see section 6).
6. Live boot + playthrough verification
Boots with zero compile errors and zero fatal errors in
log/debug.log across every test session in this write-up (grep
count: 0 every time). lpcc_check.sh full-corpus batch sweeps hit
FluffOS's normal "batch mode never unloads" memory ceiling on this
unusually large corpus (3,800 files -- the full Dead Souls 3.8.6 engine
plus the bundled 1,185-file DikuMud port) before finishing a complete
pass every time it was tried (killed by this session's own 8-9.5GB RSS
safety net, per AGENTS.md section 10.4's documented memory-balloon
caution for mega-libs); the largest completed sample covered 2,590 of
3,800 files (68%) with a 99.2% pass rate and zero unexplained failures
after the section 3 fixes landed, so per section 10.4's own guidance
("on mega-libs the boot + interactive test is the sufficient
verification gate") the live boot below is the authoritative check,
not the partial sweep.
Verified live, twice with two independent new characters
(fluffos/qintest) plus one full reconnect:
- Full registration flow: name -> confirm -> 13+ age gate -> screen- reader question -> password (+confirm) -> gender -> email (validated -- a deliberately-malformed address was correctly rejected and re-prompted) -> race pick (8 races: dwarf, elf, half-elf, half-orc, halfling, human, orc, poleepkwa) -> full skill selection (6 primary/ 4 secondary/4 minor skill slots, all 28
secure/cfg/skills.cfgskills reachable and correctly bookkept slot-by-slot) -> character summary -> arrival in/domains/default/room/start, wearing starting clothes. enter towncorrectly moves a new player into Saquivor's "Village Road Intersection" (the real starting town, distinct from the tutorial start room) with correct room text, exits, and inventory (clock tower).- Etnar verified:
goto /domains/etnar/wyr/wyr/room/rm_174reaches "The Lounge" in the village of Wyr with correct room text, ASCII minimap, and exits -- the bespoke, still-in-progress fantasy setting the repo's ownreadme.txtdescribes. - Bundled diku-alfa content verified:
goto /domains/diku-alfa/room/30.zon/rm_3001reaches "The Temple of Midgaard" with correct room text and exits. look/score/update(admin)/quitall produce correct output.- Reconnect (
fluffos/Mud@2026) restores the exact same character, in the exact same room last left in (viagoto), with the same worn inventory (t-shirt, jeans) -- confirmed across two separate reconnects.
7. A known, pre-existing content gap (not fixed -- matches upstream, not a driver-compat bug)
domains/diku-alfa/room/90.zon/rm_9000.lpc is genuinely truncated
mid-create() (opens the function, sets climate/light, then the file
just ends -- no closing braces at all). Confirmed this is not
conversion fallout: cloned the sibling repo
LashMUD/DikuMud-to-Dead-Souls-Port directly and its
room/90.zon/rm_9000.c is byte-for-byte the same 17-line truncated
file. This is an authentic upstream content gap in the original DikuMud
port, left as-is per this project's content-vs-driver-compat boundary
(AGENTS.md's standing rule: fix programming bugs, don't invent missing
content).
Also left as-is, matching classes already documented on
ds386/dshakkard's own lpcc sweeps (pre-existing, non-bugs):
obj/stargate.lpc's deliberate #include "this is here on purpose to
prevent this from loading" anti-load trap; secure/cmds/admins/
opcprof.lpc's call to the opcprof() efun, which this driver doesn't
implement; and two builder scratch/template files
(open/prog.lpc's $S template placeholder and #define with no
name, obj/area_room.lpc's reference to a ../customdefs.h template
file that was never meant to exist standalone).
8. §9 LPC formatter
Ran format-corpus.mjs across all 3,817 .lpc files: 3,812
reformatted, 5 unchanged, 0 errors. All three documented blind-spot
checks came back clean: zero ::-parent-call-split hits (grep -rnE
':\s:\s*[a-zA-Z_]+\(' ), zero damaged-escape-sequence hits (grep -rl
'\\ n'), and a manual review of every case LABEL: //comment line in
the corpus (diku-alfa's magic_user.lpc switch statement and
secure/daemon/imc2.lpc's mode-name comments) confirmed no
comment-swallowing damage -- all case bodies and fall-throughs intact.
Re-booted and re-ran the full fluffos-reconnect smoke test after
formatting: zero new compile/fatal errors, same room/inventory/output
as before formatting.
9. §10.7 deep functional test (round two, 2026-08-31)
Full continuous native-driver session beyond the onboarding smoke test,
with a fresh mortal (Questora, human, PRIMARY blade/melee
attack+defense/stealth/detection, SECONDARY bargaining/healing/
tracking/concealment, MINOR faith/fishing/stealing/multi-hand) driven
via scripts/tmux_mud.sh, plus the seeded fluffos admin for
eval/goto-assisted navigation between this lib's disconnected
content clusters (etnar's bespoke domain and the bundled diku-alfa port
share no real exits with domains/town, confirmed by grep --
eventMoveLiving(), the same primitive secure/cmds/creators/goto.lpc
itself uses, is the correct way to relocate a living object here;
object->move(dest) is NOT a real function in this codebase and
silently no-ops with no error via ->-dispatch -- a footgun worth
recording for any future session scripting movement here).
Tooling note: this lib's registration flow ("Do you use a screen
reader...") drives an ANSI-cursor-addressed overhead-map/stat-panel
HUD that assumes a normal ~24-row terminal. A tmux_mud.sh-style pane
taller than that (the tool's default -y 500) makes tmux capture-pane
show badly interleaved stale-and-fresh text (the HUD only repaints
rows within its assumed viewport, leaving everything below frozen at
whatever was last drawn there) -- looks exactly like a hung/unresponsive
connection but isn't. Fix: tmux resize-window -t <session> -y 50
right after start. Confirmed via independent eval
file_name(environment(player)) ground-truth checks that the game
state was always correct even when the pane looked frozen/garbled.
Tested and confirmed working correctly, live: guild-independent skill
training via ask <trainer> to train <skill> (the class's own
in-character hint text, not the more natural-sounding but WRONG ask
<trainer> train <skill> or bare train <skill>, both of which this
verb's own rule table -- verbs/common/ask.lpc's SetRules("LIV STR",
...) routes to a plain spoken-sentence handler, not
eventAsk()/CommandResponses at all -- confirmed correct rejection
"You need more training points!" at level 1/0 training points, per
design); real melee combat vs. a placed diku-alfa mob (Beastly Fido,
bidirectional limb-targeted damage, a live "You are a bit more adept
with your melee attack" skill-improvement message, clean flee); the
Pet Shop's economy loop end-to-end (inquire correct price list,
adopt <pet> correctly refused for insufficient gold, then correctly
succeeded once funded, with the right currency deduction); etnar's Wyr
village (The Lounge -> The Common Room -> The Entrance to the
Cyclops Inn, matching onboarding's own documented room text) and
diku-alfa's Midgaard city square area, both with correct room
text/exits and zero new debug.log errors; quit -> debug.log grep
(clean) -> a real ~3.5-minute gap (the long-sit watch below) ->
reconnect, correctly restoring the exact same character/location/
worn-inventory/vitals; a ~200s synchronous idle long-sit boot watch
(python3 scripts/mudclient.py ... --timeout 200 --idle 300, this lib
has no WASM build yet) sitting on an open connection at the login
prompt -- ended in the login object's own normal inactivity timeout,
zero new debug.log errors, driver RSS stable (~2.2GB, expected for
this 3,800+-file mega-lib per its own onboarding notes).
Death/respawn and a full guild-class questline were not reached -- budgeted out in favor of the two real bugs below and the broad etnar+diku-alfa content-verification pass the task specifically asked for; flagged honestly as unverified-live rather than silently skipped.
Bugs found and fixed
1. AGENTS.md §7.193 (NEW) -- two DikuMud-port SetShort() calls hold
a full "long room-appearance" sentence instead of a bare noun
phrase, and this codebase's living-NPC room-listing code
unconditionally appends a posture verb phrase to GetShort()
regardless of what it already says, producing a doubled,
grammatically broken line. domains/diku-alfa/room/30.zon/npc/
3095_pet_shop_boy.lpc had SetShort("A Pet Shop Boy is here,
humming gently."); domains/diku-alfa/room/41.zon/npc/
4101_troll.lpc had SetShort("A large mean-looking troll is
here"). lib/body.lpc's GetHealthShort() just wraps
GetShort() in a health-color code with no stripping; lib/events/
describe.lpc's room-listing code then buckets livings by
GetPosition() and appends " is standing here."/" is lying
down."/etc. unconditionally to that same string for the
POSITION_STANDING (etc.) bucket -- confirmed live: looking at
the Pet Shop showed "A Pet Shop Boy is here, humming gently. is
standing here." Every OTHER living NPC checked in the same corpus
(3064_drunk.lpc: "a singing, happy Drunk", 3061_janitor.lpc:
"the Janitor", 3062_fido.lpc: "Beastly Fido") correctly uses a
bare noun phrase for SetShort(), matching a DikuMud port
convention where the original Diku MOB file's "long description"
(Diku's own room-listing line, self-contained) was supposed to stay
separate from the short combat-message name -- these 2 files
mistakenly got the Diku long-description text copied into
SetShort() instead. (Non-living scenery objects like
3600_candlestick.lpc/3134_bench.lpc correctly DO bake "is
standing here" directly into their own SetShort(), because
inanimate items are rendered via a different, non-appending display
path -- confirmed by checking all_inventory(env) is filtered by
living(ob) before the posture-bucketing code ever runs, so this
is not a contradiction, just two different, both-legitimate
conventions for two different object categories.) Fixed by
stripping the redundant sentence fragment from both SetShort()
calls, matching the established living-NPC convention ("a humming
Pet Shop Boy", "a large mean-looking troll"). Verified live
(destruct + respawn a fresh instance of each): the pet shop now
correctly shows "A humming Pet Shop Boy is standing here."
How to apply generally: any Dead-Souls lib hosting a DikuMud (or
similar Diku-lineage) port is suspect for this exact class --
grep -rE 'SetShort\("[^"]* is (here|standing|lying)' domains/ (or
the equivalent short-description setter) to find any living NPC
whose short description was left as a full self-contained sentence
instead of a bare noun phrase.
2. domains/diku-alfa/room/30.zon/rm_3031.lpc's pet-shop adopt
command has the if (!name)/if (name) branches swapped/confused
for 4 of 5 pet types, a copy-paste mistake (confirmed via the
file's own cmd_adopt-equivalent switch statement): the if
(!name) branch (meant for "no custom name given") for wolf,
rottweiler, puppy, and kitten still executed ob->SetShort("a pet
<animal> named " + capitalize(name)) with name actually 0/undefined,
producing a dangling "a pet kitten named " (rendered live as "A
pet kitten named is standing here." once combined with bug #1's
posture-append behavior) -- confirmed by adopting an unnamed kitten
and reproducing this exact broken line. The SetId() calls in the
same branch also uselessly included the undefined name/
capitalize(name) values in the identifier array. The beagle case
had the OPPOSITE bug: its if (name) branch (custom name given) was
byte-identical to its if (!name) branch, so a beagle NEVER got its
custom name applied even when the player supplied one. Fixed all 5:
the if (!name) branches for wolf/rottweiler/puppy/kitten now just
set a bare "a pet <animal>" short description (matching the
beagle's own already-correct no-name branch) with no bogus name
values in SetId(); the beagle's if (name) branch now actually
applies "a pet beagle named " + capitalize(name) (matching the
pattern the other 4 pets already use in their own if (name)
branches). Verified live, both directions: adopt puppy (no name)
now correctly shows "A pet puppy is standing here."; adopt puppy
Rex (with a name, after destructing/re-adopting) correctly shows
"A pet puppy named Rex is standing here." No new AGENTS.md entry --
this is a narrow, single-room copy-paste bug in bespoke vendor
script, not a shared-library pattern likely to recur elsewhere.
Non-bugs (documented, not fixed)
doc/RELEASE_NOTES_HTTP's cached response timestamp updated during this session's boots despite NOTES.md §4's earlier claim of "No RELEASE_NOTES/version-check HTTP fetch runs automatically" -- apparently a real outbound HTTP GET does still fire somewhere in the boot/autoexecchain after all (the file'sDate:header advanced across reboots). Not chased further (out of this pass's scope, and the response itself is cached/served from a local file either way, not a live dependency of anything tested) -- flagged as a correction to that earlier claim for whoever next cares about this lib's network footprint, not fixed or re-verified in depth.
WASM measurement (2026-09-03)
meta.json was already playable from the 2026-08-31 deploy-unblock;
the README had no WASM line. Cold-boot under the shared
~/src/fluffos/build-wasm succeeded (secure/sefun/sockets.lpc
already stubbed). secure/daemon/imc2.lpc still fails to compile on
socket_status() — a graceful preload skip, not on the login path.
Verified with scripts/wasm_client.js: fluffos / Mud@2026
through the news pager into the Temple of Midgaard
(/domains/diku-alfa/room/30.zon/rm_3001), hp: 430/430, quit
printed "Please come back another time!" / "Fluffos quits The Brass
Ring." Shop/combat/death were not exercised this pass.
Shop (2026-09-04 librarian slice)
The 2026-08-31 §10.7 pass already did the diku-alfa pet-shop adopt
loop. This pass did a regular paid retail buy at the bundled Dead
Souls town store (/domains/town/room/shop), which that pass never
touched. Seeded creator fluffos / Mud@2026: eval return
this_player()->AddCurrency("silver", 80) (purse was gold-only),
goto the store, list (wooden torch 60 silver), buy wooden torch
from otik → Otik "Here is an old wooden torch for 60 silver!",
inventory has the torch, money 20 silver + 134 gold.
Same heartbeat bug as deadsouls_fluffos: lib/body.lpc called
hobbled(this_player()) (0 during heart_beat). Fixed identically
(this_object(), plus !objectp guard in disable.lpc). No new
collapse/call_other(0) spam after the reboot used for this buy.
Pet-shop adopt was not re-run. 拜师 analogue is Dead Souls class
join / skill trainers, already covered 2026-08-31.
2026-10-03 — elevator buttons
domains/town/obj/ebutton1.lpc and ebutton2.lpc called car->SetDoor(1), the name the elevator had before
it renamed its own function SetDoorClosed (it shadowed LIB_EXITS::SetDoor(dir, file)); the old name
resolves to the inherited exit function and the call is a silent no-op, so the call buttons never closed the
car door. Changed to SetDoorClosed(1), as in dsIII and ds386 (KB 06 §7.211).
深度功能测试(§10.7,2026-10-03)— compile warnings, inherit diamonds, and the ds386 fixes ported
Method. work/ is the corpus formatter's output of the Dead Souls 3.8.6 sources plus this lib's own Diku-Alfa
zone, Wyr domain and a few lib classes (factions, rent, the skill-picking login). For 1409 of the 1508
files ds386's warning pass changed, brassring's tokens equal ds386's pre-fix tokens, and format(ds386 pre)
reproduces brassring's HEAD byte for byte (1360 files; 49 more are byte-identical unformatted), so those files
were set to format(ds386 post) with scripts/lpc_twin_port.py adopt (KB 08 §10.13): they equal ds386's
verified result token for token. The other 87 files carry brassring's own code; they went through a fuzzy hunk
applier and scripts/lpc_warnings.py brassring --fix, and lpc_twin_port.py audit then listed every hunk
ds386 made that brassring lacked (three empty if () {} shells, cedit's two int ret, master's
inactive-branch locals, player's CanGet, the council's prototypes), which were finished by hand. Eleven
admin-realm sample files ds386 touched do not exist here. 2778 files changed: 2631 .lpc, 144 .h, and the
runtime-swapped secure/lib/connect.real, secure/daemon/update.patch/update.blank (KB 06 §7.216).
Result: 9795 -> 4 distinct diagnostics. The four are the same three dead archive files ds386 keeps:
obj/area_room.lpc (includes a ../customdefs.h that does not exist), obj/stargate.lpc and open/prog.lpc
(deliberately uncompilable). scripts/lpc_diamonds.py brassring lists no overlapping inherits. The baseline was
4243 Redeclaration rows (2058 files), 3452 nosave functions (2602 files), 468 unused locals, 120 override
argument-count disagreements, 58 unknown escapes, 15 bare return;, 15 (: "name" :) pointers and the
inherited from both families.
Brassring-only changes (everything else is ds386's, see its NOTES):
lib/player.lpcinheritsLIB_FACTIONSandLIB_RENT, which both defineCheckTimer();heart_beat()called each by name and nothing called the bare one, so the player now definesCheckTimer()once andheart_beat()calls it.CanGet()names living's, as in ds386. The Diku-Alfaetc/trainer.lpcgets the sameinit()pair aslib/trainer.lpc(KB 06 §7.214).- Wyr's
bard_stool,dummy_chairanddummy_sofa(sit + surface, once alsoLIB_BASE_DUMMY) defineisDummy(), callSetNoSink(1)/SetInvis(1)themselves and asksit::CanGet()first, asLIB_CHAIRdoes: a seated NPC now makesget stoolanswer "Fostaine Pyre is using it right now." instead of "The stool does not budge." (KB 06 §7.213 kind 5).parchment.lpcinheritedLIB_PERSISTandLIB_READnext toLIB_ITEM, which holds both (7 duplicated globals, 24 overlap rows).30.zon/obj/dump[bak].lpc, a draft that inherited a room (LIB_FURNACE) and the item base, is the furnace room it inherits now:SetKeyName/SetId/SetAdjectivesmean nothing on a room, and nothing loads it. - About sixty Diku-Alfa NPCs declared an unused
object env = environment(this_object())inCheckNPC()(deleted); the fixer's list of side-effect-free calls grew for it (scripts/lpc_fix_unused_init.py).combat.lpc/combat_r_o.lpckeep theirroom_environment()call as a statement, as ds386 does.
Real bugs found while fixing warnings:
domains/diku-alfa/room/74.zon/npc/7045_jones_ettin.lpclacked a;afterSetClass("fighter"), so the file never compiled and Jones's room (rm_7419) died inSetInventory()with "No program in object" every time it loaded; the room loads, with Jones in it, now.domains/diku-alfa/room/90.zon/rm_9000.lpcstops insidecreate()in the archive copy; the function is closed and the room loads as an empty shell (the archive has no description or exits for it).- Eight Diku-Alfa armors and a sword gated wearing on
GetMorality() > 700 | GetMorality() < -700, a bitwise OR of two booleans that was meant as||(KB 04 §6.10); same result, no short circuit. - Wyr rooms
rm_159andrm_197listed/domains/etnar/wyr/wyr/virtual/dummy_{chair,table,sofa,cabinet}(four paths) where the objects live inobj/;SetInventory()raised "couldn't find object" increate()beforeSetExits()ran, so the guardhouse and the sofa room loaded withObvious exit:empty and no furniture, and every visitor got a stack trace. They load whole now (look at chair,sit on chair, exits down and east). - Everything ds386 found in the shared files carries over: the 15 Praxis
(: "name" :)pointers (look at gallowsprintedlong_func;stone.lpc'slong_funcreturns its text now),virt_land's clobberedSetCoordinates, the shadowed trainerinit(), the glow counted twice (SetRadiantLight(7)read back 14), thebooks.lpcno-op==, and the rest of that list.
Verification. Golden-master oracle (HEAD vs working tree, 228 programs, KB 08 §10.12): 1398
public -> protected flips (the mechanical pass), 26 definer changes (player CanGet/CheckTimer, the
chamber/elevator/vehicle door and language picks, trainer init, worn_storage GetRadiantLight,
virt_land's rename), 130 duplicate variables removed or renamed, 63 radiance rows (14 -> 7, the glow fix) and
three added functions (SetVirtualCoordinates); nothing else moved. Paired live sessions as admin
fluffos/Mud@2026 on a HEAD tree and a working-tree copy (165 family steps plus 63 brassring-specific ones):
the differences are the fixes above, the river's You can't enter that! -> You can't enter that., the
time-of-day text and wandering-NPC chatter. A fresh mortal registered through the skill-picking login
(PickSkillsorClass .. InputPrimarySkills, rewritten by the pass), killed an orc in the start room and
survived; log/runtime and log/catch stayed empty.
深度功能测试(§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 brassring
--pre HEAD --apply (all 21 are formatted twins: format(ds386 fixed file)). 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 前后对比,主控载入段只少了这两行。
Deep test (§10.7, 2026-10-08) -- fixed-width .lpc suffix slices
The .c -> .lpc rename changed the string but not the slice width: f[<2..] == ".lpc" compares two characters with four and is never true (!= always true), so suffix filters and strips never ran or cut x.l (KB 06 §7.238). scripts/lpc_lpc_suffix_slice.py --apply fixed 1 comparison(s) and 1 strip(s) (e.g. daemon/help.lpc); the changed files load at HEAD and in the tree (fresh processes) with no regression.
- 2026-10-14: FluffOS 970d9f09 warns
Float value truncated to int(#1426). 20 sites in 12 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). - 2026-10-14:
lib/combat.lpc(and its copycombat_r_o.lpc) set the auto-flee thresholdWimpy = 0.20;intoprivate int Wimpy, so it was always 0 and players never fled; everything that reads it treats it as a percentage (Wimpy < percent(hp, max),scoreprintsN%, thewimpycommand sets an integer). NowWimpy = 20;withint SetWimpy(int)/int GetWimpy(), as mainline Dead Souls has it.
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, 9 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), /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, the help index names, telnet and setreboot without an argument (2026-10-21, KB 06 7.212, 7.296, 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 index also cut three characters from every command name (f = function(string str) { return str[0..<3]; }, assigned above the get_dir() calls where the 2026-10-20 pass does not look): help commands listed abandon.l and help telnet found nothing; now [0..<5]. 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 brassring --account ... --clone ...: the administrator cloned /domains/town/npc/orc_shaman, /domains/Ylsrim/npc/balrog, /domains/default/npc/dummy, /domains/Praxis/cemetery/mon/ghost3, /domains/Praxis/obj/mon/goblin_fighter, /estates/f/fluffos/area/npc/fighter 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. 4 statement(s) in 4 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 4 changed files, HEAD vs tree: 4 load at HEAD, 4 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. 1 more are commented out by the author with the pointer left behind: on purpose, untouched.
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 2 subdirectories of log/: log/harass (lib/interface.lpc), 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/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.