fix(chat): CH4 review fixes — allegiance ownership guard, house-abandon confirmation
Blocker 1: an unrecognized "@allegiance <sub>" subcommand escaped TryMatchAllegiance (which only claimed "info"/"hometown") and fell through the unregistered-tag channel fallback, broadcasting the raw subcommand text to the Allegiance chat channel (0x02000000). Retail's own DoAllegiance never reaches DoChannelCommand for an unrecognized subcommand — it claims the whole verb and prints its own client-local refusal. TryMatchAllegiance now claims "allegiance"/"all" unconditionally and shows retail's "Please see @help Allegiance..." text; ChatCommandRouter also gained a blanket RetailClientCommandCatalog.KnownVerbs ownership guard in TryDispatchChannelFallback as defense in depth. Blocker 2: "@house abandon" sent 0x021F immediately with no confirmation. Retail runs a real two-stage dialog before Event_AbandonHouse(); ported both verbatim strings and chained two ShowConfirmation calls. Should-fixes: a bare unregistered tag with no text now passes through silently instead of showing a refusal that belongs to a different retail function; @join/@leave update RuntimeCharacterOptionsState locally (new SetOptionBit) before the wire push so the Turbine membership gate stops refusing a just-joined room; @permit accepts multi-word names; @clist/ @on/@off validate shape only and raise WeenieError 0x422 for an unknown tag; @mr/@pr help text is now the verbatim retail strings; corrected issue #360, register row TS-68, the campaign doc's B.7 note, and a stale RetailChannelTagTable comment; filed issue #363 + register row AP-183 for the deferred error-typing debt. Nits: fixed TryMatchHouse's stale doc comment, the AP-182/@title "stores the value" comments (the binding is a no-op), IsUnregisteredFallbackTag's olthoi false-positive, added /g and /rp binding-level conformance pins, made @index ignore extra arguments, and noted the six removed invented verbs in ISSUES.md. Suite: 12,216 passed / 4 skipped / 0 failed (Release), up from CH4's 12,190/4/0 — net +26 tests, no removals. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
090825e703
commit
724ef2d389
17 changed files with 853 additions and 85 deletions
|
|
@ -171,15 +171,44 @@ public class ChatCommandRouterTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void UnregisteredChannelTag_WithNoText_ShowsRetailRefusal_AndPublishesNothing()
|
||||
public void UnregisteredChannelTag_WithNoText_PassesThroughToServer()
|
||||
{
|
||||
// CH4 REJECT-review SHOULD-FIX 3 (2026-08-09): retail's
|
||||
// DoChannelCommand @0x005774A7 returns 0 SILENTLY on argc<=0 for an
|
||||
// UNREGISTERED tag; DoCommand's own final fallback then sends the
|
||||
// raw @-line to the server via Event_Talk. "You must specify the
|
||||
// text you wish to say!" belongs to DoStupidChannelHack
|
||||
// @0x0057B144, which only runs for REGISTERED channel verbs — it
|
||||
// must never appear for one of the 22 unregistered fallback tags.
|
||||
var (vm, log, bus) = Fixture();
|
||||
|
||||
var outcome = ChatCommandRouter.Submit("/sentinel", vm, bus, ChatChannelKind.Say);
|
||||
|
||||
Assert.Equal(SubmitOutcome.Sent, outcome);
|
||||
var command = Assert.IsType<SendServerCommandCmd>(Assert.Single(bus.Published));
|
||||
Assert.Equal("@sentinel", command.Text);
|
||||
Assert.DoesNotContain(log.Snapshot(), entry => entry.Text.Contains("You must specify the text"));
|
||||
}
|
||||
|
||||
// ── CH4 REJECT-review Blocker 1 (2026-08-09) ────────────────────────
|
||||
// "@allegiance <sub>" must never broadcast to the Allegiance channel
|
||||
// or reach the server for an unrecognized subcommand — retail's own
|
||||
// DoAllegiance claims the entire verb unconditionally and shows its
|
||||
// own client-local refusal.
|
||||
|
||||
[Theory]
|
||||
[InlineData("/allegiance boot Bob")]
|
||||
[InlineData("/all boot Bob")]
|
||||
public void AllegianceUnrecognizedSubcommand_ShowsRetailRefusal_NeverBroadcastsOrSends(string input)
|
||||
{
|
||||
var (vm, log, bus) = Fixture();
|
||||
|
||||
var outcome = ChatCommandRouter.Submit(input, vm, bus, ChatChannelKind.Say);
|
||||
|
||||
Assert.Equal(SubmitOutcome.ClientHandled, outcome);
|
||||
Assert.Empty(bus.Published);
|
||||
Assert.Contains(log.Snapshot(), entry => entry.Text == "You must specify the text you wish to say!");
|
||||
Assert.Empty(bus.Published); // no SendRawChannelCmd, no SendServerCommandCmd
|
||||
Assert.Contains(log.Snapshot(), entry =>
|
||||
entry.Text == "Please see @help Allegiance for more information on how to use this command.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -208,6 +237,23 @@ public class ChatCommandRouterTests
|
|||
Assert.Contains(log.Snapshot(), entry => entry.Text.Contains("Returns you to the last lifestone"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/help mr", "@mr <text> - Sends the text to the last person who used @m to send you a message. This only works for monarchs.")]
|
||||
[InlineData("/help pr", "@pr <text> - Sends the text to the last vassal who used @p to send you a message.")]
|
||||
public void HelpVerb_MrPr_ShowsVerbatimRetailText(string input, string expected)
|
||||
{
|
||||
// CH4 REJECT-review SHOULD-FIX 7 (2026-08-09): these were
|
||||
// previously fabricated acdream summaries; now the verbatim retail
|
||||
// strings from data_7daa08/data_7daa80 (the double space before
|
||||
// "you" is confirmed byte-level, not a typo).
|
||||
var (vm, log, bus) = Fixture();
|
||||
|
||||
var outcome = ChatCommandRouter.Submit(input, vm, bus, ChatChannelKind.Say);
|
||||
|
||||
Assert.Equal(SubmitOutcome.ClientHandled, outcome);
|
||||
Assert.Contains(log.Snapshot(), entry => entry.Text == expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HelpVerb_UnknownVerb_ShowsFallbackMessage()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue