Asset Bridge phase 1, docs half. Code: RunicGateway/servuo-plugins#28,
RunicGateway/link#41.
## The correction, which is most of this
**New §4.8.** The animation path has §4.5's shared-buffer defect too, and 357 of the
1,144 bodies §1.1 counted are **wrong pictures on a stock client** — ids with `length 0`
that return whichever body was decoded before them. Proved by decoding body 320 after a
dragon (a dragon), a wolf (a wolf) and a human (a human).
So the catalogue is **787 bodies**, and the numbers that were derived from 1,144 move
with it: §11's working set, its ~173,000-frame full set (now ~119,000), phase 3's scope.
**§5.2's table was wrong in the direction that matters.** The elf ghosts were listed as
decoding; their index entry has no record, and what came back was the elf female. Four
of twelve player bodies have art, not six — which takes phase 4's UOP decoder from six
ids to eight.
§1.1 now says outright that every "decoded" count in it is an upper bound. It is not a
table to size anything from any more.
## What phase 1 settled
- **§3.3** — the two numbers: a 512 KiB batch budget under a 1 MiB inbound line cap, with
the factor of two load-bearing rather than cautious.
- **§3.2** — flow control is enforced **on the shard**, as a single slot answering
`bridge.busy`, not serialised in the sidecar and not left to the website as a
convention. Records what it costs: a status poll shares the slot.
- **§3.4, new** — one paging envelope (`more`/`cursor`/`cut`) for all five families that
will page, defined before the first one needs it. `cut` because "short page" has three
meanings and only one of them means finished.
- **§6** — hashing had to come off the request path entirely. The gate is unchanged; what
changed is that "the normal case must cost nothing" now also means "and the abnormal
case must not time out", because the first hash of 1.06 GB does not fit in 10 s.
- **§14** — which commands exist now, and which phase brings the rest.
- **§16, §17** — phase 1 done; decisions 6 and 7.
## Elsewhere
- **`SHARD_PREREQS.md`** gains the libgdiplus requirement (§4.4) — Linux hosts only, with
the archived-upstream caveat and the `NO_IMAGING` status the shard now reports on the
source gate.
- **`INTEGRATION.md`** advertised `X-UOLink-Version: 6`. It was already two versions stale
before this change; now 8.
- [x] AI-assisted — Claude Code (Opus 5)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
- Repoint doc-to-doc references from the old docs/ prefix to the co-located
sibling filenames (docs live under link/ here now).
- Replace the personal ServUO checkout path (C:\Users\...\servuo) with a
<servuo> placeholder throughout.
ScriptCompiler.Compile() runs `dotnet build Scripts/Scripts.csproj -c Release`
with no Platform, so MSBuild defaults to AnyCPU. Scripts.csproj gated both
OutputPath and DefineConstants on Configuration|Platform == Release|x64, so
under the server's own build the DLL landed in Scripts/bin/Release/ (while the
core loads Scripts.dll from the base directory) and TRACE;NEWTIMERS;ServUO went
undefined (XmlSpawner compiled its non-ServUO branches).
Compile() also never checks the build's exit code before Assembly.LoadFrom, so
the failure was silent and the stale DLL reloaded. Runtime script compilation
had had no effect since 2026-05-30.
Condition both property groups on Configuration alone. Server.csproj is left
alone: nothing under Server/ uses those symbols, and giving it OutputPath=..\
would make the boot-time build try to overwrite the running ServUO.exe.
Verified end-to-end: a plain boot now logs "Core: Compiling scripts... / Build
succeeded." and loads 206208 items, 42771 mobiles.
Also adds the implementation plan, the measured performance budget, the test
scaffolding used to produce it (seeder + probe, both default-off), and the
record of shard repairs that had to precede any of this.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>