docs(teams): use the correct presentation of the project name, and match both forms #152

Merged
whitlocktech merged 1 commits from docs/teams-name-presentation into main 2026-08-17 10:07:24 +00:00
Showing only changes of commit 6f8b722acf - Show all commits

View File

@@ -466,7 +466,7 @@ Two reads, OR'd. `viaGrant` is reported **even when membership also holds** —
coexist; the UI presents membership as the current reason while the grant is kept as audit history" coexist; the UI presents membership as the current reason while the grant is kept as audit history"
requirement, and it falls out of not collapsing the two booleans into one. requirement, and it falls out of not collapsing the two booleans into one.
- A grant may name **any** RunicGateway account, including one with no linked game identity of any - A grant may name **any** Runic Gateway account, including one with no linked game identity of any
kind. That is the point: letting an unlinked guildmate into the forum must not be a staff ticket. kind. That is the point: letting an unlinked guildmate into the forum must not be a staff ticket.
- Granting **never** writes `team_members`. Revoking never writes `team_members`. A test asserts a - Granting **never** writes `team_members`. Revoking never writes `team_members`. A test asserts a
byte-identical `team_members` row set across a grant/revoke cycle. byte-identical `team_members` row set across a grant/revoke cycle.
@@ -505,7 +505,7 @@ Four hops, three of them stored in different places, and the design's most commo
confusion — "this account is linked" answers only *one* of them. confusion — "this account is linked" answers only *one* of them.
``` ```
RunicGateway account users.id Runic Gateway account users.id
│ hop 1: linked GAME identity module-owned: shard_account_links(account → user_id) │ hop 1: linked GAME identity module-owned: shard_account_links(account → user_id)
game account / character team_members.member_key, team_members.user_id game account / character team_members.member_key, team_members.user_id
@@ -569,6 +569,16 @@ runtime configuration):
| The project | `Runic Gateway` — impersonating the software project is as much a problem as impersonating the operator | | The project | `Runic Gateway` — impersonating the software project is as much a problem as impersonating the operator |
| Operator additions | a `teams_reserved_terms` setting, comma-separated, for anything a particular community needs | | Operator additions | a `teams_reserved_terms` setting, comma-separated, for anything a particular community needs |
> **The project's name has two legitimate presentations, and both must match.** **Runic Gateway** (two
> words) is the correct form; **RunicGateway** is accepted only where the name has to condense to a
> single token — the Gitea org, a package name, a URL segment. A reserved term is therefore stored in
> its correct two-word form and matched against *both*, which §2.8.2's whitespace-insensitive
> comparison gives for free. Listing the condensed form as a separate term would be a second thing to
> keep in sync, and it would still miss `runic-gateway` and `Runic_Gateway`.
>
> The same applies to a deployment's own brand: `BRAND_NAME` is free text and an operator may well
> have set a spaced name whose condensed form is what a would-be impersonator types.
**Not `filter_words`.** That table exists but is **bot-owned** (its own pool, `bot/src/model/`, **Not `filter_words`.** That table exists but is **bot-owned** (its own pool, `bot/src/model/`,
never read by the website — `MODERATION_APPEALS.md` §2 is explicit that the two sides share no live never read by the website — `MODERATION_APPEALS.md` §2 is explicit that the two sides share no live
FK) and it is a profanity filter, which is a different question with a different answer. Reusing it FK) and it is a profanity filter, which is a different question with a different answer. Reusing it
@@ -587,6 +597,18 @@ Normalisation: case-fold, strip punctuation and repeated characters, collapse wh
**no leet-speak folding** in v1 (`4dm1n`) — it multiplies false positives, and the consequence of a **no leet-speak folding** in v1 (`4dm1n`) — it multiplies false positives, and the consequence of a
miss is a hidden-by-a-human Team rather than a breach. miss is a hidden-by-a-human Team rather than a breach.
**A multi-word term is additionally compared with whitespace removed on both sides**, so a term stored
as `Runic Gateway` matches `RunicGateway`, `runic-gateway`, `Runic_Gateway` and `RUNIC GATEWAY`
alike. Without this the whole-word rule fails on exactly the case that matters: `RunicGateway` is a
*single* word and would never match a two-word term, so the condensed form — the one an impersonator
would reach for, because it is what the Gitea org and every URL already use — would sail straight
through.
That widening applies **only to terms containing whitespace**, which keeps it away from the
single-word terms where whole-word matching is doing the false-positive work: `admin` is still
compared as a word and still does not fire on "Badminton". A two-word term is specific enough that
running the letters together cannot collide with ordinary vocabulary.
#### 2.8.3 What a match does: hide, never reject #### 2.8.3 What a match does: hide, never reject
A Team whose name trips the list is created **normally** and then **auto-hidden**: `hidden = 1`, A Team whose name trips the list is created **normally** and then **auto-hidden**: `hidden = 1`,
@@ -1175,7 +1197,7 @@ setting is, the second appears only at the moment of change and is what the ackn
> - Complying with applicable laws and regulations > - Complying with applicable laws and regulations
> - Establishing policies for your community > - Establishing policies for your community
> >
> RunicGateway does not provide hosted storage or content moderation services. All uploaded content > Runic Gateway does not provide hosted storage or content moderation services. All uploaded content
> is stored on your own infrastructure. > is stored on your own infrastructure.
**(b) Confirmation dialog** — shown only when changing the mode *to* `uploads`: **(b) Confirmation dialog** — shown only when changing the mode *to* `uploads`: