Skip to content

fix(schema): add minProperties guard + finite numeric maximums (P3 schema hardening) - #3

Merged
yshengliao merged 1 commit into
mainfrom
fix/schema-min-max-hardening
Jun 13, 2026
Merged

fix(schema): add minProperties guard + finite numeric maximums (P3 schema hardening)#3
yshengliao merged 1 commit into
mainfrom
fix/schema-min-max-hardening

Conversation

@yshengliao

Copy link
Copy Markdown
Member

Summary

Closes the P3 "Schema hardening" open item from REVIEW.md.

  • animations must be non-empty — the compiler now rejects animations: {} with InvalidGraphError("animations must declare at least one animation"), mirroring minProperties: 1 already in the JSON Schema file.
  • Finite maximums for duration fieldsdefaultFrameDuration and per-frame duration are capped at MAX_DURATION = 86_400_000 ms (24 hours). Values above this are rejected with InvalidGraphError.
  • Finite maximum for speed — state speed multiplier is capped at MAX_SPEED = 1_000. Values above this are rejected with InvalidGraphError.
  • JSON Schema updatedduration (frames), defaultFrameDuration, and state speed gain matching maximum constraints so editors and CI validators agree with the runtime.

Rationale for chosen bounds

Field Maximum Rationale
duration / defaultFrameDuration 86 400 000 ms (24 h) Eliminates accidental huge values (e.g. copy-paste of a Unix timestamp). No real animation frame should last a full day.
speed 1 000 A 1000× multiplier already compresses a 100 ms frame to 0.1 ms; anything higher is indistinguishable from zero-duration.

Non-finite values (Infinity, NaN) were already rejected by the existing guard — these new maximums close the gap for finite-but-absurd values.

RED → GREEN evidence

4 tests were added first (RED), then the runtime and schema were fixed (GREEN).

RED run (before fix):

  • rejects an empty animations map with 'at least one animation' message — FAIL (wrong error message)
  • rejects a frame duration above the 24-hour ceiling — FAIL (did not throw)
  • rejects defaultFrameDuration above the 24-hour ceiling — FAIL (did not throw)
  • rejects a state speed above 1000× — FAIL (did not throw)

GREEN run (after fix): 140/140 tests pass.

Test plan

  • pnpm test — 140 tests, all green
  • pnpm prepublishOnly — typecheck, lint, coverage 100%, build, verify:dist/exports/llms, check:size all pass
  • Schema: aispritejs/schema subpath exports the updated JSON Schema with minProperties:1, maximum:86400000, maximum:1000

Notes for leader

  • No version bump, no CHANGELOG edit (leader owns release).
  • Public API unchanged — this only tightens validation.
  • STABILITY.md and README.md already note that schema hardening improves editor feedback without replacing runtime validation. The new bounds are consistent with that framing; no release-doc edits needed beyond what the leader decides to add at release time.
  • llms-full.txt verified up-to-date (verify:llms passed).

🤖 Generated with Claude Code

Runtime now rejects:
- animations map with zero entries (InvalidGraphError: "animations must
  declare at least one animation") — mirrors the existing minProperties:1
  already present in the JSON Schema file but previously absent from the
  compiler.
- frame duration or defaultFrameDuration above MAX_DURATION (86 400 000 ms,
  i.e. 24 hours) — eliminates accidental giant values that would make a
  single-frame clip play for a day.
- state speed multiplier above MAX_SPEED (1 000 ×) — mirrors the > 0
  lower-bound guard already present.

JSON Schema updated to match: duration and defaultFrameDuration gain
maximum: 86400000; speed gains maximum: 1000. The animations block already
carried minProperties: 1.

8 new tests added (4 RED → GREEN). All 140 tests green; prepublishOnly passes
(typecheck, lint, coverage 100 %, build, verify:dist/exports/llms, check:size).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yshengliao
yshengliao marked this pull request as ready for review June 13, 2026 16:28
Copilot AI review requested due to automatic review settings June 13, 2026 16:28
@yshengliao
yshengliao merged commit 572f2de into main Jun 13, 2026
2 checks passed
@yshengliao
yshengliao deleted the fix/schema-min-max-hardening branch June 13, 2026 16:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens SpriteGraph validation to better align runtime checks with the published JSON Schema, preventing empty animations maps and rejecting finite-but-absurd numeric values for durations and state speed.

Changes:

  • Add runtime guard rejecting animations: {} with a dedicated InvalidGraphError message.
  • Enforce maximum allowed values for defaultFrameDuration, per-frame duration, and state speed in the compiler.
  • Update the JSON Schema to add matching maximum constraints, plus add tests covering these bounds.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
test/validation.test.ts Adds tests asserting rejection/acceptance at the new MAX_DURATION and MAX_SPEED ceilings and the new empty-animations error message.
src/sprite/compile.ts Adds compiler-time validation for non-empty animations and maximum caps for durations and speed.
schemas/aispritejs-graph.schema.json Adds maximum constraints for frames.*.duration, defaultFrameDuration, and states.*.speed to match runtime validation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/sprite/compile.ts
Comment on lines 56 to +60
export function compileGraph(graph: SpriteGraph): CompiledGraph {
if (Object.keys(graph.animations).length === 0) {
throw new InvalidGraphError("animations must declare at least one animation");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants