Skip to content

Commit 1ca7a80

Browse files
docs(qa): six platform-checklist clauses re-pointed to the behaviour the product has since ruled (#23121) (#23132)
Fixes #23121 Clause-②: no The browser pass of #23104 scored six acceptance clauses in the platform test checklist as `fail`. In each case the product is right and the clause is out of date: it pins a shape the product has since ruled away. This PR revises the five items that carry those clauses. Each item gets `revision` +1 and one appended `history` entry. No product code, test or fixture changes. Before each edit, I checked the row's "what the product does now" against code and tests. I did not use a browser or boot the app. I read objectui source at this repo's `.objectui-sha`, `1fb1ced36243`. Every objectui file cited below is byte-identical at `7578323a544e`, the pin the dispatch named (`git diff --quiet` exit 0). ## Rows: item, clause, old to new, and what it was checked against Clause indices are zero-based, like a run record's `clause`. `#23104 X` is the QA run's own label. | item · clause | old | new | checked against | |---|---|---|---| | `platform-core.home-admin-cluster-links` · acceptance[2] (#23104 A2) · rev 2 → 3 | roles, positions and permissions redirect to the `sys_position` / `sys_permission_set` object routes | roles and positions go to `/apps/setup/metadata/position?scope=environment` and permissions to `/apps/setup/metadata/permission?scope=environment`: the Setup metadata catalog, via `SystemCatalogRedirect` (objectui#7611). `users` and `organizations` are unchanged | objectui `apps/console/src/AppContent.tsx:167-171,289-293` · `apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx:344-382` · `packages/app-shell/src/views/metadata-admin/catalog-scope.ts:55` @ `1fb1ced36243` | | `identity-auth.auth-method-matrix` · acceptance[9] (#23104 A9) · rev 6 → 7 | delete-user answers 404 "to every caller, authed or not" | delete-user is never 2xx: a signed-in caller gets 404 (the capability switch) and an anonymous one gets 401 `UNAUTHORIZED` (session guard). The existing wiring test is the oracle | `packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts:320-375` (anonymous 401 at :349, authed 404 at :352, callback 404 at :372) · `auth-route-ledger.ts:157` @ `f931e765b` | | `identity-auth.self-signup-gate` · negative[4] (#23104 N5) · rev 2 → 3 | under stock `invite_only` the login page offers the register link and `/register` renders the form | no generic sign-up link, and `/register` shows the by-invitation notice with no form. The form is offered only for an `/accept-invitation/ID` redirect or on a deployment with no owner. The negative now fails the old offer-then-refuse shape, and still fails an invitee left without a form | objectui `packages/app-shell/src/console/auth/signUpOffer.ts:144-157` · `apps/console/src/pages/auth/RegisterPage.tsx:125-143,229-257` · `LoginPage.tsx:146-153,361-362` · `__tests__/signUpFollowsPosture-11691.test.tsx:156-260` @ `1fb1ced36243`; server unchanged: `packages/plugins/plugin-auth/src/auth-manager.ts:6809-6816` @ `f931e765b` | | `access-security.owd-save-gate` · acceptance[3] (#23104 A3) · rev 3 → 4 | widening a packaged object's OWD answers 403 `PERMISSION_DENIED` with `declaredCode: owd_widening_forbidden` (R1) | 403 `NOT_OVERRIDABLE` from the managed-content seal, or `ITEM_LOCKED` with `?package=`. The seal is saveMetaItem's package door. It is asked ahead of every check that judges the body (#22338), and the hatch does not open it (ADR-0131 D6, #22401). R1 cannot be reached here on stock, so its oracle is its unit pins, named in the item. No fixture package was built for it | `packages/metadata-protocol/src/protocol.ts:20652` (the door, in `saveMetaItem`, ahead of `runAuthoringGate` at :21233) · `:17465-17537` (`refusePackagedBaseOverride`) · `:16669-16672` (`isSealedManagedItem`) · `packages/spec/src/kernel/metadata-plugin.zod.ts:786` (`object`: `allowEnvironmentOverlay: false`) · `packages/rest/src/meta-object-owd-gate.test.ts:346-430` · `packages/plugins/plugin-security/src/object-posture-gate.test.ts:61-131` @ `f931e765b`; commits `35afb1587`, `e02833c24` | | `api-backend.formula-stdlib-matrix` · acceptance[0] (#23104 C1) · rev 1 → 2 | 27 registered stdlib functions; the joinNonEmpty row is the literal `joinNonEmpty(['a', null, ' ', 'b'], '-')` | 29 functions: the 27 plus `isoDate` and `isoDatetime` (`345d3f3d8`, #22347), with their known answers. The joinNonEmpty row now feeds the same values through record fields and expects `'a-b'`. The receiver method `can` is named as outside the count | `packages/formula/src/stdlib.ts:261-423` (29 chained `registerFunction` calls, counted from source; `can` registered at :267 → :196) · `packages/formula/src/validate.ts:1240-1280` (the 29 tally) · `content/docs/data-modeling/formulas.mdx:178-198` (29 names, 19 rows) @ `f931e765b`; probe against the built `packages/formula/dist/index.mjs` (below) | | `api-backend.formula-stdlib-matrix` · acceptance[5] (#23104 C6) · rev 1 → 2 | EXPECTED-FAIL: an unregistered function is a silent null at head | positive: an active object save whose formula calls `sqrt(...)` answers 422 `INVALID_METADATA` (rule `expression-invalid`, a NAME fault), and nothing is stored. A draft promotion is refused the same way. The read-path residual is named | `packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts:1630-1700` · `packages/lint/src/runtime-gate.object-formula-writes.test.ts:66-107` · `packages/formula/src/validate.ts:548` · `packages/objectql/src/engine-formula-fault-log.test.ts` @ `f931e765b`; commit `f85a83b83` (#22031; card #22019) | The C6 pin search found a test that pins this refusal: the `'runtime authoring gate on OBJECT writes — the formula field verdict (#22019)'` block. The item names it, so the clause does not rest on a browser reading alone. **Probe against the built formula package** (`pnpm --filter '@objectstack/formula...' build` under the shared lock, then `celEngine` imported from `packages/formula/dist/index.mjs` at `f931e765b`): ```text joinNonEmpty(['a', null, ' ', 'b'], '-') -> ok:false "List elements must have the same type, expected type 'string' but found 'null'" joinNonEmpty([record.a, record.b, record.c, record.d], '-') with record a='a' b=null c=' ' d='b' -> ok:true 'a-b' isoDate(date('2026-02-28T13:45:00Z')) -> '2026-02-28' isoDatetime(date('2026-02-28T13:45:00Z')) -> '2026-02-28T13:45:00.000Z' isoDate(today()), now 2026-08-30T22:00Z, Asia/Shanghai -> '2026-08-31' isoDate('2026-01-01') -> ok:false found no matching overload for 'isoDate(string)' sqrt(4) -> ok:false found no matching overload for 'sqrt(int)' ``` **Coupled fields.** Each row also revises the fields of the same item that restate the same stale fact, so that no item contradicts itself after the edit: - **A2:** the title, step 4, and the AppContent source note. - **A9:** step 9. - **N5:** the title and step 1. Step 2 drops its "submit the register form" half and keeps the direct POST, because the stock `/register` has no form for an uninvited visitor. Also one new objectui source note. - **A3:** the title, step 5, the R1 knownGap, the first knownGap's "packaged tighten-only" parenthetical, and the R1 variant. Also two new source notes, including the anchor `protocol.ts#refusePackagedBaseOverride`. - **C1:** the title, step 1, step 3, the 27-function knownGap, the clause's evidence, and the `registerStdLib` source note. - **C6:** the title, step 7, and negative[2]. Also two new source notes, including the anchor `packages/lint/src/authoring-rules.ts#EXPRESSION_INVALID`. Each `history` entry lists the fields it touched. ## Gates All gates ran at `c84cc2314` (`git rev-parse --short HEAD` after the last commit). Each ran in its own foreground process with its own log, and the exit code was read before any pipe. | command | exit | verdict line | |---|---|---| | `node scripts/check-ci-filter-parity.mjs` | 0 | `OK: all 197 declared cross-package glob(s) (144 unique) are covered …` | | `node scripts/check-closing-keyword-parity.mjs` | 0 | `check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords …)` | | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | `✓ … 40 assertions, 5 mutations of the shipped parsers each driven to red.` | | `node scripts/check-comment-mask-corpus.mjs` | 0 | `✓ comment-mask corpus sweep …: 8933 files, 0 disagree, 0 unparseable` | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 | `✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 474 files …` (first run exited 3, PREREQUISITE NOT MET: lint was unbuilt; re-run after `pnpm --filter '@objectstack/lint...' build`) | | `pnpm check:cross-package-test-inputs` | 0 | `OK: 30 package(s) read outside themselves, all declared …` | | `pnpm check:doc-authoring` | 0 | `✓ doc authoring guard: 421 files clean …` | | `pnpm check:driver-memory-census` | 0 | `check-driver-memory-census: OK …` | | `pnpm check:gitlink-declared` | 0 | `check-gitlink-declared: OK (11177 index entries …)` | | `pnpm check:nul-bytes` | 0 | `check-nul-bytes: OK (scanned 11168 text file(s) … no raw ASCII control bytes).` | | `pnpm check:platform-checklist` | 1 | `check-platform-checklist: 8 problem(s)`, the same 8 lines at the base `f931e765b` (sorted problem lines diff empty). None is in the five items, so this PR adds no problem (see Acceptance notes) | | `pnpm check:refd-timer-probe` | 0 | `OK check-refd-timer-probe: 8927 source file(s) swept …` | | `pnpm check:watch-hint-literal` | 0 | `✓ check-watch-hint-literal: 73 declaration(s) across 4 rostered name(s) …` | `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE`, run after the edits with no paths so the script derives the change set (4 paths vs merge base `f931e765b`), printed `✓ dispatch-gates --ran: 13 derived famil(ies) accounted for — 13 run, 0 NOT-MEASURED (a DERIVED zero …)`. This is the same 13 the dispatch named. Symbol anchors per file rose and never fell (`--anchor-census`: access-security 64, api-backend 66, identity-auth 90, platform-core 67, all above their floors). `skip-changeset`: `docs/qa/**` ships in no package. ## Acceptance notes - **The `check:platform-checklist` red predates this PR.** At `f931e765b` it reports 8 problems: - 5 ABSENT SYMBOL in `access-security.public-form-withdrawal-layers` (`protocol.ts#anonymousFormIntakeOrgScopeRefusal`, `#anonymousFormIntakeReopenRefusal` and `#envWideRawViewRows`, the last two each cited twice); - 1 ABSENT SYMBOL in `attachments-storage.attach-requires-parent-edit` (`attachment-access-hooks.ts#canEdit`), plus that file's SYMBOL ANCHORS LOST (27 resolve, floor 28); - 1 ABSENT SYMBOL in `search.rls-both-personas` (`protocol.ts#countable`). All 8 are outside this card's file surface and untouched here. Carrier: the daily `platform-checklist-watchdog` workflow, which files or refreshes one issue while `main` is red. Not filed. - **`identity-auth.self-signup-gate`, other text.** acceptance[2] ends "which is exactly why the register form stays rendered under the closed posture". After objectui#11691 that is true for an invitee only. That clause is outside this row and is left as written. Its two older objectui source notes also cite line ranges (`RegisterPage.tsx,69-88`, `LoginPage.tsx,136,298`) that no longer match the pin. - **`access-security.owd-save-gate`, other text.** fixtures.requires[1] still says to author the R2 probe with `?mode=draft`, while step 3 says to drive it at the active door. That predates this PR and sits outside the row. - **R1 now has no live path.** No write reaches R1's packaged-baseline comparison through `PUT /api/v1/meta/object/NAME` on any kernel topology: the seal answers first, as the REST pin's own comment records. R1 keeps only its in-process unit pins. This is an observation, not a defect, so it is not filed. - **`can` is undocumented.** `current_user.can(object, verb)` is registered inside `registerStdLib` (as a receiver method) but appears in no doc outside release notes; the formulas.mdx stdlib table and its variable-scope table omit it. This is a doc observation, not filed. - **Pin discrepancy.** The dispatch named `.objectui-sha` `7578323a544e`. `origin/main` moved it to `1fb1ced36243` (#23110) after the PM's read at `e9e10fdab`. I read at the current pin. Every cited file is byte-identical across the two. ## 维护者速读(草稿) **改了什么**:平台测试清单里五个测试项的六条验收子句改了指向:Setup 旧链接的落点、删除账号接口的应答、注册页在「仅限邀请」下的表现、受管对象 OWD 的拒绝码、公式函数数量与未注册函数的拒绝。只改了 `docs/qa/platform-checklist/areas/` 下四个 JSON 文件,产品代码一行未动。 **为什么改**:#23104 浏览器测试把这六条判成 fail,但产品行为是对的,是清单写的时候早于后来的裁决或实现。不改的话,每次发版 QA 都会重复报出这六个假失败,把真问题淹没。 **风险与代价(含回滚)**:不发布任何包(`skip-changeset`),不影响运行时。风险只在于清单措辞:若某条改写不准,下次 QA 会把它判成 fail,而不是漏报。回滚就是 revert 本 PR,清单回到旧措辞。 **席位意见**: **你要做的**:无需操作。合并由席位按常规非受管路径完成。 --- _Generated by [Claude Code](https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 287fd6e commit 1ca7a80

4 files changed

Lines changed: 63 additions & 43 deletions

File tree

‎docs/qa/platform-checklist/areas/access-security.json‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,10 +1318,10 @@
13181318
},
13191319
{
13201320
"id": "access-security.owd-save-gate",
1321-
"title": "OWD save gate: external ≤ internal on every object write, and a packaged object's OWD can only be tightened at runtime — Studio inline AND server-side",
1321+
"title": "OWD save gate: external ≤ internal on every object write, and a packaged object's OWD cannot be changed at runtime — the managed-content seal refuses the write before any OWD rule judges it — Studio inline AND server-side",
13221322
"since": "v16",
13231323
"status": "active",
1324-
"revision": 3,
1324+
"revision": 4,
13251325
"priority": "P1",
13261326
"surface": "mixed",
13271327
"personas": [
@@ -1335,16 +1335,16 @@
13351335
"the Studio object designer Settings tab (objectui ObjectSettingsPanel / PackageOwdOverviewPanel), which computes isExternalWider inline"
13361336
],
13371337
"knownGaps": [
1338-
"runtime EVALUATION of externalSharingModel against external principals is liveness `planned` (#2696) — this item tests the AUTHORING/save gate (external ≤ internal at write; packaged tighten-only), NOT external-principal enforcement; do not tick an external-principal read/write result",
1339-
"R1 (owd_widening_forbidden) fires on a STOCK deploy too — the escape hatch is NOT what reaches it. What selects the answering layer is the DIRECTION OF THE SUBMITTED BODY, not the deploy posture (measured on stock showcase, #9477): saveMetaItem runs the plugin-security authoring gate BEFORE the overlay/package doors on the host-config kernel the showcase boots (environmentId undefined, so protocol.ts's env-partitioned NOT_OVERRIDABLE branch is skipped), so a WIDENING body meets R1 first and always answers 403 owd_widening_forbidden — hatch open or closed, ?package= named or not. A body that does NOT widen passes R1 and only then meets the overlay door: 403 NOT_OVERRIDABLE (no ?package=) or 403 ITEM_LOCKED (?package= names the read-only base) on stock, and 2xx under OS_METADATA_WRITABLE=object. ⚠ WRITABLE_PACKAGE_REQUIRED was observed on NONE of those six legs — do not expect it here. The run must still record WHICH layer answered the 4xx, and must read the code from `declaredCode`: the dispatcher maps this refusal to `code: PERMISSION_DENIED` on the wire and carries the ledgered spelling in `declaredCode: owd_widening_forbidden`, so a check keyed on `code` alone MISSES it"
1338+
"runtime EVALUATION of externalSharingModel against external principals is liveness `planned` (#2696) — this item tests the AUTHORING/save gate (external ≤ internal at write; a packaged object sealed against runtime change), NOT external-principal enforcement; do not tick an external-principal read/write result",
1339+
"R1 (owd_widening_forbidden) is UNREACHABLE through the metadata door on a stock deploy, and with OS_METADATA_WRITABLE=object too. saveMetaItem asks the package door (refusePackagedBaseOverride, predicate isSealedManagedItem: the item is artifact-backed and `object` opens no overlay channel) on every kernel topology, ahead of the runtime lint door and the plugin-security authoring gate (#22338). Since ADR-0131 D6 (#22401) the escape hatch no longer opens an item a managed package ships. So any OWD write onto showcase_announcement is refused 403 NOT_OVERRIDABLE (no ?package=) or 403 ITEM_LOCKED (?package= names the read-only base), whatever its direction: widening or tightening, hatch open or shut. The revision-3 reading, measured at #9477, no longer holds: a widening body met R1 first and answered 403 PERMISSION_DENIED with declaredCode owd_widening_forbidden, and a tightened control passed R1 and met NOT_OVERRIDABLE, or 2xx under OS_METADATA_WRITABLE=object. R1 keeps its oracle in unit pins: packages/plugins/plugin-security/src/object-posture-gate.test.ts for its verdict, and packages/rest/src/meta-object-owd-gate.test.ts for the door order that now puts the seal in front of it. ⛔ Do not build a fixture package only to reach R1 live (#23121 triage). If a run does see the R1 refusal on some other door, read the code from `declaredCode` (owd_widening_forbidden), not `code`: the wire `code` is PERMISSION_DENIED"
13401340
]
13411341
},
13421342
"steps": [
13431343
"boot showcase with the console; admin session",
13441344
"Studio inline (browser): open the object designer Settings for a writable/draft object; set sharingModel=private and externalSharingModel=public_read; screenshot — the panel must flag the D11 external-wider violation inline (owd-sharing.ts isExternalWider) and not offer a clean save",
13451345
"server reject: PUT /api/v1/meta/object/qa_owd_probe with sharingModel:'private' + externalSharingModel:'public_read' — capture the 4xx + error code. ⚠️ Drive this at the ACTIVE-state door, NOT ?mode=draft: the D11 refusal is raised by the runtime lint block (validateSecurityPosture, rule security-external-wider-than-internal), and draft saves deliberately defer it to the draft→active promotion gate (#4463 D1), so a ?mode=draft PUT is ADMITTED and the clause cannot be observed there",
13461346
"server admit: PUT the same object with externalSharingModel:'private' (≤ private) — capture the 2xx (the gate orders, it does not blanket-deny)",
1347-
"packaged tighten (R1): PUT /api/v1/meta/object/showcase_announcement widening its shipped sharingModel public_read→public_read_write (keep externalSharingModel:'private' so the D11 lint is not tripped instead) — capture the 4xx AND its code. Expect 403 with `declaredCode: owd_widening_forbidden` (wire `code` is PERMISSION_DENIED) on a STOCK deploy, no escape hatch needed. Control leg, to prove the probe reached R1 rather than a blanket deny: re-PUT the same body TIGHTENED (public_read→private) — R1 passes it and the next door answers 403 NOT_OVERRIDABLE (or ITEM_LOCKED with ?package=com.example.showcase), 2xx under OS_METADATA_WRITABLE=object",
1347+
"packaged object (the seal): PUT /api/v1/meta/object/showcase_announcement widening its shipped sharingModel public_read→public_read_write (keep externalSharingModel:'private' so the D11 lint is not the door under test). Capture the 4xx AND its code. Expect 403 NOT_OVERRIDABLE from the managed-content seal (saveMetaItem's package door, ADR-0131 D6), on a stock deploy and under OS_METADATA_WRITABLE=object alike. With ?package=com.example.showcase the same door answers 403 ITEM_LOCKED. Control leg, to show that the seal answers and not a direction-keyed gate: re-PUT the same body TIGHTENED (public_read→private). It is refused the same way, because a managed item is sealed whatever the body says. R1 (owd_widening_forbidden) is not reached on this door; clause 4 names its unit pins",
13481348
"GET /api/v1/meta/object/showcase_announcement before and after the denied PUT — confirm byte-identical",
13491349
"cross-check the shipped declarations: GET /api/v1/meta/object/showcase_account and showcase_announcement — both satisfy external ≤ internal"
13501350
],
@@ -1368,10 +1368,10 @@
13681368
"evidence": "the PUT trace + read"
13691369
},
13701370
{
1371-
"clause": "a packaged object's OWD cannot be widened at runtime: the widening PUT on showcase_announcement answers 4xx with a ledgered code, recorded with WHICH layer answered. On a stock deploy that is 403 owd_widening_forbidden from the plugin-security authoring gate — the gate runs ahead of the overlay/package doors here, so the escape hatch is not what reaches it (#9477)",
1371+
"clause": "a packaged object's OWD cannot be changed at runtime: the widening PUT on showcase_announcement is refused 403 with a ledgered code, recorded with WHICH layer answered. On a stock deploy that is 403 NOT_OVERRIDABLE from the managed-content seal, saveMetaItem's package door (ADR-0131 D6, #22401). It answers ahead of every check that judges the body, on every kernel topology (#22338), and OS_METADATA_WRITABLE does not open it. So the plugin-security R1 gate (owd_widening_forbidden) is unreachable here on stock, and R1's oracle is its unit pins, not this run",
13721372
"oracle": "api",
1373-
"verify": "PUT /api/v1/meta/object/showcase_announcement (widened) status >=400 and the ledgered code is owd_widening_forbidden. ⚠ read it from `declaredCode`, not `code`: the dispatcher answers `{code: 'PERMISSION_DENIED', declaredCode: 'owd_widening_forbidden'}` on the live REST route, so a check keyed on `code` alone misses the gate it is looking for (measured #9477; note the unit pin packages/rest/src/meta-object-owd-gate.test.ts reads the bare spelling off `code`, which is the in-process shape, not the wire shape)",
1374-
"evidence": "the PUT trace + the code + the answering-layer note"
1373+
"verify": "PUT /api/v1/meta/object/showcase_announcement (widened, no ?package=) answers 403 with code NOT_OVERRIDABLE and no declaredCode; with ?package=com.example.showcase, which names the read-only base, the same door answers 403 ITEM_LOCKED. Either way the answering layer is the package door, not R1. The door order is pinned by packages/rest/src/meta-object-owd-gate.test.ts (the '[#7674] R1 owd_widening_forbidden through PUT /api/v1/meta/object/:name' block: a widening overlay of a packaged object answers 403 NOT_OVERRIDABLE with no declaredCode and stores nothing, hatch open). R1's own verdict is pinned in-process by packages/plugins/plugin-security/src/object-posture-gate.test.ts (the 'R1 — env-tighten-only over a packaged declaration (ADR-0086 D1)' block). Cite both pins per rule 6 for R1; do not build a fixture package to reach it live",
1374+
"evidence": "the PUT trace + the code + the answering-layer note (+ the two cited pin outputs for R1)"
13751375
},
13761376
{
13771377
"clause": "the denied widening is inert: GET /api/v1/meta/object/showcase_announcement is byte-identical before and after the refused PUT",
@@ -1393,7 +1393,7 @@
13931393
],
13941394
"variants": [
13951395
"R2 external ≤ internal (authoring gate, all object writes)",
1396-
"R1 env-tighten-only (packaged/artifact-backed objects)"
1396+
"the managed-content seal (packaged/artifact-backed objects: 403 NOT_OVERRIDABLE, or ITEM_LOCKED with ?package=, ahead of R1); R1 env-tighten-only is unreachable on this door and unit-pinned"
13971397
],
13981398
"traps": [
13991399
"stale-console-bundle",
@@ -1404,7 +1404,9 @@
14041404
"packages/lint/src/validate-security-posture.ts#OWD_WIDTH (OWD_WIDTH + SECURITY_EXTERNAL_WIDER lint parity)",
14051405
"objectui packages/app-shell/src/views/studio-design/owd-sharing.ts (isExternalWider) + PackageOwdOverviewPanel.tsx + ObjectSettingsPanel.tsx",
14061406
"examples/app-showcase/src/data/objects/announcement.object.ts#externalSharingModel + account.object.ts (externalSharingModel declarations)",
1407-
"ADR-0090 D11, ADR-0086 D1, ADR-0124 D1, #3050, objectui#2508"
1407+
"packages/metadata-protocol/src/protocol.ts#refusePackagedBaseOverride (saveMetaItem's package door — the managed-content seal: isSealedManagedItem, 403 NOT_OVERRIDABLE, or ITEM_LOCKED for a named read-only base; asked on every kernel topology ahead of the body checks since #22338, and not opened by OS_METADATA_WRITABLE since ADR-0131 D6, #22401)",
1408+
"packages/rest/src/meta-object-owd-gate.test.ts (the door-order pin: a packaged object's overlay is refused by the package door before the lint door and R1, hatch open) + packages/plugins/plugin-security/src/object-posture-gate.test.ts (R1's in-process unit pins)",
1409+
"ADR-0090 D11, ADR-0086 D1, ADR-0124 D1, ADR-0131 D6, #3050, objectui#2508"
14081410
],
14091411
"history": [
14101412
{
@@ -1414,7 +1416,8 @@
14141416
"ref": "claude/platform-test-checklist-ocwugl"
14151417
},
14161418
{ "revision": 2, "date": "2026-08-18", "change": "corrected clauses 1-2 and steps 2-3 for the #8310 retirement (maintainer ruling 2026-08-13). The item tested R2 owd_external_wider / 403 at the ?mode=draft door; R2 is RETIRED from object-posture-gate.ts as a duplicate of the runtime lint door, whose refusal is 422 INVALID_METADATA rule security-external-wider-than-internal raised at the ACTIVE-state door — and draft saves deliberately defer to the draft-to-active promotion gate (#4463 D1), so the clause was unobservable where it was pointed (#9453 CF-2). ⚠️ #9453 CF-3 (that the R1 knownGap mispredicts which layer answers) was NOT applied: object-posture-gate.ts states verbatim that R1 applies only to overlay writes over an artifact-backed object and that 'the default deploy already 403s these before this gate runs' (if (!ctx.isArtifactBacked) return), which is what the knownGap and clause 4 already say", "ref": "#9386" },
1417-
{ "revision": 3, "date": "2026-08-19", "change": "the R1 knownGap, step 5 and clause 4 named the WRONG answering layer, and #9453 CF-3 was RIGHT — re-measured on a genuinely stock showcase boot and OVERTURNING the revision-2 note above (#9477). Proven stock from the server process's own /proc/<pid>/environ: zero METADATA_WRITABLE occurrences among 147 vars. Target artifact-backed, proven by GET ?layers=true returning a populated `code` layer (_packageId com.example.showcase) with `overlay: null`. A widening PUT then answered 403 declaredCode owd_widening_forbidden — reproduced twice, object byte-identical after. The mechanism the old text missed: saveMetaItem runs runAuthoringGate BEFORE the overlay/package doors on the host-config kernel the showcase boots (environmentId undefined, so protocol.ts's env-partitioned NOT_OVERRIDABLE branch never arms — the #7674 note in that file says the showcase is exactly that shape). So the deploy posture does not select the layer; the body's DIRECTION does. Control leg (same boot, same object, tightened body) passed R1 and answered 403 NOT_OVERRIDABLE, i.e. the door the knownGap called 'earlier' is in fact LATER. Six legs measured (widen/tighten x stock/hatch x ?package= present/absent) and WRITABLE_PACKAGE_REQUIRED appeared on none. ⛔ Not a product defect: every widening leg refused and the object never changed — object-posture-gate.ts behaved exactly as its executable guard (if (!ctx.isArtifactBacked) return) specifies; only the prose parenthetical in that file's header, and this item, mispredicted the door order", "ref": "#9477" }
1419+
{ "revision": 3, "date": "2026-08-19", "change": "the R1 knownGap, step 5 and clause 4 named the WRONG answering layer, and #9453 CF-3 was RIGHT — re-measured on a genuinely stock showcase boot and OVERTURNING the revision-2 note above (#9477). Proven stock from the server process's own /proc/<pid>/environ: zero METADATA_WRITABLE occurrences among 147 vars. Target artifact-backed, proven by GET ?layers=true returning a populated `code` layer (_packageId com.example.showcase) with `overlay: null`. A widening PUT then answered 403 declaredCode owd_widening_forbidden — reproduced twice, object byte-identical after. The mechanism the old text missed: saveMetaItem runs runAuthoringGate BEFORE the overlay/package doors on the host-config kernel the showcase boots (environmentId undefined, so protocol.ts's env-partitioned NOT_OVERRIDABLE branch never arms — the #7674 note in that file says the showcase is exactly that shape). So the deploy posture does not select the layer; the body's DIRECTION does. Control leg (same boot, same object, tightened body) passed R1 and answered 403 NOT_OVERRIDABLE, i.e. the door the knownGap called 'earlier' is in fact LATER. Six legs measured (widen/tighten x stock/hatch x ?package= present/absent) and WRITABLE_PACKAGE_REQUIRED appeared on none. ⛔ Not a product defect: every widening leg refused and the object never changed — object-posture-gate.ts behaved exactly as its executable guard (if (!ctx.isArtifactBacked) return) specifies; only the prose parenthetical in that file's header, and this item, mispredicted the door order", "ref": "#9477" },
1420+
{ "revision": 4, "date": "2026-10-13", "change": "clause 4, acceptance[3], re-pointed to the managed-content seal, with step 5, the R1 knownGap, the first knownGap's packaged tighten-only parenthetical, the R1 variant, the title and two new source notes (stale spec, #23104 A3). Revision 3 measured, at #9477, that a widening PUT on showcase_announcement met R1 first and answered 403 PERMISSION_DENIED with declaredCode owd_widening_forbidden. Two later changes reorder that. #22338 made saveMetaItem ask the package door on every kernel topology, ahead of the checks that judge the body. ADR-0131 D6 (#22401, e02833c24) made the OS_METADATA_WRITABLE hatch stop opening an item a managed package ships. A packaged object, whose type opens no overlay channel, is now refused 403 NOT_OVERRIDABLE (ITEM_LOCKED with ?package=) whatever the body says, so R1 is unreachable on this door on stock. The protection holds: nothing widens. Per the #23121 triage, no fixture package is built to reach R1. Its oracle is its unit pins, named in the clause: plugin-security object-posture-gate.test.ts for the verdict, and rest meta-object-owd-gate.test.ts, whose R1 block now pins the package door answering first, hatch open", "ref": "#23121" }
14181421
]
14191422
},
14201423
{

0 commit comments

Comments
 (0)