Skip to content

refactor(protocol): migrate plugin transport to canonical xcore-protocol model #5

Merged
osp54 merged 26 commits intomainfrom
xcore-protocol-migration
May 3, 2026
Merged

refactor(protocol): migrate plugin transport to canonical xcore-protocol model #5
osp54 merged 26 commits intomainfrom
xcore-protocol-migration

Conversation

@osp54
Copy link
Copy Markdown
Collaborator

@osp54 osp54 commented Apr 26, 2026

Summary

  • Migrate XCore-plugin transport messages from local payload types to generated XCore-protocol V1 contracts.
  • Align Redis routing, transport metadata, and event handling with the canonical protocol message names and stream definitions.
  • Remove obsolete legacy transport payloads and update tests to validate the plugin against the generated protocol-based message flow.

osp54 added 2 commits April 26, 2026 18:48
Map outbound BanData publishes to the canonical moderation.ban.created contract so the protocol-first migration can proceed without changing Redis stream or envelope semantics. Keep Gson serialization and runtime transport ownership in XCore-plugin while validating the new slice with targeted and full transport checks.
Replace the sibling source-set wiring with the published xcore-protocol Java artifact so the moderation migration branch builds through the shared Maven path. Keep the current protocol mapping slice intact while aligning local and CI resolution with the canonical publish flow.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ade8c23680

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +309 to +314
if (event instanceof BanData banData) {
return gson.toJson(ModerationProtocolMapper.toBanCreated(
banData,
config.server,
Instant.ofEpochMilli(now)
));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve BanData payload when routing BanData events

send now rewrites every BanData event to ModerationBanCreatedV1 JSON, but the receive path still deserializes moderation.ban payloads as BanData (dispatchStreamMessage uses gson.fromJson(payloadJson, type) for type == BanData.class). That makes subscribe(BanData.class, ...) decode mostly default/empty fields because keys like uuid, name, and expireDate are no longer present in the payload. Any consumer using the existing BanData subscription contract will silently get corrupted moderation data.

Useful? React with 👍 / 👎.

osp54 added 5 commits April 27, 2026 20:04
Replace legacy moderation wire payloads with canonical xcore-protocol DTO wrappers so Redis routes, publishers, and handlers share one transport contract. Update moderation transport tests to lock the canonical stream and command identities across the plugin.
Send and receive moderation transport messages as generated xcore-protocol DTOs so the wire layer no longer depends on local wrapper events. Align routing, handlers, and tests with the canonical moderation contracts while keeping stream identities and build validation green.
Drop unused moderation wrapper records so the transport layer matches the direct DTO moderation flow. This reduces leftover legacy surface without changing runtime behavior.
Switch the Discord link and admin transport flows to released xcore-protocol DTOs and canonical routes so XCore-plugin no longer depends on local wrapper events for this family.
Generalize RPC request and response handling so generated protocol DTOs can participate in Redis roundtrips, then switch the maps.list flow to canonical request and response messages. This keeps the transport surface aligned with xcore-protocol while preserving existing maps.remove behavior for a later slice.
@osp54
Copy link
Copy Markdown
Collaborator Author

osp54 commented Apr 28, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61e5d38efb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return new ModerationAuditAppendedV1(
toAuditEntryType(record.action),
new PlayerRefV1(
requireNonBlank(record.target == null ? null : record.target.uuid, "audit target uuid"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Accept IP-only targets in moderation audit mapping

ModerationService.tempBanByUuidOrIp and tempUnban both allow uuid to be null, and auditTarget(...) normalizes that to an empty string for audit records. This mapper now enforces requireNonBlank on record.target.uuid, so valid IP-only moderation operations throw IllegalArgumentException when posting ModerationAuditAppendedV1, failing the request after persistence has already happened.

Useful? React with 👍 / 👎.

) {
return new ModerationKickBannedCommandV1(
new PlayerCommandTargetV1(
requireNonBlank(playerUuid, "playerUuid"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Permit IP-only moderation commands without UUID

The command mapper now requires a non-blank playerUuid, but the moderation service explicitly supports UUID-less IP-based actions (tempBanByUuidOrIp/tempUnban). For those valid inputs, building the kick/pardon command throws instead of publishing, so cross-server enforcement and pardon propagation break for IP-only moderation flows.

Useful? React with 👍 / 👎.

osp54 added 6 commits April 29, 2026 18:40
Consume xcore-protocol 0.2.0 and relax moderation command and audit mapping so UUID-or-IP targets can round-trip through the plugin. Skip ban-created emission for IP-only temporary bans while preserving the stricter event contract.
Switch the remaining maps.remove RPC flow to generated xcore-protocol DTOs and canonical route metadata so the maps RPC family no longer depends on local transport request and response wrappers.
Switch the heartbeat producer and transport metadata to the generated server.heartbeat DTO so Phase 5 starts on the canonical protocol surface. Remove the dead local heartbeat wrapper now that routing and validation are fully aligned.
Switch the chat message and global chat transport flow to generated xcore-protocol DTOs and canonical routes so the Phase 5 broadcast path no longer depends on local wrapper events.
Switch the Discord ingress transport flow to the generated protocol command and canonical route metadata so the Phase 5 chat ingress path no longer depends on a local wrapper event.
Consume xcore-protocol 0.3.0 and switch the cross-server private-message relay to the canonical chat.private contract so the Phase 5 chat flow no longer depends on a local wrapper event.
@osp54 osp54 marked this pull request as draft April 30, 2026 16:27
osp54 added 7 commits April 30, 2026 20:15
Move server action and player join/leave traffic onto generated protocol DTOs and remove the raw fallback route so Redis transport only emits canonical metadata.

This completes the remaining Phase 5 tail work and adds regression coverage for unsupported payload rejection.
Move map load transport onto the generated protocol command so the plugin uses the canonical maps.load.command contract across routing and tests.
Remove obsolete maps request and response scaffolding now that the plugin uses generated protocol DTOs for the live maps transport path.
Switch the custom nickname, active badge, and badge symbol color mode transport flow to generated protocol commands so plugin routing and handlers use the canonical server-targeted contract.

This also updates the protocol dependency to the snapshot containing the new chat-family player-session commands and removes the replaced legacy transport records.
…s to V1

Switch producer (BadgeAdminController) and consumer (ModerationTransportHandler)
from legacy TransportEvents records to ChatMessages V1 command DTOs.
Update routing (RedisRouteRegistry, RedisTransportTopology) to use
PAYLOAD_SERVER resolver and canonical event type names.
Remove dead legacy types PlayerBadgeInventoryChanged/PlayerPasswordReset
from TransportEvents. Add ModerationTransportHandler consumer tests.
Update plugin mappers and transport-facing tests to consume the\nlatest canonical xcore-protocol actor/source DTO shapes, enum\nmodels, and map file naming.\n\nThis keeps XCore-plugin aligned with the generated protocol\nsurface and avoids reintroducing local contract drift.
@osp54
Copy link
Copy Markdown
Collaborator Author

osp54 commented May 2, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e66238f6a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

network.post(new ServerHeartbeatV1(
config.server,
config.discordChannelId,
Math.toIntExact(config.discordChannelId),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve full Discord channel ID in heartbeat payload

Converting config.discordChannelId with Math.toIntExact(...) will throw for normal Discord snowflake IDs (they are 64-bit and typically exceed Integer.MAX_VALUE), so servers configured with real channel IDs will fail to publish heartbeats every cycle and silently lose liveness telemetry. The field is already stored as long in Config, so this narrowing conversion introduces a runtime failure path in production.

Useful? React with 👍 / 👎.

osp54 added 3 commits May 2, 2026 13:05
Force CI build, snapshot publish, and release publish jobs to refresh Gradle dependencies before running tests. This reduces stale xcore-protocol snapshot cache issues in GitHub Actions for the migration branch.
Flush Redis between integration tests to avoid shared stream state leaking across cases. Align moderation payload assertions with the runtime Gson payload shape so CI validates the actual transport contract.
Publish heartbeat events with the full Discord snowflake instead of narrowing the configured channel ID to int. Update the router test to cover the widened protocol contract that now resolves from the refreshed protocol snapshot.
@osp54 osp54 changed the title Migrate moderation transport to xcore-protocol Migrate to xcore-protocol May 2, 2026
@osp54 osp54 marked this pull request as ready for review May 2, 2026 11:51
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a3830a2a84

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (Structs.contains(e.expectServers(), config.server)) return;
} else if (e.expectServers().length > 0 && !Structs.contains(e.expectServers(), config.server)) {
network.subscribe(ServerCommandExecuteCommandV1.class, e -> {
if (!e.targetServers().isEmpty()) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Guard null targetServers before filtering execute command

The new execute-command handler assumes targetServers is always present and calls e.targetServers().isEmpty() unconditionally, but during phased migration the same Redis stream still carries legacy ExecuteCommand payloads that do not contain this field. Those messages deserialize with targetServers == null, causing a NullPointerException and dropping distributed command execution for that message batch.

Useful? React with 👍 / 👎.

network.subscribe(TransportEvents.PardonPlayer.class, e -> {
Administration.PlayerInfo info = netServer.admins.getInfoOptional(e.uuid());
network.subscribe(ModerationPardonCommandV1.class, e -> {
Administration.PlayerInfo info = netServer.admins.getInfoOptional(e.target().playerUuid());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Handle legacy/nullable pardon targets before dereference

The pardon listener dereferences e.target() without a null check. Legacy PardonPlayer payloads on the same stream (or malformed payloads) deserialize without a nested target object, so this throws before any unban cleanup runs. In mixed-version rollout, a single legacy unban command can repeatedly fail instead of being processed.

Useful? React with 👍 / 👎.

public void registerListeners() {
network.subscribe(TransportEvents.DiscordLinkConfirmEvent.class, e -> {
network.subscribe(DiscordLinkConfirmCommandV1.class, e -> {
Integer playerPid = e.player().playerPid();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Null-check Discord link command player envelope

The confirm-link listener immediately reads e.player().playerPid() with no guard for a missing player object. Legacy confirm payloads on the same Redis command stream use top-level player fields, so player deserializes as null and the handler throws, preventing link confirmation in mixed-version deployments.

Useful? React with 👍 / 👎.

osp54 added 3 commits May 3, 2026 14:12
…ization

BREAKING: Redis payload_json now emitted via ProtocolPayload.toPayload()
which injects messageType/messageVersion and canonical nested ref shapes.

- Bump xcore-protocol-java: 0.3.0-SNAPSHOT → 0.4.0
- RedisNetworkBackend.payloadJson() uses toPayload() for ProtocolPayload
- RPC request/response serialization uses same path
- Integration tests assert messageType/messageVersion in payload_json
- Clean up unused TransportEvents imports
@osp54 osp54 changed the title Migrate to xcore-protocol refactor(protocol): migrate plugin transport to canonical xcore-protocol model May 3, 2026
@osp54 osp54 merged commit 4e4d498 into main May 3, 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