@@ -42,22 +42,56 @@ dependency is `gopkg.in/yaml.v2`, which the GoMud engine itself uses.
4242- ** arch_test.go** : purity guardrail — fails if any file imports a
4343 ` GoMudEngine/GoMud/internal ` path.
4444- ** moduledata_test.go** : validates the SHIPPED YAML files under
45- ` files/datafiles/ ` . For emote tables: parseable, ` filename == weather+".yaml" ` ,
46- at least one outdoor-default and one indoor-default line. For mutator specs:
47- parseable, ` mutatorid ` is ** ` weather- ` or ` season- ` ** namespaced (both
48- namespaces validated under the same rules), filename matches
49- ` fileNameFor(mutatorid) ` (mirrors ` util.ConvertForFilename ` ), ` respawnrate `
50- forbidden (would fight the orchestrator), ` decayintoid ` forbidden (upstream
51- ` MutatorList.Remove ` resets ` SpawnedRound ` and runs ` Update ` whose decay
52- branch has no liveness guard — the decay target is instantly resurrected),
53- ` decayrate ` required (self-heal safety net). A count assertion requires at
54- least ** 14** shipped mutator specs (8 weather + 6 season) so a sync/copy
55- mistake is loud. For emote tables it also validates ` seasonal: ` variant keys
56- (each must be a season of a shipped track and carry at least one line), and a
57- separate check (` TestShippedSeasonalAmbience ` ) loads ` emotes/seasons/ ` ,
58- asserts the six (track, season) ambience tables are present with outdoor +
59- indoor default lines, and that each file obeys the ` <track>_<season>.yaml `
60- filename rule.
45+ ` files/datafiles/ ` . Helpers: ` fileNameFor ` mirrors the engine's
46+ ` util.ConvertForFilename ` ** byte-exactly** (lowercase, drop ` ' ` , keep
47+ ` [a-z0-9] ` , everything else → ` _ ` ; byte-level, so names must stay ASCII) —
48+ used for both mutator and buff filename checks; ` knownBiomes() ` is the
49+ canonical biome-key set — the keys of ` sim.DefaultClimate() ` plus
50+ ` "default" ` — and ` checkBiomeKeys ` fails any emote-table biome key outside
51+ it (a key no room ever reports is unreachable prose) or with zero lines.
52+ - ** Emote tables** (` TestShippedEmoteTables ` ): parseable,
53+ ` filename == weather+".yaml" ` , at least one outdoor-default and one
54+ indoor-default line, every biome key (base sections AND inside ` seasonal: `
55+ blocks) validated via ` checkBiomeKeys ` , and ` seasonal: ` variant keys must
56+ each be a season of a shipped track and carry at least one line. A separate
57+ check (` TestShippedSeasonalAmbience ` ) loads ` emotes/seasons/ ` , asserts the
58+ six (track, season) ambience tables are present with outdoor + indoor
59+ default lines (biome keys validated too), and that each file obeys the
60+ ` <track>_<season>.yaml ` filename rule.
61+ - ** Mutator specs** (` TestShippedMutatorSpecs ` ): parseable, ` mutatorid ` is
62+ ** ` weather- ` or ` season- ` ** namespaced (both namespaces validated under the
63+ same rules), filename matches ` fileNameFor(mutatorid) ` , ` respawnrate `
64+ forbidden (would fight the orchestrator), ` decayintoid ` forbidden (upstream
65+ ` MutatorList.Remove ` resets ` SpawnedRound ` and runs ` Update ` whose decay
66+ branch has no liveness guard — the decay target is instantly resurrected),
67+ ` decayrate ` required (self-heal safety net — it is also what lazily heals
68+ stale per-room mutators). ** Indoor-variant rules (M4)** : every outdoor
69+ ` weather-<type> ` must have a ` weather-<type>-indoor ` twin (pairing
70+ completeness — a 9th type can't ship half-finished), and indoor variants
71+ are sheltered by construction: ` lightmod ` , ` playerbuffids ` , ` mobbuffids ` ,
72+ and ` alertmodifier ` are all forbidden on them. A ** bidirectional type-list
73+ drift guard** requires the shipped outdoor ` weather-<type> ` id set to equal
74+ ` sim.KnownWeatherTypes ` minus ` clear ` — shipped-but-unlisted and
75+ listed-but-unshipped both fail (the list is what ` BuffOverrides.<type> `
76+ config enumeration keys off). A count assertion requires at least ** 22**
77+ shipped mutator specs (8 weather + 8 indoor + 6 season) so a sync/copy
78+ mistake is loud.
79+ - ** Buff specs** (` TestShippedBuffSpecs ` , M4): validates
80+ ` files/datafiles/buffs/ ` against what the engine's plugin buff loader
81+ (` internal/buffs/plugin.go ` ) will accept — parseable under
82+ ` yaml.UnmarshalStrict ` against the full engine ` BuffSpec ` schema (typos in
83+ field names fail), ids inside the module's documented ** 59001–59099**
84+ range with no duplicates, filename exactly the engine's computed
85+ ` <BuffId>-<ConvertForFilename(Name)>.yaml ` (via ` fileNameFor ` ; the loader
86+ rejects any other name), a player-visible description, ` triggerrate ` set
87+ and ` triggercount ` in 1..5 (the mutator re-applies every round the weather
88+ holds, so a short count means the buff fades shortly after shelter), and
89+ the ** gentleness policy** : every statmod must be in [ -10, 0] — a small
90+ penalty or zero; no damage, no scripts, no bonuses (a positive mod is
91+ rejected as a design change needing explicit review). A ** cross-check** then walks every shipped
92+ mutator spec: each ` playerbuffids ` entry must be one of the shipped buffs
93+ (no borrowing engine ids like 31/33, which vary by world and are harsher
94+ than weather warrants). At least 3 buff specs must ship.
6195- ** doc.go** : package-level comment.
6296
6397### Key Types
0 commit comments