refactor: simplify web event guard#82
Open
ALX99 wants to merge 1 commit into
Open
Conversation
This was referenced Jul 7, 2026
5cf571d to
dd748db
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Simplification
Reuse the existing
isServerEvent()protocol guard in the pi-web frontend bridge instead of repeating the same server-event validation locally withisObject(msg) && isServerEventType(msg.type)plus a manual cast.Why the current design is overcomplicated
pi-web/src/protocol.tsalready owns and tests the server-event type guard used at the WebSocket protocol boundary.pi-web/src/web/bridge.tshad a second, ad hoc validation path for the same event shape, which required importing the lower-level event-type predicate and then casting the message back toServerEventafter checking it.That duplicated a protocol responsibility in the UI bridge and created two places to reason about what counts as a valid server event.
Behavioral contract
The frontend WebSocket bridge must keep the same behavior:
{ type: "response", ok: ... }messages are still dispatched as responses first.eventreducer actions.session_startevents still trigger a session-list refresh.No wire format, public command, response shape, reducer behavior, persistence, logging, metrics, or user-visible behavior changes.
Before and after
Before:
pi-web/src/web/bridge.tsimportedisServerEventTypedirectly fromshared/wire.ts.isObject(msg) && isServerEventType(msg.type).msg as ServerEventbefore dispatching the event.After:
pi-web/src/web/bridge.tsimportsisServerEventfrom../protocol.ts.isServerEvent(msg)directly.msgto the event type without a local cast.Specific evidence:
isServerEventTypehelper.ServerEventimport and manual cast from the message handler.pi-web/tests/protocol.test.ts.Validation
Static validation performed through repository inspection:
isServerEvent()is implemented inpi-web/src/protocol.tsasisObject(value) && isServerEventType(value.type).pi-web/tests/protocol.test.tscovers accepted SDK-shaped events and rejected commands/unknowns/nulls.Commands not run in this environment:
cd pi-web && npm run build && npm run typecheck && npm testThis PR is intentionally narrow because local command execution was unavailable here.
Risk assessment
Risk is low because this replaces a local validation expression with the existing protocol-level guard that performs the same object/type check and is already tested. The response path remains first, so response messages are not reclassified. The event dispatch and
session_startrefresh behavior are unchanged.Behavior-sensitive areas examined:
session_start,Scope
Intentionally not simplified:
isResponse()remains local because there is no existing shared response guard with identical behavior.isObject()remains local becauseisResponse()still needs it.