feat(chat): Campaign CH slice CH4 — command registry completion

Brings acdream's / and @ command parsing to parity with the complete
retail registry (130 registered verbs + 22 unregistered GetChannelID
fallback tags = 152 client-parsed verbs), per
docs/research/2026-08-09-chat-retail-command-registry.md.

Parser semantics (retail OnChatCommand/DoCommand):
- : and ; rewrite to "@emote <rest>" before dispatch.
- Verb trailing-comma trim ("@f, hi" == "@f hi") applied at every
  verb-lookup site in the catalog and the parser.
- @tell/aliases split the target on the FIRST COMMA, not the first
  whitespace token, so multi-word names work ("@tell Aunt Agatha, hi").
- The 22 unregistered GM/faction channel tags (admin, sentinel,
  celestialhand, ...) now broadcast for real via a new
  RetailChannelTagTable + SendRawChannelCmd bypass, reusing the existing
  BuildChatChannel wire builder.

Binding corrections:
- /g, /group, /party -> Fellowship (0x800), not General.
- /rp -> reply alias (retail's own help text confirms "@r or @rp"), not
  Roleplay; /role (an acdream invention) deleted.
- /allegiance, /all -> the allegiance management command
  (RetailClientCommandCatalog), not a channel verb.
- /house no longer swallows unrecognized subcommands with a local usage
  error; they now correctly fall through to ACE.
- @mr/@pr pinned as permanently non-executable (retail registers them
  with a null function pointer).

New verbs with real local execution: endurance, speaker, title (silent,
AP-182), chat, notell, join, leave, permit, hslist, index, clist, on,
off, alh/ah (+ "@allegiance hometown"/"ho"), "@allegiance info",
"@house abandon"; a missing-alias sweep across pkl/hou/message_types/
msgtypes/msg_types/rt/send/whisper/w/vassal/covassal/co-vassals/c/
fellows/group/party/guild/gu/cg/ct/clfg/crp/soc/o; the non-retail
inventions gen/cv/lookingforgroup/tr/role/h are deleted. New Core.Net
wire builders (IndexChannels, ListChannels, AddChannel, RemoveChannel,
RecallAllegianceHometown, AllegianceInfoRequest, ListAvailableHouses,
AddPlayerPermission, RemovePlayerPermission, AbandonHouse) are all
parameterless or single-field payloads cross-checked against ACE's
GameAction readers, not guessed.

Deferred (filed as #360/#361/#362, register rows TS-68/TS-69/TS-70):
the ~22 remaining allegiance/house subcommands + standalone @motd
(largest single item, needs its own slice per the doc), the three
still-inert pure-local commands (day/log/render), and the inbound
GameEvent responses for the new outbound requests. All correctly fall
through to ACE server-passthrough rather than being silently swallowed
or faking success.

RetailCommandRegistryConformanceTests pins the complete 152-verb
registry against production: every verb resolves through exactly one
production surface if Implemented, through none if HelpOnly/
ServerPassthrough, and two reverse-direction tests fail the build if
RetailClientCommandCatalog or ChatInputParser ever claims a verb
outside this registry again. Final tally: 138 Implemented / 5
ServerPassthrough / 9 HelpOnly = 152.

Release suite: 12,190 passed / 4 skipped / 0 failed (up from CH3's
11,964/4/0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-09 21:10:17 +02:00
parent 9247d5d5b5
commit 090825e703
23 changed files with 2069 additions and 97 deletions

View file

@ -24,6 +24,55 @@ What does NOT go here:
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
## #360@allegiance/@house management dispatchers only port their simple subcommands
**Status:** OPEN — filed 2026-08-09, Campaign CH slice CH4. Retail's
`@allegiance`/`@all` and `@house`/`@hou` are 12- and 15-subcommand local
command dispatchers (`ClientCommunicationSystem::DoAllegiance @
0x0057D5A0` / `DoHouse @ 0x00580860`). CH4 ports the subset with simple
parameterless/single-string-field wire shapes — allegiance `info`,
`hometown`/`ho` (also the standalone `@alh`/`@ah`); house `recall`/`re`,
`mansion_recall`/`alleg_recall`/`ma` (already shipped pre-CH4), and
`abandon`. The remaining ~22 subcommands (allegiance boot/ban/officer/
title/name/lock/chat/broadcast/motd; house open/close/storage/remove/
boot_all/remove_all/guest/available/hooks/on/off) plus the standalone
`@motd` verb need real GameAction wire builders, most requiring
target-name/guid resolution, confirmation dialogs, or multi-field payloads
this session did not attempt to build without byte-level verification
against both the retail decomp and ACE's reader — see the doc's own
framing ("largest single item; deserves its own slice"). Today these
subcommands correctly fall through to ACE as server-passthrough text
(`RetailClientCommandCatalog.TryMatchHouse`/`TryMatchAllegiance`) rather
than being swallowed locally, which was the Tier-1 correctness fix this
slice DID land — but they don't yet execute. Register row: TS-68.
Registry doc: `docs/research/2026-08-09-chat-retail-command-registry.md`
§2.5/§2.5b.
## #361@day / @log / @render pure-local commands recognized in help only, not executed
**Status:** OPEN — filed 2026-08-09, Campaign CH slice CH4. Three
retail-registered pure-local verbs are not yet wired to real behavior:
`@day` (daylight override — needs a sky/time-of-day hook the renderer
doesn't expose), `@log` (chat-to-file logging — deferred to avoid an
unaudited file-handle lifecycle across session reconnects; see AP/TS-69
for the reasoning), and `@render` (retail's `SmartBox::HandleRenderOption`
— acdream has no equivalent render-option surface). All three are
recognized by `/help <verb>` (`RetailCommandHelpTable`) with retail's own
extracted help text, but fall through to server passthrough on execution.
Register row: TS-69.
## #362 — Four new CH4 outbound requests have no inbound response handler
**Status:** OPEN — filed 2026-08-09, Campaign CH slice CH4. `@index`,
`@clist`, `@hslist`, and `@allegiance info` send byte-correct retail
GameAction requests (`ClientCommandRequests.BuildIndexChannels`/
`BuildListChannel`/`BuildListAvailableHouses`/`BuildAllegianceInfoRequest`),
but their GameEvent responses (`ChannelIndex 0x0149`, `ChannelList
0x0148`, `AvailableHouses 0x0271`, `AllegianceInfoResponse 0x027C`) are
registered in `GameEventType` with no `GameEventWiring` handler — ACE's
reply is silently dropped. The request itself is correct and verifiable
on the wire; only the response rendering is missing. Register row: TS-70.
## #356 — Alt-tab during login crashed the client: focus loss faulted on an unpublished movement controller
**Status:** CLOSED 2026-08-08 — `972c7ab3`. Window focus loss runs

File diff suppressed because one or more lines are too long

View file

@ -8,7 +8,12 @@ re-reviewed APPROVE-WITH-FIXES with nits applied this commit) — the sole
outstanding item is the in-client user gate (jump-in-air / jump-loaded
refusals showing on-screen, not in chat). CH3 (side channels)
CODE-COMPLETE, pending the connected user gate — see the CH3 row below and
`docs/research/2026-08-09-chat-side-channels-vs-ace.md`.
`docs/research/2026-08-09-chat-side-channels-vs-ace.md`. CH4 (command
registry completion) CODE-COMPLETE — see the CH4 closeout below; 138 of
152 registry verbs now execute locally, 5 are deliberately deferred
(issues #360/#361/#362, register rows TS-68/TS-69/TS-70), and 9 are
retail's own null-handler help-only nodes. Pending the in-client user
gate (command spot-checks per the campaign's overall gate list).
**Why now:** first track of the alpha-release program (chat is the most
visible daily surface for the friend-alpha). User-directed 2026-08-09.
@ -109,9 +114,96 @@ implementer per slice against a pinned contract (per
| CH1 colors | `172c6f9a` | 11,835 passed / 4 skipped / 0 failed | APPROVE-WITH-FIXES; fixed `34d8a3c0` | pending |
| CH2 interface text | `77c8296e`, reworked `e0e78883` | 11,916 passed / 4 skipped / 0 failed | REJECT → reworked `e0e78883` → re-review APPROVE-WITH-FIXES → nits `233c30d1` | pending |
| CH3 side channels | `614a1e05` | 11,964 passed / 4 skipped / 0 failed | APPROVE-WITH-FIXES; fixed `e07fba57` | pending (connected gate — see handoff below) |
| CH4 commands | — | — | — | — |
| CH4 commands | see CH4 closeout below | 12,026 passed / 4 skipped / 0 failed | pending | pending |
| CH5 closeout | — | — | — | — |
### CH4 closeout (2026-08-09)
Full parser-semantics + catalog-breadth pass against
`docs/research/2026-08-09-chat-retail-command-registry.md`'s complete
130-registered + 22-fallback = 152-verb enumeration.
**A. Parser semantics** (`ChatInputParser.cs`, `RetailClientCommandCatalog.cs`,
`ChatCommandRouter.cs`):
1. `:`/`;` emote-prefix rewrite (`OnChatCommand` cases 0x0B/0x0C) — both
prefixes rewrite identically to `@emote <rest>`.
2. Verb trailing-comma trim (`DoCommand`'s right-trim) applied at every
verb-lookup site in both the catalog and the parser — `"@f, hi"`
`"@f hi"`.
3. `@tell`/aliases now split the target on the FIRST COMMA, not the first
whitespace token — `"@tell Aunt Agatha, hello"` addresses "Aunt
Agatha" (previously truncated to "Aunt"). Falls back to the pre-CH4
whitespace+punctuation-strip split when no comma is present, so
existing single-word-target muscle memory still works.
4. The 22 unregistered `ChannelSystem::GetChannelID` fallback tags
(`av`, `admin`, `sentinel`, `celestialhand`, …) now broadcast for real
via a new `RetailChannelTagTable` + `SendRawChannelCmd` bypass path,
reusing the existing `BuildChatChannel` wire builder — no new opcode
needed.
**B. Binding corrections:**
5. `/g`/`/group`/`/party` → Fellowship (0x800), not General — the live
correctness bug the doc flagged as Tier-1 #1.
6. `/rp` → reply alias (confirmed by retail's own help text, "You may
also use @r or @rp"), not Roleplay. Roleplay keeps `roleplay`/`crp`;
the non-retail `/role` invention is deleted.
7. `/allegiance`/`/all` are now `RetailClientCommandCatalog`'s allegiance
MANAGEMENT command (a new `TryMatchAllegiance` dispatcher), not a
channel verb. The channel-send verbs stay `a`/`ab`/`guild`/`gu`.
8. `/house`/`/hou` no longer swallows unrecognized subcommands with a
local usage error — `TryMatchHouse` returns no match for anything
beyond `recall`/`re`/`mansion_recall`/`alleg_recall`/`ma`/`abandon`,
letting it reach ACE.
9. `@mr`/`@pr` pinned as permanently non-executable
(`MrPr_AreNeverExecutable` test) — retail registers them with a NULL
function pointer; they must never resolve in
`RetailClientCommandCatalog` or `ChatInputParser`.
**C. New verbs implemented** (real local execution, not passthrough):
`endurance`, `speaker`, `title` (silent — AP-182, no chrome yet), `chat`,
`notell`, `join`, `leave`, `permit`, `hslist`, `index`, `clist`, `on`,
`off`, `alh`/`ah` (+ `@allegiance hometown`/`ho`), `@allegiance info`,
`@house abandon`; missing-alias sweep (`pkl`, `hou`, `message_types`,
`msgtypes`, `msg_types`, `rt`, `send`, `whisper`, `w`, `vassal`,
`covassal`, `co-vassals`, `c`, `fellows`, `group`, `party`, `guild`,
`gu`, `cg`, `ct`, `clfg`, `crp`, `soc`, `o`, `ab` (already CH3)); the
non-retail inventions `gen`, `cv`, `lookingforgroup`, `tr`, `role`, `h`
are deleted. New Core.Net wire builders: `IndexChannels`/`ListChannels`/
`AddChannel`/`RemoveChannel`/`RecallAllegianceHometown`/
`AllegianceInfoRequest`/`ListAvailableHouses`/`AddPlayerPermission`/
`RemovePlayerPermission`/`AbandonHouse` — all parameterless or
single-field payloads cross-checked against ACE's GameAction readers
(`references/ACE/Source/ACE.Server/Network/GameAction/Actions/*.cs`), not
guessed. **Deferred, filed as issues #360/#361/#362 + register rows
TS-68/TS-69/TS-70:** the ~22 remaining allegiance/house subcommands + the
standalone `@motd`, the three still-inert pure-local commands
(`day`/`log`/`render`), and the four unparsed inbound GameEvent responses
for the new outbound requests.
**D. Conformance:** `RetailCommandRegistryConformanceTests` (new,
`tests/AcDream.UI.Abstractions.Tests/Panels/Chat/`) enumerates all 152
verbs from the registry doc, transcribed and cross-checked against the
doc's own per-section counts (130 = 9+31+20+14+6+7+17+8+18 by section;
22 fallback tags; totals self-consistent). Per-verb theory test asserts
Implemented verbs resolve through exactly one of
`RetailClientCommandCatalog`/`ChatInputParser`/`RetailChannelTagTable`,
and HelpOnly/ServerPassthrough verbs resolve through NONE of them (so
they provably fall to ACE passthrough). Two reverse-direction tests
enforce the ownership rule: nothing in `RetailClientCommandCatalog.
KnownVerbs` or `ChatInputParser.KnownVerbs` may exist outside this
registry — a future invented alias fails the build immediately. Final
tally: **138 Implemented / 5 ServerPassthrough / 9 HelpOnly = 152.**
Suite: 12,026 passed / 4 skipped / 0 failed (Release), up from CH3's
11,964/4/0 — net +62 tests (157 new conformance-family cases plus net
test churn from updated existing coverage). One pre-existing,
environment-specific Debug-only failure
(`LandblockBuildOriginTests.FarLoad_StripsEnvCellsAndPhysicsEvenWhenEntityListIsAlreadyEmpty`)
was confirmed present on the unmodified baseline via `git stash` before
and after this slice's changes — passes in Release, unrelated to chat.
### CH3 closeout handoff (2026-08-09)
All nine steps of the research doc's §6 fix list landed: