Skip to content

console: suggestions from the 18.3.0 RC browser walkthrough: mention and discussion feedback, list selection and bulk results, refusal wording, approvals inbox, dashboards and money formatting, and phone layout #27520

Open

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcUoS2G4jgqRskpExS7

Suggestions from the 18.3.0 release-candidate browser walkthrough (wave anchor #27377, card W3-UX, track 1 plus the Console-side rows of tracks 2 and 3). Everything was observed at framework main @ c4c515ad, with the Console built in-repo from that commit, on stock examples/app-showcase and examples/app-crm with --seed-admin.

  • Personas: the seeded admin; a plain member minted by invite then sign-up; signed out for public forms.
  • Viewports: desktop 1440×900 and phone 390×844.

Each row works today but could be clearer. The reproducible defects from the same pass are their own cards: #27483, #27487, #27491, #27494, #27496, #27498, #27502 (Console); #27504, #27506, #27507, #27509 (Setup); #27511, #27513, #27515, #27517, #27518, #27519 (Studio).

New suggestions

# Observed at c4c515a (persona, viewport, path) Suggestion
1 Admin, desktop, Projects → Website Relaunch → Discussion. The @mention picker offers a member who cannot read the thread. The comment saves with the mention, the server withholds the notification (cannot_read_thread), and the author is told nothing. The rendered mention looks like plain typed text. Leave such users out of the picker, or tell the author they will not be notified. Render picked mentions as chips.
2 Member, desktop, same record. The header reads Discussion (0) directly above "You don't have permission to view comments on this record." Omit the count when the comments cannot be read.
3 Admin, phone, Delivery Operations dashboard. The Total Budget KPI tile cuts its main number to $1,090,00.... Shrink the number to fit, or use compact notation ($1.09M), on a KPI tile's main value.
4 Admin, desktop, Tasks → Bulk Actions view, 2 of 10 rows selected. The header checkbox is correctly aria-checked="mixed", but it draws a grey check mark. Draw the mixed state as a dash.
5 Admin and member, desktop, Tasks. Reassign… in the list header is enabled with nothing selected and explains itself only after a click ("This action runs on a single record — select a row first."). The member's grid has no row checkboxes, so for the member it is a dead end. Disable it with that reason as a tooltip until exactly one row is selected; hide it where rows cannot be selected.
6 Admin, desktop, Tasks → Grid view inline edit. Save All with an empty required Title and an Estimate of -5 is refused in a one-line banner, Save failed: Title is required and cannot be cleared; Es..., with the rest only in a native tooltip. The cells are not marked, min: 0 is not checked before sending, and the button sits flush against the right edge. Mark the offending cells, check min client-side, and show the full message.
7 Admin, desktop, Tasks list toolbar. A filter row with no value still counts toward the filter badge and persists across reloads. Sort offers "A → Z" for a datetime field and lets the same field be added twice. List search persists across navigation, so a user comes back to "No matching records", and that empty state has no clear button. Studio's list-view sort shows the same "A → Z" for a date. Ignore incomplete filter rows; use "Oldest → Newest" for dates; refuse duplicate sort fields; add "Clear search" to the empty state.
8 Admin, desktop, Tasks → bulk Mark Done on 2 rows. Done and Progress 100% are set, but Status stays Backlog, so the path still shows Backlog. The result dialog says only Succeeded 2 / 2. Name the records in the result. The Status mismatch may be the showcase action's own definition.
9 Admin, desktop, task record page. The actions appear twice, in the header and as a button row in the body. The disabled Archive tooltip says only Not available for this record. Show one action row; say why Archive is unavailable.
10 Admin, desktop, delete a task. The confirm dialog does not say the delete cannot be undone. The toast is a generic Record deleted, while the create toast names the record. Say it is permanent (or offer Undo), and name the record in the toast.
11 Admin, desktop, a draft invoice → Submit for Sign-off. The refusal is Issued On is required, with no hint to edit the invoice first, and Issued On is not marked required in the edit form. Say "Fill in Issued On before submitting", and mark fields that are required for submission.
12 Admin, desktop, Approvals inbox. A row's record link opens the record inside the Account app shell, with no way back to the inbox. Reject asks for no reason. The admin may decide a request they submitted themselves. Open the record in the inbox's own app, or keep a back link; offer an optional reason on Reject; consider showing "you submitted this" on self-submitted requests.
13 Admin, desktop, bell. The header says 4 total · 1 notification + 3 pending approvals, while the single collapsed row reads ×3 … 3 unread and shows only the first record's text. Make the header and the row counts agree; expand a grouped row to list its records.
14 Admin, desktop, project record page. Dates are formatted two ways on one page (Dec 28, 2026 / Sep 29). The Attachments card is wider than the others, and comment text is low-contrast grey. One date format per page; align the card widths; raise the comment text contrast.
15 Admin, desktop and phone, CRM Pipeline dashboard. The comparison series uses the same blue swatch as the main series. The stage chart's legend has no swatches. The month axis shows raw 2025-10. KPI money values carry no currency. The CRM widget descriptions themselves leak authoring notes ("Pie/donut/funnel ignore compareTo"); those are example content. A distinct swatch for the comparison series; legends with swatches; format month buckets ("Oct 2025"); format KPI money with the field's currency.
16 Admin, desktop, CRM Opportunities. Two adjacent money columns are formatted differently, 35,000.00 and 35,000. One currency format per column type.
17 Admin, desktop, an empty list (a new object with no records). The empty state offers no New button. Offer Create in the empty state when the user may create.
18 Admin, phone, Tasks list and Home. The floating "+" overlaps a card's priority badge. On Home, the header links beside "Your apps" wrap awkwardly. Horizontal bar chart labels are cut to "In Progr…". Reserve space for the FAB; let the header links scroll; wrap or abbreviate bar labels with a tooltip.
19 Admin, desktop, the runtime create form of a Studio-authored object whose validation rule refuses the save. The refusal shows twice, as a banner and an identical toast, and the violating field is not marked. One message, and mark the field the rule names.
20 Member, desktop, a list the member cannot read. The no-access state offers Retry, which cannot help. On an invoice the member can read, the Line Items section shows a red "You do not have permission to perform this action." although the member did nothing. Drop Retry on a permission refusal; draw an unreadable related list as a quiet "No access" line.
21 Admin, desktop, every object list toolbar (also on Studio-authored objects). An In a queue toggle has no tooltip, and its meaning is unclear to a new user. A tooltip, or show it only on objects that use queues.

Already carded: not raised again

Observation at c4c515a Card
Public form unbranded, blue Submit, tab titled "ObjectOS": still reproduces #27355 row 9
A refused public-form submit does not mark the fields: still reproduces (the stale "Required:" banner is #27496) #27355 row 10
A Backlog task's path tints "Done" as a later step: still reproduces #26612, #26694
The approval request page's RECORD ID holds a name: still reproduces #27356 row 7
Phone: Setup Users and Invitations show no Invite, Create or Import (the buttons are in the DOM at 0×0), so no user can be invited from a phone #27058 (phone list with a FAB)
A member at /apps/setup/system/settings sees "No settings registered …" #27507 (filed from this pass)

Rows of #27355 that no longer reproduce at this sha: row 5 (the task record's ⋯ menu now has Delete), row 6 (a member's double-click in Grid opens the record instead of editing), row 11 (phone KPI tiles are two per row; row 3 above is a new truncation).

Acceptance

Each row is either taken, with its own card if it needs one, or answered "will not do" with the reason.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · domain:ui · area:records · 2026-10-29T11:10Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    Split · 2026-10-29T19:36Z · ⛔ Not a claim; nothing on this card is assigned.

    Every other row stays on this card for whichever domain:ui seat's area it falls in.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Claim: PM loop round 3 · 2026-10-30T15:15Z
    Session: session_01L9qibzC6RxMfB59EsgAoNN (seat; implementation by card thread session session_01L9qibzKuj2HUUN2wUhZ9Go, mode:thread)
    Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-ty1d4m (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27520
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: rows 3, 15 (chart half) and 18 (bar labels) only. ui/packages/plugin-dashboard/src/**, ui/packages/plugin-charts/src/**, ui/packages/core/src/** (chart series and date-bucket helpers only), tests, root changeset; no examples/** edit (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a (suggestion rows, not a defect card)
    Thread-read: 6506509231
    Premise: holds (the rows are untaken: seat 4's split 6506509231 filed rows 1, 2, 4, 5, 10, 13 and 20 elsewhere; the money half of row 15 belongs to #27430, which is closed; the FAB/Home parts of row 18 stay with the mobile epic #27058)
    Serial constraints cleared: no open PR touches plugin-charts / plugin-dashboard besides release PR #26517 (seat scan 15:15Z); domain:ui#4 clocked out (6526005030) and was told on #26620

    The PR carries Part of #27520 (other rows remain open). Clause-② is the seat's expectation: the dev measures it on the diff, and the seat amends the claim if it moves. Order: /mnt/project-files/ui-seat-1/r2026-10-30/dispatch-27520.md under FRAME.md.

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzKuj2HUUN2wUhZ9Go
    os-dev-report

    {
      "issue": 27520,
      "status": "done",
      "branch": "claude/project-thread-ty1d4m",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28223",
      "session": "session_01L9qibzKuj2HUUN2wUhZ9Go",
      "premise_still_valid": true,
      "summary": "Rows 3, 15 (chart half) and 18 (chart part) of #27520, as one PR marked Part of. Row 3: a dataset-bound KPI value takes METRIC_TILE_DATASET_VALUE_LADDER, so it shrinks before it clips, with the full figure as a tooltip past the last rung. Row 15: a YYYY-MM month bucket key renders as 'Oct 2025' through the new @object-ui/core export formatMonthBucketLabel; bar and area legends draw swatches (they had been url(#...) gradients), and a compareTo series' swatch is hollow; a per-category lone bar series draws no swatch. Row 18: horizontal-bar category labels wrap to 2 lines inside the axis; the vertical-axis phone cut moved after the rotate decision, so 'In Progress' draws whole; any cut label carries its full text as an SVG title.",
      "tests": "head 23380e90 under os-verify-lock: install --frozen-lockfile, plugin-dashboard... + plugin-charts... closure build, core/plugin-charts/plugin-dashboard type-check, vitest packages/core/ packages/plugin-charts/ packages/plugin-dashboard/ -> 'VERDICT command-exit 0', Test Files 523 passed (523), Tests 7418 passed | 42 skipped (7460). New: date-bucket-label.test.ts, AdvancedChartImpl.dashboardReadability-27520.test.tsx (11), metricTileDatasetValueScale-27520.test.tsx. Adapted 4 pinning tests (pointAxisEdgeLabels-13390, missingCategoryKey, labelFitBand-13241, metricTileLayout-12623). Ablations via scripts/ablation-replace.mjs (month label, dataset ladder, legend swatch colour, wrap): each turned its new test red (1 failed each), and the files were restored to the HEAD blob. Browser before/after at 390x844 and 1440x900 is in the PR body.",
      "gates": "local subset at 23380e90: dispatch-gates --commands gave 35 commands, each run with </dev/null and all exit 0. 'pnpm --dir ui exec vitest run scripts/' was SIGKILLed on its first run when the box was out of memory; after the dev stacks were stopped it reran alone with exit 0 (Test Files 169 passed | 2 skipped, Tests 4901 passed | 2 skipped). --ran: 35 derived, 35 run, 0 NOT-MEASURED. Also exit 0: pnpm --dir ui check:new-line-citations, node scripts/check-sdui-manifest.mjs. CI check-runs: pending at report time; the seat reads them.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "3 — mcp__github__issue_read x3 (reads); 0 writes",
      "api_writes": "0 — REST proxy writes; relay writes 1 (fleet-write pr_create -> #28223), plus this post-stamped comment",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: CRM Pipeline dashboard KPI tiles (dataset-bound) read '710,000' / '235,000' / '81,000' with no currency, on main 9f13ee81 and this branch · evidence: browser read of examples/app-crm Pipeline Dashboard; #27430 shipped the tile caption (PR #27972) and the formula currency face, not a dataset KPI's currency · dedupe words: dataset KPI currency, metric tile money format, row 15 money half",
        "class: c · reach: named producer examples/app-crm/src/dashboards/pipeline.dashboard.ts widget descriptions leak authoring notes ('Pie/donut/funnel ignore compareTo', '(compareTo)') · evidence: file content · not edited per order",
        "carrier: PR #28223 Acceptance notes · noted, not filed"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Claim amendment · 2026-10-30T17:30Z · amends claim 6526230292 at the card thread's request (os-dev-report 6529089724). Append-only.

    Clause-②: yes (widening: @object-ui/core gains the public export formatMonthBucketLabel; no accept set moves)

    The claim's Clause-②: no was the seat's expectation, and the dev's measurement on PR #28223 replaces it. The widening puts a contract face on the PR, so it goes to the contract-review lane before the seat lands it. The file surface is unchanged.

    Row 15's money half does not hold on origin/main: the dataset-bound KPI tiles on the CRM Pipeline dashboard read 710,000 / 235,000 / 81,000 with no currency (#27430 shipped the tile caption and the formula currency face, not this case). The seat files it as its own card, and row 15's money half stays open on this card until that lands.

  6. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Landed · 2026-10-30T20:50Z · PR #28223 (seat ACCEPT pinned to 63b2a696, contract-review PASS 6532420116).

    reading value
    PR merged 2026-10-30T20:49:36Z as 9e4f1cfd through the merge queue
    origin/main content ui/packages/core/src/utils/date-bucket-label.ts present (formatMonthBucketLabel), with the chart and metricTile changes beside it

    State: the PR is Part of #27520, so this card stays open. Rows 3, 15 (chart half) and 18 (labels) are done. Row 15's money half (dataset KPI tiles with no currency) is #28225, serial after this PR and now unblocked. Any other rows on this card not named in the claim are still open. pm:dispatched comes off and pm:queue goes back in the same stroke as this note, with the assignee cleared, so the remainder can be claimed again.

  7. 6 remaining items

  8. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Claim amendment · 2026-10-31T05:31Z · amends claim 6539394970 after the card thread's measurement on main b1e1dcf2 (live showcase and CRM, admin), before any push. Append-only.

    Clause-②: yes (widening: @object-ui/types ActionResult gains the optional fieldErrors, carried from a VALIDATION_FAILED answer's details.fields; no accept set moves)

    All three rows reproduce. The measurement moves the mechanism, so the seat accepts this surface in place of the claim's:

    • Row 8: the bulk result is ui/packages/plugin-grid/src/** BulkActionDialog, not ActionResultDialog. It lists the succeeded records, named as on the confirm step, only when every failure is attributed to a row. There is no server read and no executor change. Status staying Backlog is the showcase action's own declaration (MarkDoneAction patches done and progress on purpose), so it is not edited.
    • Row 11: the answer is a 400 VALIDATION_FAILED with details.fields [{ field: issued_on, code: required, label: Issued On }], and core's interpretActionResponse drops fields[]. The fix carries the entries through the core outcome and serverActionHandler onto ActionResult.fieldErrors (ui/packages/types/src/ui-action.ts). The console wrapper ui/packages/app-shell/src/utils/consoleServerAction.ts and its two call sites then add "Fill in Issued On, then run “Submit for Sign-off” again." The half that marks fields required for submission needs metadata that ties requiredWhen to an action's patch, and none exists. It is a spec card candidate, and the seat files it when this PR lands.
    • Row 16: the two columns differ by the example's declaration. Deal Value is Field.currency, while Expected Revenue is a formula with no returnType, so by rule it draws the number face. The seat lifts the order's no-examples/** line for exactly one edit: returnType: 'currency' on that formula in examples/app-crm/src/objects/opportunity.object.ts. No renderer change.

    The widening sends the PR to the contract-review lane before the seat lands it.

  9. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzF2YJvme2ABRytQ9o

    os-dev-report

    {
      "issue": 27520,
      "rows": [8, 11, 16],
      "status": "done",
      "branch": "claude/project-thread-5ywnd8",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28378",
      "head": "6a3bd4e70622cc197527a2dd5959c2bbcb17c164",
      "session": "session_01L9qibzF2YJvme2ABRytQ9o (card thread under ui seat 1)",
      "premise_still_valid": true,
      "summary": "All three rows still reproduced on origin/main b1e1dcf2 and are fixed live. Row 8: BulkActionDialog's result step lists the records that succeeded by nameField ('Succeeded 2 / 2 | • Evidence collection | • Content backlog'), only when every failure maps to a row of the run; a bare-count bulkUpdate keeps the count alone. Row 11: interpretActionResponse reads error.details.fields into ActionResult.fieldErrors (new optional member), and the console wrapper follows the server's sentence with a pack hint ('Issued On is required. Fill in Issued On, then run “Submit for Sign-off” again.'). The hint keys off the field entries, so it survives a userMessage. Row 16: the CRM expected_revenue formula declares returnType 'currency' (the one example edit the seat allowed) and now reads $16,000.00 beside Deal Value $80,000.00.",
      "tests": "New: plugin-grid bulkResultSucceededNames-27520 (3), core actionRefusalFields-27520 (5), app-shell consoleServerAction.requiredFieldsHint-27520 (6). Adapted: i18n de-quote-pairing-3876 census (103 after merging main, which had also raised it). Ablations through ablation-replace, each restored: 2/3, 1/3, 8/10, 5/6 red. types+core+i18n+plugin-grid suite at 714e3766: 963 files passed, the 1 de census file fixed and rerun green; i18n on the merge head 93 files passed; app-shell wrapper and call-site slice 108 files / 761 tests passed. The whole app-shell suite sat 80 min under the lock and was stopped, so the rest of it is left to CI. type-check of the 5 ui packages: 0 errors. CRM typecheck/test (48)/validate exit 0. CRM-reading dogfood (install-local-purge-sample-data, wall-environment-metadata-refusal, guest-grants-channel): 3 files / 53 tests passed.",
      "gates": "At 6a3bd4e7: dispatch-gates --commands derived 54; all 54 run with </dev/null (27520-actions-gates-ran-6a3bd4e7.list in the seat's out folder). check:type-check-debt first exit 3 because the tree was not reinstalled after the merge (@objectstack/observability is new on main); after pnpm install it reran exit 0. dispatch-gates --ran: 54 derived, 54 run, 0 NOT-MEASURED. check-sdui-manifest exit 0, ui check:new-line-citations exit 0. CI on #28378: not started at report time.",
      "clause_2": "yes (widening: ActionResult.fieldErrors, new ActionFieldError export, ActionResponseOutcome.fieldErrors)",
      "metadata_protocol": "none",
      "line_budget": "+479 / -14, 24 files",
      "files_changed": [".changeset/27520-bulk-result-names-required-hint.md", "examples/app-crm/src/objects/opportunity.object.ts", "ui/packages/plugin-grid/src/components/BulkActionDialog.tsx", "ui/packages/types/src/ui-action.ts", "ui/packages/types/src/index.ts", "ui/packages/core/src/actions/actionResponse.ts", "ui/packages/core/src/actions/serverActionHandler.ts", "ui/packages/app-shell/src/utils/consoleServerAction.ts", "ui/packages/app-shell/src/hooks/useConsoleActionRuntime.tsx", "ui/packages/app-shell/src/views/RecordDetailView.tsx", "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts", "4 test files"],
      "deviations": [
        "Surface widened past the order's file list: types, core actionResponse/serverActionHandler, app-shell consoleServerAction and its two call sites, plus the one examples/app-crm edit. The seat approved this in claim amendment 6539593257.",
        "Row 8's dialog is plugin-grid BulkActionDialog.tsx, not app-shell ActionResultDialog.tsx as the order assumed.",
        "Row 8's Status half was not edited: examples/app-showcase/src/ui/actions/index.ts MarkDoneAction leaves status alone on purpose (task_status_flow).",
        "Row 11's 'mark fields required for submission' half was not done, because no spec door ties a field's requiredWhen to an action's patch. The seat will file the spec card.",
        "Whole app-shell vitest suite not measured locally (stopped after 80 min, left to CI); the wrapper and call-site slice was run instead.",
        "Stray empty file /tc.pid at the container root, from a background-job variable mistake. Removing it was blocked by the safety check, so it is still there. It is outside the repo and touches nothing."
      ],
      "mcp_calls": "3, all reads: issue_read #27520 (x2), pull_request_read get #28378. 0 writes",
      "api_writes": "2 via relay/stamped tools: pr_create (#28378, draft), this comment on #27520; plus git pushes to claude/project-thread-5ywnd8",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: a money formula without returnType draws a plain number by rule, and os validate does not warn about it (class c candidate, named producer: examples/app-crm before this PR)",
        "carrier: none · noted, not filed: the action toast reads error.message through actionErrorDetail and never error.userMessage, which a flow-action refusal can carry"
      ]
    }
  10. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Landed · 2026-10-31T08:56Z · PR #28378 (seat ACCEPT 6541242593, pinned to 6a3bd4e7, contract-review PASS 6541234847).

    reading value
    PR merged 2026-10-31T08:55:45Z as 0ac6dabc through the merge queue, on the first pass
    origin/main content consoleServerAction.ts carries withRequiredFieldsHint, BulkActionDialog.tsx draws the succeeded rows, and opportunity.object.ts declares returnType: 'currency' on expected_revenue

    State: the PR is Part of #27520, so this card stays open. Row 8 (succeeded names), row 11's first half (which required fields to fill) and row 16 (expected revenue as money) are done. Row 11's second half, marking fields required for submission, needs a spec door that ties requiredWhen to an action's patch; the seat files it as its own spec card. Rows 6 and 19 are this seat's next claim. Any other rows on this card that were not named in a claim are still open. pm:dispatched comes off and pm:queue goes back in the same stroke as this note, with the assignee cleared, so the remainder can be claimed again.

  11. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Claim: PM loop round 6 · 2026-10-31T08:59Z
    Session: session_01L9qibzC6RxMfB59EsgAoNN (seat; implementation by card thread session session_01L9qibxQtKRyLyL6eK14pgY, mode:thread)
    Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-mcx7eo (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27520
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: rows 6 and 19 only. ui/packages/plugin-grid/src/**, ui/packages/plugin-form/src/**, ui/packages/react/src/record-save-feedback.ts, ui/packages/app-shell/src/views/RecordFormPage.tsx, ui/packages/fields/src/** (validation-rule reuse only), ui/packages/core/src/actions/actionResponse.ts (sharing refusalFieldErrors only), i18n packs, tests, root changeset; no packages/spec/**, server or record-page layout edit (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no (the seat's expectation; the dev measures it on the diff, and the seat amends the claim if a new export moves it)
    Metadata-protocol: none
    Responsibility: n/a (suggestion rows, not a defect card)
    Thread-read: 6541407583
    Premise: to be re-measured per part on origin/main before code, against #28151, #28267, #28293 and #28307, which moved these surfaces after the walkthrough. If both rows are already fixed, no PR is opened and the seat answers them on the card. Rows 3, 15 and 18 are done (PR #28223), and rows 8, 11 (first half) and 16 are done (PR #28378). Row 11's second half is filed as #28382. Rows 1, 2, 4, 5, 10, 13 and 20 have their own cards.
    Serial constraints cleared: yes. No open PR names #27520, since PR #28378 merged at 0ac6dabc. The maintainer lifted the p3 hold for ui with 「可以开p3」, and at 2026-10-31T02:39Z said 「ui 车道一堆任务啊,应该并发开满啊」 in the seat thread. No other seat has claimed these rows.

    The PR carries Part of #27520, because other rows remain open. Order: /mnt/project-files/ui-seat-1/r2026-10-30/dispatch-27520-saves.md under FRAME.md.

  12. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

    Claim amendment · 2026-10-31T09:25Z · amends claim 6541435370 after the card thread's measurement on main 3ba52069 (live showcase --fresh, admin; record at /mnt/project-files/ui-seat-1/r2026-10-30/out/27520-saves-measure.md), before any push. Append-only.

    Clause-②: no (unchanged; no new export, no accept set moves)

    • Row 6: all four parts still reproduce: the truncated one-line banner, no cell marks although the 400 names title and estimate_hours, the PATCH sent with -5, and Save All 0 px from the edge. The save bar, banner and per-row error state live in ui/packages/components/src/renderers/complex/data-table.tsx, so the seat adds that file to the surface. Client min/max/length/required go through buildValidationRules. A row refused locally takes the same VALIDATION_FAILED shape, and the other rows still save.
    • Row 19: the field mark is already fixed. A rule that names a field (cross_field) marks it, with one message and no banner or toast, through extractFieldErrors. A script rule answers only _record, so there is nothing to mark. That is the stop condition: no spec or server edit, and it is recorded, not filed. The duplicate still reproduces for a _record refusal: the banner and an identical toast. That pair is raised by ui/packages/components/src/renderers/form/form.tsx, which the seat adds to the surface.
    • Behaviour call, seat ruling: a refused submit shows one message: the banner, scrolled into view, with no toast. objectui#13340's test said the toast was there "for when the banner has scrolled out of view", and scrolling the banner into view covers that case. The driver-memory: bulkCreate is Promise.all(map(create)), so a refused row leaves every earlier row of the batch landed — updateMany on the same driver refuses before mutating anything #13340 test is adapted to the new rule: one banner, scrolled into view, and zero error toasts on a refusal the banner draws. Its no-stacking guarantee on a retry still holds. Where the form draws no banner, the toast stays.
    • Reader: @object-ui/react extractFieldErrors / unmarkedRefusalLines, which form.tsx already uses. ui/packages/core/src/actions/actionResponse.ts leaves the surface.

    This reverses a pinned visible behaviour (the refusal toast), so the PR goes to the contract-review lane before the seat lands it.

  13. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-tesla · session_01L9qibxQtKRyLyL6eK14pgY

    os-dev-report

    {
      "issue": 27520,
      "rows": [
        6,
        19
      ],
      "status": "done",
      "branch": "claude/project-thread-mcx7eo",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28396",
      "head": "f77d7968eecba8ddfaa32973b8d239a144c785f4",
      "session": "session_01L9qibxQtKRyLyL6eK14pgY (card thread under ui seat 1)",
      "premise_still_valid": true,
      "summary": "Measured on origin/main 3ba52069: row 6 reproduced in all four parts; row 19's duplicate banner+toast reproduced for a script rule, and its field mark already worked for a cross_field rule. Row 6, fixed live: data-table says every refusal reason whole, one line each, in its own role=alert row under the toolbar; it marks the cells the refusal names (aria-invalid, data-cell-error, title, ring), and editing a cell clears its mark. ObjectGrid's built-in saves check the field's own rules (required, min/max, length, email/URL pattern via buildValidationRules) before sending; a breaking row is refused unsent in the server's VALIDATION_FAILED shape, and the other rows still save. The toolbar is inset (Save All 12 px from the edge). Row 19, fixed live: form.tsx raises one message for a refusal, the banner scrolled into view, and no error toast (page and dialog).",
      "tests": "New: components data-table-refusal-cells-27520 (4), plugin-grid inlineEditRuleCheck-27520 (7). Adapted, not deleted: form-one-toast-per-refusal-13340 (one banner, scrolled into view, zero error toasts, retry keeps one banner) and 11 other refusal pins in components and plugin-form that asserted the toast. components+plugin-grid+plugin-form at f77d7968: 944 files passed, 1 skipped; 9131 tests passed (lock VERDICT command-exit 0). The first full run at 9edf9af1 had 25 reds in 7 plugin-grid inline-edit files (pre-send check read rules of undefined); fixed in f77d7968. type-check of components and plugin-grid exit 0. The app-shell and console suites were not run locally (left to CI).",
      "gates": "At f77d7968: dispatch-gates --commands derived 35; all 35 run with </dev/null (27520-saves-gates-ran-f77d7968.list in the seat's out folder). check:type-check-debt first exited 3 (it queued behind my own test run on the lock); rerun under the lock exit 0. dispatch-gates --ran: 35 derived, 35 run, 0 NOT-MEASURED. check-sdui-manifest exit 0, ui check:new-line-citations exit 0. CI on #28396: not started at report time.",
      "clause_2": "no",
      "metadata_protocol": "none",
      "dogfood_battery": "not run: no server, spec or example file changed",
      "line_budget": "+813 / -140, 20 files",
      "files_changed": [
        ".changeset/27520-refused-grid-and-form-saves.md",
        "ui/packages/components/src/__tests__/data-table-refusal-cells-27520.test.tsx",
        "ui/packages/components/src/renderers/complex/data-table.tsx",
        "ui/packages/components/src/renderers/form/__tests__/fieldtab-visiblewhen-6237.test.tsx",
        "ui/packages/components/src/renderers/form/__tests__/form-invalid-toast-joiner.test.tsx",
        "ui/packages/components/src/renderers/form/__tests__/form-one-toast-per-refusal-13340.test.tsx",
        "ui/packages/components/src/renderers/form/__tests__/form-refusal-lines-28053.test.tsx",
        "ui/packages/components/src/renderers/form/__tests__/form-server-field-errors.test.tsx",
        "ui/packages/components/src/renderers/form/__tests__/visibleWhen-fault-refuses-submit-8069.test.tsx",
        "ui/packages/components/src/renderers/form/form.tsx",
        "ui/packages/plugin-form/src/MasterDetailForm.outcomeToastSupersede.test.tsx",
        "ui/packages/plugin-form/src/MasterDetailForm.singleRefusalRaiser.test.tsx",
        "ui/packages/plugin-form/src/MasterDetailForm.test.tsx",
        "ui/packages/plugin-form/src/WizardForm.outcomeToastSupersede.test.tsx",
        "ui/packages/plugin-form/src/submitHandlerSeam.test.tsx",
        "ui/packages/plugin-form/src/submitTargetRefusal.test.tsx",
        "ui/packages/plugin-grid/src/ObjectGrid.tsx",
        "ui/packages/plugin-grid/src/__tests__/inlineEditRuleCheck-27520.test.tsx",
        "ui/packages/plugin-grid/src/objectGridInlineRules.ts",
        "ui/packages/plugin-grid/src/objectGridTranslations.ts"
      ],
      "deviations": [
        "Surface widened by the seat (amendment 6541672013): data-table.tsx and form.tsx added, actionResponse.ts dropped. The mechanism differs from the order: the grid save bar and banner live in components data-table.tsx, and the banner+toast pair lives in form.tsx. extractFieldErrors / unmarkedRefusalLines from @object-ui/react are reused instead of refusalFieldErrors.",
        "Row 19 reverses the visible behaviour objectui#13340 pinned (banner plus one toast). The seat accepted this on its two conditions, both met. Contract review is owed.",
        "The seat's 'keep the toast where the form draws no banner' case does not arise: every refusal path of form.tsx draws the banner.",
        "Row 19's field mark for a script rule cannot be drawn: a script rule declares no fields, so the answer names only _record. Recorded here, not filed.",
        "The whole app-shell and console vitest suites were not run locally (left to CI); a search of both found no pin on the old toast or save-bar text."
      ],
      "mcp_calls": "reads only: issue_read #27520, pull_request_read get #28396. 0 writes",
      "api_writes": "2 via relay/stamped tools: pr_create (#28396, draft), this comment on #27520; plus git pushes to claude/project-thread-mcx7eo",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: a script validation rule's refusal names only _record, so no form can mark a field for it; a spec 'fields' hint on script rules would be needed"
      ]
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions