fix(rust): lowercase the reward option-source ids, and test the grammar
The first boot against real core refused the whole module at register: `rust.options.runZones` fails core's EVENT_ID grammar, which is lowercase dotted segments only. The fake api validates none of it, so 310 green tests said nothing. The four fixed-choice sources and the chat-server source are renamed, and entry.test now holds every action, budget, lease and option-source id against a copy of the grammar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -293,11 +293,11 @@ const participationOpen = {
|
||||
params: [
|
||||
{ name: 'server', type: 'string', required: true, example: 'main', source: 'rust.options.servers',
|
||||
description: 'Which server counts.' },
|
||||
{ name: 'zone', type: 'string', required: false, example: 'Airfield brawl', source: 'rust.options.runZones',
|
||||
{ name: 'zone', type: 'string', required: false, example: 'Airfield brawl', source: 'rust.options.runzones',
|
||||
description: 'The name an earlier "Open a zone" step of this run gave its zone. Left blank, the whole server counts (D100).' },
|
||||
{ name: 'score', type: 'string', required: true, example: 'both', source: 'rust.options.scoreModes',
|
||||
{ name: 'score', type: 'string', required: true, example: 'both', source: 'rust.options.scoremodes',
|
||||
description: 'What earns a place: seconds present, kills, or both.' },
|
||||
{ name: 'killsOf', type: 'string', required: false, example: 'npcs', source: 'rust.options.killsOf',
|
||||
{ name: 'killsOf', type: 'string', required: false, example: 'npcs', source: 'rust.options.killsof',
|
||||
description: 'Whose deaths count as a kill: players, NPCs (animals included), or both. The last hit gets it. Needed unless the score is seconds.' },
|
||||
{ name: 'killWeight', type: 'float', required: false, example: DEFAULT_KILL_WEIGHT,
|
||||
description: `For a score of both: how many minutes one kill is worth. Left blank, ${DEFAULT_KILL_WEIGHT}.` },
|
||||
@@ -477,7 +477,7 @@ const kitEntitle = {
|
||||
params: [
|
||||
{ name: 'kit', type: 'string', required: true, example: 'main/vip-starter', source: 'rust.options.kits',
|
||||
description: 'The kit, as server/kit. The reward reaches only that server (D102).' },
|
||||
{ name: 'recipients', type: 'string', required: true, example: 'top', source: 'rust.options.recipientModes',
|
||||
{ name: 'recipients', type: 'string', required: true, example: 'top', source: 'rust.options.recipientmodes',
|
||||
description: 'Who gets it: everyone who scored, the top N, a score of at least X, N drawn at random, or the top X per cent.' },
|
||||
{ name: 'count', type: 'float', required: false, example: 3,
|
||||
description: 'N for top and random, X for a minimum score, the percentage for top per cent. Not used for everyone.' },
|
||||
@@ -641,7 +641,7 @@ const announce = {
|
||||
version: 1,
|
||||
budgetMs: BUDGET_MS,
|
||||
params: [
|
||||
{ name: 'server', type: 'string', required: true, example: 'main', source: 'rust.options.chatServers',
|
||||
{ name: 'server', type: 'string', required: true, example: 'main', source: 'rust.options.chatservers',
|
||||
description: 'Which server, or * for every server (D105).' },
|
||||
{ name: 'message', type: 'string', required: true, example: 'The airfield brawl starts in five minutes!',
|
||||
description: `The line, up to ${MAX_CHAT} characters.` },
|
||||
@@ -805,18 +805,18 @@ const OPTION_SOURCES = [
|
||||
// Free text: the zones a run will open do not exist when it is authored, and
|
||||
// the name is checked when the step runs (D100). Declared so the field is
|
||||
// documented rather than a bare box, and answers nothing.
|
||||
fixed('rust.options.runZones', 'Zones this run opens', 'The name an earlier "Open a zone" step of the same run gave its zone. Type it; it is checked when the step runs.', []),
|
||||
fixed('rust.options.scoreModes', 'Score', 'What earns a place in a tally.', [
|
||||
fixed('rust.options.runzones', 'Zones this run opens', 'The name an earlier "Open a zone" step of the same run gave its zone. Type it; it is checked when the step runs.', []),
|
||||
fixed('rust.options.scoremodes', 'Score', 'What earns a place in a tally.', [
|
||||
{ value: 'seconds', label: 'Seconds present' },
|
||||
{ value: 'kills', label: 'Kills' },
|
||||
{ value: 'both', label: 'Both — minutes plus a weight per kill' },
|
||||
]),
|
||||
fixed('rust.options.killsOf', 'Kills of', 'Whose deaths count as a kill.', [
|
||||
fixed('rust.options.killsof', 'Kills of', 'Whose deaths count as a kill.', [
|
||||
{ value: 'players', label: 'Players' },
|
||||
{ value: 'npcs', label: 'NPCs, animals included' },
|
||||
{ value: 'both', label: 'Players and NPCs' },
|
||||
]),
|
||||
fixed('rust.options.recipientModes', 'Recipients', 'Who a reward goes to (D101).', [
|
||||
fixed('rust.options.recipientmodes', 'Recipients', 'Who a reward goes to (D101).', [
|
||||
{ value: 'everyone', label: 'Everyone who scored' },
|
||||
{ value: 'top', label: 'The top N (ties in)' },
|
||||
{ value: 'minScore', label: 'A score of at least X' },
|
||||
@@ -824,7 +824,7 @@ const OPTION_SOURCES = [
|
||||
{ value: 'topPercent', label: 'The top X per cent (ties in)' },
|
||||
]),
|
||||
{
|
||||
id: 'rust.options.chatServers',
|
||||
id: 'rust.options.chatservers',
|
||||
label: 'Chat servers',
|
||||
description: 'Every enabled server, or * for all of them.',
|
||||
async resolve() {
|
||||
|
||||
@@ -203,6 +203,24 @@ test('the event verbs are registered, and every budget has a verb that spends it
|
||||
}
|
||||
})
|
||||
|
||||
test('every event id is one the core grammar accepts (phase 13b)', () => {
|
||||
const { api } = register()
|
||||
|
||||
// Core's EVENT_ID (modules/registries.js), copied rather than imported: this
|
||||
// module cannot reach core's tree. The fake api validates none of it, and
|
||||
// phase 13b's first boot against real core refused the WHOLE module over one
|
||||
// camelCase source id (`rust.options.runZones`). Lowercase dotted segments only.
|
||||
const EVENT_ID = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/
|
||||
const ids = [
|
||||
...api.record.eventActions.map((a) => a.id),
|
||||
...api.record.eventBudgets.map((b) => b.id),
|
||||
...api.record.eventOptionSources.map((s) => s.id),
|
||||
...api.record.eventLeases.map((l) => l.id),
|
||||
]
|
||||
for (const a of api.record.eventActions) for (const p of a.params) if (p.source) ids.push(p.source)
|
||||
for (const id of ids) assert.match(id, EVENT_ID, id)
|
||||
})
|
||||
|
||||
test('the leases and their option sources are registered, every source a lease reads (phase 12)', () => {
|
||||
const { api } = register()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user