Repository navigation
Description
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Filing gate: ④ coordination node, a per-flow child of maintainer card #29040, split as its triage comment orders ("the ui lane splits it when it claims, one child card per flow, each with Part of #29040") · filed by domain:ui#4 · ⛔ Not a claim.
Part of #29040.
Business reason (from #29040). objectstack-ai/mobile 2.0 hosts the Console in a WebView (objectstack-ai/mobile#144), so phone users get the Console's responsive layout and nothing else. This child covers the Forms flow: the create / edit form, lookups, date and select fields, and validation errors.
Ask. Drive the flow in a real browser at 375×812 and 390×844 against the showcase and CRM examples. Record what breaks and fix it. Check each of these:
- no horizontal page scroll;
- touch targets of at least 44 px;
- dialogs and drawers fit the viewport;
- the virtual keyboard does not cover the focused field;
- long lists stay responsive on a mid-range Android device profile (CPU throttling 4×).
Acceptance.
- A run record for this flow in the PR body: each check, pass or fail, at both widths, with the page and example it ran on.
- A fix for every failure, or a filed card for each failure this PR does not fix.
- Playwright coverage at a phone viewport is welcome where a fix lands, not required (Console at phone width: audit and fix the key flows at 375px (the mobile app now hosts the Console) #29040 requires it for Approvals and Record only).
- Screenshots before and after each fix stay in the project folder, not on GitHub.
Reader. domain:ui#4 (the ui lane split #29040 per flow: domain:ui#4 takes Approvals, Record and Forms; domain:ui#1 takes Lists, Navigation, Notifications, Dashboards and Auth). Size M.
Dedupe. Searched 375 in:title (0), phone in:title is:open (3: #29040, #28911, #29057), mobile width in:title (1: #29040), Part of #29040 (1: #29040). No per-flow child existed.
Links back: #29040, objectstack-ai/mobile#144.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim: PM loop round 11 · 2026-11-02T08:00Z
Session:
session_01QsR2jUqXiWNJKjMJYThRr1(card thread, os-dev); dispatched by seat sessionsession_01QsR2jR7ZFkpqmm4U8S1f9yAccount:
zhuangjianguoBranch:
claude/project-thread-bi35xl(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-29072Domain:
domain:uiSeat:
domain:ui#4File surface: the create / edit form surfaces (form layout, lookup, date and select controls, validation-error display) in
ui/apps/console/src/andui/packages/*/src/that the fixes need, an optional phone-viewport spec underui/e2e/, their tests, and a changeset; not the files #29019, #29021, #29078, #29107, #28915 and #29039 hold (stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: defaultClause-②: no
Metadata-protocol: none
Responsibility:
the mobile app now hosts the Console in a WebView, so a phone user fills in create and edit forms at 375 px and nothing else, and nobody has verified the keyboard, pickers and validation there | forms are where phone users enter data | every user of the mobile appThread-read: none
Premise: holds (at
origin/main, no phone-viewport spec covers the create / edit form)Serial constraints cleared: #29019 and #29021 build beside it on other files; sheet.tsx is #29078's and dialog.tsx is #29107's
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jUqXiWNJKjMJYThRr1
os-dev-report
Draft PR up as of 2026-11-02T09:34Z; re-runs and landing are the seat's.
{ "issue": 29072, "status": "done", "branch": "claude/project-thread-bi35xl", "pr": "https://github.com/objectstack-ai/objectstack/pull/29209", "head": "6034e7ec20a8e534f2919b3810f16d375afb46df", "session": "session_01QsR2jUqXiWNJKjMJYThRr1", "premise_still_valid": true, "measured": "Run first at merge base a4015ab4, Chromium (Playwright, isMobile, hasTouch, DPR 2) at 375x812 and 390x844, Console from source over examples/app-crm and examples/app-showcase (objectstack dev --seed-admin --fresh): CRM lead and opportunity, showcase task; list, phone create button, create form, select, date picker, lookup dropdown, browse-all record picker, keyboard check, validation submit, seeded record, Edit form. Before: only check 2 (touch targets) failed, at both widths on all three objects: inputs, select and lookup triggers 40 px, select options 32, calendar days 32, date buttons 28, lookup search 32, quick-create 36, picker search 40, Filters 36, picker Close 16x16, line-item cells 32, Add line 36, percent slider 8. Checks 1 (no horizontal scroll), 3 (fit), 4 (keyboard, adjustResize model) and validation (first error focused, in view) passed before and after. After at 6034e7ec's widget sources: every form control at least 44 px; the only check-2 failure left is the picker's DialogContent Close at 16x16 (dialog.tsx, #29107). Check 5 on the production bundle (pnpm console:build, served at /_console, 303 accounts, 4x CPU via CDP): before, Account lookup open max Event Timing 176 ms (375) and 192 ms (390), typing 64 and 72, scroll no long task; after, open 184 to 256 ms over 3 runs (2 of 6 samples over 200), typing at most 88, scroll tasks at most 51 ms. The diff adds classes only, so the open cost predates it: finding. Main merged at dedc3505 (26 commits, none touching fields, plugin-form or the calendar/input/button primitives).", "summary": "The create / edit form's registered field widgets in @object-ui/fields now carry the same phone touch floor the form renderer's built-in controls already use, min-h-[44px] sm:min-h-0, through a package-internal module widgets/touchTarget.ts (not re-exported). Covered: text, email, phone, URL, number, currency, percent inputs and the percent slider's hit area; select trigger and options; lookup trigger, clear, browse-all, dropdown search, show-all and quick-create; record picker search and Filters; date picker input (right padding pr-24 below sm so text stops short of the two 44 px buttons), clear and calendar buttons, Today/Tomorrow, and a 44 px calendar cell below sm ([--cell-size:2.75rem] sm:[--cell-size:2rem] handed to the Calendar primitive; seven days plus padding measure 332 px inside the 343 px column at 375); line-item grid cells, options, row buttons and Add line. plugin-form: the modal, drawer and master-detail form footers' Cancel/Reset/Submit. From sm up every control keeps its previous height. No primitive in components/src/ui is edited; FormPage.tsx is not touched.", "tests": "New: ui/packages/fields/src/widgets/touchTarget.formControls-29072.test.tsx, 13 cases pass; reverse-verified, 12 of 13 red with the widget sources restored from the merge base (the token-shape case reads only the new module). New: ui/e2e/form-controls-phone-touch.spec.ts, 3 cases pass (real Tailwind compiled for the classes read from source; 375 and 390 px controls and seven calendar days at least 44 px, calendar ends inside the column, no page scroll; 1024 px keeps 40/28/40/32); red on the merge base. Regression: the touched widgets' and form footers' existing test files, 106 files / 768 tests pass, before and after the merge of main. Type-check: turbo type-check for @object-ui/fields and @object-ui/plugin-form under os-verify-lock, 49 tasks, VERDICT command-exit 0. ESLint on the changed ts/tsx: 0 errors.", "gates": "dispatch-gates --commands derived 34; all 34 run, each exit 0 (check:type-check-debt under os-verify-lock). pnpm --dir ui exec vitest run scripts/ was SIGKILLed once in the sweep while the five run-record servers held about 6 GB; rerun alone under os-verify-lock it passed, 169 files, 4900 tests, VERDICT command-exit 0, and the reconciliation records that exit. --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. check-sdui-manifest 0 after the merge. PR-body gates on the exact body sent (GITHUB_EVENT_PATH): check-changeset-no-major --base origin/main 0, check-adr-0087-registration --base origin/main 0, check-closing-keyword-parity 0. CI check-runs on #29209: not read at report time.", "dogfood_battery": "n/a: no ! in the title and no (narrowing) arm", "line_budget": "19 files, +383 / -35 = 418 changed lines, under the 3000-line threshold", "files_changed": [ ".changeset/29072-form-controls-phone-touch.md", "ui/e2e/form-controls-phone-touch.spec.ts", "ui/packages/fields/src/widgets/{CurrencyField,EmailField,GridField,LookupField,NumberField,PercentField,PhoneField,RecordPickerDialog,SelectField,TextField,UrlField}.tsx", "ui/packages/fields/src/widgets/date-picker/DatePickerField.tsx", "ui/packages/fields/src/widgets/touchTarget.ts", "ui/packages/fields/src/widgets/touchTarget.formControls-29072.test.tsx", "ui/packages/plugin-form/src/{DrawerForm,MasterDetailForm,ModalForm}.tsx" ], "deviations": [ "The run record was driven by a Playwright harness against the Console served from source by Vite (proxying objectstack dev), not the production bundle; check 5 alone was read on the production bundle, because the dev server's unbundled React reads 2 to 3 times slower.", "Check 4 (virtual keyboard) uses the WebView adjustResize model: focus, shrink the layout viewport by 336 px, let the browser scroll the editable into view, assert its box and elementFromPoint. No real device IME was exercised.", "No object in either example declares the page or drawer form mode, so RecordFormPage was not reached; the drawer form footer gets the token for parity, unmeasured in the browser.", "A Vite watcher served a stale transform after the before-run source restore; restarted with --force and confirmed the served module carries the token before the after-run.", "Calendar cell size is set through the Calendar primitive's --cell-size variable by className; tailwind-merge keeps the later value, which the e2e fixture mimics.", "Brief rule over session context: the PR has no assignee and no review request, and no GitHub MCP write was made." ], "mcp_calls": "2: GitHub MCP issue_read get on #29072 x1 and get_comments on #29040 x1, both reads. No GitHub MCP write. Separately (claude-code-remote, not GitHub MCP): get_session x3, read_documentation x4.", "api_writes": "2: relay repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches x2 (pr_create #29209, run 41421493892, read back 11014 bytes identical; this os-dev-report comment via post-stamped). git push x2 is not a REST write.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: CRM lead / opportunity Account lookup and showcase task Project lookup, browse-all record picker, its Close button measures 16x16 px at 375x812 and 390x844 (target 44) · evidence: the picker renders the plain DialogContent, whose built-in close is the primitive's own; dialog.tsx is #29107's file · carrier: #29107 · dedupe words: record picker close button, DialogContent close 16px, lookup browse-all dialog", "class: b · reach: CRM opportunity create, open the Account lookup dropdown over 303 accounts at 4x CPU on the production bundle: one 150 to 215 ms task; click Event Timing 176 ms (375) and 192 ms (390) before this PR, 184 to 256 ms over three runs after (2 of 6 samples over 200 ms); typing at most 88 ms, scroll tasks at most 51 ms · evidence: this PR adds classes only, so the open cost predates it · dedupe words: lookup dropdown open slow, LookupField 4x CPU, Event Timing over 200 ms", "observation · reach: CRM opportunity create (MasterDetailForm) at 375x812: the Cancel / Create bar sits at the end of the scrolling body, not in a sticky footer like the modal form's, so Create is not on the first screen · none of the five checks covers it · dedupe words: master-detail footer not sticky, opportunity create button below fold" ] }objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim amended · 2026-11-02T09:39Z · the file surface widens by one file. Branch, session and declaration lines are unchanged.
Clause-②: no
Metadata-protocol: none
File surface (added):
ui/packages/fields/src/widgets/FileField.tsx. It is the Forms flow's file field, which #29071's phone run measured at 36 px ("Take photo"). Two class additions use this PR's internalwidgets/touchTarget.tstoken:PHONE_TOUCH_HEIGHTon the camera button andPHONE_TOUCH_SQUAREon the 24×24 per-file remove button. They come with a pin in the touch-target test. No export, prop or behaviour changes.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Seat review · 2026-11-02T10:12Z · PR #29209 at
99a5359b: ACCEPT (on the PR;Clause-②: no, no contract review owed). It goes to the merge queue now.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Landed · 2026-11-02T11:29Z · PR #29209 merged through the merge queue as
39951d2a. Record: ACCEPT 6574540165 at99a5359b(Clause-②: no, no contract review owed).39951d2a~1)origin/main)PHONE_TOUCH_SQUARE =inui/packages/fields/src/widgets/touchTarget.ts[--cell-size:2.75rem] sm:[--cell-size:2rem]inui/packages/fields/src/widgets/date-picker/DatePickerField.tsx(the 44 px calendar day on a phone)PHONE_TOUCH_SQUARE)inui/packages/fields/src/widgets/FileField.tsx(the per-file remove button)The card closed through
Fixes.pm:dispatchedcomes off with this note. The record picker's 16 px Close stays with #29107 (dialog.tsx). Tracker #29040 keeps its remaining children.Generated by Claude Code