Skip to content

Commit 55337f4

Browse files
docs(qa): re-point the wave-5 checklist lines and add the package export round-trip item (#30128)
<!-- claude-projects-attribution: {"github_login":"marchtian"} --> _Requested by **田騏** · [project thread](https://claude.ai/code/project/chan_01VmuUhXU9SSUzqJYyXSmYSi?thread=cmsg_01VmuUhXU9SSUzqJYyXSmYSiNjyvCdXYygFqntMNR7S2dW)_ Fixes #29906 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:按 18.3.0 第五轮复测(#29890、#29893、#29877、#29870)的发现,更新了 45 个测试清单条目和 RUNNER 说明,并新增 1 个条目,覆盖“整个部署导出、到新环境再安装”这条链路。 - 为什么改:这些步骤和判定写的还是旧行为。下一轮测试照着跑,会把正常行为误判为失败,或者白白多出 422 和卡住的步骤。 - 风险与回滚:只改了 docs/qa 下的清单 JSON 和 RUNNER.md,产品代码没有动。回滚就是 revert 这个 PR。 - 先看:RUNNER.md 新写的两条环境事实,一条是覆盖已发布视图或模板的方式(走 .custom 定制包),一条是首次进入时的币种/时区弹窗;再看新条目 platform-core.package-export-round-trip。 - 两分钟验证:在分支上运行 `node scripts/check-platform-checklist.mjs`,应返回 OK,退出码 0。 - 需要你做的:无,席位落地 ## What changes Each card line was re-read against the code at base `f68b47ca` before it was applied. 45 existing items get a revision bump and a history row that cites #29906; one item is new. - **Part A (W5-FAIL, #29890): 19 items.** - The aggregate bulk action goes through the action door, `POST /api/v1/actions/showcase_task/showcase_recalc_selection` with `{params:{_selectedIds}}`. - ADR-0146 D11 pair staging: list-view negatives and the email-template admin edit. - `/batch` is no longer offered as a 400 door. - `connectorConfig` is closed, and run records hold echoed secrets. - Email: the non-string display name probe, the `failed` row after a refused send, the unreachable no-locale branch and `?member=`. - Flow clone: 11 dropped keys, and the 'Added' row mark beside the 'In {pair}' header chip. - 'Switched on / off for this deployment'. - The New flow dialog is proven by creating a flow. - The app-id canonicalisation hop, and Keyboard shortcuts only inside an app. - No Activity tab for a member. - surface-matrix: `--maxWorkers=1`, a field-help variant, and a stock zh confirm specimen (`sys_session.revoke_my_other_sessions`, read from source only). - adhoc: a quick search, and sign-out through the account menu. - Dashboard: the wave-4 held filter shape, and a two-dimension sankey with no root. - `?mode=draft` on a read answers 400. - The no-entry matrix: lockedBy (#29312), the sortable observables (#29896, #30024), non-default probes, `modalSize` and the CEL envelope. - `sharingModel` for a published fixture object. - disabled-control: Archive's own reason, the ledger switch, the ~all item page (#29897). - Invite outcome copy, and the per-group approval read from `sys_approval_action`. - PERMISSION_DENIED vs FORBIDDEN for the same `manage_metadata` refusal. - **Part B (W5-STUDIO, #29893): 24 studio-authoring items.** - Studio routes for the picklist fixture, the scratch-copy boot and the Add record dialog. - Spelled-out values for `indexes` and `contextSelectors`. - Autosave wording. - Validation rule shapes. - Script action capabilities. - 'New dataset' exists. - The joined report hold. - Record page autosave, and the member leg driven. - The command-center queue filter, a planted foreign task, Display › Layout and the publish door. - The sealed-sentence scope. - Dataset plus measure. - Leave-guard label and user activation. - 'Switched on / off'. - The edge Condition control. - The qualified view name. - The pair link lands on the base. - RLS operation `select`. - Clear falls back to the object grant. - Ensure is asked once per editing session. - **Part C (W5-P0, #29877).** `studio-authoring.first-run-loop` knownGaps[3] becomes a regression row (#29673 is fixed by #29790). RUNNER's console-auth fact names the Packaged Actions page; the retired Packaged Automation page now redirects to Studio. - **Part D (W5-EXPORT, #29870).** New `platform-core.package-export-round-trip` (api + cli, P1, v18.3, active), with 7 acceptance clauses, 5 negatives, source anchors and partial automated pins. Clauses [3] and [6] cite #29871 and #29872 as **fixed**: both are closed completed at base, so the clauses state the fixed behaviour and name the card a regression would reopen. - **RUNNER.md.** - The "`view` is overlay-allowed, a bare PUT answers 2xx" fact is replaced by the D11 rule. A package-less write onto a shipped name answers 403 NOT_OVERRIDABLE; the recipe is ensure-customization, then PUT `?package=com.example.showcase.custom` with `overrides`; a fresh name still writes. - A new fact covers the first-page currency / timezone prompt (`workspace-timezone-prompt-decline`, 'Not now'). This also lands the card's "all page items" fixture line. - **Deviation, not on the card.** `platform-core.manifest-install-contract` source[1] is re-pointed from `protocol.ts#assertProtocolCompat`, which no longer resolves, to `protocol-package-install.ts#installPackage`. The checker refused `platform-core.json` at base for this anchor, and this PR edits that file. **Overlap with #29819.** The `studio-authoring.picklist-bound-select` fixture line (`fixtures.requires[0]`: the scratch copy and no `--compile`) lands here, so #29819 should skip it. **Lines not applied** (6 of the card's 66): - `offclause.zh-cn-studio-save-29790`, all 4 lines: no ledger item carries this off-clause, so there is nothing to re-point. - `studio-authoring.org-scope-flows` fixtures.requires[1]: a confirmation, and the ledger already says it. At base a fresh-name package-less PUT still writes and a shipped name answers 403, so no change. - `studio-authoring.permission-matrix-editor-ux` A5: the card says the metadata-admin door draws no object expander on a read-only set. At base, `PermissionMatrixEditor.tsx` draws the chevron expander on every object row of that door with no read-only gate, so the reading could not be confirmed and the clause is unchanged. **Lines where the code at base differs from the card, applied as the code reads** (8): - held-edit-leave-guard: the card's steps[2] is steps[1] at base. - picklist-bound-select: steps[4] names no route, so it is unchanged. - report-authoring-options: only steps[2] has a Joined switch; steps[0] is unchanged. - `modalSize`: the record modal's form view is the default form, or the `create` form view for a create, not only the "isDefault" form. - Email locale: the channel names the recipient's `sys_user.locale`, else the deployment default, rather than always `en`. - Part D [3] and [6] are fixed rather than failing. - The Packaged Automation fact is re-pointed to its successor, Packaged Actions, from source. - The "all page items" currency line lands as one RUNNER fact plus `app-and-nav-properties` steps[1], not on each page item. ## Tests Documentation and checklist only; no product code or test changes. The ledger is validated by `scripts/check-platform-checklist.mjs`. Every edit was applied text-level, then re-parsed and deep-compared against the intended object before it was written. ## Acceptance notes - Every line was re-read at base `f68b47ca` before it was applied; the skipped and changed lines are named above. - Part D lands with `status: active` and its pins. The two clauses the card proposed as failing cite #29871 and #29872, both closed completed. - No line-number citations were added. Every `file#symbol` anchor added resolves to a declaration, and no anchor was removed. ## Verification - `node scripts/check-platform-checklist.mjs` → exit 0 (16 areas, 360 items). - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 16 commands, and all 16 ran → exit 0. - `check:doc-formula-expressions` first exited 3 because a prerequisite was not built. I ran the build it prescribes (`turbo run build --filter=@objectstack/formula --filter=@objectstack/lint`), and the gate then exited 0. - `--ran` reconciliation: 16 derived, 16 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero, from recorded exit codes). - `origin/main` merged once before opening (merge `97ee2c53`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5d7ada3 commit 55337f4

9 files changed

Lines changed: 561 additions & 192 deletions

File tree

‎docs/qa/platform-checklist/RUNNER.md‎

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,40 @@ Standing facts about the stock showcase environment that have each cost a run a
181181
detour. They are briefing material, not verdicts — re-confirm one only when a run
182182
contradicts it, and correct it here when it does.
183183

184-
- **`view` is in the overlay-allowed set, so authoring a view on the stock read-only
185-
showcase package is NOT blocked and needs no escape hatch.** The org-overridable
186-
types are derived from the metadata-type registry, not a hand-written list, and are
187-
exactly **`view`, `dashboard`, `report`, `translation`, `email_template`**
188-
(`packages/spec/src/kernel/metadata-plugin.zod.ts` — the `allowEnvironmentOverlay: true`
189-
entries; pinned by `protocol.org-scoped-write-refused.test.ts` G5). So
190-
`PUT /api/v1/meta/view/<name>` answers 2xx on stock showcase with no
191-
`OS_METADATA_WRITABLE` and no `?package=` trick, while the same shape on `object`,
192-
`field`, `hook`, `seed`, `mapping` or `flow` is refused. ⛔ Do not record a view
193-
step as `blocked(environment)` on a "the showcase package is read-only" assumption:
194-
read-only-ness is per metadata TYPE here, not per package, and the read-only-package
195-
lock the console renders is a *different* gate (see
196-
`access-security.readonly-package-locks-studio`).
184+
- **Customizing a view, dashboard, report, translation or email template the stock
185+
showcase ships goes into its pair, `com.example.showcase.custom`; a package-less
186+
write onto a shipped name is refused.** The five overlay types are derived from the
187+
metadata-type registry, not a hand-written list: **`view`, `dashboard`, `report`,
188+
`translation`, `email_template`** (`packages/spec/src/kernel/metadata-plugin.zod.ts`,
189+
the `allowEnvironmentOverlay: true` entries; pinned by
190+
`protocol.org-scoped-write-refused.test.ts` G5). Since ADR-0146 D11 a write naming no
191+
package onto an item of one of them that the read-only showcase ships, such as
192+
`PUT /api/v1/meta/view/showcase_task.done` with no `?package=`, answers **403
193+
`NOT_OVERRIDABLE`**, whose sentence names the pair to save into
194+
(`packagelessOverlayWriteRefusal`,
195+
`packages/metadata-protocol/src/protocol-packaged-base-refusal.ts`; QA run #29890
196+
met it on a view and on an email template). The working recipe:
197+
`POST /api/v1/packages/com.example.showcase/ensure-customization` (201 the first
198+
time, 200 after), then `PUT /api/v1/meta/<type>/<name>?package=com.example.showcase.custom`
199+
with the item's body plus `overrides: { package: 'com.example.showcase', basedOn: '0.1.0' }`;
200+
revert with `DELETE /api/v1/meta/<type>/<name>?package=com.example.showcase.custom`.
201+
A fresh name no package ships still writes package-less (200). The same shape on
202+
`object`, `field`, `hook`, `seed`, `mapping` or `flow` stays refused as before.
203+
⛔ Do not record such a step as `blocked(environment)` on a "the showcase package is
204+
read-only" assumption: the pair is the door, and the read-only-package lock the
205+
console renders is a *different* gate (see `access-security.readonly-package-locks-studio`).
206+
207+
- **A fresh organization's first page opens under a one-time prompt: "Set the default
208+
currency", or the system timezone, or both in one dialog.** An administrator is asked
209+
once while `localization.timezone` is still the manifest default or the organization
210+
has no default currency (`ui/apps/console/src/pages/settings/WorkspaceTimezonePrompt.tsx`,
211+
`workspaceTimezonePromptLogic.ts`), so on a fresh DB the dialog
212+
(`data-testid="workspace-timezone-prompt"`) sits over the first page the admin opens,
213+
Studio and app pages included (QA runs #29890 and #29893). Dismiss it with **Not now**
214+
(Keep the default when only the timezone is asked), `data-testid="workspace-timezone-prompt-decline"`,
215+
before any screenshot or DOM read. The answer is remembered per organization and user in
216+
that browser's `localStorage` (`os:workspace-timezone-prompt:<org>:<user>`), so a new
217+
browser context asks again. ⛔ Do not score a clause FAIL for chrome hidden under it.
197218

198219
- **`objectstack verify --rls` is a separate invocation — bare `verify` prints no RLS
199220
section at all.** `runRlsProofs` runs only behind the flag
@@ -460,16 +481,22 @@ contradicts it, and correct it here when it does.
460481
bearer seam. So a session driven with the localStorage token alone gets **401
461482
`AUTH_REQUIRED`** from `POST /api/v1/storage/upload/presigned` while
462483
`GET /auth/get-session` on the same page returns 200 — a convincing fake "avatar
463-
upload is broken". The Setup app's **Packaged Automation** page (component ref
464-
`automation:packaged`) needs it too: every request it makes, its
465-
`GET /api/v1/automation/_status` and `GET /api/v1/meta/flow` loads and its toggle
466-
and clone writes, is a bare `fetch` with `credentials: 'include'` and no
467-
`Authorization` header (`ui/packages/app-shell/src/views/setup/PackagedAutomationPage.tsx`),
468-
so a token-only session renders a load failure ending `HTTP 401` (`automation
469-
status HTTP 401` or `flow metadata HTTP 401`, whichever load is refused first) in
470-
the page's `role="alert"` box instead of the flow list (QA run #27409). ⛔ Do not
471-
drive any storage/upload surface or the Packaged Automation page from an injected
472-
token: **sign in through the form** so both halves exist.
484+
upload is broken". The Setup app's **Packaged Actions** page (component ref
485+
`automation:packaged-actions`) is built the same way: its `GET /api/v1/meta/object`
486+
and `GET /api/v1/data/sys_metadata_activation` loads and its
487+
`POST /api/v1/actions/_activation/<object>/<action>` toggle are bare `fetch`es with
488+
`credentials: 'include'` and no `Authorization` header
489+
(`ui/packages/app-shell/src/views/setup/PackagedActionsSection.tsx`), so a token-only
490+
session should expect a load failure ending `HTTP 401` (`object metadata HTTP 401` or
491+
`activation ledger HTTP 401`) in the page's `role="alert"` box instead of the action
492+
list. That is read from source; QA run #27409 measured the shape on the Packaged
493+
Automation page (`automation:packaged`), which retired with ADR-0146 D11: a bookmark of
494+
`/apps/<app>/component/automation/packaged` now opens Studio's Automations pillar
495+
(`packagedAutomationStudioPath`,
496+
`ui/packages/app-shell/src/views/studio-design/setupMetadataRedirect.ts`), where a
497+
packaged flow's switch and its New similar are. ⛔ Do not drive any storage/upload
498+
surface or the Packaged Actions page from an injected token: **sign in through the
499+
form** so both halves exist.
473500

474501
- **A stock showcase boot refuses self-registration — no item can mint a member by
475502
"fresh sign-up".** The showcase declares no `auth.audience`, so its posture is the

‎docs/qa/platform-checklist/areas/api-backend.json‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3295,7 +3295,7 @@
32953295
"title": "Error answers made honest on v18: a hook refusal on a hand-built write route answers 400 with the hook's own sentence, a crash answers a generic 500 that withholds the caught message, and a unique-constraint refusal is 409 UNIQUE_VIOLATION with details at the action door, MCP and sandboxed bodies too",
32963296
"since": "v18",
32973297
"status": "active",
3298-
"revision": 6,
3298+
"revision": 7,
32993299
"priority": "P2",
33003300
"surface": "api",
33013301
"personas": [
@@ -3310,7 +3310,7 @@
33103310
]
33113311
},
33123312
"steps": [
3313-
"POST a /data write route on the object whose hook refuses (POST /api/v1/data/OBJECT, or its /batch or /createMany door); read the body",
3313+
"POST a /data write route on the object whose hook refuses (POST /api/v1/data/OBJECT, or its /createMany door; not /batch: POST /api/v1/data/OBJECT/batch answers 200 with a per-row report, each refusal in results[i].errors[0] with its code and httpStatus, so it never answers the 400 this item reads, packages/rest/src/batch-routes.ts); read the body",
33143314
"invoke the script action that inserts a duplicate value: POST /api/v1/actions/OBJECT/ACTION",
33153315
"force a server fault on a storage route (e.g. a malformed adapter config on the scratch boot — QA run #24558 set storage.local_root under /dev/null through PUT /api/settings/storage) and read error.message"
33163316
],
@@ -3387,6 +3387,12 @@
33873387
"date": "2026-11-02",
33883388
"change": "acceptance[1] (clause, verify) and the automated.ref prose re-pointed to HOOK_ABORTED — stale spec from QA run #28929 (release-18.3.0-w4-c2a, at 7fa9873f), api-backend.error-sentences-and-unique-violation-wire-code acceptance[1], re-point card #28936. r5 asserted the pre-ruling shape: no `code` on the /data doors and 400 VALIDATION_ERROR (REFUSED_400) on the nested-envelope rows. #27597 gave an undeclared hook abort the ledgered ADR-0112 code HOOK_ABORTED (UNDECLARED_HOOK_REFUSAL_CODE in packages/types/src/thrown-http-error.ts, stamped by mapDataError) and #27672 carried it to the doors that resolve through resolveThrownHttpError (package publish). Re-read at base 135054ebaa: error-sentences-live.dogfood.test.ts asserts code HOOK_ABORTED on both /data doors, rest-hook-script-fault-envelope.test.ts asserts HOOK_ABORTED and no declaredCode through mapDataError, and rest-write-route-hook-refusal-sentence.ledger.test.ts answers HOOK_ABORTED_400 on every sharing-rule, suggested-binding, approval and package-publish row (no REFUSED_400 remains). Status and sentence unchanged; the clause now names the code instead of its absence, so it is narrower, not weaker. No other clause changed",
33893389
"ref": "#28936"
3390+
},
3391+
{
3392+
"revision": 7,
3393+
"date": "2026-11-04",
3394+
"change": "steps[0] corrected from QA run #29890 (W5-FAIL, at 589049b0): the /batch door is dropped from the doors that answer the clause's 400. It answers 200 with a per-row report (results[i].errors[0]). Read at base f68b47ca",
3395+
"ref": "#29906"
33903396
}
33913397
]
33923398
}

0 commit comments

Comments
 (0)