- commit
- a0f6f7cff1f10e32eb274231b9c293017421747b
- parent
- 97f08a513998d69b99f8125a5fdd27c7be8cd81d
- author
- Dami <dami.etoile@gmail.com>
| A | openspec/ | 2 | + |
| A | openspec/ | 82 | ++++++++++++++++++++++++++++++ |
| A | openspec/ | 37 | ++++++++++++++ |
| A | openspec/ | 80 | +++++++++++++++++++++++++++++ |
| A | openspec/ | 33 | ++++++++++++ |
@@ -0,0 +1,82 @@
1+## Context2+3+The current loader validates `manifest.engine` as the data/schema version and4+defaults an omitted value to `MOD_SCHEMA_VERSION`. It has no equivalent field5+for behavioral semantics. W6 changes precedence, transform reading order, and6+contact order while preserving the existing manifest shape, so an old pack7+needs an explicit compatibility signal.8+9+## Decisions10+11+### A monotonic integer revision12+13+The host exports one current rules revision, `CURRENT_RULES_VERSION = 2`.14+Revision `2` means the post-W6 contract: PUSH precedence over STOP, defeat15+before win, `X IS X` self-blocking, reading-order transform conflicts, one-link16+transform chains per turn, and complete `AND` noun reading. Future semantic17+changes bump the integer. This field is deliberately separate from18+`manifest.engine`, which continues to describe the validated data API.19+20+`manifest.rules` is a positive integer no greater than the current revision.21+Non-integers, zero, negative values, and other types are validation errors.22+A value greater than `2` is rejected as an unsupported future rules revision;23+the loader must fail before it registers any part of the pack.24+25+### Missing means legacy revision one26+27+An omitted `manifest.rules` is interpreted as revision `1`, the pre-W6 rules28+contract. Normalization materializes the effective revision so local imports,29+shared decoding, CommonJS export, catalog records, pack-service preview views,30+and cloned or persisted views agree. Every projection boundary, including31+`manifestFromView()` and `createPackView()`, must carry `rules` forward instead32+of rebuilding a manifest that drops it. The engine still runs the current rules33+implementation; this revision is a compatibility declaration and does not34+select an alternate simulator.35+36+First-party packs that are authored for the current runtime declare37+`rules: 2` explicitly. Imported packs without the field stay usable and receive38+the legacy note below.39+40+### One transient pack-level warning41+42+For an effective revision below the host revision, diagnostics returns one43+bounded warning with the pack identity and source detail. Its player message is44+exactly:45+46+> This pack was made for older rules; some proofs may play differently.47+48+The warning is nonfatal and appears in both local CommonJS and data-only shared49+previews. It uses the existing warning envelope, with `word: 'RULES'`,50+`levelId: null`, `levelTitle: null`, and `sentence: null`; `detail` identifies51+`manifest.rules`, the effective revision, and the current revision. It is52+emitted once per preview, not once per proof, and does not count authored53+levels as separate warnings. The warning is recomputed on preview and is never54+copied into normalized authored data, catalog records, snapshots, exports, or55+shared payloads.56+57+### Keep preview and installation atomic58+59+Validation happens before catalog registration. An unsupported future revision60+returns the normal structured pack error and leaves the catalog unchanged. A61+known older revision returns `errors: []`, installs normally when selected, and62+retains the effective revision in the pack's normalized manifest.63+64+## Risks and mitigations65+66+- Existing packs omit the field. Treating absence as revision one preserves67+ loading while making the semantic mismatch visible.68+- A warning can be mistaken for a compatibility mode. The message and docs say69+ the current rules run; no legacy simulator is introduced.70+- Local and shared paths can drift. Run the same fixtures through `loadMod`,71+ `decodeSharedPack`, and pack-service previews, then compare warning envelopes72+ and normalized manifests.73+- First-party world packs may be edited by their owners. Ask each owner to add74+ `rules: 2` rather than mutating team-owned pack files in this change.75+76+## Non-goals77+78+- Reimplementing pre-W6 rules or adding a rules-version switch to the engine.79+- Changing `manifest.engine`, share envelope version, feature negotiation, or80+ warning thresholds for long proof titles.81+- Changing puzzle content, solver search semantics, or presentation copy beyond82+ the one compatibility note.@@ -0,0 +1,37 @@
1+## Why2+3+`manifest.engine` identifies the shape of the mod API, but it cannot tell the4+host which interpretation of a valid board the pack was authored against.5+The W6 precedence and rule-reading changes alter puzzle outcomes while keeping6+the CommonJS data shape valid. Without a separate semantic revision, an older7+pack can load successfully and quietly play differently.8+9+## What Changes10+11+- Add a numeric `manifest.rules` compatibility revision for puzzle semantics.12+- Define revision `2` as the current post-W6 rules contract.13+- Treat a missing revision as legacy revision `1` for imported packs and emit a14+ nonblocking W11 diagnostic explaining that the proofs may play differently.15+- Emit the same diagnostic for any known older revision while evaluating the16+ pack with the host's current semantics.17+- Reject a pack that declares a future rules revision the host does not know,18+ with an actionable compatibility error before installation.19+- Preserve the effective revision through local loading, shared links, exports,20+ installed pack records, and pack preview views without serializing warnings.21+22+## Capabilities23+24+### Modified Capabilities25+26+- `commonjs-mods`: validate and normalize the semantic rules revision at the27+ mod boundary.28+- `level-sharing`: apply the same revision compatibility and nonfatal warning29+ contract to local and data-only shared previews.30+31+## Impact32+33+The mod loader, pack service, share encoder/decoder, and first-party pack34+manifests are affected. Current packs should declare `rules: 2`; older packs35+remain loadable with a visible note. Engine behavior is never downgraded for an36+older pack, and the diagnostic remains outside authored data, snapshots, and37+portable warning-free payloads.@@ -0,0 +1,80 @@
1+## ADDED Requirements2+3+### Requirement: Pack manifests SHALL declare or derive a semantic rules revision4+5+The loader SHALL validate `manifest.rules` as a positive integer no greater6+than the host's current rules revision. The host's current revision SHALL be7+`2`, representing the post-W6 precedence, transform-reading, and contact-order8+contract. An omitted field SHALL mean legacy revision `1` and SHALL be9+materialized in normalized pack data. A value greater than `2` SHALL reject the10+pack before any catalog mutation.11+12+All pack-service manifest projections, including `manifestFromView()` and13+`createPackView()`, SHALL preserve the effective revision. A view round trip or14+persisted catalog record SHALL not silently remove `manifest.rules`.15+16+#### Scenario: A current pack loads without a compatibility note17+18+- **WHEN** a valid pack declares `manifest.rules: 2`19+- **THEN** local preview succeeds with `errors: []`, no rules-version warning,20+ and normalized data retains `manifest.rules: 2`21+22+#### Scenario: An omitted revision uses legacy semantics metadata23+24+- **WHEN** a valid imported pack omits `manifest.rules`25+- **THEN** preview succeeds, normalized data contains `manifest.rules: 1`, and26+ the catalog remains unchanged until the caller explicitly installs it27+28+#### Scenario: A pack view preserves its revision29+30+- **WHEN** a legacy pack is previewed, installed, and projected back through a31+ pack-service view32+- **THEN** the view and any later export/share operation retain33+ `manifest.rules: 1` rather than rebuilding a manifest without the field34+35+#### Scenario: Malformed revisions fail validation36+37+- **WHEN** a pack declares `manifest.rules` as `0`, `-1`, `1.5`, or a string38+- **THEN** preview fails with a `manifest.rules` validation error and does not39+ install or partially register the pack40+41+#### Scenario: Future revisions fail atomically42+43+- **WHEN** a pack declares `manifest.rules: 3`44+- **THEN** preview fails with an actionable unsupported-rules-revision error and45+ the catalog contains none of that pack's levels46+47+### Requirement: Older rules SHALL produce one nonblocking W11 warning48+49+The preview service SHALL return one bounded, nonblocking warning when a50+pack's effective rules revision is below the host revision.51+52+When a pack's effective rules revision is below the host revision, local53+CommonJS and data-only shared previews SHALL return one warning, while keeping54+`errors: []` and allowing explicit installation. The warning SHALL have55+`word: 'RULES'`, `levelId: null`, `levelTitle: null`, `sentence: null`, and the56+player message `This pack was made for older rules; some proofs may play differently.`57+Its technical detail SHALL identify the declared or derived revision and the58+current host revision. The host SHALL continue to run current rules semantics;59+the warning is not a legacy simulation mode.60+61+#### Scenario: An explicit old revision is surfaced once62+63+- **WHEN** a valid pack declares `manifest.rules: 1` and contains seven proofs64+- **THEN** preview succeeds with one pack-level warning, the exact player65+ message, and detail showing `1` versus current `2`; it does not emit seven66+ duplicate warnings67+68+#### Scenario: Local and shared previews agree69+70+- **WHEN** the same legacy pack is previewed from CommonJS and from a data-only71+ shared link72+- **THEN** both previews expose the same warning envelope and normalized73+ `manifest.rules: 1` without installing the pack as a side effect74+75+#### Scenario: Warnings remain transient76+77+- **WHEN** a warned legacy pack is installed, exported, or encoded as a shared78+ link79+- **THEN** its normalized manifest retains only `rules: 1`, no warning field is80+ serialized, and the warning is recomputed when the pack is previewed again@@ -0,0 +1,33 @@
1+## 1. Contract and normalization2+3+- [ ] 1.1 Define and export the current rules revision (`2`) separately from4+ `MOD_SCHEMA_VERSION`.5+- [ ] 1.2 Validate `manifest.rules` as a positive integer at or below the6+ current revision; reject malformed and future revisions before registration.7+- [ ] 1.3 Normalize an omitted revision to legacy revision `1` and preserve the8+ effective revision through local loads, shared decode/encode, CommonJS9+ export, catalog records, and pack-service views. Update both manifest10+ projection helpers (`manifestFromView()` and `createPackView()`) so cloned or11+ persisted views cannot drop the field.12+- [ ] 1.4 Add `rules: 2` to current first-party manifests through their owning13+ pack authors; do not rewrite team-owned world files from this change.14+15+## 2. Diagnostics and sharing16+17+- [ ] 2.1 Add one bounded, transient pack-level W11 warning for effective18+ revisions below `2`, with the exact player message and source detail defined19+ in the level-sharing spec.20+- [ ] 2.2 Return the same warning and normalized manifest for local CommonJS21+ and data-only shared previews; keep warning fields out of installed data,22+ exports, and share payloads.23+- [ ] 2.3 Add focused tests for explicit current, explicit legacy, omitted24+ legacy, malformed, and future revisions, including atomic catalog behavior.25+26+## 3. Verification and handoff27+28+- [ ] 3.1 Run focused mod, pack-service, catalog, share, and diagnostics tests.29+- [ ] 3.2 Run the full Node suite and production build.30+- [ ] 3.3 Ask the design and worlds teams to review the warning wording and add31+ current `rules: 2` declarations to owned first-party packs.32+- [ ] 3.4 Archive this change only after the compatibility fixtures and both33+ preview paths pass.