- commit
- af337db37cd5ae8be58572d2d18aeca769b7969e
- parent
- 68af59a011c7e7043098c09ade54da703f853488
- author
- Dami <dami.etoile@gmail.com>
| M | openspec/ | 16 | ++++++++----- |
| M | openspec/ | 3 | ++- |
| M | src/ | 6 | +++++ |
| M | tests/ | 37 | ++++++++++++++++++++++++++++++ |
@@ -32,17 +32,21 @@ persisted catalog record SHALL not silently remove `manifest.rules`.
3232 - **THEN** the view and any later export/share operation retain3333 `manifest.rules: 1` rather than rebuilding a manifest without the field3434 35-#### Scenario: Malformed revisions fail validation35+#### Scenario: Malformed revisions fail validation with player copy3636 3737 - **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 pack38+- **THEN** preview fails with the player message `This pack's rules version39+ isn't valid, so it can't be installed.`, preserves the technical40+ `manifest.rules` validation detail, and does not install or partially register41+ the pack4042 41-#### Scenario: Future revisions fail atomically43+#### Scenario: Future revisions fail atomically with player copy4244 4345 - **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+- **THEN** preview fails with the player message `This pack needs a newer47+ version of Miau Is True. Update the game to play it.`, preserves the48+ technical unsupported-rules-revision detail, and the catalog contains none49+ of that pack's levels4650 4751 ### Requirement: Older rules SHALL produce one nonblocking W11 warning4852 @@ -21,7 +21,8 @@
2121 and data-only shared previews; keep warning fields out of installed data,2222 exports, and share payloads.2323 - [x] 2.3 Add focused tests for explicit current, explicit legacy, omitted24- legacy, malformed, and future revisions, including atomic catalog behavior.24+ legacy, malformed, and future revisions, including atomic catalog behavior25+ and the accepted player-facing copy for malformed and future rules.2526 2627 ## 3. Verification and handoff2728 @@ -14,6 +14,12 @@ function playerError(detail, source) {
1414 if (/^manifest\.features(?:\[\d+\])?: unsupported feature\b/.test(detail)) {1515 return { message: 'This pack needs a newer Miau.', detail };1616 }17+ if (/^manifest\.rules: unsupported future rules revision\b/.test(detail)) {18+ return { message: 'This pack needs a newer version of Miau Is True. Update the game to play it.', detail };19+ }20+ if (/^manifest\.rules: must be a positive integer\b/.test(detail)) {21+ return { message: "This pack's rules version isn't valid, so it can't be installed.", detail };22+ }1723 const levelMatch = /^levels\[(\d+)\](?:\.([^:]+))?:\s*(.*)$/.exec(detail);1824 if (!levelMatch) return { message: `Pack data: ${detail}`, detail };1925 const index = Number(levelMatch[1]);@@ -169,10 +169,47 @@ test('future rules revisions fail before catalog registration', () => {
169169 assert.equal(preview.ok, true);170170 const rejected = service.importPackText(`module.exports = ${JSON.stringify(future)};`, 'future.cjs');171171 assert.equal(rejected.ok, false);172+ assert.equal(rejected.errors[0].message, 'This pack needs a newer version of Miau Is True. Update the game to play it.');172173 assert.match(rejected.errors[0].detail, /manifest\.rules: unsupported future rules revision 3/);173174 assert.deepEqual(service.catalog.getPacks(), before);174175 });175176 177+test('malformed rules revisions use player language while preserving technical detail', () => {178+ const malformed = structuredClone(example);179+ malformed.manifest.id = 'malformed-rules';180+ malformed.manifest.rules = 'two';181+ const service = createPackService();182+ const preview = service.importPackText(`module.exports = ${JSON.stringify(malformed)};`, 'malformed.cjs');183+ assert.equal(preview.ok, false);184+ assert.equal(preview.errors[0].message, "This pack's rules version isn't valid, so it can't be installed.");185+ assert.match(preview.errors[0].detail, /manifest\.rules: must be a positive integer/);186+ assert.equal(service.catalog.getPacks().some(pack => pack.id === 'malformed-rules'), false);187+});188+189+test('shared rules compatibility errors use the same player language', () => {190+ const sender = createPackService({ baseUrl: 'https://fcbc.n.zip/' });191+ assert.equal(sender.installPack(example).ok, true);192+ const shared = sender.packLink('gift-pack');193+194+ const futurePayload = tamperSharedPayload(new URL(shared.url).hash.slice('#pack='.length), pack => {195+ pack.manifest.rules = 3;196+ });197+ const malformedPayload = tamperSharedPayload(new URL(shared.url).hash.slice('#pack='.length), pack => {198+ pack.manifest.rules = 'two';199+ });200+ const receiver = createPackService();201+ const future = receiver.decodePackLink(`#pack=${futurePayload}`);202+ const malformed = receiver.decodePackLink(`#pack=${malformedPayload}`);203+204+ assert.equal(future.ok, false);205+ assert.equal(future.errors[0].message, 'This pack needs a newer version of Miau Is True. Update the game to play it.');206+ assert.match(future.errors[0].detail, /manifest\.rules: unsupported future rules revision 3/);207+ assert.equal(malformed.ok, false);208+ assert.equal(malformed.errors[0].message, "This pack's rules version isn't valid, so it can't be installed.");209+ assert.match(malformed.errors[0].detail, /manifest\.rules: must be a positive integer/);210+ assert.equal(receiver.catalog.getPacks().length, 1);211+});212+176213 test('local and shared previews expose fallback world metadata and notes', () => {177214 const authored = structuredClone(example);178215 authored.manifest.id = 'world-preview';