Players intermittently remain in the elytra flying pose after landing on Minecraft 26.3. The server and other players can see them standing while their own client remains flying; creative flight can also behave incorrectly. Mitigated in production with /glidefix; root cause is NOT fixed. Resume from the confirmed self-metadata recovery experiment below, rather than restarting the broad proxy investigation.
Current state (2026-10-26 UTC)
- Production: GlideFix 1.0.0 enabled and command confirmed working by the user. Old GlideDiagnostics / GlidePacketDiagnostics / GlidePacketTrace JARs and capture folders removed after separate backups. Temporary command-registration helper self-disabled and its JAR was removed.
- Staging: GlideFix and the expanded GlidePacketTrace probe installed. Automatic takeoff recording was armed for 30 minutes, not indefinitely; re-arm when resuming. Do not assume a session remains active.
- No production tracker configuration changes. A live staging async-tracker experiment was reverted to the exact original configuration.
- Scope: fix the underlying synchronization defect and eventually remove the manual workaround. Related release context: ADT-193. MyWorlds portal recovery is tracked separately in ADT-218.
Symptoms and reproduction
Reports were widespread on production, including the investigator. Landing is the common trigger. Observer sees standing; affected client sees flying. Relogging, death, or changing worlds has sometimes cleared it. One historical chat report explicitly said “only in the city”; Reveille-only is not established by controlled tests.
Initially the same players could not reproduce on staging, even after matching UniverseSpigot and testing Velocity. On Oct 26, Paradaux reproduced on staging through Velocity, in Reveille. This made a takeoff-to-failure packet capture possible.
Suggested next baseline: same player/client and world, fresh takeoff/landing, record whether anyone else actually tracks that entity. Do not rely on a nearby player being present: vanish and visibility rules may mean zero tracking observers.
Strongest evidence: takeoff through confirmed failure
Staging capture packets-10548211687054582634.tsv:
| Observation | UTC / result |
|---|
| Uncancelled glide start | 01:24:20.016 |
| Uncancelled glide stop | 01:24:20.701 |
| User-confirmed stuck marker | 01:24:41.904 |
| Post-landing state | 589 samples: gliding=false, ground=true, STANDING, flying=false, allowFlight=true, inVehicle=false |
| Outgoing position corrections | 0 |
| Own-entity metadata observed | 0 |
| Bukkit movement events | 565 allowed, none cancelled |
| Capture drops / decode errors | None |
This occurrence disproves the earlier position-packet flood as a necessary cause and excludes a server-maintained glide state, active mount, or cancelled movement/glide-stop for this capture.
Successful recovery experiment
At 01:26:22 and again at 01:26:36 the live server snapshot showed:
- authoritative entity flags = 0;
- pose = STANDING;
- SynchedEntityData.isDirty() = true;
- Player.getTrackedBy().size() = 0.
At 01:26:36 we explicitly resent only the player's current shared flags (metadata index 0) and STANDING pose (index 6) to that same player, without teleporting or changing server entity state. Capture packets-15158287410648573828.tsv observed the resulting self-metadata packet at both PacketEvents LOWEST and MONITOR, uncancelled, with flags=0 and pose=STANDING. The user immediately answered “Yes, it cleared.”
Confirmed: copying authoritative flags/pose back to the client recovers this occurrence.
Leading hypothesis: the player's own metadata is not synchronized when there are zero tracking observers.
Not yet proven: exactly which backend tracking branch, optimization, plugin, or interaction suppresses the update. Dirty=true is an aggregate metadata flag, not proof of which individual entries remain dirty. Do not label this conclusively a client bug, Velocity bug, MyWorlds bug, or async-tracker bug.
Other captures and what they establish
Production, Oct 25
b4daab05-capture.tsv, 16:55:33–16:57:33, 2,297 rows: uncancelled start 16:55:36.686; grounded stop 16:55:39.132; false/STANDING immediately afterward; “stuck” marker 16:55:42.414. All 2,169 post-stop ticks remained non-gliding/STANDING. No world change or death. No metadata-105 errors during this interval.
- Glide event listeners included LibsDisguises, WeaponMechanics, WorldGuardExtraFlags, and diagnostics. No MyWorlds glide listener was observed. Captured stop was not cancelled.
packets-1995881960626701819.tsv, 17:10:42–17:10:50: 136 incoming movement packets observed at two priorities; grounding arrived uncancelled; server stopped gliding; user marked stuck. No selected self-metadata or decode errors. The v0.1 probe lacked broad outbound positive controls, so absence alone was not proof of missing wire packets.
837bf0e0-capture.tsv, 17:31:45–17:31:56: 159 samples with creative flying=true, allowFlight=true, gliding=false, STANDING and vy=0. Supports disagreement with reported creative descent, but no symptom marker and no position coordinates: zero velocity alone does not prove unchanged physical Y.
Staging, Oct 26
packets-3287832090587614724.tsv: already-stuck marker 01:15:23; 833 non-gliding/STANDING/ungrounded server samples; 407 outgoing position packets in ~42 seconds. Positive control: 828 metadata packets for other entities reached the player's pipeline, but none for their own entity. No dropped rows. Origin of this flood remains unresolved and it may be a separate symptom/consequence.
- Subsequent captures showed normal grounded samples and isolated position IDs 846/847, acknowledged in ~83–86 ms. No persistent broken teleport-ack path in those intervals.
packets-7200592734401469964.tsv: 5,730 rows; two position packets, both acknowledged; 953 allowed moves, zero cancelled. One uncancelled DISMOUNT teleport originated in vanilla Player.rideTick / ServerPlayer.dismountTo, not a plugin caller. This does not establish dismounting as the original cause.
- Network encoder stack traces start after the async send queue and cannot identify the original producer. Plugins merely appearing in the outbound Netty stack are not evidence of culpability.
- Live async-tracker test: dirty=true/observers=0 before at 01:27:45; disabled only asynchronous.tracker.enabled and ran universespigot reload at 01:27:47; still dirty=true/observers=0 at 01:27:53. No self-metadata flush observed; capture ended when player disconnected. Live reload effectiveness was not independently verified, so this is inconclusive about the actual async execution path. Original config restored.
Environment and earlier hypotheses
- UniverseSpigot 26.3 plus build a605d98; Java 25.0.2 GraalVM. PacketEvents 2.14.0; LibsDisguises 26.9.26; MechanicsCore / WeaponMechanics / Cosmetics 4.3.1; BKCommonLib 2.0.5 ADT193 custom build; MyWorlds 2.0.1 custom build.
- Staging tested Paper, then matching Universe; ViaVersion/Backwards and relevant configs compared. Vanilla Velocity 4.3.0 build 44 and Velocity-CTD 4.3.1 build 411 were tried before staging eventually reproduced. Earlier negative reproductions do not rule out any component.
- Historical reports that proxy restart helped were not controlled. Direct-versus-proxied reproduction under the same zero-observer conditions remains outstanding.
- CTD artifact probes: 200k raw metadata/movement packets and 40k compression/framing cases preserved bytes/order. These synthetic tests did not exercise real sessions, TCP, plugins, or clients and do not exonerate the proxy.
- Reveille world overrides inspected: no relevant movement/tracking override found. Global tracker async enabled, player update interval 2, legacy-order=false; world ticking async disabled. Stage/prod configs were compared.
- MyWorlds refreshState restores OnGround on world change, not ordinary landing; no direct glide/pose setter found in inspected paths. BKCommonLib supports self broadcasts but that does not show it installs custom controllers on all players.
- No configured GPFlags NoElytra or matching WorldGuard glide flags found. GSit configs compared. LibsDisguises' inspected wrapped gliding setter updated cached state rather than directly calling Bukkit setGliding. These are narrower findings, not blanket exonerations.
Metadata serializer 105 errors
Production also logged “Unknown entity metadata type id: 105 version V_26_3” in LibsDisguises / WeaponMechanicsCosmetics decoding paths. 105 is a metadata serializer ID inside a packet, not an outer packet ID. No such errors coincided with the first two confirmed captures. Do not merge this into the elytra RCA without temporal/packet correlation. PacketEvents reader-position and re-encoding behavior matters; synthetic probe tests validated that cloning/decoding did not change the original buffer/cancellation state. Use the installed V_26_3 registry for pose serializer IDs, not a hard-coded old value.
Production mitigation: GlideFix
- Players:
/glidefix, permission glidefix.use defaults true.
- Staff/console:
/glidefix <exact-player>, permission glidefix.others defaults op.
- Five-second per-target cooldown; requires server not gliding and pose STANDING.
- Reads actual NMS shared flags, preserves invisibility/other flags, sends index 0 plus index 6 STANDING to that player only. No inventory/game-mode/position/server-pose mutation.
- Minecraft 26.3 / Java 25 / PacketEvents 2.14.0; fails closed on unsupported Minecraft version.
- Staging runtime verified send and cooldown. User-confirmed recovery was first demonstrated with the identical diagnostic resend; user subsequently confirmed the production command works.
- JAR SHA256:
12f5c836e0fc5b15bcb74ba2be1aa987c2f10c8a561ae8a0ead4ff8aa327ee49.
- Production enabled 01:33:39 Oct 26. SFTP upload was read back and checksum verified.
- This is temporary mitigation. Do not close the RCA because /glidefix exists.
Separate deployment trap: PlugMan command registration
Production PlugManX 2.4.1 differs from staging 3.2.1. Hot-loaded GlideFix enabled but both command forms were unknown. Inspected 2.4.1 wrapper returns without registering when its old versioned-package detection leaves nmsVersion null. CraftServer.syncCommands only sends the existing tree; it does not add missing command nodes. Earlier same-identifier diagnostic reloads also hit stale plugin-provider registration.
A one-shot helper registered glidefix and glidefix:glidefix via BukkitCommandNode.of against the existing GlideFix PluginCommand, filled missing declared permissions, refreshed players' command trees, and disabled itself. Success logged 01:39:04; user confirmed it worked. Helper JAR removed. Do not blindly hot-reload through the old PlugMan again. Normal cold-start command availability still needs verification at the next scheduled restart.
Evidence and source handoff
Workspace: /home/paseo/.paseo/worktrees/0zr4sw49/money-peacock.
- Latest canonical findings:
.context/elytra-audit/staging-repro-20261026T011433Z/findings.json plus named TSV files above.
- Production summaries:
.context/elytra-audit/b4daab05-analysis.json, packet-capture-findings.json, 837bf0e0-analysis.json.
- Probe source/build:
.context/elytra-audit/packet-probe/. Commands: glidetrace start <player>, mark <label>, stop, arm <online-player-or-UUID>, disarm; permission glidepackets.admin. Arm lasts 30 min; each capture 120 s, 24,000 row / 20-file caps. Observe footer dropped count. Probe includes a deliberate resync <player> send intervention—label it, do not treat it as passive observation.
- Latest probe records glide transitions, state including mount/flight, packet IDs/ACKs, metadata raw/wrapper views, limited stack samples, Bukkit teleport causes and move-cancellation counters.
- Mitigation source:
ops/glidefix/; standalone Gradle project. At handoff it is uncommitted local source, not a published repository release.
- Artifact and runtime checks:
.context/glidefix/build/.
- Deployment, separate backup manifest, original debug JARs/captures:
.context/glidefix/production-deployment.json, production-backup-manifest.json, production-backup/.
- One-shot registration repair source/result:
.context/glidefix/command-repair/.
- Staging async-toggle original config was copied to
staging-repro-20261026T011433Z/universe-global-before-tracker-test.yml; restored, not moved.
- Some previous server bytecode dumps are extracted Paper base classes, not proven effective transformed Universe runtime. Do not infer an executed Universe branch from those alone.
- Staging evidence report; earlier packet comparison.
- Raw production logs may include unrelated player data; use the scoped diagnostic captures, not whole-log publication. No console credentials available to the agent: production activation commands were run by the user; SFTP handled files.
Next discriminating experiments
- Restore the same native client/session test on staging and capture BEFORE takeoff. Record effective tracker observer count, visibility/vanish, exact flags/pose entries and dirty state across landing.
- Controlled zero-observer vs one-real-observer comparison, same player/world/client. Verify actual getTrackedBy count, then isolate visibility, world, and distance. Check whether adding a real observer flushes pending self-metadata and prevents recurrence.
- Instrument the effective runtime path from setting flags/pose -> dirty-item packing -> tracker tick eligibility -> sendToTrackingPlayersAndSelf -> backend packet pipeline. Identify where the update first disappears. Investigate zero-observer early exits or stale tracker state; do not consume dirty metadata just to inspect it.
- Verify effective runtime async setting before comparing synchronous/async tracker. If a restart is needed, schedule a staging restart after preserving the failing state. The live toggle did not prove this branch.
- If backend self-metadata is emitted but client still fails, trace through the proxy and compare direct connection under identical observer conditions. Do not start by assuming Velocity is responsible.
- Fix the demonstrated component; add regression coverage for a lone player, tracked player, vanish visibility, survival/creative, and repeated takeoffs/landings. Compare Reveille and another world without conflating world-switch recovery with prevention.
- Commit/publish the mitigation source and preserve essential traces in a durable team-accessible location. Verify /glidefix self/staff permissions and cold-start registration. Keep backups separate.
- Remove the stopgap and diagnostic plugins only after repeated native-client verification of the real fix.
Acceptance
- Reproducible causal explanation supported by the actual failing runtime path.
- Landing reliably clears local flying pose/movement without manual resend, reconnect, teleport, or world change.
- Tests cover zero and nonzero observers, visibility/vanish, supported game modes/worlds, and the same proxy path.
- No inventory, permission, movement, or pose regressions.
- Staging validation recorded before production rollout; production verified; mitigation retired with rollback available.