fix/botgen-place-fishing-default #235

Merged
sickday merged 3 commits from fix/botgen-place-fishing-default into main 2026-08-17 14:57:18 +00:00
Owner
No description provided.
Reported from a sitting: revoking `staff.crown.admin` left the crown in
place.

`holds?/2` answers true for every node on a root account -- that is the
operator override and it is right -- and `staff_level/1` was built on it,
so `Contract.Crown` drew a root account as an administrator whatever the
granted set said. The node was never what it was holding the crown by, so
revoking one could not take it off.

The carve-out already exists for `bot.exempt`, whose polarity is inverted
for the same reason: `granted?/2` is `holds?/2` without the override. A
crown is a claim about who is talking to you rather than something its
holder may do, so an account that can do everything is not thereby someone
every other player must be told about. `crown_level/1` asks the granted set
and `Contract.Crown` reads that.

Deliberately not moved with it: the login block's staff level, which comes
from `Registry.usable?/1` -- any command node at all. Script 73 posts a `::`
line as public chat when the client's `staffModLevel` is 0, so making that
byte follow the crown would cost every crownless operator their commands and
broadcast them to the world instead. A test now pins the pair apart.

A root account wears no crown until granted one, which is the point.
refactor(commands): namespace the command surface by subject
Some checks failed
ci / gates (pull_request) Has been cancelled
d199942f8f
`::botgen` becomes `::bot.gen`, `::botcleardb` becomes `::bot.cleardb`, and
the rest of the families follow: bot (14), npc (3), perm (3), log (3), tele,
find.npc, password.set. 64 commands, 91 names.

Namespaced by **subject** rather than by the permission node's own first
segment, because those are two different things: `bot.` names what a command
acts on, while `admin.`, `mod.` and `player.` name who may run it. Taking the
node as the name would give `::admin.tele` and `::player.pos` -- authority in
the vocabulary, and a command whose name changes when its tier does. Bare
verbs stay bare: `::tele`, `::find`, `::item`, `::b`.

Every old name still dispatches as a hidden alias, so nothing typed today
breaks, and `::help` and the generated README document one vocabulary.

Script 73 was read first, per the standing rule: it forwards everything once
`staffmodlevel()` is non-zero and intercepts only `bank`, `toggleroof` and
`displayfps` by name, so a dot is just a character in the string opcode 5020
carries.

Three things that would have broken silently:

  * the executor handed the module the name the operator *typed*, so a module
    implementing several commands needed a clause per alias -- and the failure
    is a usage line for a command that exists. It passes `entry.name` now: a
    module implements the command, not the spelling.
  * a module can branch on the name in its body rather than its heads.
    `logs.ex` had `if name == "unmute"`, so renaming the heads alone swapped
    mute and unmute while every head still matched.
  * an alias rides the same wire as a name, so the test that no command
    collides with one the client keeps now sweeps every name rather than every
    command. A colliding alias is a command that never arrives.

`::help` learned both halves: an alias resolves to its command's entry, and a
name prefix is a group beside a permission prefix -- otherwise `::help log`
answers "no such command" about a family the operator can see three of.
docs(commands): carry the rename into the prose the generator does not touch
All checks were successful
ci / gates (pull_request) Successful in 3m39s
build / image (push) Successful in 33s
ci / gates (push) Successful in 3m42s
d958dc37b7
`mix revenant.commands.readme` rebuilds the command table and nothing else,
so the hand-written paragraphs around it kept the old names: the chat
README's whole `::persona` block and two `::grant` mentions. Both are the
form an operator reads and then types.

The aliases mean none of it was broken, which is exactly why it would have
sat there.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Revenant/Server!235
No description provided.