|
27 | 27 | * enforced too: `name`, the `namespace` grammar, the closed value sets, the |
28 | 28 | * retired-key tombstones and the nested blocks it closes. §8 pins that. |
29 | 29 | * |
30 | | - * ## What is deliberately NOT refused — the declaration decides |
| 30 | + * ## The wrapped TOP LEVEL — refused too, because the declaration closed it |
31 | 31 | * |
32 | | - * An unknown key at the TOP LEVEL of the wrapped form. The wrapped branch is a |
33 | | - * plain `z.object` (strip mode) and its docblock forbids closing it here, so |
34 | | - * `{ manifest, bogus }` parses green with `bogus` dropped. ⛔ No case below |
35 | | - * pins that as intended behaviour in either direction: §5 asserts the door |
36 | | - * AGREES WITH THE DECLARATION on it, which stays green whichever way the |
37 | | - * declaration is later decided. |
| 32 | + * An unknown key at the TOP LEVEL of the wrapped form was the one position |
| 33 | + * this door still admitted when the whole-body parse landed: the wrapped |
| 34 | + * branch was strip mode, so `{ manifest, enabledOnInstall: false }` — a |
| 35 | + * misspelled `enableOnInstall` — parsed green with the key dropped and |
| 36 | + * installed the package ENABLED. Decision batch #227 item 3, letter A (ruling |
| 37 | + * record `5856869656`) closed that branch in `@objectstack/spec`, and the door |
| 38 | + * followed with no edit of its own, because it asks the declaration. §5 pins |
| 39 | + * the refusal at this door: the status, the named key, and that nothing was |
| 40 | + * installed. |
38 | 41 | * |
39 | 42 | * ## Envelope |
40 | 43 | * |
@@ -170,6 +173,8 @@ describe('§0 the declaration is what the door is held to', () => { |
170 | 173 | { ...m, enableOnInstall: false }, |
171 | 174 | { ...m, overwrite: true }, |
172 | 175 | { ...m, settings: { a: 1 } }, |
| 176 | + { manifest: m, enabledOnInstall: false }, |
| 177 | + { manifest: m, _source: 'studio' }, |
173 | 178 | ]; |
174 | 179 | for (const body of refused) { |
175 | 180 | expect(PackageInstallBodySchema.safeParse(body).success, JSON.stringify(body)).toBe(false); |
@@ -315,23 +320,58 @@ describe('§4 row 4 — install options on the BARE form are refused, naming the |
315 | 320 | }); |
316 | 321 |
|
317 | 322 | // ═══════════════════════════════════════════════════════════════════════ |
318 | | -// §5 — the door follows the declaration, including where it strips |
| 323 | +// §5 — the wrapped TOP LEVEL: refused, because the declaration closed it |
319 | 324 | // ═══════════════════════════════════════════════════════════════════════ |
320 | 325 |
|
321 | | -describe('§5 the door answers what the declaration answers', () => { |
322 | | - it('an unknown TOP-LEVEL key on the wrapped form: door and declaration agree, whichever way that is', async () => { |
323 | | - // ⛔ Deliberately a PARITY assertion, not a status pin. The wrapped |
324 | | - // branch strips today, so both accept; if the declaration is ever |
325 | | - // closed, both must refuse — and the door follows with no edit, |
326 | | - // because it asks the declaration. |
| 326 | +describe('§5 an unknown TOP-LEVEL key on the wrapped form is refused by name, and nothing installs', () => { |
| 327 | + // A STATUS pin, ⛔ not the parity assertion this section used to hold |
| 328 | + // («door and declaration agree, whichever way that is»): parity stays green |
| 329 | + // when the declaration is re-opened, because both would then accept, so it |
| 330 | + // could not tell a closed branch from a strip-mode one. The ruling decided |
| 331 | + // the direction (decision batch #227 item 3, letter A), so the direction is |
| 332 | + // what is pinned. Each refusal case reads the declaration's verdict on the |
| 333 | + // same body too, AFTER the door's answer, so a regression reddens the door |
| 334 | + // assertion first and the trailing read names whether the declaration moved. |
| 335 | + |
| 336 | + it('a MISSPELLED option — `enabledOnInstall: false` — is refused naming the key, ⛔ never installed ENABLED', async () => { |
327 | 337 | const { registry, install } = door(); |
328 | | - const m = manifest('toplevel.unknown'); |
329 | | - const body = { manifest: m, bogus: 1 }; |
330 | | - const declared = PackageInstallBodySchema.safeParse(body).success; |
| 338 | + const m = manifest('toplevel.misspelled'); |
| 339 | + const body = { manifest: m, enabledOnInstall: false }; |
331 | 340 | const r = await install(body); |
332 | 341 |
|
333 | | - expect(r.response?.status).toBe(declared ? 201 : 400); |
334 | | - expect(registry.getPackage(m.id) !== undefined).toBe(declared); |
| 342 | + expectRefused(r); |
| 343 | + // The inversion this ruling is about: before it, this id was installed |
| 344 | + // and ENABLED with the caller's `false` dropped. Refused, it is neither. |
| 345 | + expect(registry.getPackage(m.id)).toBeUndefined(); |
| 346 | + expect(persistedDisabled().has(m.id)).toBe(false); |
| 347 | + // Named subjects, ⛔ not prose: the key the caller wrote, and the |
| 348 | + // declared option the refusal offers in its place. |
| 349 | + expect(messageOf(r)).toContain('`enabledOnInstall`'); |
| 350 | + expect(messageOf(r)).toContain('`enableOnInstall`'); |
| 351 | + // Read LAST, so the door's own answer is what a regression turns red first. |
| 352 | + expect(PackageInstallBodySchema.safeParse(body).success, 'the declaration refuses it').toBe(false); |
| 353 | + }); |
| 354 | + |
| 355 | + it('a PRIVATE key — `_source` — is refused naming the key, and nothing installs', async () => { |
| 356 | + const { registry, install } = door(); |
| 357 | + const m = manifest('toplevel.private'); |
| 358 | + const body = { manifest: m, _source: 'studio' }; |
| 359 | + const r = await install(body); |
| 360 | + |
| 361 | + expectRefused(r); |
| 362 | + expect(registry.getPackage(m.id)).toBeUndefined(); |
| 363 | + expect(messageOf(r)).toContain('`_source`'); |
| 364 | + expect(PackageInstallBodySchema.safeParse(body).success, 'the declaration refuses it').toBe(false); |
| 365 | + }); |
| 366 | + |
| 367 | + it('control — the same body with the option spelled as declared installs, DISABLED as asked', async () => { |
| 368 | + const { registry, install } = door(); |
| 369 | + const m = manifest('toplevel.control'); |
| 370 | + const r = await install({ manifest: m, enableOnInstall: false }); |
| 371 | + |
| 372 | + expect(r.response?.status).toBe(201); |
| 373 | + expect(registry.getPackage(m.id)?.enabled).toBe(false); |
| 374 | + expect(persistedDisabled().has(m.id)).toBe(true); |
335 | 375 | }); |
336 | 376 | }); |
337 | 377 |
|
|
0 commit comments