test: re-point core's suite at what core still owns
All checks were successful
PR Checks / bot-install (pull_request) Successful in 18s
PR Checks / client-build (pull_request) Successful in 27s
PR Checks / server-tests (pull_request) Successful in 29s

25 of 82 test files left with the module. Three that core keeps needed splitting
rather than moving, and the split is the boundary in each case.

announceJobs.test.js keeps the announce PIPELINE -- the shared backoff schedule,
the parent-status rollup, core's Discord leg -- and loses the town-crier text
building and classification, which are a module's leg. pushDispatch.test.js
keeps the SSRF guard and publish() delivering a content-free tickle, and loses
mapShardEvent and the shard fan-out, which are a module's catalog.

playerRouteAccess.test.js is the one worth explaining. It guards a real past bug
-- an admin 403'd off their own characters -- and it did so through
/player/shard/accounts, which is now module-owned. The guarantee it protects is
CORE's, though: /player/* is role-agnostic self-service, staff are a superset of
players. So it stays here and asserts that through /player/appeals, a core route
with the same gate. Moving it would have left core with no test of its own tier
rule, which is precisely what regressed once before.

The remaining updates are core's own tests catching up: ctx has four more
members, registerCore now registers only what core owns (one stream, one leg, no
filled slot), and the extension-slot test asks for the DECLARED slot's router
rather than the filled one, since core declares it and a module fills it. The
gated-surface floor drops from >100 to >50 -- it is there so a filter matching
nothing fails loudly, not to track core's exact route count.

616 core tests and 160 client tests pass; the module's own suite is 351.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-11 12:08:26 -05:00
committed by Claude
parent 39d731d87a
commit f5e6025dcc
6 changed files with 75 additions and 206 deletions

View File

@@ -6,11 +6,9 @@ process.env.DB_PORT = '59999'
const { test, after } = require('node:test')
const assert = require('node:assert/strict')
const { mapShardEvent, createTracker } = require('../src/config/shardStreams')
const pushDispatch = require('../src/utils/pushDispatch')
// fromShardEvent moved out of pushDispatch in PR 4: core publishes, the shard
// side resolves an event to a stream and an owner (MODULE_SYSTEM.md §1.8).
const shardPush = require('../src/utils/shardPush')
const db = require('../src/utils/db')
after(() => db.close())
@@ -33,71 +31,11 @@ function withEnv(vars, fn) {
}
}
// ── mapShardEvent ───────────────────────────────────────────────────────────
test('server.hello / shutdown / crashed map to the public server.status stream', () => {
const t = createTracker()
assert.deepEqual(mapShardEvent({ kind: 'server.hello', bootId: 'b1' }, t), [
{ streamId: 'server.status', ref: 'up:b1' },
])
assert.deepEqual(mapShardEvent({ kind: 'server.shutdown' }, t), [{ streamId: 'server.status', ref: 'down' }])
assert.deepEqual(mapShardEvent({ kind: 'server.crashed' }, t), [{ streamId: 'server.status', ref: 'down' }])
})
test('house.decay INTO idoc yields the public idoc.warning AND the owner-keyed house.idoc', () => {
const t = createTracker()
const out = mapShardEvent({ kind: 'house.decay', to: 'IDOC', serial: '0x40', ownerAcct: 'bob' }, t)
assert.deepEqual(out, [
{ streamId: 'idoc.warning', ref: '0x40' },
{ streamId: 'house.idoc', ref: '0x40', ownerAccount: 'bob' },
])
// A non-IDOC decay stage produces nothing.
assert.deepEqual(mapShardEvent({ kind: 'house.decay', to: 'Fairly', serial: '0x41' }, t), [])
})
test('champ.update fires champ.start only on the inactive→active transition', () => {
const t = createTracker()
// First sight active → start.
assert.deepEqual(mapShardEvent({ kind: 'champ.update', serial: 'c1', active: true }, t), [
{ streamId: 'champ.start', ref: 'c1' },
])
// Still active → no re-fire.
assert.deepEqual(mapShardEvent({ kind: 'champ.update', serial: 'c1', active: true }, t), [])
// Goes inactive, then active again → fires again.
assert.deepEqual(mapShardEvent({ kind: 'champ.update', serial: 'c1', active: false }, t), [])
assert.deepEqual(mapShardEvent({ kind: 'champ.update', serial: 'c1', active: true }, t), [
{ streamId: 'champ.start', ref: 'c1' },
])
})
test('city.update fires governor.election only on a real governor change, never on first sight', () => {
const t = createTracker()
// First sight of the city → no election (could be a reconnect snapshot).
assert.deepEqual(mapShardEvent({ kind: 'city.update', city: 'Britain', governor: { serial: '0x1' } }, t), [])
// Same governor → nothing.
assert.deepEqual(mapShardEvent({ kind: 'city.update', city: 'Britain', governor: { serial: '0x1' } }, t), [])
// New governor → election.
assert.deepEqual(mapShardEvent({ kind: 'city.update', city: 'Britain', governor: { serial: '0x2' } }, t), [
{ streamId: 'governor.election', ref: 'Britain' },
])
})
test('personal streams are owner-keyed and sensitive kinds never yield a public target', () => {
const t = createTracker()
const sale = mapShardEvent({ kind: 'vendor.sale', ownerAcct: 'bob', t: 7 }, t)
assert.deepEqual(sale, [{ streamId: 'vendor.sale', ref: '7', ownerAccount: 'bob' }])
const login = mapShardEvent({ kind: 'account.login.attempt', acct: 'bob', ip: '1.2.3.4', t: 9 }, t)
assert.deepEqual(login, [{ streamId: 'account.login', ref: '9', ownerAccount: 'bob' }])
// Every personal target carries an ownerAccount (never a bare public push).
for (const target of [...sale, ...login]) assert.ok(target.ownerAccount, 'personal target must be owner-keyed')
// A truly sensitive, unmapped kind produces nothing at all.
assert.deepEqual(mapShardEvent({ kind: 'cheat.fastwalk', acct: 'bob' }, t), [])
assert.deepEqual(mapShardEvent({ kind: 'admin.audit', actor: 'staff' }, t), [])
})
// `mapShardEvent` and `fromShardEvent` left with module-uo in Phase 3: which
// shard event becomes which stream is the module's catalog, not core's
// infrastructure. What stays here is what core owns — the SSRF guard on the
// configured ntfy endpoint, and `publish()` delivering a content-free tickle to
// the right subscribers.
// ── isAllowedEndpoint (SSRF guard) ──────────────────────────────────────────
test('isAllowedEndpoint pins the configured ntfy origin and rejects everything else', () => {
@@ -188,51 +126,3 @@ test('publish skips endpoints that fail the SSRF guard', async () => {
assert.equal(calls[0].url, 'https://relay.test/ok')
})
})
// ── fromShardEvent (owner resolution) ───────────────────────────────────────
test('fromShardEvent resolves a personal event to the owning user, or drops it if unlinked', async () => {
await withEnv({ NTFY_BASE_URL: undefined, NTFY_ALLOWED_ORIGINS: undefined }, async () => {
const { calls, fetchImpl } = captureFetch()
const userStreamCalls = []
const shardLinks = { getByAccount: async (acct) => (acct === 'mine' ? { userId: 42 } : null) }
const pushDevices = {
endpointsForStream: async () => [],
endpointsForUserStream: async (userId, s) => {
userStreamCalls.push([userId, s])
return [{ endpoint: 'https://relay.test/UPc' }]
},
}
const deps = { shardLinks, pushDevices, fetchImpl, tracker: createTracker() }
await shardPush.fromShardEvent({ kind: 'vendor.sale', ownerAcct: 'mine', t: 1 }, deps)
assert.deepEqual(userStreamCalls, [[42, 'vendor.sale']])
assert.equal(calls.length, 1)
// Unlinked account → nobody to notify → no publish.
userStreamCalls.length = 0
calls.length = 0
await shardPush.fromShardEvent({ kind: 'vendor.sale', ownerAcct: 'stranger', t: 2 }, deps)
assert.equal(userStreamCalls.length, 0)
assert.equal(calls.length, 0)
})
})
test('fromShardEvent fans a public shard event to the streams subscribers', async () => {
await withEnv({ NTFY_BASE_URL: undefined, NTFY_ALLOWED_ORIGINS: undefined }, async () => {
const { fetchImpl } = captureFetch()
const publicCalls = []
const pushDevices = {
endpointsForStream: async (s) => {
publicCalls.push(s)
return []
},
endpointsForUserStream: async () => [],
}
await shardPush.fromShardEvent(
{ kind: 'server.hello', bootId: 'b1' },
{ pushDevices, fetchImpl, tracker: createTracker() },
)
assert.deepEqual(publicCalls, ['server.status'])
})
})