feat: declare rust as the module's identity capability (phase 5, D16) #5

Merged
whitlocktech merged 1 commits from feat/phase-5-capability into edge 2026-09-17 09:22:14 +00:00
Member

The one thing phase 5 needs from this repo, ahead of the Android leg itself.

Why a sixth capability

The Android app gates a whole navigation group on one capability string — module-uo's five shard rows all hang on shard, because that is the only question a capability can answer: is the module there. This module declared five strings and every one of them names a surface (servers, killfeed, leaderboard, presence, wipes).

That is not enough to gate on. Core flattens every started module's capabilities into a single list, so servers is a generic word another module could declare tomorrow — and the app would silently render Rust screens on a site that does not run Rust.

rust is the string only this module can mean.

Why it is not redundant with id

Worth writing down before somebody tidies it away, so the README now does:

  • id is a mount prefix. §2.1 requires it to equal the directory core loads the module from.
  • MODULE_API.md §2.9 forbids a client inferring a route from a capability. Gating on id would quietly make the two the same thing, and the day a client builds /<id>/servers from it, the contract that lets this module move its own pages is gone.

What is in the diff

  • module.jsonrust first in capabilities.
  • server/test/entry.test.js — a test asserting the identity capability is declared and equals manifest.id, so a future id change cannot strand the string the app gates on.
  • README.md — a short "What a client feature-detects on" section under What ships today.

No route changes, so no swagger regeneration and no frozen-manifest churn. 102 server tests pass.

Note on the base branch

This targets edge, not main. The org lead moved all three Rust repos onto edge for the rest of the workstream (2026-09-16); pr-checks.yml here already triggers on [main, edge], and release.yml still fires only on a push to main, so releases come at the cutover rather than per phase.

AI disclosure

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

🤖 Generated with Claude Code

https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4

The one thing phase 5 needs from this repo, ahead of the Android leg itself. ## Why a sixth capability The Android app gates a whole navigation group on **one** capability string — `module-uo`'s five shard rows all hang on `shard`, because that is the only question a capability can answer: *is the module there*. This module declared five strings and every one of them names a **surface** (`servers`, `killfeed`, `leaderboard`, `presence`, `wipes`). That is not enough to gate on. Core flattens every started module's capabilities into a single list, so `servers` is a generic word another module could declare tomorrow — and the app would silently render Rust screens on a site that does not run Rust. `rust` is the string only this module can mean. ## Why it is not redundant with `id` Worth writing down before somebody tidies it away, so the README now does: - **`id` is a mount prefix.** §2.1 requires it to equal the directory core loads the module from. - **`MODULE_API.md` §2.9 forbids a client inferring a route from a capability.** Gating on `id` would quietly make the two the same thing, and the day a client builds `/<id>/servers` from it, the contract that lets this module move its own pages is gone. ## What is in the diff - `module.json` — `rust` first in `capabilities`. - `server/test/entry.test.js` — a test asserting the identity capability is declared **and equals `manifest.id`**, so a future id change cannot strand the string the app gates on. - `README.md` — a short "What a client feature-detects on" section under *What ships today*. No route changes, so no swagger regeneration and no frozen-manifest churn. 102 server tests pass. ## Note on the base branch This targets **`edge`**, not `main`. The org lead moved all three Rust repos onto `edge` for the rest of the workstream (2026-09-16); `pr-checks.yml` here already triggers on `[main, edge]`, and `release.yml` still fires only on a push to `main`, so releases come at the cutover rather than per phase. ## 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-17 02:55:59 +00:00
feat: declare rust as the module's identity capability
All checks were successful
PR Checks / server-tests (pull_request) Successful in 14s
PR Checks / client-build (pull_request) Successful in 14s
PR Checks / frozen-manifest (pull_request) Successful in -1m4s
8df850f73e
Phase 5 is the Android app's leg of this module's read path (R10), and it
gates its Rust navigation on one capability string the way `module-uo`'s five
shard rows gate on `shard`. There was no such string here: the five this module
declared all name a SURFACE, and core flattens every started module's
capabilities into one list, so `servers` is a word another module could declare
tomorrow and silently reveal these screens on a site that does not run Rust.

`rust` is the string only this module can mean. It is asserted against
`module.json`'s own `id` rather than a literal, so the two cannot drift.

The README says why it is not redundant with `id`: `id` is a mount prefix, and
MODULE_API.md §2.9 forbids a client inferring a route from a capability. Gating
on `id` would quietly make those the same thing.

Decided by the org lead as D16, 2026-09-16.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
whitlocktech merged commit 28e46771b1 into edge 2026-09-17 09:22:14 +00:00
whitlocktech deleted branch feat/phase-5-capability 2026-09-17 09:22:15 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Module-Rust#5
No description provided.