Repository navigation
QA run · area:ux-conventions (3/3) · 2034975a · 2026-10-16 · 0 PASS / 0 PARTIAL / 3 FAIL / 0 BLOCKED / 0 NOT-RUN #23953
Description
QA run record for the area:ux-conventions slice of the #23878 wave (cloud runner for session session_01K3qUoyh1xFGoWzAACPMbXJ). Text only, per checklist-test §4.
Environment fingerprint
| key | value |
|---|---|
| framework sha | 2034975a47193f04db4791614f4ac9331ff211d3 (main) |
.objectui-sha pin |
daeb77fc84dd824e74c95b87cdede85afdb248e7 |
| console bundle | objectui daeb77fc built against spec a35f7a67^ (34b740f) in a separate worktree (pnpm objectui:build fails on main, #23908); pnpm check:console-sha matches; each FAIL's code path re-checked on objectui main d66ceea5 (still present) |
| boot | isolated boot on port 41751 with its own file DB, objectstack dev --ui --seed-admin, OS_PORT exported |
| personas | seeded admin; member member.ux@example.com minted with admin create-user + change-password (showcase_member_default + member_default) |
| fixtures | scratch package com.qa.uxscratch (object uxscratch_widget "QA Widget", permission sets "QA Readers" / "QA Auditors", app "QA Widget Center" made in Studio); deleted at teardown (DELETE 200, then GET 404) |
| browser | Playwright (Node) + /opt/pw-browsers/chromium, one context per persona, form sign-in, role/ref-targeted clicks, real keyboard typing |
| run window | 2026-10-16 13:10Z – 13:45Z |
| execution | driven by a runner subagent of this session (one of two parallel browser groups); verdicts relayed as text evidence; FAIL code paths re-checked here in objectui source |
Scope
Selector area:ux-conventions → 3 runnable items (no planned, no blocked-hidden items).
| item | revision |
|---|---|
| ux-conventions.write-feedback | 2 |
| ux-conventions.disabled-control-reason | 2 |
| ux-conventions.labels-over-machine-names | 2 |
Per-clause verdicts
| item | # | verdict | evidence (text) |
|---|---|---|---|
| write-feedback | 0 | pass | every write that landed showed feedback within 2 s (variant table); kanban card sits in the column the server read returns |
| write-feedback | 1 | fail | Studio Discard toast reads Draft discarded: object/uxscratch_widget — the raw type/name while the label "QA Widget" exists (2 fresh loads). Not scored as fails: "Task created successfully" (names the object label, not the record) and "Settings saved" |
| write-feedback | 2 | pass | Mark Done declared Task marked done. = shown; Invite User declared Invitation sent to ${result.email} → shown Invitation sent to invitee.ux@example.com |
| write-feedback | 3 | pass | required fields empty: blocked in the browser, no request; inline "Title is required" / "Project is required" + toast "Please check the highlighted fields: Title, Project", no success toast. Broken rule: kanban move PATCH /data/showcase_task/ID {"status":"done"} → 400, toast "Invalid task status transition.", card reverted, no success toast |
| write-feedback | 4 | pass | open Priority editor, re-pick the same value, Esc/click away: no PATCH/PUT, no "modified" / "Save All" (objectui#11816 regression row holds) |
| write-feedback | 5 | blocked(fixture) | no stock surface offers Undo (knownGaps[3]); none appeared in any captured toast |
| disabled-control-reason | 0 | fail | Studio validation editor on the read-only showcase package (Task → Validations → Task Status Flow): 20 disabled controls show no tooltip or adjacent reason on a 1.5 s hover. Every other probed control showed one |
| disabled-control-reason | 1 | fail | not in the tab order and no aria-describedby/title: the validation editor's 20 controls (new) and the field inspector Label / API name / Type / Move up-down (known, objectui#12303). Archive, Publish, Enabled toggle, Remove and import Next pass via a focusable wrapper with aria-describedby |
| disabled-control-reason | 2 | fail | validation editor reason is empty. Elsewhere: Archive generic ("Not available for this record"); Publish / Enabled / Remove / inspector specific ("Read-only package — switch to or create a writable package to edit."); import Next specific ("Can't continue — required field(s) not mapped: Title (title)…") |
| labels-over-machine-names | 0 | fail | (a) Explain access → Principal card chips render org_member, everyone, showcase_member_default, member_default while GET /api/v1/meta/position/org_member → "Organization Member" and GET /api/v1/meta/permission/showcase_member_default → "Showcase Member (Default)"; the result banner reads Read on "uxscratch_widget" is DENIED (label "QA Widget"). (b) Studio Interfaces → object nav item → Properties → LIST VIEW "Columns" chips read title, owner_ref (labels "Widget Name", "Owner Ref"; the "Add field" picker in the same panel shows labels). Both reproduced twice |
| labels-over-machine-names | 1 | pass | Explain principal "Mia Member member.ux@example.com" (id small beneath); record page Created/Updated by "Mia Member"; audit log User "Dev Admin"; approvals Requester "Mei Phone (demo)" |
| labels-over-machine-names | 2 | pass | machine names beside labels are small/muted/monospace: object header chip, permission-set list, Changes panel, Lookup related object, flow trigger object, Display-field and Add-field pickers |
| labels-over-machine-names | 3 | pass | no dotted Zod path or class name in renderer-built text. Not scored: a showcase-authored flow label carries a tracker reference, and the server-built Explain prose cites ADR numbers (accuracy note 5) |
write-feedback variant table
| variant | persona | request → status | feedback verbatim | server read |
|---|---|---|---|---|
| record create | admin | POST /data/showcase_task → 201 | "Task created successfully" | record reads back |
| record create | member | POST → 201 | "Task created successfully" | owner_id = member |
| inline edit (Save row / Save All) | admin | PATCH {"priority":"high"} → 200 | "1 row saved" | priority=high |
| inline edit / bulk delete / kanban move | member | not drivable — member holds no update/delete on showcase_task (direct PATCH 403) | — | — |
| bulk delete | admin | 2× DELETE → 200 after "Delete 2 Task records?" | "Deleted 2 Task records" | both 404 |
| kanban move | admin | PATCH {"status":"todo"} → 200 | card under TO DO | status=todo |
| kanban refused move | admin | PATCH {"status":"done"} → 400 | "Invalid task status transition."; card reverted | status unchanged |
| Mark Done | admin / member | POST /actions/showcase_task/showcase_mark_done → 200 | "Task marked done." | done=true |
| Invite User | admin | POST /auth/organization/invite-member → 200 | "Invitation sent to invitee.ux@example.com" | sys_invitation + sys_email rows |
| approval decision | admin | POST /approvals/requests/ID/approve {"comment":…} → 200 | Approved "EXP-2001" |
approve action with the comment |
| import (2 rows) | admin | POST /data/showcase_task/import → 200 | "Import Complete · 2 created" + "Imported 2 rows." | both rows read back |
| Studio autosave | admin | PUT /meta/object/uxscratch_widget?mode=draft → 200 | "Saved 01:13 PM", "Unpublished draft", "Changes · 1" | draft label changed, active unchanged |
| Studio publish | admin | POST /packages/com.qa.uxscratch/publish-drafts → 200 | "Published 1 item in this package (one atomic release)" | active label changed |
| Studio discard | admin | confirm "Discard the pending draft for object/uxscratch_widget?" → DELETE ?state=draft → 200 | "Draft discarded: object/uxscratch_widget" | draft 404 |
| settings save | admin | PUT /api/settings/localization {"currency":"USD"} → 200 | "Settings saved" | currency USD (tenant) |
disabled-control-reason variant table
| variant | control | hover | Tab | description/title | class |
|---|---|---|---|---|---|
declared disabled (admin + member) |
Archive, header + section | yes | yes (span wrapper) | yes | generic |
| Studio Publish, read-only package | Publish | yes | yes (wrapper) | yes | specific |
| Studio read-only controls | automation Enabled toggle; inspector Remove | yes | yes | yes | specific |
| Studio read-only controls | inspector Label / API name / Type / Required / Move up-down | yes (panel tooltip) | no | none | FAIL-known objectui#12303 |
| Studio read-only controls | validation editor: Type, Severity, rule name, label, message, status field, 10 transition inputs, Runs on, Priority, Enabled | no | no | none | NEW FAIL |
| import wizard, Title unmapped | Next | adjacent banner | yes (wrapper) | yes | specific |
| disabled form submit | none on stock | — | — | — | forms validate on submit |
| member toolbar/bulk | none rendered disabled | — | — | — | gated by removal |
Reproduction rules
write-feedback clause 1 — 1. As admin, make a draft of a scratch-package object (Studio label rename, or PUT /api/v1/meta/object/OBJ?mode=draft&package=PKG). 2. Open /_console/apps/setup/metadata/object/OBJ. 3. Click "Discard draft", accept the native confirm. Expected: a toast naming the label ("QA Widget"). Actual: Draft discarded: object/uxscratch_widget (the confirm also reads …for object/uxscratch_widget?). Source: objectui packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (tFormat('engine.edit.draftDiscarded', …, { type, name })) and i18n.ts key 'Draft discarded: {type}/{name}'; unchanged on objectui main d66ceea5.
disabled-control-reason clauses 0–2 — 1. As admin open /_console/studio/com.example.showcase/data?surface=object%3Ashowcase_task. 2. Click "Validations"; rule "Task Status Flow" opens. 3. Hover the Severity combobox ("error (rejects the save)") 1.5 s: no [role=tooltip]; no title / aria-describedby / tabindex on it or its ancestors. 4. Tab through the page: no form control receives focus. Expected: hover and keyboard reach "Read-only package — switch to or create a writable package to edit." as the Publish button and Enabled toggle do. Reproduced on 2 fresh loads with hover() and coordinate hover, after a screenshot confirmed render.
labels-over-machine-names clause 0 (a) — Studio → any package → Access → Explain access; User = a member, Object = any; Explain. Principal card "Positions:" / "Permission sets:" chips show org_member, showcase_member_default…; labels exist (GET /api/v1/meta/position/org_member → "Organization Member"). POST /api/v1/security/explain returns names only in principal.positions / permissionSets.
labels-over-machine-names clause 0 (b) — In a scratch package: Studio → Interfaces → create an app with "Add this package's objects as menu items"; select the object nav item; Properties → LIST VIEW → "Columns" chips read the field names (title, owner_ref) where the labels are "Widget Name" / "Owner Ref"; no title attribute.
Dispositions: all product defects whose fix lands in objectui — extracted there (see close-out comment).
Derived item verdicts
| item | verdict |
|---|---|
| ux-conventions.write-feedback | fail |
| ux-conventions.disabled-control-reason | fail |
| ux-conventions.labels-over-machine-names | fail |
Fixture gaps
- showcase_task has no create-time validation rule (
task_status_flowruns on update only), so "create with a value that breaks a validation rule" is not drivable; the server-refusal half used the kanban state-machine move. - The stock member persona holds no update/delete on showcase_task, so the member inline-edit, bulk-delete and kanban rows cannot be driven.
- No stock surface disables a submit button (disabled-control variant 5); no Undo anywhere (write-feedback clause 5).
Checklist-accuracy notes (closed out on the wave anchor, not extracted)
- write-feedback knownGaps are stale at daeb77fc: grid Save All now toasts "1 row saved"; Studio Discard now gives feedback (with the machine name above); Approve toasts
Approved "EXP-2001"(declared successMessage nowApproved "${result.request.record_title}"). - write-feedback acceptance[3] expects a 4xx for the required-field case; the console blocks in the browser and sends no request — the oracle should admit that shape.
- write-feedback variants: the "Approvals inbox" link opens the review-queue page, the decision drawer is at
/_console/apps/com.example.showcase/system/approvals; the grid has no "Edit inline" button (double-click + Save row / Save All). - disabled-control-reason knownGaps[1] is stale for Studio Publish and import Next — both keyboard-reachable with a description now.
- labels-over-machine-names knownGaps[0] (objectui#11862) is mostly stale (permission-set list, Changes panel, Display-field picker now pass) and the server-authored UI text (family card): the approvals drawer's Approve says only "Approved.", and Explain access's Principal resolution prose names the user by raw id #23157 principal-prose row looks fixed ("Principal Mia Member (member.ux@example.com; id …)"); clause 3 does not say whether ADR references in server prose or tracker ids inside authored labels count.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 16, 2026
Close-out for this record (checklist-test §5), 2026-10-16T18:19Z. 0 pass · 0 partial · 3 fail of 3. Every
failis a product defect whose fix lands in objectui. Each is extracted there:The cards cover these defects:
type/nameinstead of the label.The fixture gaps (no stock Undo, no disabled submit, no create-time validation rule, member persona without update/delete) and the five checklist-accuracy notes close out on #23878. Closed by the
domain:devxseat 1 PM (seat post #6023) ·os-sales·session_014eFvbvGK4FjXvscggDNTD4, as part of the paced close-out of the #23878 wave.Generated by Claude Code