Skip to content

Match protocol tag names case-sensitively - #267

Merged
sproctor merged 2 commits into
mainfrom
case-sensitive-tags
Aug 12, 2026
Merged

Match protocol tag names case-sensitively#267
sproctor merged 2 commits into
mainfrom
case-sensitive-tags

Conversation

@sproctor

@sproctor sproctor commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Wrayth matches tag names exactly: <streamWindow> and <openDialog> are recognised, <streamwindow> and <opendialog> are dropped without even an error (verified in utils/wrayth-lab). We lowercased every name and looked it up in a lowercase-keyed table, so we accepted spellings no game ever sends.

That leniency was not harmless. It hid a bug in our own lab bootstrap, whose <opendialog> meant the vitals bar had never once rendered there — which is exactly the kind of thing the lab exists to catch.

What changed

The table is keyed by the protocol's exact spelling and lookup no longer lowercases.

Every spelling was read off captured DR/DRT/GS4 sessions rather than inferred. That mattered more than expected: the handler class names look like a guide but are not one, since UpdateVerbsHandler answers to <updateverbs>, all lowercase. The existing tests already used the camelCase forms, which corroborates them independently.

Two tags appear in no capture at all — dynaStream and launchURL — so both forms of each stay registered rather than guessed at. Picking wrong would silently drop a tag the game does send. There is a comment to collapse each to one entry once one shows up in a log.

Unrecognised tags now mean something

Every other tag those sessions contain is registered as an IgnoredTagHandler: the settings blob the server replays at login and its one-letter entries (<i> palette, <k> macro key, <w> window, <o> option, <p> preset, <m> misc, <s> script), plus timestamp, sep, command, playerID, switchQuickBar, endSetup, the expose*/deleteContainer family, and the rest — 44 in all.

So a tag reaching the unhandled path now means the protocol has grown something or a spelling is wrong, and the handler warns once for each, naming the nearest spelling it does hold. WraythUnhandledTagEvent was a commented-out no-op before this, so a wrong spelling was completely invisible; this is the check that would have caught the bootstrap bug on the first run.

Lowercase <opendialog> is deliberately not in the ignore list — it only ever appears in our own lab logs, and it should warn.

The bootstrap

Fixed to what the games actually send: <openDialog> with location='statBar' (not statusbar), and the inventory window with no location at all rather than the invented location='inv' that Wrayth rejects — real sessions send <streamWindow id='inv' title='My Inventory' target='wear' ifClosed='' resident='true'/>.

Verified by booting the lab with it: recv is clean of bad location, and the vitals bar renders in the status bar for the first time.

Testing

./gradlew check -PiosSkip=true -PlintSkip=true is green. Two new cases in WraythProtocolHandlerTests (18 passing): one that <openDialog> is handled while <opendialog> is not, and one that a knowingly-ignored tag is not reported as unhandled.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Corrected protocol tag handling to recognize valid case-sensitive tags and aliases.
    • Fixed vitals and inventory window configuration for reliable display.
    • Prevented known unsupported tags from being incorrectly reported as unhandled.
    • Improved warnings for unrecognized or incorrectly cased tags.
    • Ensured distinct unrecognized tags continue to be reported without excessive warning accumulation.
  • Tests
    • Added coverage for case-sensitive tag handling, intentionally ignored tags, and repeated unknown-tag reporting.

Wrayth matches tag names exactly: <streamWindow> and <openDialog> are
recognised, <streamwindow> and <opendialog> are dropped without even an
error. We lowercased every name and looked it up in a lowercase-keyed
table, so we accepted spellings no game ever sends - and that leniency hid
a bug in our own lab bootstrap, whose <opendialog> meant the vitals bar
had never once rendered there.

The table is keyed by the protocol's exact spelling now, and lookup no
longer lowercases. Every spelling was read off captured DR/DRT/GS4
sessions rather than inferred: the handler class names look like a guide
but are not one, since UpdateVerbsHandler answers to <updateverbs>. Two
tags appear in no capture at all - dynaStream and launchURL - so both
forms of each stay registered rather than guessing, because guessing wrong
would silently drop a tag the game does send.

Every other tag those sessions contain is registered as an IgnoredTagHandler:
the settings blob the server replays at login and its one-letter entries,
plus timestamp, sep, command, playerID and the rest. So an unrecognised tag
now means something, and the handler warns once for each one it sees,
naming the nearest spelling it does hold. That is the check that would have
caught the bootstrap bug on the first run.

The bootstrap itself is fixed to what the games actually send: <openDialog>
with location='statBar' (not 'statusbar'), and the inventory window with no
location at all rather than the invented location='inv' that Wrayth rejects.
Verified in the lab - the vitals bar renders and recv is clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Wrayth protocol handling now preserves tag case, uses exact protocol spellings, reports unknown or miscased tags, and ignores registered unsupported tags. Bootstrap examples and tests reflect the updated protocol behavior.

Changes

Wrayth tag handling

Layer / File(s) Summary
Exact tag registry and dispatch
wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt
The handler uses case-sensitive tag lookup, supports aliases, preserves exact end-tag matching, and dispatches registered tags through their handlers.
Unknown-tag diagnostics
wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt
The handler reports distinct unknown tags once and suppresses further warnings after 256 distinct names.
Ignored tags and protocol validation
wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt, wrayth/src/commonTest/kotlin/WraythProtocolHandlerTests.kt, utils/wrayth-lab/bootstrap.txt
IgnoredTagHandler handles registered unsupported tags without unhandled-tag events. Tests cover casing, unknown tags, and ignored tags. Bootstrap tags use accepted names and locations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WraythParser
  participant WraythProtocolHandler
  participant TagListener
  participant WraythUnhandledTagEvent
  WraythParser->>WraythProtocolHandler: pass original-case start tag
  WraythProtocolHandler->>WraythProtocolHandler: perform exact listener lookup
  alt registered tag
    WraythProtocolHandler->>TagListener: dispatch tag
  else unknown or miscased tag
    WraythProtocolHandler->>WraythUnhandledTagEvent: emit unhandled-tag event
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: protocol tag names now match case-sensitively.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch case-sensitive-tags

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt`:
- Around line 66-79: Bound retention in warnOnUnknownTag by enforcing a fixed
maximum size for unknownReported. When the set reaches the limit, emit a single
overflow warning and stop adding further tag names, while preserving one warning
per distinct tag before the limit.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 233d75a2-2ad3-47cb-a808-b0a6eb5a36ba

📥 Commits

Reviewing files that changed from the base of the PR and between e7b56a4 and 9507e81.

📒 Files selected for processing (3)
  • utils/wrayth-lab/bootstrap.txt
  • wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt
  • wrayth/src/commonTest/kotlin/WraythProtocolHandlerTests.kt

Nothing on the wire promises a finite set of tag names: the connection
carries whatever a Lich script emits, and the de-duplication set lives as
long as the connection does, so a stream of generated names would grow it
without limit.

It now stops at 256 distinct names - well above the whole known protocol,
so a real vocabulary can never reach it - and says so once on the way past.
At that point neither the warnings nor the set are any use anyway: something
is generating names rather than sending a vocabulary.

Raised by CodeRabbit on #267.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt (1)

84-101: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test the overflow diagnostic directly.

The endless-tag test only checks that each call emits WraythUnhandledTagEvent. An implementation that retains all 2,000 names would also pass that assertion. Add a test seam or logger assertion for the 256-name limit and the single overflow warning.

Based on the supplied WraythProtocolHandlerTests.kt context.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt`
around lines 84 - 101, The tests for WraythProtocolHandler must verify the
unknown-tag tracking limit, not only emitted WraythUnhandledTagEvent instances.
Extend the relevant endless-tag test or add a focused test seam around
warnOnUnknownTag to assert that exactly MAX_UNKNOWN_TAGS_REPORTED (256) names
are retained/reported and that the overflow logger warning is emitted only once
after the limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt`:
- Around line 84-101: The tests for WraythProtocolHandler must verify the
unknown-tag tracking limit, not only emitted WraythUnhandledTagEvent instances.
Extend the relevant endless-tag test or add a focused test seam around
warnOnUnknownTag to assert that exactly MAX_UNKNOWN_TAGS_REPORTED (256) names
are retained/reported and that the overflow logger warning is emitted only once
after the limit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 10a77582-96fb-4432-a69d-60856b0c3281

📥 Commits

Reviewing files that changed from the base of the PR and between 9507e81 and c389f29.

📒 Files selected for processing (2)
  • wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt
  • wrayth/src/commonTest/kotlin/WraythProtocolHandlerTests.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • wrayth/src/commonTest/kotlin/WraythProtocolHandlerTests.kt

@sproctor
sproctor merged commit 2432c19 into main Aug 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant