fix(teams): say "game server", not "shard", on the never-synced Teams panel
All checks were successful
PR Checks / bot-tests (pull_request) Successful in 39s
PR Checks / client-build (pull_request) Successful in 58s
PR Checks / server-tests (pull_request) Successful in 12m43s

Admin → Teams told an operator that an unsynced projection "is not a
confirmed empty shard". Teams is a core primitive and core's word for the
host is the game server; "shard" is Ultima Online's. The detail now reads
"What is shown below does not confirm that the game server has no Teams."

The matching test, and the four comments that said "shard" about the same
state, follow it. Found while making runicgateway.com's core docs
game-neutral (runicgateway.com#34), which had to paraphrase this line
rather than quote it.

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-22 14:43:37 -05:00
parent 6890a74c7c
commit 8012a457fc
6 changed files with 9 additions and 9 deletions

View File

@@ -41,7 +41,7 @@ export function relativeTime(when, now = Date.now()) {
* Distinct from `teamAdmin.freshnessOf`, which is worded for an operator
* debugging a sync. A visitor needs one sentence about whether what they are
* looking at is current, and specifically must never be shown an unconfirmed
* empty projection as though it were a confirmed empty shard.
* empty projection as though it were a confirmed empty one.
*/
export function freshnessNote(sync = {}, now = Date.now()) {
// Nothing supplies Teams here, so there is nothing to be stale ABOUT. A
@@ -57,7 +57,7 @@ export function freshnessNote(sync = {}, now = Date.now()) {
* Group feed items into days, newest first, preserving order within a day (§4.3).
*
* Keyed by local calendar date rather than by a UTC slice: "yesterday" is a
* property of where the reader is sitting, and a shard's evening raid landing at
* property of where the reader is sitting, and a game server's evening raid landing at
* 00:30 UTC belongs on the day the players experienced it.
*/
export function groupByDay(items = [], locale = undefined) {

View File

@@ -3,7 +3,7 @@
//
// Plain JS with tests, following lib/moduleAdmin.js. The reason it is worth
// splitting here specifically: this screen's job is to tell an operator the
// difference between "the shard has no Teams" and "core has not been able to ask
// difference between "the game server has no Teams" and "core has not been able to ask
// for two hours", and those two produce almost the same page. Getting that
// wording right is logic, not markup.
@@ -31,7 +31,7 @@ export function freshnessOf(sync = {}) {
return {
tone: TONE.bad,
label: 'Never synced',
detail: 'Core has never had an answer it could trust. What is shown below is not a confirmed empty shard.',
detail: 'Core has never had an answer it could trust. What is shown below does not confirm that the game server has no Teams.',
}
}
if (sync.stale) {

View File

@@ -14,7 +14,7 @@ import TeamVoice from './TeamVoice.jsx'
// Three panels, in the order an operator needs them:
//
// 1. **Sync state**, verbatim, including the last error. The screen's first job
// is to make "the shard has no Teams" and "core has not been able to ask for
// is to make "the game server has no Teams" and "core has not been able to ask for
// two hours" impossible to confuse — they render almost identically
// otherwise, and one is fine while the other is an outage.
// 2. **The review queue** — Teams auto-hidden because their name matched the

View File

@@ -19,7 +19,7 @@ test('a deployment with no provider is not stale, it is uninvolved', () => {
assert.equal(freshnessNote({ configured: false }, NOW), null)
})
test('never synced is a warning, and never reads as a confirmed empty shard', () => {
test('never synced is a warning, and never reads as a confirmed empty roster', () => {
const note = freshnessNote({ configured: true, lastSyncAt: null }, NOW)
assert.equal(note.tone, 'warn')
assert.match(note.text, /Not yet confirmed/)

View File

@@ -21,13 +21,13 @@ test('no provider is idle, not a fault', () => {
assert.match(f.label, /No Team provider/)
})
test('never synced is reported as never synced, not as an empty shard', () => {
test('never synced is reported as never synced, not as a game server with no Teams', () => {
// The failure this prevents: an empty projection core has never confirmed,
// rendered as though the game genuinely has no Teams.
const f = freshnessOf({ configured: true, lastSyncAt: null })
assert.equal(f.tone, TONE.bad)
assert.equal(f.label, 'Never synced')
assert.match(f.detail, /not a confirmed empty shard/)
assert.match(f.detail, /does not confirm that the game server has no Teams/)
})
test('stale says how old it is', () => {

View File

@@ -135,7 +135,7 @@ async function syncStatus() {
configured: true,
lastSyncAt,
// Never synced at all is stale: a page must not present an empty projection
// as a confirmed empty shard.
// as a confirmed empty one.
stale: ageS > intervalS * STALE_INTERVALS,
consecutiveFailures: state ? state.consecutive_failures : 0,
}