fix(server): widen ModifierKindIdSchema to accept custom modifier ids
T3 audit gap 1 (BLOCKER). The server's ModifierKindIdSchema was still z.enum([built-ins]) even after the client-side mirror was widened during T29. Effect: any multiplayer room.create or modifier-profile.update carrying a profile whose perType[i].kind is a user-authored CustomModifierId (e.g. 'custom:shield') was rejected server-side as INVALID_MESSAGE. Symmetric fix: accept any non-empty string, defer kind validity to the engine's registry-dispatch fallback at apply time (MODIFIER_REGISTRY → engine.customModifiers → warn-and-skip). The built-in id list is preserved as a doc comment + void-referenced constant so it can't silently drift. Test updated: 'rejects a profile with unknown modifier kind' inverted to 'accepts a profile with arbitrary modifier kind (T3 widening)' + new 'rejects empty-string modifier kind' to preserve the min(1) guard.
This commit is contained in:
parent
6cddb1dcd0
commit
7cc9617f3e
2 changed files with 41 additions and 4 deletions
|
|
@ -681,12 +681,31 @@ describe("ModifierProfileSchema", () => {
|
|||
expect(r.success).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects a profile with unknown modifier kind", () => {
|
||||
it("accepts a profile with arbitrary modifier kind (T3 widening for custom ids)", () => {
|
||||
// Pre-T3 the wire enum rejected unknown kinds. The widening was
|
||||
// forced by user-authored CustomModifierIds (arbitrary strings like
|
||||
// "custom:shield"); kind validity is now enforced by the engine's
|
||||
// registry-dispatch fallback at apply time, not at the wire.
|
||||
const r = ModifierProfileSchema.safeParse({
|
||||
...validProfile,
|
||||
perType: [
|
||||
{
|
||||
kind: "teleport",
|
||||
kind: "custom:teleport",
|
||||
pieceType: "pawn",
|
||||
color: "white",
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(r.success).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects a profile with empty-string modifier kind", () => {
|
||||
const r = ModifierProfileSchema.safeParse({
|
||||
...validProfile,
|
||||
perType: [
|
||||
{
|
||||
kind: "",
|
||||
pieceType: "pawn",
|
||||
color: "white",
|
||||
value: 1,
|
||||
|
|
|
|||
|
|
@ -195,14 +195,32 @@ export type ResolvedLayout = z.infer<typeof ResolvedLayoutSchema>;
|
|||
// assertion below.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const ModifierKindIdSchema = z.enum([
|
||||
/**
|
||||
* Built-in modifier ids — documented here for reference; the actual
|
||||
* parse schema below accepts ANY non-empty string.
|
||||
*
|
||||
* T3 widens `kind` away from a literal enum because user-authored
|
||||
* custom modifier descriptors use arbitrary ids (e.g. "custom:shield").
|
||||
* Rejecting unknown kinds server-side would drop every profile that
|
||||
* references a custom descriptor, breaking multiplayer end-to-end.
|
||||
*
|
||||
* Validity of the kind is enforced ELSEWHERE: the chess engine's
|
||||
* apply pipeline looks the id up in MODIFIER_REGISTRY (built-ins)
|
||||
* then engine.customModifiers (user-authored). Unknown kinds are
|
||||
* warned and skipped — forwards-compat with a new built-in by
|
||||
* design.
|
||||
*/
|
||||
const BUILTIN_MODIFIER_KINDS = [
|
||||
"hp-bonus",
|
||||
"range-bonus",
|
||||
"direction-additions",
|
||||
"capture-flags",
|
||||
"promotion-override",
|
||||
"damage-resistance",
|
||||
]);
|
||||
] as const;
|
||||
void BUILTIN_MODIFIER_KINDS; // documentation anchor; server parse accepts any string
|
||||
|
||||
const ModifierKindIdSchema = z.string().min(1);
|
||||
|
||||
const ModifierColorExtSchema = z.enum(["white", "black", "both"]);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue