a5881d5a5532dfacf8a86519fec04d2d67cd798c
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| fc2d4872f6 |
docs(link): the panel, and the two deletions it could see and no test could (Phase 8)
v8.md section 12.2 records the admin surface as built: one page, Admin -> Client
Files, over the creature catalogue, item and land art, and the cliloc table --
one page because they come off one client install and change on one event. The
four decisions are written down, including the one that kept the phase to a
single repo: section 14's "activity view" is the last import's own summary
rather than a filtered feed, which would have needed a core activity filter, a
`ctx.activity.list` helper and a MODULE_API bump to re-read rows the panel can
keep itself.
The part worth reading twice is what the walk found. Two of the three defects
were DELETIONS, both predate phase 8, and neither was reachable by a test that
did not already suspect them:
* the body import diffing its manifest against every family's rows, so 313
item pictures were staged for deletion under a sentence that was wrong about
what had happened;
* an approved vanish unlinking the sprite and keeping the row, so the key came
back for review forever and the count never moved.
The rule they share is now stated: after phase 5, `shard_assets` is three
collections in one table, and every read of it that feeds a decision has to say
which one it means. Two of the three that did not were deletions.
CLILOCS.md and SPAWN_ATLAS.md now name the button that exists (Admin -> Client
Files) instead of the one they promised, and modules/uo/API.md records that a
`needsReview` reply carries each vanished key's picture.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
|
|||
| a4b63d87d2 |
docs(link): the hue belongs where the files are, and the cache poisons it (Phase 5)
§11.1 is new and carries what phase 5 measured: 49,152 addressable static ids (not the 81,884 `artidx.mul` declares -- `FileIndex` sizes its table from its length ARGUMENT), 39,189 with art, 4,244 land tiles, 9,963 + 12,140 empty index slots, and the whole set at 81 MB decoding in 34 s. That last number reopens the bulk question and the answer is still no: 108 MB of base64 through a 512 KB single-slot channel to store 43,433 pictures a shard displays a few hundred of. Two traps, both §4.5's failure mode -- a confident, plausible, wrong picture: - `Art.GetStatic` hands back the SAME cached Bitmap and `Hue.ApplyTo` repaints in place, so hueing edits the library's own copy: the plain key comes back hued from then on, and the next hue stacks. `Files.CacheData` off process-wide fixes it and also stops a game server retaining 74 MB of Bitmap. Copying instead does not solve the retention, and `new Bitmap(src)` throws on ARGB1555 anyway. - `PartialHue` (13,259 of 65,536 ids) decides whether a hue repaints every pixel or only the grey ones, from a file only the shard has. Item 597 is a wooden screen with painted flowers; one mode reddens the flowers, the other the whole screen, and both decode. Hence land takes no hue segment and `h0` is not a key. Plus the namespace trap that compiled: unqualified `TileData` binds to ServUO's own `Server.TileData`, because the enclosing namespace beats `using Ultima;`. §14 records what the wire gained -- the `static` and `land` families, `families` on `assets.sources`, and `assets.fetch` becoming shared plumbing whose family is DERIVED from the keys (§5 made the key the address; a request naming its family too would have two places to be wrong and one of them silent). Additive, so the protocol stays 8 and EXTRACTOR_VERSION stays 2. §15 records that `link` needed nothing in phases 4 or 5: it forwards verbatim in both directions. §17.10 is the four org-lead decisions. §12 and modules/uo/SCHEMA.md carry the website side: `uploads/items/`, per-row `catalog` staleness, and why a key with no art writes no row at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4 |
|||
| 6ef4b06c76 |
docs(link): two of the eight player bodies existed, and 233 nobody asked about (Phase 4)
Phase 4 built 4.3's UOP animation reader. What it found first changed what the phase
was worth, so the plan is corrected rather than merely annotated.
- New 4.9: what phase 4 measured. Of the EIGHT player bodies 4.8 assigned this
phase, two are in the client at all -- gargoyles 666/667, in AnimationFrame3.uop.
The six ghost bodies are in no package, and that is established rather than
unfound: the five packages hold 10,724 entries and the
build/animationlegacyframe/%06d/%02d.bin scheme claims every one, leaving no room
for another naming. Also the format as read (AMOU, a per-frame ARGB1555 palette,
direction as a slice of the frame table), the nine bodies whose frame count is not
a multiple of five, the validate-as-we-go bounds and the measurement that says
they refuse nothing real, and the live rig.
- 5.2 rewritten: the player-body set is the LIVING pair per race, six ids not
twelve. Ghost ids left it because no client has art for any of them. Still asked
of the shard, never hardcoded -- only the question changed. And with phase 4 in,
all six have art for the first time.
- 4.3 rewritten against what was measured, including why searching five UOP packages
for one body is NOT the never-sweep rule being broken: a legacy index is addressed
by position, a UOP entry by the hash of a name carrying the body id, which the
payload then declares again.
- 11 sizing: the catalogue is 1,022, not 787. The mix is recorded because "add every
body" sounds like it changes what a catalogue is, and it does not -- the legacy
787 was already 366 equipment bodies.
- 14: manifest and fetch rows carry `source` (legacy/uop). Additive, so protocol
stays 8; EXTRACTOR_VERSION 1 -> 2 is the change consumers actually see.
- 16 phase 4 marked DONE; 17.9 records the four org-lead decisions (fallback applies
to every body; ghost ids leave the set; own PNG encoder; NO_IMAGING stays flat).
- 4.8 and 8.1 keep their numbers as the record of what those phases measured, with a
pointer to where the answer landed.
Two consumer docs repeated the ghost claim as fact and are corrected:
website/SPAWN_ATLAS.md (787 -> 1,022, and "two thirds of the playable ghost and
gargoyle bodies have no art" -> about half the addressable body range) and
modules/uo/API.md (same sentence).
Code: servuo-plugins#31.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
|
|||
| 1a7481e9f4 |
docs(link): the catalogue is real, and UOFiddler's last job is gone (Phase 3)
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
|
|||
| cd0d22a225 |
docs(engagement): Phase 11b's live walk — three decisions and six defects
The walk is the last piece of 11b and it was not a formality. It found six
defects, four of them in code shipped by earlier phases, and none of the six was
visible in a unit test: each is a disagreement between two things that agree with
each other in a fixture.
Three of the fixes were decisions rather than repairs, all settled by the org
lead before any code:
11 `uo.house.idoc_warning` ships delay_seconds: 900 and nothing could cancel
it -> add `uo.house.refreshed`, a 26th trigger with a body and a rule
12 a rule with a cooldown delivered on exactly ONE of its channels
-> `channel` joins the cooldown key; a cooldown is per DELIVERY
13 `uo.vendor.expiring` could not fire, because the market sweep does not
diff fees -> widen BridgeMarket.Signature() with exempt +
periodsRemaining
Files:
website/ENGAGEMENT.md the three decisions, the four repairs, and what the
walk proved rung by rung; the 11b bullet and the §8.6
family table now read 26 triggers / 34 bodies
website/BACKEND_DESIGN.md engagement_cooldowns gains `channel` in its PRIMARY
KEY, with the migration's information_schema guard and
why MariaDB forces one
link/v5.md the sweep has to DIFF the fees or the frame never
comes -- stated as the general rule for the next
enrichment, since it is emit cadence and not shape
modules/uo/API.md §5.7a the cancel-shaped trigger and the Ageless-vs-
LikeNew ServUO fact; §5.7b every link comes from
config/clientPaths.js, and the two mistakes that made
every call-to-action a dead link
Pairs with website#<core>, Module-uo#<uo> and servuo-plugins#<plugin>.
Co-Authored-By: Claude <noreply@anthropic.com>
|
|||
| 9d50e5cacf |
docs(engagement): Phase 11b — the seed API, the in-universe voice, the governor's letter
Four decisions settled by the org lead before any 11b code, plus MODULE_API
1.9.0 and what building it found.
DECISION 7 is the one 11a could not have discovered, because 11a seeded nothing.
The plan's own sentence — "24 rules, all enabled = 0; bespoke template bodies" —
described work with NO MECHANISM to land in: templateSeeds.js and coreRules.js
are core files with core arrays, and registries.js has no registerTemplates.
Adds api.registerEngagementSeeds({ templates, ruleGroups }). Templates re-ensure
every boot; rule groups are one-shot per named group, which is 11a's seed-key
finding stated as an API rather than as a warning.
DECISION 8: the game-powered families read in-universe, with a per-family sender
rather than one voice. The crown writes about the crown's business and nothing
else. This is also why the bodies had to be the module's: §5.2 says core stays
ignorant of a module's domain, and check:modules reads identifiers, never prose —
so the boundary is honoured deliberately here rather than leaned on.
DECISION 9: nine bodies stay plain. A failed-login notice written as a letter is
indistinguishable in register from the phishing mail it warns about.
DECISION 10 corrects a fact the plan had wrong by omission. §8.6 records that
uo.points.rank_changed cannot address a person, and the same reasoning was
silently assumed to cover the governor. city.update's `governor` is written by
BridgeJson.Actor(), which emits acct and webId — the new governor is addressable
today, no protocol change. uo.governor.appointed is the 25th trigger.
Also records what building it found: the no-conditionals/empty-string collision
that the presentational fragments exist for, the render sweep that found three
defects no check could see (an optional in a subject line, multi-optional detail
lines, a trailing fragment used as a leading one), the trigger-bound template
that could not reference its own unsubscribe link, and the trigger-id/template-key
grammar mismatch.
docs/modules/uo/API.md gains §5.7 and §5.8.
Co-Authored-By: Claude <noreply@anthropic.com>
|
|||
| 561e5308e4 |
docs(engagement): MODULE_API 1.8.0, the UO trigger catalogue, the news path
The documentation half of Phase 11a (website#177, Module-uo#22). Three files,
each carrying one obligation from 6.0b's Phase 11a row.
**MODULE_API.md -> 1.8.0.** A seventh audience ceiling, `admin`, as a child of
`staff`. One addition, no removal, so minor -- every declaration valid under
1.7.0 is valid now and no stored value changes. 2.4's ceiling bullet now names
seven values rather than six, and says the thing a module author actually needs:
`admin` is the ONLY pair in the whole lattice with real containment, so
`permits('staff','admin')` holds and it is the only place `permits` is true
between two values below `authenticated`.
Also corrects two 2.3 rows that were stale rather than wrong: `ctx.inbox.push`
has not thrown since Phase 7, and both members now name the consumer that
actually calls them.
**modules/uo/API.md gains 5**, the full trigger catalogue -- which 6.0b asked for
in as many words ("the full trigger catalogue, its audiences and its ceilings,
not one entry"). The 24 triggers grouped by ceiling with the reason for each
ceiling; the four rows that deliberately do NOT ship with their recorded reasons;
the two that need a patch tier or a v5 overlay; the three things a rule cannot
express and are therefore done in the mapper; the three registered audiences; and
the ingest ORDERING, which is load-bearing rather than incidental.
**BACKEND_DESIGN.md -- the news publish path.** It described a direct
`pushDispatch.publish('news.post', ...)` from the create/publish-post path. That
call is gone: it is an emit through the engagement engine now, so news push rides
a rule, and core seeds that rule disabled. The note says so as an operator-visible
upgrade step, names the separate one-shot settings key and states what did NOT
change -- the announce legs and the post hooks still fire exactly as they did.
Co-Authored-By: Claude <noreply@anthropic.com>
|
|||
| 42867d7ef8 |
docs(modules): close Phase 4 — de-UO the backend reference, record the acceptance run
Phase 4 slice 4. BACKEND_DESIGN.md had never been de-UO'd: Phase 3 rewrote core's code and README, but §5.2's identifier check reads code, not prose, so nothing ever looked at the design document. It still described 27 shard_* tables, 20 UO route rows and the shard visibility ladder as core's, a phase after core stopped being able to serve any of them. Moved, text unchanged: BACKEND_DESIGN §3 six shard_* schema sections (226 lines) → modules/uo/SCHEMA.md BACKEND_DESIGN §4 13 public + 7 admin UO route rows → modules/uo/API.md BACKEND_DESIGN §6.5 the audience ladder (70 lines) → modules/uo/API.md §4 Core keeps the seam and gains the eight /admin/modules routes it had never documented. §6.5 becomes "Module-owned audience boundaries": core's security boundary ends at authentication, roles and the session, and a module that serves game data brings its own. Also fixed on the way: users.router.js was still listed as 15 routes (it is 9 — six went to the extension slot), and the push section still promised config/shardStreams.js "moves out with it" four slices after it left. The acceptance table now carries results. Criterion 2 was proved for real against module-uo v0.3.0 on an empty database, which turned up the uninstall ordering defect fixed in website#146. AI disclosure: this contribution was AI-assisted (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> |