Skip to content

QA run · adr-0146-new-items (7/7) · 128681f4 · 2026-11-02 · 4 PASS / 0 PARTIAL / 3 FAIL / 0 BLOCKED / 0 NOT-RUN #29560

Open

Description

@objectstack-fleet

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/objectstack main at 128681f4, built in the worktree of branch claude/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 was pnpm install --frozen-lockfile followed by pnpm build.
  • Backend: ui/e2e/live/ci/start-backend.sh, which runs the workspace CLI as objectstack dev --seed-admin --fresh on 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 own OS_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 by vite preview on port 5291, which proxies /api to 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's manager_review routes to the admin;
    • one member made for the run with admin create-user and then change-password.

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__c on showcase_task;
  • showcase_budget_approval switched 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

  1. The base export carries a dashboard or report override (restore-display, clause 4; product defect).
    On a fresh showcase, signed in as admin:

    1. POST /api/v1/packages/com.example.showcase/ensure-customization.
    2. Take item from GET /api/v1/meta/dashboard/showcase_ops_dashboard?package=com.example.showcase, drop the _ keys, set label to "Delivery Operations REPRO", and add overrides: {package:'com.example.showcase', basedOn:'0.1.0'}.
    3. PUT /api/v1/meta/dashboard/showcase_ops_dashboard?mode=draft&package=com.example.showcase.custom with that body, then POST /api/v1/packages/com.example.showcase.custom/publish-drafts.
    4. GET /api/v1/packages/com.example.showcase/export.

    Expected: dashboards[] holds the shipped item, with the label "Delivery Operations" and no overrides key. Actual: it holds label "Delivery Operations REPRO" with overrides. The same happens with report showcase_hours_by_status. For view showcase_task.in_progress the base export is unchanged. Deleting the pair's draft and row returns the base export to the original.

  2. 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/flow or /studio/~all/metadata/object?package=all as admin. Expected: the URL stays on /studio/~all/metadata/TYPE. Actual: it goes to ?package=com.example.showcase and then to /studio/com.example.showcase/metadata/TYPE?package=com.example.showcase. The cause is ResourceListPage.tsx's ?package= repair, which runs while the area names no package (host.packageId null).

  3. A writable package's All metadata area reads customizations (counts, clause 2; assertion defect). Open /studio/<writable>/metadata/dashboard. The console sends GET /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.

  4. The ?package item 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-customization answers 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=all on the ~all list is rewritten (finding 3 below).

Found:

  1. A published fieldPatches label 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).
  2. The 422 WRITABLE_PACKAGE_REQUIRED remedy still says to save an item under its own name, the package-less save that D11 closed.
  3. The ~all list rewrite (reproduction rule 2).
  4. The object_extension list draws the pair's extension row with "—" as its name.
  5. 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-customization answers 201 with the pair com.objectstack.plugin-auth.custom, namespace sys_custom, dependency ^3.
  • The declared PUT into the pair (overrides: {package:'com.objectstack.plugin-auth', basedOn:'3.0.1'}) answers 200.
  • publish-drafts answers published, with one runtime probe issue: widget_query_failed on widget_packages_installed, because admin is denied read on sys_package_installation.
  • The bare read, the base-named read and /layers serve the override, and /customizations counts overrides 1.
  • The pair was deleted afterwards (200).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions