Match protocol tag names case-sensitively - #267
Conversation
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>
📝 WalkthroughWalkthroughWrayth 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. ChangesWrayth tag handling
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
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (3)
utils/wrayth-lab/bootstrap.txtwrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.ktwrayth/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>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.kt (1)
84-101: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest 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.ktcontext.🤖 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
📒 Files selected for processing (2)
wrayth/src/commonMain/kotlin/warlockfe/warlock3/wrayth/protocol/WraythProtocolHandler.ktwrayth/src/commonTest/kotlin/WraythProtocolHandlerTests.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- wrayth/src/commonTest/kotlin/WraythProtocolHandlerTests.kt
Wrayth matches tag names exactly:
<streamWindow>and<openDialog>are recognised,<streamwindow>and<opendialog>are dropped without even an error (verified inutils/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
UpdateVerbsHandleranswers to<updateverbs>, all lowercase. The existing tests already used the camelCase forms, which corroborates them independently.Two tags appear in no capture at all —
dynaStreamandlaunchURL— 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), plustimestamp,sep,command,playerID,switchQuickBar,endSetup, theexpose*/deleteContainerfamily, 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.
WraythUnhandledTagEventwas 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>withlocation='statBar'(notstatusbar), and the inventory window with nolocationat all rather than the inventedlocation='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:
recvis clean ofbad location, and the vitals bar renders in the status bar for the first time.Testing
./gradlew check -PiosSkip=true -PlintSkip=trueis green. Two new cases inWraythProtocolHandlerTests(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