Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,9 @@ derivatives separate "instant" commands from round-based combat resolution.
7. **Accounts & auth**: see below. New Telnet connections currently prompt
for a plain name (no identity verification) as a placeholder until this
phase lands.
8. **Moderation/admin tooling**, **procedural frontier generation**,
**in-game building/scripting**: later phases (see Deferred/Open Items).
8. **Moderation/admin tooling**: implemented β€” see below.
9. **Procedural frontier generation**, **in-game building/scripting**: later
phases (see Deferred/Open Items).

## Accounts & Auth βœ… implemented

Expand All @@ -169,6 +170,20 @@ login prompt, one character per login (no separate Account entity, no
placeholder name-only prompt has been replaced by the real thing; local CLI
still has no login at all, per the original decision.

## Moderation & Admin Tooling βœ… implemented

`SecurityRole` flags enum + `RoleGuardedCommand`/`MuteGuardedCommand`
decorators around `ICommand`, registered via
`ICommandRegistry.RegisterWithRole` (vs. the unguarded `RegisterOpen`).
`boot`/`mute`/`unmute`/`announce`/`ban`/`unban`/`rolegrant`/`rolerevoke`
commands under `src/SharpMud.Engine/Commands/Builtin/Admin/`. Bootstrap: the
`SHARPMUD_INITIAL_ADMIN` env var (see
[docs/deployment.md](docs/deployment.md)) grants the first `FullAdmin` on
login. See [ADR-0005](docs/adr/0005-security-role-model-and-moderation-commands.md)
and [PLAN-0005](docs/plans/0005-security-role-model-and-moderation-commands.md).
Audit logging of moderation actions remains undesigned β€” tracked as an open
item below.

## Deployment

Containerized (Docker) βœ… β€” multi-stage `Dockerfile` at the repo root, built
Expand All @@ -185,13 +200,10 @@ configuration and open items.

Explicitly out of scope for v1, to revisit later:

- **Moderation/admin tooling**: permission levels, mute/kick/ban, admin
commands β€” designed, see
[ADR-0005](docs/adr/0005-security-role-model-and-moderation-commands.md)
and
- **Moderation audit logging**: which actions get logged, retention, and
where β€” undesigned. Tracked as an open item in
[PLAN-0005](docs/plans/0005-security-role-model-and-moderation-commands.md);
not yet implemented. Audit logging remains undesigned, tracked as an
open item in PLAN-0005.
the moderation commands themselves are implemented (see above).
- **Soft-code/scripting engine**: revisit once data/config-driven NPC and room
behavior proves insufficient.
- **Procedural frontier generation algorithm**: choice of generation approach
Expand Down
14 changes: 6 additions & 8 deletions docs/accounts-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ name-only placeholder):
username existed), retry up to 3 attempts (not a considered final policy
β€” see Open Items), then loop back to the username prompt rather than
dropping the connection outright. Correct password, and:
- the character's `PlayerBehavior.IsBanned` (ADR-0005) β†’ `"This account
has been banned."`, connection dropped, before any of the checks
below β€” a banned account never reaches the already-logged-in/Linkdead
branches.
- the character is still actively `Playing` with a live, connected
session β†’ `"That character is already logged in."`, connection
dropped (unchanged by ADR-0004 β€” see
Expand Down Expand Up @@ -149,15 +153,9 @@ silently skipped).
"non-empty" is enforced.
- Password reset flow β€” with no email/OAuth identity backing the account,
there's no "forgot password" recovery path; not designed. Likely
admin-assisted reset only (ties into the moderation tooling designed in
[ADR-0005](adr/0005-security-role-model-and-moderation-commands.md), not
yet implemented).
- Ban enforcement β€” designed in
admin-assisted reset only (ties into the moderation tooling in
[ADR-0005](adr/0005-security-role-model-and-moderation-commands.md)/
[PLAN-0005](plans/0005-security-role-model-and-moderation-commands.md)
(a banned `PlayerBehavior.IsBanned` rejects login at password
verification), not yet implemented β€” today, login has no concept of a
banned user at all.
[PLAN-0005](plans/0005-security-role-model-and-moderation-commands.md)).
- The password itself travels in cleartext over Telnet (only the on-screen
*display* is suppressed) β€” no transport encryption exists yet; SSH (see
[networking.md](networking.md)) would be the natural place this gets
Expand Down
32 changes: 32 additions & 0 deletions docs/adr/0005-security-role-model-and-moderation-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,38 @@

**Decision Makers:** solo (design dive conducted with the user)

**Correction (2026-07-23, before implementation started):** the file paths
and call chain this ADR's Decision Outcome/bootstrap section describe
(`src/SharpMud.Host`, `TelnetHostContext`, `HostRunner`,
`src/SharpMud.Ruleset.Classic`, `ClassicCommands.RegisterAll`) reflect the
architecture as of this ADR's acceptance date β€” that architecture no longer
exists. [ADR-0006](0006-nuget-package-distribution.md) (accepted and
implemented before this slice's implementation began) split `SharpMud.Host`
into `SharpMud.Hosting` (DI composition helpers) + `SharpMud.Adapters.*`
(transport, e.g. `TelnetTransportBackgroundService` replacing `HostRunner`)
+ a consumer composition root (now `samples/SharpMud.Samples.Classic
/Program.cs`, not a project called `SharpMud.Host`), and moved ruleset
content out of a packaged `SharpMud.Ruleset.Classic` into that same
unpackaged sample. [ADR-0008](0008-ruleset-scaffolding-tier.md) later
extracted the reusable combat scaffolding from that sample into
`SharpMud.Ruleset.Rpg`. None of this changes what was decided here
(`SecurityRole`, the Decorator pattern, `RegisterOpen`/`RegisterWithRole`,
role accumulation, the bootstrap env var) β€” only where the mechanism's
pieces physically live, which is why this is a correction note rather than
a supersession. The bootstrap mechanism specifically is also simplified in
the implementation (see [PLAN-0005](../plans/0005-security-role-model-and-moderation-commands.md)):
`LoginFlow` is DI-constructed now (it wasn't, structurally, when this ADR
was written β€” there was no `TelnetHostContext` to thread a value through),
so the original two-separate-checkpoints design (a boot-time Program.cs
check plus a `MaybeCreateAsync` check) collapses to one check inside
`LoginFlow` itself, run against whichever `Thing` it's about to return
(new or existing) β€” same outcome (idempotent grant, covers fresh-server and
restart cases), fewer moving parts. Corrected here rather than superseded
because the actual decision - what gets built and why - is unchanged; only
implementation-mechanism detail moved, and that detail belongs in the plan
per this repo's own ADR/plan split, not repeated (and inevitably going
stale again) here.

## Context

Per ADR-0001, this is Slice 3 of the WheelMUD reconciliation roadmap.
Expand Down
9 changes: 4 additions & 5 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,11 @@ actually implemented as of the inventory/items build-order phase:
- **Meta** βœ…: `help`, `quit`.
- **Builder/OLC verbs** (`@dig`, `@describe`, etc.) explicitly excluded β€”
those belong to the deferred in-game building phase (see
[world-model.md](world-model.md)). **Moderation/admin verbs**
[world-model.md](world-model.md)). **Moderation/admin verbs** βœ…
(`boot`/`mute`/`unmute`/`announce`/`ban`/`unban`/`rolegrant`/
`rolerevoke`) are a separate thing β€” designed in
[ADR-0005](adr/0005-security-role-model-and-moderation-commands.md), not
yet implemented (see
[PLAN-0005](plans/0005-security-role-model-and-moderation-commands.md)).
`rolerevoke`) are role-gated via `ICommandRegistry.RegisterWithRole` β€”
see [ADR-0005](adr/0005-security-role-model-and-moderation-commands.md)
and [PLAN-0005](plans/0005-security-role-model-and-moderation-commands.md).

## Open Items

Expand Down
7 changes: 7 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ debugging inside the container) without rebuilding.
| Mode | `--telnet` (anywhere in args) | `SHARPMUD_MODE=telnet` | CLI (local single-player) |
| Telnet port | `--telnet <port>` (looked up by index, not positional - can combine with `--db-path` in either order) | `SHARPMUD_TELNET_PORT` | `4000` |
| SQLite DB path | `--db-path <path>` | `SHARPMUD_DB_PATH` | `./sharpmud.db` (`/data/sharpmud.db` in the container image) |
| Initial admin username | *(none)* | `SHARPMUD_INITIAL_ADMIN` | unset (no bootstrap grant) |

`SHARPMUD_INITIAL_ADMIN` (ADR-0005) names the one character `LoginFlow`
grants `SecurityRole.FullAdmin` to on login β€” the only path to a `FullAdmin`
on a fresh deployment, since granting a role itself requires `FullAdmin`.
Idempotent (checked every login, no-op once already held), so it's safe to
leave set permanently rather than unsetting it after first use.

The Dockerfile sets `SHARPMUD_MODE=telnet`, `SHARPMUD_TELNET_PORT=4000`, and
`SHARPMUD_DB_PATH=/data/sharpmud.db` as image defaults, plus `EXPOSE 4000`
Expand Down
4 changes: 2 additions & 2 deletions docs/plans/0001-wheelmud-reconciliation-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ reconciliation effort stands.
- [x] **Slice 2 β€” Session/connection state machine + reconnect.** ADR-0004
Accepted, PLAN-0004 Done. See
[PLAN-0004](0004-session-state-machine-and-reconnect.md).
- [ ] **Slice 3 β€” Permission/security-role model + moderation commands.**
ADR-0005 Accepted, PLAN-0005 Not Started. See
- [x] **Slice 3 β€” Permission/security-role model + moderation commands.**
ADR-0005 Accepted, PLAN-0005 Done. See
[PLAN-0005](0005-security-role-model-and-moderation-commands.md).
- [ ] **Slice 4 β€” World-building/OLC command surface.** Not yet designed;
bundles with Slice 3.
Expand Down
Loading