Repository navigation
QA run · surface:browser (61/61) · 316be321 · 2026-10-04 · 38 PASS / 8 PARTIAL / 15 FAIL / 0 BLOCKED / 0 NOT-RUN #21782
Description
17.7 pre-release verification, browser half: every runnable surface:browser item against origin/main as it stood when the browser run started, with the Console built from the bumped pin (#21710). 17.7 is not cut yet, and the packages still read 17.6.0. The non-browser half is #21720 (subject 251a7dd4). surface:mixed gets its own record against the same subject. Text only. Screenshots were consulted live as oracles and are not attached. The durable truth stays in docs/qa/platform-checklist/areas/.
Environment fingerprint
- Framework (subject):
objectstack-ai/objectstack316be321(fix(runtime)!: an app-authored body may not read the stored-metadata tables; it reaches them through the metadata API only (#21594) (#21660)). This is 25 commits past251a7dd4and includes the console pin bump chore(objectui): bump the console pin to 2e818d0b51ec (carries objectui#11466, #11574, #11578, #11581 and #11583) #21710. It ran in a dedicated detached worktree. Framework and console both built, and a smoke boot answered health 200 and/_console200. - Console: built from objectui pin
2e818d0b51ec(.objectui-sha, chore(objectui): bump the console pin to 2e818d0b51ec (carries objectui#11466, #11574, #11578, #11581 and #11583) #21710). Every lane checked that the dist stamp equals the pin. Console source questions were read at that revision (git show 2e818d0b51ec:{path}). For the "predates 17.6.0" notes, the 17.6.0 references are framework617f25f8aand objectui pin31971ff1e. - Checklist: items,
RUNNER.mdandscripts/checklist-select.mjscome from the subject tree. The table gives every item's revision, and each one matchesareas/*.json. - App / boots:
examples/app-showcasebooted withOS_PORT={p} objectstack dev --ui --seed-admin -p {p} -d file:/tmp/qa1770fe/{lane}/{item}.db. Each item had its own file DB, and lanes used disjoint port ranges inside 44101–45909 (the egress proxy port 41333 was excluded). The browser was Playwright on/opt/pw-browsers/chromium. Admins signed in through the console form, so both the bearer and the cookie halves existed. Members were minted with admininvite-member+sign-up/emailor withadmin/create-user+change-password. Identity was proven withGET /auth/get-sessionbefore each persona cell. Scratch fixtures were authored at runtime inside each item's own DB, or in a scratch copy of the showcase under/tmp. - Deviations, stated:
- CRM package in the shared tree. Lane FE2 installed the CRM package (
os package install, needed for the marketplace item) into the shared subjectexamples/app-showcase/.objectstack/installed-packages/from 12:28 to 12:36Z. FE1's boots on 44105–44108 (account-app-entry, docs-portal-render, home-admin-cluster-links, url-overlay-contract) started in that window and registeredcrm_appnext to the three stock apps. None of their clauses depends on the app list, so the clauses are unaffected. FE2 removed the package through the API, and lanes were ordered from then on to install only into scratch copies. - One shared DB in FE2. Seven FE2 items ran on one boot with one shared
main.db: keyboard, theme, installability, palette, ai-gating, api-console, and marketplace boot A. As a result, the api-console tree also listedData: crm_*groups. - Port moved in FE4. One FE4 item moved from 44408 to 44409 because the session process held 44408 as an outbound ephemeral port.
- CRM package in the shared tree. Lane FE2 installed the CRM package (
- Execution: this selector was run by six parallel runner subagents (FE1–FE6). Independent verifiers VF1–VF4 checked the results under RUNNER rule 7, and VF3 and VF4 re-derived every fail in this selector. Everything ran in Claude Code session
session_018zT8d8NpiQ1ExhuNd5TxY6. The lanes ran on 2026-10-04 from 12:06Z, and verification finished on 2026-10-05. After an earlier overload of the box, concurrency was capped at three lanes (a maintainer order), with verifiers counted as lanes. Tier-1 pins that live in this repository were run and are cited in the table. Items whoseautomated.reflives only in objectui were driven by hand as manual browser runs (RUNNER environment facts, option a).
Scope
node scripts/checklist-select.mjs surface:browser --json returned 61 runnable items. One item is hidden as blocked and was not run: approvals.quorum-m-of-n. The selector returned no planned items. All 61 items received a verdict.
| item | rev | verdict | evidence (server truth / browser) |
|---|---|---|---|
| access-security.share-link-landing-page | 1 | PASS | anonymous context: redacted fields absent from the record and named in the notice; password, revoked / expired (410), invalid (404) and signed-in legs render their own states; no shell, form or session in the anonymous context (hand-driven, the pin is objectui-only) |
| ai.console-ai-surface-gating | 1 | FAIL | A4 stale clause (SystemHubPage retired, objectui#10507); A6 known expected-fail K2 (empty-queue state under the 501 alert, 5 s poll never backs off); A1–A3, A5 pass, entitled side blocked(fixture) as the clause prescribes |
| api-backend.api-console-discovery-execute | 1 | PASS | groups follow /discovery; List showcase_task 200 equals a direct GET; 404 RECORD_NOT_FOUND and 400 VALIDATION_FAILED shown verbatim from the wire |
| approvals.per-group-signoff | 6 | PASS | per_group finance / manager tallies match the API at every stage; the run stays paused until the last group decides; a foreign actorId is refused 403 |
| approvals.inbox-metadata-actions | 3 | FAIL | A2: Recall is also offered to an override actor (admin) on another submitter's request, by design (#3424 / #12716) — stale clause; a non-override approver sees neither; A1, A3–A5 pass |
| approvals.viewer-gating-submitter-side | 6 | PASS | submitter sees only Send reminder / Recall; can_act=false; forged approve / reject 403 and the reads before and after are byte-identical |
| approvals.notification-deep-link | 4 | PASS | reminder action_url opens the drawer on 2 cold loads via both routes; an unknown id answers 404 with the named toast |
| approvals.record-page-decisions | 1 | PASS | Approve / Reject lead the header; one dialog and exactly one POST; lockRecord gates inline edit; reassignment moves the buttons |
| approvals.account-app-entry | 2 | PASS | bundle (stamp = pin) carries the approvals:inbox contribution; drawer approve round-trips; deep link opens; zh-CN labels hold (objectui#11326 fixed) |
| approvals.setup-nav-entry | 1 | PASS | served group_approvals order equals the sidebar; lands on the inbox component; zh-CN labels; nav-contribution pin 1/1 |
| approvals.pending-count-surfaces | 1 | PASS | badge "9+"; popover, Home card, My Pending tab and API agree (6 → 5 after one decision) |
| approvals.inbox-keyboard-flow | 1 | PASS | j / k / arrows clamp; r / a open one dialog and send one POST on confirm; inert in search, drawer, alertdialog and on dynamic-approval rows |
| attachments-storage.inline-grid-receipt-cells | 3 | PASS | one Receipt file cell; presigned → PUT → complete; the atomic batch stores the bare id; sys_file committed with ref_object / ref_id / ref_field |
| automation.screen-flow-roundtrip | 3 | PASS | trigger → paused at collect; screen dialog; resume completes and the task reads the new assignee; empty inputs 400, Cancel sends nothing |
| automation.setup-packaged-automation-board | 2 | PASS | 30 rows = 30 packaged flows; toggle persists to the activation ledger; 409 / 403 sentences verbatim; setup-packaged-automation-nav pin 4/4 |
| dashboards.chart-first-paint | 2 | PASS | cold load draws bars and axes on Chart Gallery and Delivery Operations; 5 bars = 5 statuses; hero tiles equal the data API |
| dashboards.drill-through-range | 2 | PASS | month, status and matrix drills each send their own bounds; drawer counts equal the aggregate |
| dashboards.chart-type-matrix | 4 | PASS | 20 variants judged per widget, counts match the API; coverage 13/13 · dashboard-compareto 17/17; A8 comparison renders (its "vs yesterday" label is a defect outside the clauses, extracted) |
| dashboards.global-filters-rescope | 2 | FAIL | A6: the named at-risk tile opts out of task_status by design (#7568) — stale clause; the composing tile kpi_awaiting_review shows the API intersection; A1–A5, A7–A9 pass |
| i18n.notification-localized-and-clears | 3 | PASS | interpolated title in zh chrome; deep link renders zh; read clears server-side and survives a hard reload; EN control |
| i18n.studio-follows-app-locale | 3 | FAIL | A3: under the language-only zh code dates render in the browser's language — held (verifier unconfirmed, re-run owed); A1, A2, A4, A5 pass |
| i18n.surface-matrix | 4 | FAIL | A1 relative-dates variant (the same held finding); A2–A5, A7–A11 pass; A6 toast half pass, confirm half blocked(fixture: no zh confirmText) |
| identity-auth.sso-enforced-first-paint | 2 | PASS | enforced boot never paints the password form (80 ms sampling, 2 loads); 20 s watchdog re-enables the button; unenforced restart shows the form |
| identity-auth.phone-signin-surfaces | 2 | PARTIAL | A2 / A3 blocked(fixture: features.phoneNumber false, no runtime lever); A1, A4 pass |
| integration-system.flow-connector-picker | 3 | PASS | picker offers exactly the 5 served connectors with origin tags; MCP action input rendered from inputSchema |
| platform-core.console-login | 4 | PASS | sign-in, reload, server sign-out → 401 on bearer and cookie, login redirect, re-login to the same route; wrong password sets nothing |
| platform-core.nav-surfaces-render | 5 | PASS | showcase-smoke 49/49; 49 nav leaves = SURFACES both ways; unknown object renders a named not-found in the live shell |
| platform-core.builtin-apps-nav-render | 4 | PASS | Setup 45/45 and Account 8/8 walked; member refused Setup in the UI and the API; marketplace catalog content blocked(environment: egress) |
| platform-core.shell-nav-personalization | 1 | FAIL | A3: no drag-reorder on any grouped navigation (every stock app) — product defect; A1, A2, A4–A6 pass |
| platform-core.marketplace-console-honesty | 1 | FAIL | A3: offline Details dead-ends on the Disabled card, reseed / purge unreachable — product defect; A4 member gets the Disabled card by design (objectui#5557) — stale clause; A1, A2, A5 pass |
| platform-core.docs-portal-render | 1 | FAIL | A5: no /home sidebar Documentation entry for any persona (the Help menu is the entry) — assertion defect; the member tree mirror holds; A1–A4, A6 pass |
| platform-core.url-overlay-contract | 1 | PASS | drawer / tab / form overlays push and pop history as specified; deep tabs; formLink pre-link; breadcrumbs; object-mismatch refusal |
| platform-core.keyboard-shortcut-surface | 1 | FAIL | A3 / A4 known expected-fail (K1a bare B, K1b five dead accelerators), still present; A5 blocked(fixture) as prescribed; A1, A2 pass |
| platform-core.home-admin-cluster-links | 1 | FAIL | A2 / A4 stale clause (SystemHubPage retired, objectui#10507); A5 assertion defect (no /home nav); A1, A3 pass by URL |
| platform-core.theme-mode-persistence | 1 | PASS | dark / light / system persist (key object-ui-theme); auto resolves per emulation; dark screen coherent |
| platform-core.console-installability-indicators | 1 | PARTIAL | A3 error leg not-run (the connection chip cannot be provoked into its error state); A1, A2, A4 pass |
| records-forms.crud-roundtrip | 8 | PARTIAL | A7 readonly half blocked(fixture: no stock readonly column is settable over HTTP); create / edit / delete diffs, History, CJK round-trip and the member gate pass |
| records-forms.list-view-capabilities | 1 | PASS | showcase-search 5/5; 11 variants hand-driven; export through a runtime allowExport grant (export is opt-in) |
| records-forms.view-type-gallery | 1 | FAIL | A2: kanban per-column summarizeField totals never render — product defect; smoke 49/49; every other variant passes |
| records-forms.form-view-gallery | 1 | FAIL | A1 drawer variant renders as a centred modal by design (RecordFormPage fallback, #1890 / ADR-0050) — assertion defect; modal blocked(fixture) as prescribed; A2–A5 pass |
| records-forms.conditional-rules-grid | 2 | FAIL | A5: an untouched sibling re-emits position only when siblings share a stored position (fixture-created) — invalid pairing; holds on stock INV-1001; A1–A4 pass |
| records-forms.master-detail-atomic-save | 3 | PASS | one atomic batch with $ref; server roll-up equals the line sum; an invalid child aborts the whole batch |
| records-forms.related-list-server-pagination | 4 | PASS | server paging, 26/26 distinct; relatedList config honoured; read gate both sides (403 / 200) |
| records-forms.upload-guard-blocks-confirm | 2 | PASS | Confirm disabled mid-flight; dispatch carries the file id; maxSize refused before the wire |
| records-forms.import-wizard-encoding-and-hints | 4 | PARTIAL | A3 blocked(dependency: the legacy per-row path is absent on a live server, pin objectui-only); GBK decode, required hint, server rows pass |
| records-forms.action-location-matrix | 6 | FAIL | A1: the fixture hosts no record_header / record_more / record_related surface for showcase_task — invalid pairing; A3 url / api legs blocked(fixture, same cause); A2, A4, A5 pass |
| records-forms.gantt-interactions | 2 | PARTIAL | A2 / A3 blocked(fixture: no dependenciesField; lockField is not a spec key); drag persists, a 403 veto rolls back |
| records-forms.kanban-drag-persistence | 1 | PASS | drop → PATCH, survives reload; an invalid transition 400 snaps back with a toast |
| records-forms.form-dirty-guard | 2 | PARTIAL | A3 not-run (pin discardGuard.test.tsx is objectui-only); A1, A2 pass hand-driven |
| records-forms.adhoc-filter-sort-builder | 2 | PASS | toolbar filter ANDs with the view filter (2 rows = API); restored per user; uf_ params deep-link |
| records-forms.calendar-interactions | 2 | PASS | drag PATCH persists; read-only 403 snaps back; month / week / day match the API; A4 on a scratch view (stock quick-create cannot satisfy the required project) |
| records-forms.record-discussion-mentions | 3 | PASS | comments-permission-matrix 10/10; a mention notifies only the mentioned user; FEEDS_DISABLED 403 on create and re-thread |
| records-forms.grid-personalization | 2 | FAIL | A2: row height lost on reload (console PUT shape; the server drops the misplaced key) — product defect; A1 resize pass, reorder / pin blocked(fixture); A3–A5 pass |
| records-forms.saved-view-management | 1 | PASS | draft + publish create; rename / default / pin / delete persist; member sees no controls and is refused 403 server-side |
| records-forms.bulk-select-all-matching | 2 | PARTIAL | A5 not-run (the 5000 cap is unreachable with 26-row sets); select-all-matching fan-out and dispatch pass |
| records-forms.lookup-picker-create-new | 2 | PASS | create-new from the picker; parent carries the child id; debounced server search; no create on the sys_user lookup |
| records-forms.record-edit-undo | 2 | PASS | undo is a real PATCH via toast, Ctrl+Z and Ctrl+Shift+Z; new audit rows; A4 observe-and-flag: undo overwrote a concurrent edit with no conflict signal, recorded as the clause asks |
| records-forms.script-action-hook-refusal-toast | 1 | PASS | 400 hook sentence in exactly one error toast; no state change; showcase + runtime refusal pins 5/5 + 5/5 |
| search.command-palette-navigation | 1 | PARTIAL | A5 blocked(fixture: no nav item with a visibility predicate); A1–A4, A6 pass |
| studio-authoring.packaged-automation-studio-lock | 1 | PASS | read-only package: no New, inert canvas and switch, forged PUT 403 NOT_OVERRIDABLE / ITEM_LOCKED, flow byte-identical |
| studio-authoring.packaged-display-class-direct-edit | 1 | PASS | view and dashboard overlays edit and go live without restart, reset to a byte-identical baseline; flows stay locked |
Totals: 38 PASS / 8 PARTIAL / 15 FAIL / 0 BLOCKED / 0 NOT-RUN. The 15 fails break down as follows:
- 4 carry a verified product defect, all in the objectui console and all predating 17.6.0. One of the four, marketplace-console-honesty, also carries a stale clause.
- 2 are held: the runner observed a fail and reproduced it, but the verifier could not confirm the mechanism, so no card is filed and a live re-run is owed.
- 1 is a known expected-fail probe only (keyboard-shortcut-surface, K1a / K1b).
- 8 fail on checklist clauses only. ai-gating's A6 there is also the known expected-fail K2.
One more defect lies outside the clauses (dashboards.chart-type-matrix, which passes) and is extracted with the four.
Every fail was re-derived by an independent verifier (VF3 or VF4). Where a verifier changed a disposition, the verifier's is recorded:
- VF4 upgraded shell-nav-personalization A3 from assertion-defect to product defect.
- VF3 refuted form-view-gallery A1 as a product defect (now assertion defect) and conditional-rules-grid A5 (now invalid pairing).
- VF4 refuted action-location-matrix A1 (now invalid pairing).
- VF3 ruled that chart-type-matrix A8's clause holds and the mislabel lies outside it.
- VF4 recorded inbox-metadata-actions A2 and global-filters-rescope A6 as stale clauses.
One item verdict is derived differently from its lane's summary: form-dirty-guard is PARTIAL rather than pass, because its A3 pin is objectui-only and was not run (RUNNER per-item derivation).
Fails — reproduction rules and dispositions
Product defects
platform-core.shell-nav-personalization A3 {card-1}: drag-reorder is never offered on grouped navigation, and every stock app's navigation is grouped.
- Server truth: the served
GET /api/v1/meta/app?id=showcase_appnavigation is grouped (8 groups), and so are the Setup and Account navigations. - Browser:
- Sign in as admin.
- Open
/_console/apps/showcase_app/showcase_task. - Hover and try to drag any sidebar entry.
- Expected: a grip, and an order that is restored after reload (useNavOrder, localStorage
objectui-nav-order-showcase_app). - Actual: 0
[aria-label="Drag to reorder"], no sortable, and the localStorage key is never written. Seen on two loads. - Root cause (VF4):
- objectui
NavigationRenderer.tsx:1590computeshasGroups. - The DndContext / SortableNavigationItem path exists only in the
!hasGroupsarm (:1614-1631). The grouped arm (:1650ff.) renders plain items. UnifiedSidebar.tsx:583passesenableReorder={!isMobile}unconditionally.useNavOrderpersists only__root__.
- objectui
- Predates 17.6.0: identical at objectui
31971ff1e. - Verifier VF4: CONFIRMED, P3. If the maintainers rule that reorder is meant for flat navigation only, the clause becomes an assertion defect; VF4's corrected wording is with the re-point.
platform-core.marketplace-console-honesty A3 {card-2}: on an offline boot, the installed package's Details page is a dead end, so reseed and purge cannot be reached from the console.
- Server truth:
- Boot with
OS_CLOUD_URL=off./runtime/configreportsmarketplace:false. os package install examples/app-crm/dist/objectstack.json -r http://localhost:{p}. Installed Apps then listscom.example.crmv4.0.0.
- Boot with
- Browser:
- Go to Setup → Installed Apps. The row offers Refresh / Details / Uninstall.
- Click Details. It opens
/system/marketplace/com.example.crm.
- Expected: reseed / purge affordances that issue
POST /api/v1/marketplace/install-local/com.example.crm/{reseed,purge}-sample-data. - Actual: the page renders "App Marketplace is turned off" and makes 0 install-local wire calls. Seen twice.
- Root cause (VF4):
- objectui
InstalledListWidget.tsx:155links Details to/system/marketplace/:packageId. MarketplacePackagePage.tsx:568returns theMarketplaceDisabledcard before the page reaches its local reseed/purge menu (:752).
- objectui
- Predates 17.6.0: identical at objectui
31971ff1e. - Verifier VF4: CONFIRMED, P3.
- Related: the endpoint behind the purge affordance has its own defect, marketplace: install-local purge-sample-data always answers 500 DRIVER_UNAVAILABLE (looks up a bare "driver" service nothing registers) — and seed records carry no id to purge by #21728 (purge answers 500), which is scored by the api lane.
records-forms.view-type-gallery A2 {card-3}: the kanban board never renders its summarizeField per-column totals.
- Server truth:
- The fixture board
showcase_task.boarddeclares{groupByField:'status', summarizeField:'estimate_hours'}(examples/app-showcase/src/ui/views/task.view.ts:262-275). - Summing
estimate_hoursper status overGET /api/v1/data/showcase_taskgives backlog 30 / todo 36 / in_progress 100 / in_review 54 / done 24.
- The fixture board
- Browser: as admin, open
/_console/apps/com.example.showcase/showcase_task/view/showcase_task.board. - Expected: those five totals in the column headers.
- Actual: the headers show only the count badge ("BACKLOG 2" … "DONE 2"), and the board's data request selects no
estimate_hours. Seen twice by the runner and twice by the verifier, all on fresh loads. - Root cause (VF3):
- Nothing in objectui
packages/plugin-kanban/srcreadssummarizeField(column header aroundKanbanImpl.tsx:1066-1100). - The only consumers,
plugin-list/src/ListView.tsx:2002and:2517, add the field to the projection. - The spec declares the key at
packages/spec/src/ui/view.zod.ts:1789with no liveness verdict, making it an ADR-0049 declared-but-unenforced key.
- Nothing in objectui
- Predates 17.6.0: no reader at objectui
31971ff1eeither. - Verifier VF3: CONFIRMED, P3.
records-forms.grid-personalization A2 {card-4}: the row height (density) is lost on reload.
- Browser:
- As admin, open
/_console/apps/com.example.showcase/showcase_task. The runner also used…/view/showcase_task.grid. - Click "Density: Compact (click to cycle)". It changes to "Comfortable" and rows go from 41 px to 45 px.
- As admin, open
- Server truth:
- The console sends
PUT /api/v1/meta/view/showcase_task.defaultand gets 200 "Saved customization overlay". - The body is the whole served item (
config{…},_provenance,scope,_diagnostics) with a flat top-level"rowHeight":"medium". - Afterwards,
GET /api/v1/meta/view/showcase_task.defaultcarries norowHeight, either at top level or inconfig. - A reload in a fresh context shows "Density: Compact" again.
- The console sends
- Expected: the chosen row height survives reload.
- Control: the same item PUT with
config.rowHeight:"tall"reads back"rowHeight":"tall". - Root cause (VF3):
- objectui
packages/app-shell/src/views/ObjectView.tsx:1181buildPersistedViewBodyspreads the patch at the envelope top level instead of intoconfig, for views the switcher classes as saved views. - The framework save door stores only the declared keys of a view body (ADR-0005 appendix (c)), so it drops the misplaced key while still answering 200. Dropping it is by design, so the fix belongs to the client.
- VF3 adds a design note: a 200 that silently discards an undeclared envelope key is a silent-loss shape, and a save diagnostic would have surfaced it.
sortandhiddenFieldspatches probably take the same path (not driven).
- objectui
- Predates 17.6.0: identical at objectui
31971ff1e. - Verifier VF3: CONFIRMED, P2.
dashboards.chart-type-matrix, outside the item's clauses {card-5}: a previousPeriod comparison on the dataset path is labelled "vs yesterday". Clause A8 passes because the comparison renders; only the label is wrong.
- Server truth:
- As admin,
PUT /api/v1/meta/dashboard/qa_compareto_probe?mode=draftwith:dateRange:{field:'created_at', defaultRange:'last_30_days'};- a metric widget on dataset
showcase_task_metrics,values:['task_count'],compareTo:{kind:'previousPeriod'}.
POST …/publish.- The dataset query shifts the whole 30-day window (
timeDimensionsdateRange[2026-09-04, 2026-10-04],task_count__compare: 1).
- As admin,
- Browser: open
/_console/apps/showcase_app/dashboard/qa_compareto_probe. - Expected: "vs previous period".
- Actual: the metric shows "9 ↑800%" with the label "vs yesterday", and the line legend reads "Tasks · vs yesterday".
- Root cause (VF3):
- objectui
packages/core/src/utils/compare-to.ts:124-136compareToTrendLabelKeyderives the label by regex-sniffing the raw filter for macro tokens (today→vsYesterday). plugin-dashboard/src/DatasetWidget.tsx:1097reuses it on the ADR-0021 dataset path, where the executor shifts the dimension window (service-analyticsdataset-executor.ts:810-819shiftRange).- The heuristic is only right on the inline path.
- objectui
- Predates 17.6.0: the same code is at objectui
31971ff1e. - Verifier VF3: CONFIRMED by code (not live-driven). P3.
- Evidence strength: the runner observed it once.
Held: observed, not verified, not extracted
i18n.surface-matrix A1 (relative-dates variant) and i18n.studio-follows-app-locale A3: dates render in the browser's language when the app locale code is the language-only zh.
- Server truth:
GET /api/v1/i18n/translations/zh-CNis the expectation set. - Browser:
- Fresh boot. Create a Chromium context with
locale:'en-US'. - Set
localStorage['objectui-locale']='zh'before the first load. This is the codei18n.notification-localized-and-clearstells runners to write. - Sign in as admin and open
/_console/apps/showcase_app/showcase_task.
- Fresh boot. Create a Chromium context with
- Expected: date cells in zh, like the rest of the page.
- Actual:
- Headers are zh, but due-date cells read "Sep 16", "Oct 24", "In 3 days" next to "逾期 6 天".
- The record page reads "截止日期 Sep 16" next to "创建于 20天前".
- The bell's activity tab reads "12 seconds ago".
- Discriminators:
- The same
zhsession in a zh-CN browser renders 9月16日 / 3天后. - The code
zh-CN(what the LocaleSwitcher writes) renders zh in an en-US browser. html langiszhin the failing case andzh-CNin the passing one.- Flipping the tenant locale has no effect (A/B on the same boot).
- The same
- Reproduction count: 2 fresh boots × 3 loads.
- Studio-specific note: Studio's own timestamps follow the app locale under
zh-CN. The studio clause fails only through the shared formatter. - Verifier VF3: UNCONFIRMED.
- The code contradicts the stated mechanism.
useDisplayLocalepasseszhtoIntlverbatim, and the date-fns resolution maps it to zh-CN. - VF3 did not render live.
- VF3 found a different possible cause: an unconfigured tenant's
en-USdefault fromGET /api/v1/auth/me/localizationoutranks the UI language. A tenant locale ofzhitself is refused by settings.
- The code contradicts the stated mechanism.
- Disposition: held. The observation stands, the mechanism is disputed, and no card is filed. A live re-run of both items is owed (RUNNER rule 7). If the observation stands, the defect belongs to the objectui console. It predates 17.6.0 by code.
Checklist clauses (no product defect)
| item · clause | disposition | what holds instead | source |
|---|---|---|---|
| platform-core.docs-portal-render A5 | assertion defect | /home has no sidebar for any persona. Every persona reaches Documentation through the top-bar Help menu → "All documentation" → /docs. The member's rendered tree equals the member API subset, and every entry opens without 401/403 (that half passes) |
objectui HomeLayout.tsx:1-6 "deliberately omits the sidebar"; AppHeader.tsx:758-793; pre-17.6.0 |
| platform-core.home-admin-cluster-links A2 / A4 | stale clause | the System hub card wall and its count badges were deleted. /apps/:app/system redirects in one hop to /system/settings, and every Settings-hub entry resolves |
objectui 9eea12a2b (objectui#10507, fixes objectui#3743), landed before 17.6.0 |
| platform-core.home-admin-cluster-links A5 | assertion defect | no persona gets a /home nav. A member's shell offers no Administration entry anywhere, and the server refusal is proven by builtin-apps-nav-render |
same root as docs-portal-render A5 |
| platform-core.marketplace-console-honesty A4 | stale clause | on a features.marketplace=false boot every viewer, member included, gets the MarketplaceDisabled card. On the enabled boot a member gets access-denied (holds) |
objectui d524bde29 (objectui#5557 via #5582), 2573ff434; before 17.6.0 |
| ai.console-ai-surface-gating A4 | stale clause | no settings hub, nav or Home surface advertises "AI Approvals" on an agent-less boot. The bare /system/ai-approvals route is scored by A6 |
objectui 9eea12a2b (#10507) |
| records-forms.form-view-gallery A1 (drawer variant) | assertion defect | the record form page falls back from drawer/modal to simple on purpose: they are presentation modes, not layouts. A JSX ObjectForm formType="drawer" (Task Desk) renders a real side panel. Named formViews.* are reachable from no console door |
objectui RecordFormPage.tsx:281-289 (#1890), ADR-0050 (Proposed) |
| records-forms.conditional-rules-grid A5 | invalid pairing | on stock INV-1001 (positions 0, 1), editing one line sends only that line. Untouched siblings are byte-identical (VF3 live). The position re-emit happens only when sibling lines share a stored position, and a second line added through the API defaults to position 0, so the collision comes from the fixture |
objectui GridField.tsx:703-707 + masterDetailTx.ts:180-195; INV-1002 ships a single line |
| records-forms.action-location-matrix A1 | invalid pairing | objectui#11270 is in the pin. The showcase hosts none of record_header / record_more / record_related for showcase_task: the task page is kind:'full' with no record-header node (objectui#7298 ruling: "a page is what its author composes"), and the project page replaces the related strip with line items |
fixture task-detail.page.ts, project-detail.page.ts; pre-17.6.0 |
| approvals.inbox-metadata-actions A2 | stale clause | Recall is offered on the viewer's own request and, for an override actor (platform/tenant admin), on any pending request. A non-admin approver (control persona Ada) sees neither Recall nor Send reminder on another submitter's request | sys-approval-request.object.ts:568-591 (#3424 lever, button #12716); clause rev 3 predates it |
| dashboards.global-filters-rescope A6 | stale clause | kpi_at_risk opts out of task_status (filterBindings:{task_status:false}) by design. The tile that composes (kpi_awaiting_review, status=in_review) shows the API intersection: 0 under In Progress, 2 under In Review |
ops-dashboard.dashboard.ts:87 (#7568), pinned by dashboard-filter-vocabulary.test.ts:230 |
Known expected-fail (not re-filed)
- platform-core.keyboard-shortcut-surface A3 / A4: defects K1a and K1b, owned by the 2026-08-30 sweep's follow-ups. Both are still present at the pin.
- A3 (K1a): bare B leaves the sidebar expanded while the dialog advertises "B". Only ⌘/Ctrl+B is handled.
- A4 (K1b): each advertised ⌘/, Ctrl+/, N, R, Ctrl/Meta+E and Ctrl/Meta+D was probed on
/_console/apps/showcase_app/showcase_taskwith focus on the body. None changed the URL, focus, dialogs, the root class or data. Seen on two fresh loads. - Verifier VF4: confirmed.
KeyboardShortcutsDialog.tsx:49lists bareB,sidebar.tsx:42,122requires the modifier, and no handler exists for the five advertised accelerators.
- ai.console-ai-surface-gating A6: defect K2, from the same follow-ups row.
- Repro: sign in as admin through the form, open
/_console/apps/setup/system/ai-approvalsand watch for 15 s. - Observed: "No actions waiting" renders under the 501 error alert, and
pending-actionsis re-polled at about +0, +4.9 and +10 s with no backoff. Seen on two runs. - Verifier VF4: confirmed at the pin (
AiPendingActionsInbox.tsx:327/:373,usePendingActions.ts:294-295).
- Repro: sign in as admin through the form, open
Partial-coverage gaps (named, not dropped)
records-forms.crud-roundtripA7 readonly half: blocked(fixture). No stock readonly column can be set over HTTP; the server answersx-objectstack-dropped-fields: lead_score;reason=readonly.platform-core.console-installability-indicatorsA3 error leg: not-run. The connection chip tracks only the initial discovery (see candidates).search.command-palette-navigationA5: blocked(fixture). No stock nav item carries a visibility predicate.identity-auth.phone-signin-surfacesA2 / A3: blocked(fixture).features.phoneNumberis false, andplugins.phoneNumberis code config with no runtime setting.records-forms.import-wizard-encoding-and-hintsA3: blocked(dependency). The legacy per-row path exists only when the data source lacksimportRecords, the live server always has it, and the pin is objectui-only.records-forms.gantt-interactionsA2 / A3: blocked(fixture). The stock view has nodependenciesField, andlockFieldis not a GanttConfig key.records-forms.form-dirty-guardA3: not-run. ThediscardGuard.test.tsxpin exists only in objectui.records-forms.bulk-select-all-matchingA5: not-run. Match sets of 26 and 10 cannot reach the 5000 cap.- Blocked legs inside judged items:
records-forms.grid-personalizationA1 reorder / pin:reorderableColumnsis off, and there is no runtime pin control.records-forms.action-location-matrixA3 url / api dispatch: the fixture hosts no ⋯ surface.i18n.surface-matrixA6 confirm half: no zhconfirmText.platform-core.keyboard-shortcut-surfaceA5 and theai.console-ai-surface-gatingA2 entitled side: blocked(fixture) as their clauses prescribe.- Marketplace catalog content (
builtin-apps-nav-render,marketplace-console-honestyboot A): blocked(environment), because egress to the catalog is denied.
Fixed since the last run
- objectui#11326 (the account-app approvals entry stayed English under zh-CN) no longer reproduces.
approvals.account-app-entryA7 holds on two loads (待我审批 / 我发起的 / 全部).
Candidates — not verified, not extracted
Each of these was seen by a runner outside the clauses. They are low severity or possibly by design, and they are listed so they are not lost:
GET /api/v1/data/{object}?top=0answerstotal:0whiletop=1gives the real total, and the console sendstop=0as its record-count probe. Two lanes saw it (FE3, FE4).- A malformed JSON body on
POST /api/v1/data/showcase_taskis treated as an empty body: the answer is 400 "Title is required; Project is required", not a parse error. - CSV export renders booleans as hard-coded 是 / 否 regardless of locale, under English headers.
- On New, select options marked
default: trueare not pre-selected (invoice status / region), so "Status is required" blocks create. Separately, an edit save wroteregion:"amer"into a row whose region was null. - A wizard default form renders flat, with no step chrome, in the New modal. Only the
/newpage route honours it. - The action-param dialog is taller than the viewport with no scroll (top at y=-198), so Confirm cannot be reached at 1440×900 or 1600×1200.
- The Log Time form dispatch leaves the app shell, heads the page with the raw target "showcase_task.form", and toasts "Action completed successfully" before any submit.
- Line amounts are computed in floating point and never rounded (3598.7999999999997).
- Related-list pages and inline-grid child fetches carry no sort, so their page order relies on natural order.
- The Field Zoo row tint does not paint the frozen #/Name columns.
- Record History shows a currency change unformatted ("— → 4250000"), while the grid shows "$4,250,000.00".
- After the submitter has approved as an approver, the approvals drawer still says "only the assigned approvers can approve or reject".
- The approvals drawer opened on an unknown
?request=id leaves an empty "Approval Request" sheet behind the correct toast. showcase_invoiceshows two fields both labelled "Owner" (the systemowner_idand its ownowner).- The record feed shows an admin's PATCH as authored by "System". The
inlineEditgrid renders two "Actions" header columns. - Deleting the view set as default leaves the object with no default view.
- The home-navigation block in
UnifiedSidebar(Home, Documentation, the Administration cluster) has no rendering surface. VF4 also notes this and suggests an item revision rather than a defect. - A cross-reference inside the app-scoped docs reader leaves the app container for
/docs/…. - Every console page logs
404 GET /api/v1/usage/storage. - Selecting a theme command in the palette (Dark / Light / System) leaves the palette open. Navigation commands close it.
- The connection chip shows nothing after a backend loss mid-session. A single aborted
/api/v1/discoveryat load strands the splash at "Preparing workspace" for 45 s or more, with no retry and no error. - The PWA manifest icon type is hard-coded
image/svg+xmleven when the favicon is a PNG. - On SSO-enforced boots, LoginForm briefly renders "Sign up" during the config-loading frame. An unenforced
invite_onlyboot shows "Don't have an account? Sign up", which leads to the 403. - Recents use humanized names ("Showcase Hours By Status") instead of nav labels.
- Every navigation PATCHes
sys_user_preference(recents), which floods the bell activity feed with "更新了 用户偏好". - The
sys_userlist "updated" cell renders date and time with no separator (10/4/20263:22 pm). - On the read-only Studio Automations pillar, a mouse click on a flow node never opens the inspector, while keyboard Enter does.
- The connector picker keeps the previous connector's action and input map after a connector switch.
ResourceHistoryPagehard-codes English ("Back to item", "by …") on a zh session.- The view designer says "This view has no object binding yet" on
showcase_task, while its Object field reads "Task". - The first click of a custom date range commits a one-day query before the second click.
- For dates, an unconfigured tenant's
en-USdefault (/auth/me/localization) may outrank the UI language. This is VF3's alternative reading of the held zh-date finding and needs a live render. - The spec still declares
FormView.typedrawer/modalanddrawerSidewith no live renderer path. This is ADR-0049 debt pending ADR-0050 (VF3). records-forms.record-edit-undoA4, observe-and-flag: an undo after a concurrent edit sends a bare PATCH with noIf-Matchand silently overwrites the other session's value. This is recorded as the clause asks, not as a fail.- Three authorization-class observations, withheld pending maintainer (RUNNER rule 2).
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 5, 2026
Close-out
Every
failhas a disposition re-derived by an independent verifier (RUNNER rule 7):Held, not extracted, and re-run owed:
i18n.surface-matrixacceptance[0] (relative-dates variant) andi18n.studio-follows-app-localeacceptance[2]. The verifier left both UNCONFIRMED, so neither gets a card until a live re-run settles the mechanism.Known expected-fail, not re-filed:
platform-core.keyboard-shortcut-surfaceacceptance[2] / acceptance[3] (K1a / K1b) andai.console-ai-surface-gatingacceptance[5] (K2). The 2026-08-30 sweep's follow-ups own them.Product defects
summarizeField(declared-unenforced)rowHeightat the envelope top level, and the server drops it with a 200previousPeriodcomparison labelled "vs yesterday"None is a 17.7 regression: every defect above reproduces against console code unchanged since the 17.6.0 pin (
31971ff1e) or earlier. No open duplicate was found for any of them.Checklist-accuracy findings (no fail attached; for the checklist owner)
invite_onlyrefuses. Docs step 4 should name the Help menu./apps/{pkg}/docslands on the reader of the first entry rather than on a separate listing.recordAction: 'drawer');/forms/:nametakes view names (showcase_task.form); the child-create path is Account → Invoices tab → New.object-ui-theme, notvite-ui-theme, and ModeToggle lives in the avatar menu under Preferences.MarketplacePackagePage, not on Installed Apps.degraded,handlerReady:false) gets no group, although the hook comment says degraded services "stay visible". This is the fail-closed direction.buildApprovalDecisionActions, and the header renders the declared actions through DeclaredActionsBar. The visible set also includes Reassign / Send back / Request info / Recall, and A5 needs a non-override persona.organization/update-member-role.steps_jsonomits post-resume nodes, so branch-taken clauses cannot be read from the run.'estimate_hours desc', spec(ui):ListViewSchema.sortstill accepts the legacy"field desc"string — it is the PRODUCER whose documents objectui now refuses loudly, and #16553 does not cover it #17053), and the view now uses the array form.$filter/$top/$skipwhile the console sendsfilter/top/skip._selectedIdsis top-level, not underparams.packages/spec/liveness/view.jsoncalls kanban "field-by-field wired", which is stale forsummarizeField./newpage route; the modal knownGap is partly stale (Task Desk renders a JSX modal form).lockFieldthat is not a spec key.{filters, search}are stored.top=0givestotal:0.grid-columns-{object}when the view has noschema.id.projectis required.series[].type/series[].yAxis, which were removed by the 2026-09-12 ruling. The compareTo probe recipe should adddashboard.dateRange, without which the executor refuses.optionsFromdashboard.zh-CNis accepted, andsys_user.localeexists. Its prescribedzhcode is also what triggers the held date finding.LOCALE_TTL_MS).writable_package_required, but the live server answers 403NOT_OVERRIDABLE/ITEM_LOCKED.confirm()accepted.Environment notes are in the record body.
Generated by Claude Code
docs(qa): re-point platform-core checklist clauses the 17.7 console r…
objectstack-fleet commentedon Oct 5, 2026
Re-run: the two held zh-date clauses (RUNNER rule 7)
The record held
i18n.surface-matrixacceptance[0] (relative-dates variant) andi18n.studio-follows-app-localeacceptance[2] as FAIL, observed but not verified. A live re-run on the same subject (316be321e, console pin2e818d0b51ec), 2 fresh boots × 2 loads plus controls, settles both:zh-CN);/api/v1/auth/me/localizationanswerszh-CN; every date formatter receiveszh-CN; list dates render 10月15日 / 3天后 / 后天, record stamps 创建于: 8天前enand restores "Oct 15" / "In 3 days"Disposition of the original fail: invalid pairing. The first lane set the UI language only in browser storage and never used the product's language switcher, so the user's stored locale stayed empty and dates followed the browser. No item step prescribes that, and the clauses are right as written.
Corrected totals for this record: 40 PASS / 8 PARTIAL / 13 FAIL / 0 BLOCKED / 0 NOT-RUN (the title still shows the pre-re-run counts).
Close-out for these two clauses: no card. One candidate outside the clauses (when the language save fails, the UI language and the date locale can disagree; console, P3) is noted for the console owner and not extracted.
Optional step wording for both items (checklist owner): "use the avatar-menu language switcher (it writes the user's locale); seeding browser storage alone is not a language switch."
Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Close-out addendum: one fail disposed. The record stays open for the rest
Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T16:08Z. The maintainer approved clearing the openqa-runrecords' close-out debt: 「同意,动手」. This was audited row by row (read-only) against checklist-test §5 before this write.Extracted: objectui#11674 · platform-core.keyboard-shortcut-surface · A3/A4
completedon 2026-10-06.ai.console-ai-surface-gatingA6 (FOLLOW-UPS K2: an empty queue renders under the 501 alert, and the poll never backs off). No card exists.identity-auth.phone-signin-surfaces,platform-core.console-installability-indicators,records-forms.crud-roundtrip,records-forms.import-wizard-encoding-and-hints,records-forms.gantt-interactions,records-forms.form-dirty-guard,records-forms.bulk-select-all-matching,search.command-palette-navigation. Each gap is named in the body, but none is parked on a card.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Close-out complete: the last fail is extracted, and the blocked partial gaps are parked. The record closes
completedTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T17:05Z. The maintainer approved clearing the openqa-runrecords' close-out debt: 「同意,动手」. ⛔ No verdict on this record is changed.Extracted: objectstack-ai/objectui#11736 · ai.console-ai-surface-gating · acceptance[5]
Parked-on: #22017 · identity-auth.phone-signin-surfaces · A2 / A3 blocked(fixture)
Parked-on: #22017 · records-forms.crud-roundtrip · A7 readonly half
Parked-on: #22017 · records-forms.import-wizard-encoding-and-hints · A3 blocked(dependency)
Parked-on: #22017 · records-forms.gantt-interactions · A2 / A3 blocked(fixture)
Parked-on: #22017 · search.command-palette-navigation · A5 blocked(fixture)
Parked-on: #22017 · records-forms.grid-personalization · A1 reorder / pin leg
Parked-on: #22017 · records-forms.action-location-matrix · A3 url / api dispatch leg
Parked-on: #22017 · i18n.surface-matrix · A6 confirm half
Parked-on: #22017 · platform-core.keyboard-shortcut-surface · A5 blocked(fixture)
Parked-on: #22017 · ai.console-ai-surface-gating · A2 entitled side
Parked-on: #22017 · platform-core.builtin-apps-nav-render · catalog content blocked(environment)
Parked-on: #22017 · platform-core.marketplace-console-honesty · boot A catalog content blocked(environment)
Every fail now has a disposition. The others were disposed earlier, in the close-out lines above this comment and in addendum
6020392202.ai.console-ai-surface-gatingA6 (K2) was the last, and it is now objectui#11736, gradedp3.The
not-runlegs stay on this record's own handoff list, as §4 requires, with ⛔ no second list:platform-core.console-installability-indicatorsA3 (the error leg);records-forms.form-dirty-guardA3;records-forms.bulk-select-all-matchingA5.The next release-candidate Tier 1 run re-selects them (§5, trigger 1).
docs(qa): re-point 25 platform-checklist clauses the 17.7 pre-release…
docs(qa): unblock 4 fixture-blocked checklist items and re-point the …
docs(qa): park the 24 partial-coverage gaps of the 17.7 pre-release r…