docs(link): the catalogue is real, and UOFiddler's last job is gone (Phase 3) #238

Merged
whitlocktech merged 2 commits from docs/asset-bridge-p3 into main 2026-09-10 23:57:20 +00:00
Member

Phase 3 is built and walked on a live shard. This records what the walk measured and corrects the two places the design of record was wrong.

§8.1 (new) — what the walk measured

The catalogue is 787, exactly as §4.8 predicted, and the whole scan of bodies 1–2047 — index validation, 787 decodes, 787 PNG encodes, 787 SHA-256s — takes 734 ms cold. So the wall-clock paging §11 was designed for never fires on this client. It stays anyway: the budget is what keeps a slower host or a larger family inside the 10 s reply timeout instead of producing replies that are always thrown away.

Every §4.8 / §5.2 prediction held once the bytes were rendered and looked at:

Asked for Answer
body/320/a0 (length 0) absent — the library would have returned the previously-decoded creature
body/607/a0, body/608/a0 (elf ghosts) absent — §4.8's two rows that moved
body/666/a0 (gargoyle → anim5) absent — the spider trap; nothing swept
direction split across 787 783 at index 1, 4 at index 0 — four player bodies, not six

The 44 shared hashes, chased rather than assumed

44 of the 787 hashes are shared by two or three bodies, which is the exact signature of the wrong-picture bug. It is the client's own Body.def aliasing — 83 {1}, 84 {1}, 138 {7}, 106 {12, 59} — and the groups match those lines rather than being runs of consecutive ids, which is what a reused stream buffer produces.

The check that settles it is at the source: Animations.Translate(ref body, ref hue) rewrites body only when bit 31 of the table entry is set, unlike the one-argument overload which always does — and BridgeAssetValidator.ResolveAnimation calls that same two-argument overload, matching GetAnimation(…, preserveHue: false, …). Validator and decoder therefore resolve the identical record, which is the property the whole §4.5 design rests on.

§12.1 (new) — §12 is right about the outcome and wrong about the mechanism

"shard_spawn_creatures.art starts being filled by the import" cannot work as written. That table is emptied and refilled by replaceAtlas on every atlas refresh, and a refresh runs on every boot — so an imported filename written there is destroyed by an ordinary re-parse of the ServUO tree, and the next Update finds the client files unchanged and never restores it. Nothing reports a fault; the pictures are just gone.

Three tables outside that blast radius, and the atlas import re-derives art on the way past. §12.1 records the shape, the join pinned to the catalogue key (so phase 6's deeper keys do not shadow the thumbnail), and the content-addressed filename.

§16 listed phase 3 as servuo-plugins, module-uo. web.rs routes every command explicitly and has no generic /assets/* forwarder, so link is in the phase. Corrected in both places, and §14 now records the three routes, why the two POSTs are reads, and 422's second meaning.

UOFIDDLER.md is deleted — two phases early

§9.1 predicted phase 5. Creature art was the only thing still on the page, so phase 3 emptied it. SPAWN_ATLAS.md §Artwork is rewritten around the import — keeping the operator's own map as the thing that wins, and keeping NULL as a first-class state — and the two index rows pointing at the deleted page are gone.

modules/uo/SCHEMA.md gains the three tables (with the argument for why they are not import-owned); modules/uo/API.md gains the two admin routes and its count goes 26 → 28.

Second commit: the phase-2 cliloc debt, now fixed here

SCHEMA.md's cliloc section still described the pre-protocol-8 world. Three sentences carried the same falsehood, so fixing only the one I originally flagged would have left the section arguing with itself:

  • "Sourced from files the operator supplies" — the base comes from the shard on any install with uo-link. Only the overlays are the filesystem's, and that asymmetry has a reason worth stating: ServUO has no server-side notion of a custom cliloc, so there is nothing on the shard to ask for.
  • "A base (the converted client table)" — not converted any more.
  • "The conversion step is not avoidable … so the shard cannot supply names on our behalf" — it supplies them. Phase 2 ported the Mythic decompressor into the overlay precisely so nobody converts anything.

Rewritten to say what is true, why the file path still exists (deprecated, not removed, so an existing install keeps working), and the two things a reader of this table actually needs: shard_cliloc_meta.payload keeps the base's fingerprint under base separately from the overlay hashes — because on the bridge the old clilocs.plain label is supposed to disappear, and one flat hash map would read that upgrade as a vanished source — and boot does not import on the bridge path at all.

Every claim checked against the code rather than from memory: shardClilocs.model.js:307 (base: fingerprint), :438-440 (refreshOnBoot returns skipped on the bridge), clilocSource.js:333 (missingOverlays).

Companion PRs: servuo-plugins, link, Module-uo.

AI disclosure

  • This contribution was AI-assisted (Claude Code).

🤖 Generated with Claude Code

https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4

Phase 3 is built and walked on a live shard. This records what the walk measured and corrects the two places the design of record was wrong. ### §8.1 (new) — what the walk measured The catalogue is **787, exactly as §4.8 predicted**, and the whole scan of bodies 1–2047 — index validation, 787 decodes, 787 PNG encodes, 787 SHA-256s — takes **734 ms cold**. So the wall-clock paging §11 was designed for never fires on this client. It stays anyway: the budget is what keeps a slower host or a larger family inside the 10 s reply timeout instead of producing replies that are always thrown away. Every §4.8 / §5.2 prediction held **once the bytes were rendered and looked at**: | Asked for | Answer | |---|---| | `body/320/a0` (`length 0`) | absent — the library would have returned the previously-decoded creature | | `body/607/a0`, `body/608/a0` (elf ghosts) | absent — §4.8's two rows that moved | | `body/666/a0` (gargoyle → `anim5`) | absent — the spider trap; nothing swept | | direction split across 787 | **783 at index 1, 4 at index 0** — four player bodies, not six | ### The 44 shared hashes, chased rather than assumed 44 of the 787 hashes are shared by two or three bodies, which is **the exact signature of the wrong-picture bug**. It is the client's own `Body.def` aliasing — `83 {1}`, `84 {1}`, `138 {7}`, `106 {12, 59}` — and the groups match those lines rather than being runs of consecutive ids, which is what a reused stream buffer produces. The check that settles it is at the source: `Animations.Translate(ref body, ref hue)` rewrites `body` **only when bit 31 of the table entry is set**, unlike the one-argument overload which always does — and `BridgeAssetValidator.ResolveAnimation` calls that same two-argument overload, matching `GetAnimation(…, preserveHue: false, …)`. Validator and decoder therefore resolve the identical record, which is the property the whole §4.5 design rests on. ### §12.1 (new) — §12 is right about the outcome and wrong about the mechanism "`shard_spawn_creatures.art` starts being filled by the import" cannot work as written. That table is emptied and refilled by `replaceAtlas` on **every atlas refresh**, and a refresh runs on **every boot** — so an imported filename written there is destroyed by an ordinary re-parse of the ServUO tree, and the next Update finds the client files unchanged and never restores it. Nothing reports a fault; the pictures are just gone. Three tables outside that blast radius, and the atlas import re-derives `art` on the way past. §12.1 records the shape, the join pinned to the catalogue key (so phase 6's deeper keys do not shadow the thumbnail), and the content-addressed filename. ### §14 / §16 — `link` was missing from the phase §16 listed phase 3 as `servuo-plugins, module-uo`. `web.rs` routes every command explicitly and has no generic `/assets/*` forwarder, so `link` is in the phase. Corrected in both places, and §14 now records the three routes, why the two POSTs are reads, and 422's second meaning. ### `UOFIDDLER.md` is deleted — two phases early §9.1 predicted phase 5. Creature art was the only thing still on the page, so phase 3 emptied it. `SPAWN_ATLAS.md` §Artwork is rewritten around the import — keeping the operator's own map as the thing that wins, and keeping NULL as a first-class state — and the two index rows pointing at the deleted page are gone. `modules/uo/SCHEMA.md` gains the three tables (with the argument for why they are *not* import-owned); `modules/uo/API.md` gains the two admin routes and its count goes 26 → 28. ### Second commit: the phase-2 cliloc debt, now fixed here `SCHEMA.md`'s cliloc section still described the pre-protocol-8 world. **Three** sentences carried the same falsehood, so fixing only the one I originally flagged would have left the section arguing with itself: - *"Sourced from files the operator supplies"* — the **base** comes from the shard on any install with uo-link. Only the overlays are the filesystem's, and that asymmetry has a reason worth stating: ServUO has no server-side notion of a custom cliloc, so there is nothing on the shard to ask for. - *"A base (the converted client table)"* — not converted any more. - *"The conversion step is not avoidable … so the shard cannot supply names on our behalf"* — it supplies them. Phase 2 ported the Mythic decompressor into the overlay precisely so nobody converts anything. Rewritten to say what is true, why the file path still exists (deprecated, not removed, so an existing install keeps working), and the two things a reader of this table actually needs: `shard_cliloc_meta.payload` keeps the base's fingerprint under `base` **separately** from the overlay hashes — because on the bridge the old `clilocs.plain` label is *supposed* to disappear, and one flat hash map would read that upgrade as a vanished source — and boot does not import on the bridge path at all. Every claim checked against the code rather than from memory: `shardClilocs.model.js:307` (`base: fingerprint`), `:438-440` (`refreshOnBoot` returns `skipped` on the bridge), `clilocSource.js:333` (`missingOverlays`). Companion PRs: `servuo-plugins`, `link`, `Module-uo`. ## AI disclosure - [x] This contribution was AI-assisted (Claude Code). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
wtclaude added 1 commit 2026-09-10 23:43:21 +00:00
Phase 3 is built and walked on a live shard. What the walk measured, and the
two places the design of record needed correcting:

§8.1, new: the catalogue is 787 exactly as §4.8 predicted, and the whole scan
of bodies 1-2047 takes 734 ms cold -- so the wall-clock paging §11 designed
never fires on this client. Every §4.8/§5.2 prediction held when the bytes were
rendered and LOOKED at: 320, 607, 608 and 666 come back absent rather than as
another creature's picture, and the direction split is 783 at index 1 against 4
at index 0 -- four player bodies, not six.

44 of the 787 hashes are shared by two or three bodies, which is the exact
signature of the wrong-picture bug, so it was chased rather than assumed. It is
the client's own Body.def aliasing (83 {1}, 84 {1}, 106 {12, 59}), and the check
that settles it is at the source: Translate(ref body, ref hue) rewrites `body`
only when bit 31 is set, unlike the one-argument overload -- and ResolveAnimation
calls that same two-argument overload, so validator and decoder resolve the
identical record.

§12.1, new: **§12 is right about the outcome and wrong about the mechanism.**
`shard_spawn_creatures` is emptied and refilled by every atlas refresh, and a
refresh runs on every boot -- so an imported filename written to that row is
destroyed by an ordinary re-parse of the ServUO tree, and the next Update finds
the client files unchanged and never restores it. Three tables outside that
blast radius, and the atlas import re-derives `art` on the way past.

§14: **§16 listed phase 3 as servuo-plugins + module-uo and that was wrong.**
web.rs routes every command explicitly, so `link` is in the phase. Corrected in
both places.

UOFIDDLER.md is DELETED, two phases earlier than §9.1 predicted -- creature art
was the only thing still on it. SPAWN_ATLAS.md §Artwork is rewritten around the
import, keeping the operator's own map as the thing that wins; the module's
SCHEMA.md gains the three tables and API.md the two admin routes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
wtclaude added 1 commit 2026-09-10 23:51:01 +00:00
SCHEMA.md's cliloc section still described the pre-protocol-8 world, two
phases after phase 2 changed it. Three sentences said the same false thing,
so fixing only the flagged one would have left the section arguing with
itself:

- "Sourced from files the operator supplies" -- the BASE comes from the shard
  on any install with uo-link configured; only the overlays are the
  filesystem's, and that asymmetry has a reason worth stating (ServUO has no
  server-side notion of a custom cliloc, so there is nothing to ask for).
- "A base (the converted client table)" -- not converted any more.
- "The conversion step is not avoidable ... so the shard cannot supply names
  on our behalf" -- it does supply them. Phase 2 ported UOFiddler's Mythic
  decompressor into the overlay precisely so nobody converts anything.

Rewritten to say what is true and why the file path still exists (deprecated,
not removed, so an existing install keeps working), plus the two things a
reader of this table actually needs: `shard_cliloc_meta.payload` keeps the
base's fingerprint under `base` SEPARATELY from the overlay hashes -- because
on the bridge the old `clilocs.plain` label is supposed to disappear and one
flat hash map would read that upgrade as a vanished source -- and boot does
not import on the bridge path at all.

Each claim checked against the code rather than from memory:
shardClilocs.model.js:307 (`base: fingerprint`), :438-440 (refreshOnBoot
returns `skipped` on the bridge), clilocSource.js:333 (`missingOverlays`).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
whitlocktech merged commit afd0772289 into main 2026-09-10 23:57:20 +00:00
whitlocktech deleted branch docs/asset-bridge-p3 2026-09-10 23:57:21 +00:00
Sign in to join this conversation.
No description provided.