clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

main
miau-is-true / openspec / changes / archive / 2026-09-24-validate-mod-feature-contract / design.md
design.md 5.8K rendered
1## Context23The engine treats core properties and each level's `automata[].property` as semantic predicates. Every other predicate becomes a noun transform. The loader validates token syntax but has no author warning for a property typo, allows an object noun to equal a custom property, and preserves unknown `manifest.features` silently. Local CommonJS and data-only shared packs both use `validateMod`; pack-service previews currently expose only errors.45Clockwork needs diagnostics without changing turn semantics. Existing `#pack` v1 links and the shipped automata example omit feature declarations, so the new host must continue accepting them.67## Goals / Non-Goals89**Goals:**1011- Distinguish unsupported property intent from a legitimate noun transform, even before a loose word forms a sentence.12- Reject known semantic property/noun collisions and unknown required features before a pack is installed.13- Return bounded nonfatal warnings in the same preview envelope for local and shared packs.14- Preserve existing v1 links, authored automata data, and the `manifest.engine: 1` contract.1516**Non-Goals:**1718- Executing custom property callbacks, `pairs`, or any new engine effect.19- Predicting every future sentence or blocking legal noun transformations.20- Treating a presentation glossary alone as proof that the engine implements a property.21- A visual layout decision for Gift/Workshop; that remains with design.2223## Decisions2425### Use one normalized diagnostic pass after validation2627Keep `validateMod()` as the existing error-array API. Add a pure diagnostic function that takes validated, normalized pack data and returns a bounded list of warning records with rule/word source context. It uses the engine's rule parser for authored horizontal, vertical, stacked, and `AND` sentences so the warning logic does not invent a second grammar. Warnings are nonfatal because a new noun transform is legal.2829The diagnostic scans **every authored word tile**, including loose words. Its known noun set contains placed object nouns and that level's automata subjects, plus nouns in the pack palette or vocabulary. This recognizes intentional future transformation targets such as Word Lab's `ROCK IS GEM`. An object in another proof alone does not make a word known here. The semantic property set is core properties plus implemented declarations in this level. If a word names a property implemented elsewhere in the pack but not here, the note says it has no property behavior here unless the word is a known noun. If a word is both an implemented property somewhere in the pack and an object noun somewhere else, the note calls out that ambiguity even when the palette or vocabulary names it.3031The rule parser still supplies context for already formed sentences. The note records `word`, `levelId`, `levelTitle`, `sentence` (or `null` for a loose word), player-language `message`, and a source-path `detail`. It is de-duplicated by word text and proof, with a cap for hostile or oversized packs. Thus two physical SHUT tiles in one proof produce one note, while a SHUT in another proof receives its own note.3233### Enforce custom property/object collisions at the level boundary3435Before validating level objects, collect that level's implemented custom property tokens. An object whose noun equals one of them is invalid, just as a core-property noun is invalid today. The engine's direct `createGame()` validator receives the same check so local modules and direct engine callers agree. This does not reserve an automaton property in unrelated levels where it has not been declared.3637### Treat feature flags as explicit minimum requirements3839`manifest.features` is an optional array of unique lowercase feature IDs. The current host recognizes `automata`; an unknown ID is a blocking validation error with player-readable upgrade guidance. A valid pack with `automata` data and no feature array remains supported so old v1 links and current examples keep working. New authored packs should declare `automata` explicitly. A future feature that needs old hosts to reject it must also change the engine schema version, because old hosts ignore unknown manifest fields; flags alone cannot retroactively protect them.4041### Keep warnings out of authored and shared data4243Local import and shared decode both run the diagnostic pass and return `warnings` in their pack-service preview envelopes. Successful results retain `errors: []`. Warnings are not serialized into CommonJS exports, share URLs, installed pack records, or engine snapshots. Gift shows an amber NOTE line and expandable detail card; Workshop shows an amber notes chip and action, as specified in design D24. A warning never silently becomes an error.4445## Risks / Trade-offs4647- [Risk] A future legitimate noun transform can mention a noun not yet placed in the proof. → Recognize palette/vocabulary nouns; keep other notes nonfatal and explain the transform consequence.48- [Risk] A word may form several different sentences during play. → Report one note for that word and proof, using an authored sentence for context when available.49- [Risk] Feature flags do not protect old deployed code. → Preserve v1 compatibility here and require a future engine version bump for a new unsupported mechanic.50- [Risk] Warning rendering can crowd the Gift card. → Use design's expandable NOTE card with at most five visible lines and a count for the remainder.5152## Migration Plan53541. Add diagnostics and validation fixtures at the loader and direct-engine boundaries.552. Expose warnings in pack-service local/share previews and render design's Gift and Workshop note affordances.563. Verify old v1 automata links still import; confirm unknown features fail before installation.574. Run browser and sharing acceptance, then ask design to review the warning card.5859## Open Questions6061None for the initial note contract. The host accepts legacy automata packs without a feature list.