Repository navigation
Description
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
QA run record for #28579 slice 3 (PR #29559): one checklist-test run over the seven ADR-0146 items that slice 2 added, plus the system_overview measurement the order asks for. The record is text only. Screenshots were consulted live and are described here in words.
Environment fingerprint
- Framework:
objectstack-ai/objectstackmainat128681f4, built in the worktree of branchclaude/issue-28579-studio-journey-e2e-s3. At build time the branch added only the live spec and the allowlist line, with no product code. The build waspnpm install --frozen-lockfilefollowed bypnpm build. - Backend:
ui/e2e/live/ci/start-backend.sh, which runs the workspace CLI asobjectstack dev --seed-admin --freshon the showcase on port 4417. It was booted fresh at 2026-11-02T17:34:40Z and not restarted for any clause. - CLI item: a separate boot of the showcase on port 4418 with its own file database (
-d file:…/db.sqlite, its ownOS_HOME). The ceremony ran against it with the server stopped. - Console:
ui/apps/console, built from the same tree (vite build, base path/) and served byvite previewon port 5291, which proxies/apito the backend. - Browser: Playwright 1.63.0 with chromium build 1243, headless, viewport 1440×900. Node v22.23.4. Linux container.
- Personas:
- the seeded admin
admin@objectos.ai, who holds manage_metadata and is also the approver:showcase_budget_approval'smanager_reviewroutes to the admin; - one member made for the run with admin create-user and then change-password.
- the seeded admin
Scope
Selector: adr-0146-new-items, the seven items that slice 2 (#29487) added. All were judged at revision 1. No item is planned.
| item | revision |
|---|---|
| platform-core.customization-pair-ensure-door | 1 |
| studio-authoring.package-customize-restore-display | 1 |
| studio-authoring.package-extension-field-c | 1 |
| automation.package-flow-override | 1 |
| cli.packageless-overlay-ceremony-and-close | 1 |
| studio-authoring.package-customization-counts-and-marks | 1 |
| platform-core.setup-metadata-redirects-to-studio | 1 |
The pins named in each item's automated.ref were run on the same tree, and every one passed:
| package | files | tests | exit |
|---|---|---|---|
| ui | 14 | 242 | 0 |
| objectql | 4 | 65 | 0 |
| service-automation | 1 | 16 | 0 |
| runtime | 4 | 97 | 0 |
| metadata-protocol | 2 | 41 | 0 |
| cli (integration project, packageless-overlays) | 1 | 5 | 0 |
The live spec ui/e2e/live/studio-customize-journey.spec.ts also ran green on this boot in 16.0 s with the pair already present.
Per-clause verdicts
platform-core.customization-pair-ensure-door (r1) — PASS
| clause | verdict | evidence |
|---|---|---|
| 0 | pass | Before the call, GET of the pair answered 404. The ensure POST answered 201 with the pair com.example.showcase.custom. Its manifest reads namespace showcase_custom and dependency {"com.example.showcase": "^0"}, and the pair is writable. |
| 1 | pass | The second ensure POST answered 200 with created: false. A GET of the pair afterwards is byte-identical to the GET after the create. |
| 2 | pass | Each refusal, in order: • a body with a key: 400 VALIDATION_ERROR, "The ensure-customization door reads no body"; • a query parameter: 400 VALIDATION_ERROR; • the pair as the base: 400 VALIDATION_ERROR, "is itself a paired customization package"; • com.example.not-installed: 404 RESOURCE_NOT_FOUND; • the writable com.example.qa-pair-base: 409 RESOURCE_CONFLICT, "is writable: customize it directly"; • the member: 403 PERMISSION_DENIED naming manage_metadata. The package list is identical before and after. |
| 3 | pass | The DELETE of com.example.qa-pair-base, with its exported pair installed, answered 409 RESOURCE_CONFLICT starting Delete the customization package "com.example.qa-pair-base.custom" first and naming GET /api/v1/packages/com.example.qa-pair-base.custom/export. The base's GET still answered 200. After the pair's DELETE (200), the base's DELETE answered 200. |
| 4 | pass | The DELETE of com.example.showcase answered 422 WRITABLE_PACKAGE_REQUIRED. The showcase and its pair are both still listed. The live spec asserts the same refusal. |
studio-authoring.package-customize-restore-display (r1) — FAIL
The dashboard is showcase_ops_dashboard, with a label edit. The report is showcase_hours_by_status. The view is showcase_task.in_progress, driven by the live spec plus a hand leg for the end user and the exports.
| clause | verdict | evidence |
|---|---|---|
| 0 | pass | Pressing Customize sent no metadata write on any variant. The dashboard sent only its analytics dataset query POSTs. The report sent one sys_user_preference PATCH, collected since page load. The first edit sent one ensure, then the draft PUT naming package=com.example.showcase.custom with overrides: {package: 'com.example.showcase', basedOn: '0.1.0'} and no _ keys. No write named the base. |
| 1 | pass | After publish, the bare read, the base-named read, the list and /layers effective all serve the edit, and they agree. /layers code equals the step 1 base. The bare read reports _packageId com.example.showcase and carries the overrides block. |
| 2 | pass | As the end user, /apps/showcase_app/dashboard/showcase_ops_dashboard and the report page show the new label after a client reload, and the shipped label again after restore. The task list view /apps/showcase_app/showcase_task/view/showcase_task.in_progress drops the Due Date column and gets it back after restore. The backend was not restarted. |
| 3 | pass | studio-override-chip reads "Overrides ObjectStack Showcase", and its title names 0.1.0. |
| 4 | fail | The pair's export carries each override with its overrides block. For the dashboard and the report, the base's export carries the override too: GET /api/v1/packages/com.example.showcase/export holds the edited label and an overrides key. For the view, the base's export is identical to the step 1 baseline. Reproduction is below. |
| 5 | pass | Cancel on the restore dialog deleted nothing. Confirm sent DELETE …?state=draft&package=com.example.showcase.custom and then DELETE …?package=com.example.showcase.custom, both answering 200. The four reads then equal the baseline, and the render reverted. |
| 6 | pass | All three variants offer Customize on the read-only base. Clauses 0 to 5 hold on each variant's own reads, except clause 4 for the dashboard and the report. |
studio-authoring.package-extension-field-c (r1) — PASS
| clause | verdict | evidence |
|---|---|---|
| 0 | pass | The preview read region__c before Create. One ensure went out, then PUT /api/v1/meta/object_extension/showcase_task?mode=draft&package=com.example.showcase.custom with exactly {extend:'showcase_task', fields:{region__c:{type:'text',label:'Region'}}}. No object PUT was sent. Adding Tier put tier__c into the same extension, with no second ensure. |
| 1 | pass | After publish, GET /meta/object/showcase_task lists region__c and tier__c, and the pair's object_extension read returns the extension. A data API create with region__c = EMEA answered 201, and the read-back carries EMEA. |
| 2 | pass | The label edit on assignee saved fieldPatches: {assignee: {label: 'Assignee QA'}} and nothing else. The Required checkbox is disabled, and field-base-patch-only names the whitelist. |
| 3 | pass | An unsuffixed plain_note in the pair answered 400 VALIDATION_ERROR with issues at fields.plain_note. note__c on an object in the run's writable package QA_PKG (namespace qacp) answered 400 VALIDATION_ERROR. Neither was stored. The object was named with the namespace prefix, qacp_qa_c_probe. As step 6 was written, with qa_c_probe, the call answers 422 NAMESPACE_PREFIX before the __c judge runs. That is a step defect, fixed in revision 2. |
| 4 | pass | Reopening Add field and typing Region shows the hint "Another field is already named region__c…", and add-field-create is aria-disabled. |
automation.package-flow-override (r1) — PASS
| clause | verdict | evidence |
|---|---|---|
| 0 | pass | Customize on showcase_budget_approval sent nothing. The next edit renamed node manager_review to manager_review_qa and relabelled it "Manager Review QA". It sent one POST /api/v1/packages/com.example.showcase/ensure-customization (200, the pair already existed), then PUT /api/v1/meta/flow/showcase_budget_approval?mode=draft&package=com.example.showcase.custom (200) with name: showcase_budget_approval and overrides: {package:'com.example.showcase', basedOn:'0.1.0'}. There was no toggle POST, and sys_metadata_activation held 0 rows. The pair's draft read returns the declaration. |
| 1 | pass | publish-drafts answered published. _status lists showcase_budget_approval once (enabled, bound, active). The bare meta read serves the override's nodes with its overrides block. The header shows studio-override-chip ("Overrides ObjectStack Showcase … 0.1.0") and auto-ledger-switch, and draws one switch. The next budget change started exactly one run, whose steps are start, then manager_review_qa. |
| 2 | pass | Run run_c0dd98d0… started on the base before the publish and waited at manager_review. After its approval request was approved, it completed with the base's node ids: start, manager_review, needs_exec, exec_review (skipped). |
| 3 | pass | auto-ledger-switch sent POST …/toggle {"enabled":false}, which answered 200. A budget change then started no run. The switch back on sent {"enabled":true} and answered 200. The next change ran the override's manager_review_qa. That run failed with DUPLICATE_REQUEST, because the earlier override run's request was still pending on the record. This is a fixture interaction, not the clause. The base's ledger row is sys_metadata_activation with package_id com.example.showcase. |
| 4 | pass | The dialog reads "…this deployment's customization … is deleted, and ObjectStack Showcase's flow runs again in its place, under the same on/off switch". Two DELETEs at the pair (state=draft, then the row) answered 200 each. The chip is gone. The next run took the base's manager_review and completed after approval. The bare read has no overrides key, and _status still has one row. |
| 5 | pass | New similar posted POST /api/v1/automation/showcase_budget_approval/clone {"name":"showcase_budget_approval_qa_copy","label":"Budget Approval QA copy"} with no package. It answered 200 with flow status obsolete and packageId com.example.showcase.custom, and the console opened the copy, with its header reading "In com.example.showcase.custom". The rail shows it Added. _status lists the copy disabled and the base enabled. |
cli.packageless-overlay-ceremony-and-close (r1) — PASS
| clause | verdict | evidence |
|---|---|---|
| 0 | pass | On the fresh database, node packages/cli/bin/run.js migrate packageless-overlays --json, run from examples/app-showcase, exited 0 with apply:false, rows:[] and the showcase host config. The sys_metadata hash and row count (0) are identical before and after, and sys_packages holds no pair. |
| 1 | pass | After staging (server stopped) one row with package_id NULL, type view, name showcase_task.in_progress, state active, version 1 and label "In Progress (staged QA)", the preview listed it with disposition: movable, base com.example.showcase, pair com.example.showcase.custom, and outcome: listed. The store hash was unchanged. |
| 2 | pass | --apply --json without --yes printed {"error":"confirmation_required","hint":"pass --yes"} and exited 1. The store hash was unchanged. |
| 3 | pass | --apply --yes --json exited 0 with moved:1 and pairCreated:true. The store holds the row in com.example.showcase.custom with overrides {package:'com.example.showcase', basedOn:'0.1.0'}, and no package-less row is left. After boot, the bare read serves "In Progress (staged QA)" with the declaration, and so do the read naming the pair and the read naming the base. /layers code is the shipped "In Progress". A re-run of the preview listed no row. The re-run preview was taken before the boot rather than after it, which is the same store state. |
| 4 | pass | The close: • the package-less PUT answered 403 NOT_OVERRIDABLE "…save it into 'com.example.showcase.custom' (?package=com.example.showcase.custom), declaring overrides…"; • the package-less DELETE answered 403 NOT_OVERRIDABLE "…remove its customization from 'com.example.showcase.custom'…"; • the base-named PUT answered 403 NOT_OVERRIDABLE "…The read-only base itself takes no customization…". The item was unchanged after each. The declared PUT into the pair answered 200, and its draft reads back. |
studio-authoring.package-customization-counts-and-marks (r1) — FAIL
The fixture was published over the API:
- a dashboard override of
showcase_ops_dashboard; - an extension
region__conshowcase_task; showcase_budget_approvalswitched off;- the added item: the flow copy from the flow item.
| clause | verdict | evidence |
|---|---|---|
| 0 | pass | GET /packages/com.example.showcase/customizations returned the counts overrides 1, extensions 1 and switchedOff 1. After the card rendered, studio-landing-customizations (data-state read) read "2 customized, 1 switched off". The pair link goes to /studio/com.example.showcase.custom/data and the switched-off link to /studio/com.example.showcase/automations. |
| 1 | pass | The directory total reads "2 customized on ObjectStack Showcase", with tiles for object 1 and dashboard 1. In the dashboard list, the override is marked "Customized (ObjectStack Showcase)" and the other 2 rows are unmarked; the filter leaves 3 → 1. In the flow list, the copy is marked "Added"; the filter leaves 33 → 1. |
| 2 | fail | The landing sent one customizations request, for the read-only base, and none for the writable card com.example.qa-writable. The pair id answered 400 VALIDATION_ERROR "…Customizations are read for the base: GET /packages/com.example.showcase/customizations". However, the writable package's All metadata area did send GET /api/v1/packages/com.example.qa-writable/customizations, twice. It answered 200 with zero counts and drew no total, no mark and no filter. The clause says a writable package is never asked. The disposition is an assertion defect: usePackageCustomizations asks every package except a pair, and metadataAreaHost.customizations-28568's "a base without a pair is unchanged" pins that read. The clause is corrected in revision 2. |
platform-core.setup-metadata-redirects-to-studio (r1) — FAIL
The console was served at /, so /_console is the root here. The chains were read from main-frame navigations.
| clause | verdict | evidence |
|---|---|---|
| 0 | fail | Every /apps/setup/… URL first rewrites its app segment to /apps/com.objectstack.setup/…, then reaches /studio/~all/metadata/…. Typed with the canonical segment, the URL reaches Studio in one hop: /apps/com.objectstack.setup/metadata/object/showcase_task goes to /studio/~all/metadata/object/showcase_task. That rewrite is an assertion defect, fixed in revision 2. The fail is a product defect on the list URLs: /apps/setup/metadata/object and /apps/showcase_app/metadata/object reach /studio/~all/metadata/object, then go on to ?package=com.example.showcase and settle on /studio/com.example.showcase/metadata/object?package=com.example.showcase, not the cross-package leg. The item URLs, the hash and the alias stay on ~all. No Setup metadata page rendered for any of them. |
| 1 | fail | ?scope=environment lands on /studio/~all/metadata/position?scope=environment, as expected. #fields survives. ?review=1 is carried to /studio/~all/metadata/object/showcase_task?review=1, and the item page then drops it. The ?package=com.example.showcase URL reaches /studio/com.example.showcase/metadata/object/showcase_task?package=com.example.showcase and then opens /studio/com.example.showcase/data?surface=object%3Ashowcase_task. The disposition is an assertion defect: a pillar type opens its pillar (areaItemPillarPath, ADR-0146 D1). Corrected in revision 2. |
| 2 | pass | The list and item URLs settle on /apps/com.objectstack.setup/metadata/datasource and …/datasource/showcase_external, the canonical app segment, with no /studio entry. They render Setup's Datasources page, listing showcase_external ("External Analytics (SQLite)"), and its edit page (metadata-edit-datasource). The legacy alias settles on the same item page. The clause's test ids are the jsdom stubs'; that is fixed in revision 2. |
| 3 | fail | With ?package=com.example.showcase, the bookmark lands on /studio/com.example.showcase/automations?package=com.example.showcase, and the pillar then selects its first flow (&surface=flow%3Ashowcase_task_completed). Without a package, it reaches /studio/~all/metadata/flow and is then rewritten to /studio/com.example.showcase/metadata/flow?package=com.example.showcase, the same product defect as clause 0. |
Reproduction rules for the fails
-
The base export carries a dashboard or report override (restore-display, clause 4; product defect).
On a fresh showcase, signed in as admin:POST /api/v1/packages/com.example.showcase/ensure-customization.- Take
itemfromGET /api/v1/meta/dashboard/showcase_ops_dashboard?package=com.example.showcase, drop the_keys, setlabelto "Delivery Operations REPRO", and addoverrides: {package:'com.example.showcase', basedOn:'0.1.0'}. PUT /api/v1/meta/dashboard/showcase_ops_dashboard?mode=draft&package=com.example.showcase.customwith that body, thenPOST /api/v1/packages/com.example.showcase.custom/publish-drafts.GET /api/v1/packages/com.example.showcase/export.
Expected:
dashboards[]holds the shipped item, with the label "Delivery Operations" and nooverrideskey. Actual: it holds label "Delivery Operations REPRO" withoverrides. The same happens with reportshowcase_hours_by_status. For viewshowcase_task.in_progressthe base export is unchanged. Deleting the pair's draft and row returns the base export to the original. -
The cross-package list of a type is rewritten to one package's leg (redirects, clauses 0 and 3; product defect). Open
/studio/~all/metadata/object,/studio/~all/metadata/flowor/studio/~all/metadata/object?package=allas admin. Expected: the URL stays on/studio/~all/metadata/TYPE. Actual: it goes to?package=com.example.showcaseand then to/studio/com.example.showcase/metadata/TYPE?package=com.example.showcase. The cause isResourceListPage.tsx's?package=repair, which runs while the area names no package (host.packageIdnull). -
A writable package's All metadata area reads customizations (counts, clause 2; assertion defect). Open
/studio/<writable>/metadata/dashboard. The console sendsGET /api/v1/packages/<writable>/customizations(200, zero counts) and draws nothing. The clause, not the console, was wrong; it is corrected in test(ui): live e2e for the Studio customization journey on a read-only base (#28579 slice 3) #29559. -
The
?packageitem URL opens the pillar (redirects, clause 1; assertion defect). Open/apps/com.objectstack.setup/metadata/object/showcase_task?package=com.example.showcase. It lands on/studio/com.example.showcase/metadata/object/showcase_task?package=com.example.showcase, and the area then opens/studio/com.example.showcase/data?surface=object%3Ashowcase_task, as ADR-0146 D1 designs. Corrected in test(ui): live e2e for the Studio customization journey on a read-only base (#28579 slice 3) #29559.
Derived item verdicts
- PASS (4):
- platform-core.customization-pair-ensure-door
- studio-authoring.package-extension-field-c
- automation.package-flow-override
- cli.packageless-overlay-ceremony-and-close
- FAIL (3):
- studio-authoring.package-customize-restore-display (clause 4, product)
- studio-authoring.package-customization-counts-and-marks (clause 2, assertion defect)
- platform-core.setup-metadata-redirects-to-studio (clauses 0 and 3, product; clause 1, assertion defect)
- PARTIAL, BLOCKED and NOT-RUN: none.
There are no fixture gaps. The product defects are listed in docs/qa/platform-checklist/FOLLOW-UPS.md §15b on the slice's PR #29559, for the seat to card.
Off-clause probe
The probe took about 15 minutes, on the same boot and as the same personas.
Doors:
- the ensure door;
- the uninstall door;
- the object and extension reads;
- the export;
- the clone door;
- Studio's All metadata area;
- the system package's Studio surface.
Boundary classes:
- a blank id:
POST /packages/%20/ensure-customizationanswers 400; - an empty JSON body:
{}to ensure answers 200 (same as no body); - no auth: ensure answers 401;
- the wrong persona: the member's DELETE of the pair answers 403;
- an unknown leg value:
?package=allon the~alllist is rewritten (finding 3 below).
Found:
- A published
fieldPatcheslabel is served only by/meta/object/showcase_task/layers. The bare read, the base-named read and the list serve the shipped label, contrary to ADR-0146 D10. It was reproduced through Studio (assignee) and over the API (priority). - The 422 WRITABLE_PACKAGE_REQUIRED remedy still says to save an item under its own name, the package-less save that D11 closed.
- The
~alllist rewrite (reproduction rule 2). - The
object_extensionlist draws the pair's extension row with "—" as its name. - A read naming the pair for an override (
GET /meta/view/V?package=com.example.showcase.custom) reports_packageId com.example.showcase, consistent with "a served override is served as the base's item".
system_overview measurement (the order's question)
Question: can the platform's system_overview dashboard be customized in its pair?
Answer: yes on the server, but not through Studio's door.
The base is com.objectstack.plugin-auth: scope system, writable: false, version 3.0.1.
Through Studio: /studio/com.objectstack.plugin-auth/interfaces?surface=dashboard:system_overview shows no read-only chip and offers no Customize, and the inspector's Label is editable. An edit sends PUT /api/v1/meta/dashboard/system_overview?mode=draft&package=com.objectstack.plugin-auth. That is refused with 403 {"error":"…save it into 'com.objectstack.plugin-auth.custom'…","code":"NOT_OVERRIDABLE"}, shown in a role=alert. The cause is that Studio's parsePackages drops packages of scope system or cloud, so Studio does not know this base is read-only.
Over the API:
POST /api/v1/packages/com.objectstack.plugin-auth/ensure-customizationanswers 201 with the paircom.objectstack.plugin-auth.custom, namespacesys_custom, dependency^3.- The declared PUT into the pair (
overrides: {package:'com.objectstack.plugin-auth', basedOn:'3.0.1'}) answers 200. publish-draftsanswers published, with one runtime probe issue:widget_query_failedonwidget_packages_installed, because admin is denied read onsys_package_installation.- The bare read, the base-named read and
/layersserve the override, and/customizationscounts overrides 1. - The pair was deleted afterwards (200).
Activity