docs: plan the app's vocabulary sweep (M20) and record weapon names

android/PLAN.md M20: the app's core screens (connect, sign-in, errors,
notifications, the push channel) stop saying "shard"; the UO screens keep
their words. Strings split by owner into strings.xml / strings_uo.xml /
strings_rust.xml with a unit-test guard using runicgateway.com's word
list, and RustFeed prints Module-Rust's new weaponName. Lands in edge
before the release that first ships the Rust screens. Org lead's
decisions of 2026-10-23.

modules/rust/PLAN.md section 36: weapons by name in the feed
(Module-Rust#60) - weaponName added at read from a table of the game's
own names for 53 ranged weapons, stripped prefab name otherwise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-23 01:25:39 -05:00
parent 6eee51ce38
commit c3a0199e34
2 changed files with 100 additions and 0 deletions

View File

@@ -1639,6 +1639,83 @@ push, and Play (M6–M8) follow the designed app.
Excluded: the rules, the mode and group styles, which are all operator configuration.
21. **M20 — the app's words for every game** (post-v1; planned 2026-10-23, to land in `edge`
**before** the `edge` → `main` release that first ships the Rust screens). This is the app's
half of the vocabulary rule the website docs and runicgateway.com already follow
(runicgateway.com `PLAN.md` §16, D63/D64). Each game's words stay on that game's screens, and
the screens every deployment shows use core words. Found while capturing runicgateway.com's
phase 18 screenshots on the emulator: the first screen a Rust community's player sees says
*Connect to your shard*, and the next one says *Sign in with your shard account*. The org lead
took four decisions on 2026-10-23:
- **Core screens only.** The UO screens keep their words, as the site's game sections do:
the shard hub, guilds, champion spawns, governors, falling houses, the market, the shard's
ruleset, *My characters / vendors / houses*, their push streams, and staff moderation
through the shard. Code identifiers (`ui/shard`, `Shard*` classes, `shard_*` keys) are
**not** renamed: that would be a large diff with no visible change.
- **A guard**, so the words cannot creep back: a JVM unit test in the existing
`./gradlew test` step (see *The guard* below).
- **It lands before the release**, so the first build with Rust screens doesn't greet a Rust
community with a UO word.
- **Weapon names come from the module.** Module-Rust's events now carry `frame.weaponName`
(Module-Rust#60, `server/model/titles/weaponNames.js`): the game's own name for a ranged
weapon, or the prefab name as words. `RustFeed.kt` prints it, and against an older module
falls back to `prefabName()` with the `.entity` / `.weapon` ending dropped. So the app never
prints "with ak47u entity", as it does today.
**Measured on `edge` (2c8ab39):** 576 strings, every visible one in `res/values/strings.xml`
(no hard-coded Compose text). 60 of them carry a game word, and about 16 of those are on
screens any deployment shows:
| String | Today | Becomes (core words, as the site uses them) |
|---|---|---|
| `connect_title` | Connect to your shard | Connect to your community |
| `connect_subtitle` | Enter your shard's website address… | Enter your community's website address… |
| `connect_url_hint` | https://your-shard.example.com | https://your-community.example.com |
| `connect_error_not_runic` | That site isn't a Runic Gateway shard. | That site isn't a Runic Gateway site. |
| `login_subtitle` | Sign in with your shard account. | Sign in with your account on this site. |
| `error_shard_offline` | The shard is offline right now. | The game server is offline right now. |
| `error_feature_unavailable` | This shard doesn't publish this here. | This site doesn't publish this here. |
| `notifications_subtitle`, `_empty`, `_unsupported`, `_relay_error` | This shard… | This site… |
| `push_channel_messages`, `_desc`, `push_service_text` | Shard notifications… | Notifications from your community… |
The list is a starting point, not the verdict. **Each string is classified by the screens that
use it**, traced in code: a string any screen a Rust deployment can reach shows is core, even
if its key says `shard_`. Two need the trace before they move. `error_shard_offline` is the
shared "server down" text (`ApiResult` offline) that both games' screens use, so it is core.
`push_stream_server_status` ("Shard status changed") is core if the stream catalog offers it
for every module.
**The guard.** The strings are split by owner into three resource files that Android merges
as one: `values/strings.xml` (core), `values/strings_uo.xml` and `values/strings_rust.xml`.
No key changes, so no Kotlin changes. A unit test reads the three files and fails, naming the
key and the word, when:
- the core file holds either game's word;
- the UO file holds a Rust word;
- the Rust file holds a UO word.
The word list is runicgateway.com's `checkTerms.mjs` list: *shard, guild, IDOC, ServUO, …* for
UO; *clan, wipe, Oxide, Carbon, uMod, rust-link, …* for Rust. Its one allowlist entry
(Discord's *guild ID*) carries over only if the app ever shows it. Splitting by file rather
than by key prefix keeps the rule visible where a translator or a new screen adds a string,
and needs no prefix list to keep in step. The alternative, one file and a prefix allowlist,
is what the decision named; the split does the same job, so it is the plan unless review
objects.
**One PR into `edge`**, with the steps in this order:
1. The trace and the split, with no text changed, so the diff shows only moves.
2. The core rewording.
3. The guard test.
4. `weaponName` in `RustFeed.kt`, with a DTO test against an older module that sends none.
**Walked on the emulator** against both demo deployments before the PR: the UO one (rgdemo)
and the Rust one (rgdemorust). First run, sign-in, the drawer, notifications, and a server
down are checked on each.
Excluded: the website's own leftovers listed in website#221 (`PlayerInbox.jsx`, `Events.jsx`,
`PlayerNotifications.jsx`, `coreTriggers.js`, `templateSeeds.js`), which belong to `website/`,
not the app.
### Deferred (not a milestone)
- **Platform Teams in the app** — **deferred 2026-08-17, no app work scheduled.** The website is