|
2707 | 2707 | }, |
2708 | 2708 | { |
2709 | 2709 | "id": "api-backend.rest-metadata-config-contract", |
2710 | | - "title": "RestServerConfig.metadata is the metadata surface's construction contract: prefix moves eleven mounts and their discovery advertisement, four endpoint switches each gate exactly the face its name states (#15542/#15854), maskObjectFields is the ADR-0106 D8 disclosure gate, and both tombstones refuse at construction", |
| 2710 | + "title": "RestServerConfig.metadata is the metadata surface's construction contract: prefix moves every metadata mount and their discovery advertisement, four endpoint switches each gate exactly the face its name states (#15542/#15854), maskObjectFields is the ADR-0106 D8 disclosure gate, and both tombstones refuse at construction", |
2711 | 2711 | "since": "v17", |
2712 | 2712 | "status": "active", |
2713 | | - "revision": 8, |
| 2713 | + "revision": 9, |
2714 | 2714 | "priority": "P1", |
2715 | 2715 | "surface": "api", |
2716 | 2716 | "personas": [ |
|
2738 | 2738 | "harness: construct with { metadata: { endpoints: { types: false } } } — GET {prefix} and GET {prefix}/types both disappear (one handler, two paths)", |
2739 | 2739 | "harness: construct with { metadata: { endpoints: { items: false } } } and enumerate what leaves: GET {prefix}/:type and NOTHING else — exactly the one mount its describe() names (#15542 moved the whole-store family off this switch; a run that still sees /diagnostics, /_drafts or POST /_migrate-stored leave with it is the old radius returning)", |
2740 | 2740 | "harness: construct with { metadata: { endpoints: { maintenance: false } } } and enumerate: GET {prefix}/diagnostics, GET {prefix}/_drafts and the POST {prefix}/_migrate-stored write door — three whole-store operations, the key #15542 created so that closing a listing read stops disarming a migration door", |
2741 | | - "harness: construct with { metadata: { endpoints: { item: false } } } and enumerate: the WHOLE per-item face — GET, PUT and DELETE {prefix}/:type/:name, /:type/:name/references, /:type/:name/layers, the history family (/history, /audit, /diff, /published, /publish, /rollback) and {prefix}/book/:name/tree; twelve mounts, writes included (#15854)", |
| 2741 | + "harness: construct with { metadata: { endpoints: { item: false } } } and enumerate: the WHOLE per-item face — GET, PUT and DELETE {prefix}/:type/:name, /:type/:name/references, /:type/:name/layers, the history family (/history, /audit, /diff, /published, /publish, /rollback), {prefix}/book/:name/tree and the app metadata bundle GET {prefix}/app/:appId/bundle; thirteen mounts, writes included (#15854; the bundle since #27627, which registers it through the same per-item registrar because every bundle member is the item read's own answer)", |
2742 | 2742 | "harness: construct with { metadata: { enableCache: false } } and confirm the item read takes the uncached branch; then with enableCache true against an app-type, a dashboard-type, a draft read, a preview-drafts read, a package-scoped read, a member-addressed read (?member=, #22877) and an audience-gated type — each is a carve-out that bypasses the cached path even when the switch is on", |
2743 | 2743 | "harness: construct with { metadata: { maskObjectFields: false } }; separately construct with the default and metaType != 'object'", |
2744 | 2744 | "harness: construct with { metadata: { cacheTtl: 3600 } }, then 0, then -1, then { metadata: { endpoints: { schema: false } } }; capture each refusal text" |
|
2757 | 2757 | "evidence": "route table + discovery body at the non-default prefix" |
2758 | 2758 | }, |
2759 | 2759 | { |
2760 | | - "clause": "each of the FOUR endpoint switches gates exactly the face its name states, and the run must ENUMERATE what each removes rather than trust the describe(): `types` takes two paths (one handler at {prefix} and {prefix}/types), `items` takes exactly one ({prefix}/:type), `maintenance` takes the three whole-store operations INCLUDING the POST {prefix}/_migrate-stored write door, `item` takes the whole per-item face (twelve mounts, PUT and DELETE and the history family included)", |
| 2760 | + "clause": "each of the FOUR endpoint switches gates exactly the face its name states, and the run must ENUMERATE what each removes rather than trust the describe(): `types` takes two paths (one handler at {prefix} and {prefix}/types), `items` takes exactly one ({prefix}/:type), `maintenance` takes the three whole-store operations INCLUDING the POST {prefix}/_migrate-stored write door, `item` takes the whole per-item face (thirteen mounts, PUT and DELETE, the history family and GET {prefix}/app/:appId/bundle included)", |
2761 | 2761 | "oracle": "test", |
2762 | 2762 | "verify": "per-switch route-table diffs against the all-true baseline; the diff sets must be exactly the routes enumerated in the steps, in both directions — a switch that GROWS a route is as much a FAIL as one that loses one. ⛔ The run records the real radius whatever it finds: the describe() strings now claim to be exhaustive (#15542/#15854), so a diff that disagrees with them is a defect in the code or in the declaration, never a reason to relax this clause", |
2763 | 2763 | "evidence": "the four route-table diffs" |
|
2790 | 2790 | "knob:prefix", |
2791 | 2791 | "switch:endpoints.types (2 mounts)", |
2792 | 2792 | "switch:endpoints.items (1 mount)", |
2793 | | - "switch:endpoints.item (12 mounts)", |
| 2793 | + "switch:endpoints.item (13 mounts)", |
2794 | 2794 | "switch:endpoints.maintenance (3 mounts)", |
2795 | 2795 | "switch:enableCache (+6 carve-outs)", |
2796 | 2796 | "switch:maskObjectFields", |
|
2862 | 2862 | "date": "2026-10-27", |
2863 | 2863 | "change": "acceptance[0], [1], [3], [4] and [5] and negative[0] are pinned at the layer their oracle names (the release-18.2.0 Tier 1 sweep #26468 scored a0 and a4 unpinned, a1 and a5 half-asserted, a3 and n0 below the HTTP layer). The new rest-config-contract-live.dogfood.test.ts fires the default mounts and the client_liaison schema diff on a booted showcase, and rest-config-contract-harness.test.ts reads the re-based table, the cache branch per carve-out and the refusal texts off a real RestServer. automated.kind is dogfood; automated.ref and acceptance[5].verify name what they assert. Measured at base c8583f80. No clause changed", |
2864 | 2864 | "ref": "#26572" |
| 2865 | + }, |
| 2866 | + { |
| 2867 | + "revision": 9, |
| 2868 | + "date": "2026-11-02", |
| 2869 | + "change": "the `item` radius is thirteen mounts, not twelve: #27627 registered GET {prefix}/app/:appId/bundle through the per-item registrar, and packages/rest/src/rest-config-mount-table.pin.test.ts moved to thirteen with it, but steps[7], acceptance[2].clause and the variants row still enumerated twelve, so the 18.3.0 release-candidate run #28929 scored the describe() drift as a FAIL. Triage ruled the radius intended and the declaration wrong (6569524266): steps[7], acceptance[2].clause and the variant now name the bundle, and the title's stale 'prefix moves eleven mounts' (the default table has twenty) says 'every metadata mount', which is what acceptance[1] asserts. Measured at base 135054eb", |
| 2870 | + "ref": "#28934" |
2865 | 2871 | } |
2866 | 2872 | ] |
2867 | 2873 | }, |
|
0 commit comments