Skip to content

test(app-shell): pin the invite outcome toast and the copy-invite-link dialog on Setup → Invitations - #28182

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-tk3ydm
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-tk3ydm

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #27797
Refs #27521 (row 6)

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

One new pin, ui/packages/app-shell/src/views/ObjectView.inviteOutcome-27797.test.tsx, beside ObjectView.inviteFeedback-11817.test.tsx. It mounts the real ObjectView over sys_invitation as a stock boot serves it, with the real action runner, console action runtime, param dialog, result dialog and toaster (sonner not mocked):

  • link_only invite answer: the toast is the declared "Invitation created for ada@example.com. Mail is not configured on this server, so no email went out. Use Copy Invite Link on the invitation to share it." and no "Invitation sent" text appears.
  • Control, sent answer: "Invitation sent to ada@example.com", and no "no email went out" text.
  • A pending row's menu offers Copy Invite Link. Its click posts to /api/v1/actions/sys_invitation/copy_invitation_link naming the row id. The result dialog titled "Invite link" shows the answered acceptUrl as text, and its copy button writes exactly that URL to the clipboard.
  • Control: an accepted row's menu offers Resend Invitation and no Copy Invite Link.

No ui code changed. Per ruling E (comment 6512831254), the server carries the fix (outcomeMessages, and a type: 'script' action answering into a resultDialog with format: 'text'). The live re-measure below shows that fix reaching the console unchanged, so no renderer change was needed.

Tests

  • Pin: 4/4 passed at 43ba24a6 (pnpm --dir ui exec vitest run packages/app-shell/src/views/ObjectView.inviteOutcome-27797.test.tsx, under scripts/pm/os-verify-lock.sh, VERDICT command-exit 0).
  • The first run failed 3 of 4 when the fixture's features omitted cloudManaged. Every served invite predicate reads features.cloudManaged != true, an absent key fails the predicate closed, and a stock boot serves cloudManaged: false. The fixture now carries the served value, with a comment saying why.
  • No ablation: the diff changes no tested behaviour, since it only adds a test.

Acceptance notes

  • Live re-measure, stock examples/app-showcase (pnpm dev -- --fresh, seeded admin, desktop 1440×900, Chromium), origin/main 10fc9bf1, full workspace build plus console build from this tree:
    • No mail transport (default log): the invite door answers outcome: "link_only". Toast: "Invitation created for ada.nomail@example.com. Mail is not configured on this server, so no email went out. Use Copy Invite Link on the invitation to share it." Resend toast: "Invitation renewed for … no email went out …". Row menu: Cancel Invitation, Resend Invitation, Copy Invite Link. The detail drawer's record header shows Copy Invite Link. The copy dialog shows http://localhost:38797/_console/accept-invitation/ID, the copy button puts that same string on the clipboard, and the URL answers 200 text/html (the accept page under the console mount).
    • Live transport: OS_EMAIL_PROVIDER=smtp against a local SMTP sink. The door answers outcome: "sent", and the toast reads "Invitation sent to grace.mail@example.com". The accept URL in the delivered mail (quoted-printable decoded) equals the copy dialog's URL byte for byte.
  • Out of scope, for the seat (class a, reach measured in the console): the result dialog's copy button (CopyButton in ActionResultDialog.tsx, used by the text / secret / qrcode / code-list / json formats) is icon-only and has no accessible name. In the live dialog its aria-label and text are both empty, so a screen reader announces an unnamed button. This affects every resultDialog, not only invitations. Dedupe words: result dialog copy button accessible name, CopyButton aria-label, resultDialog copy icon.
  • skip-changeset is right for this diff: it is tests only, in @object-ui/app-shell ("private": true, files lists dist, and the built dist has 0 hits for the test against a positive control of 8 for ActionResultDialog). The seat applies the label after its own check.

Verification

Derived gates (dispatch-gates --commands, 24) — all exit 0 at 43ba24a; --ran: 24 run, 0 NOT-MEASURED, 0 UNRUN
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0   (169 files passed, 2 skipped; 4901 tests passed)
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
Outside the derivation
cd ui && node scripts/check-new-cross-file-line-citations.mjs :: exit 0   (0 new citations)
cd ui/packages/app-shell && tsc -p tsconfig.test.json --noEmit :: exit 0   (0 errors; its include covers src/**/*.test.tsx)
cd ui && eslint packages/app-shell/src/views/ObjectView.inviteOutcome-27797.test.tsx :: exit 0

Generated by Claude Code

…g on Setup → Invitations

Drive the served sys_invitation through the real ObjectView: a link_only
invite answer toasts the declared created/no-mail copy and never "sent", a
sent answer keeps "Invitation sent to …", and the pending row's Copy Invite
Link runs the server action and copies the answered acceptUrl from the
result dialog; an accepted row offers no copy action.

Claude-Session: https://claude.ai/code/session_01L9qibvGisaRusgvzEwJxoQ
Co-Authored-By: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

席位核对

ACCEPT · seat domain:ui#1 · head 43ba24a6 · 2026-10-30T15:46Z

席位意见:服务端修复(#27843,PR #27902)已经到达控制台。没有配置邮件服务时,邀请提示说「已创建、没有发出邮件、请用 Copy Invite Link」,不再说「已发送」。待处理的邀请在行菜单和抽屉头部都有 Copy Invite Link,复制出的是控制台挂载下的接受页链接。本 PR 只加一个测试把这条链路钉住,不改产品代码,符合裁决 E(6512831254)。

  1. Shape: Fixes #27797, Refs #27521 (row 6), draft, base main. 1 file, +357/−0: ui/packages/app-shell/src/views/ObjectView.inviteOutcome-27797.test.tsx, beside ObjectView.inviteFeedback-11817.test.tsx as the order named. Clause-②: no and Metadata-protocol: none hold: tests only, no export, no metadata.
  2. Seat read of the pin: it mounts the real ObjectView → ActionRunner → console action runtime → ActionParamDialog / ActionResultDialog / ConsoleToaster (sonner unmocked, real i18next en). The two toast cases differ only in the answer's outcome. The copy case asserts the door call names the row id and that navigator.clipboard.writeText receives exactly the answered acceptUrl. The accepted-row control proves the visible predicate gates the action. The fixture abridges the served sys_invitation metadata; the dev measured it from a stock boot, and the cloudManaged: false comment explains the one non-obvious key.
  3. Live re-measure (dev, stock app-showcase at 10fc9bf1): log transport gives outcome: link_only and the no-mail toast; the row menu and drawer both offer Copy Invite Link, and /_console/accept-invitation/ID answers 200. SMTP to a local sink gives outcome: sent, "Invitation sent to …", and the mailed URL is byte-identical to the dialog URL.
  4. Gates / check-runs: the dev's 24 derived gates exit 0 (--ran 0 unrun), app-shell test tsc 0, eslint 0, pin 4/4. skip-changeset applied by the seat: tests only, under src of the private @object-ui/app-shell, nothing publishes. Check Changeset's only red at this head was the no-changeset message the label answers. The other runs are green or still running at this record.
  5. Out of scope: ActionResultDialog's icon-only copy button has no accessible name. Filed as Action result dialog: the copy button has no accessible name #28186 (needs-triage), serial behind Setup and Studio: suggestions from the 18.3.0 RC browser walkthrough: Setup naming and machine values, invitation and user onboarding, permission-set authoring, dialog focus, Studio first run, validation and flow builders, and publish-panel wording #27521's claim on the same file.
  6. Landing: check-governed-merges --pr 28182: NOT governed, 357 changed lines ≤ 3000. Not in check-owed-reviews (no contract face). The same seat session dispatched and reviewed this PR. The seat readies it and arms auto-merge on the maintainer's 「按 pm-dispatch 审过的pr你可以自主落地」 (seat thread, 2026-10-30T14:19Z).

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · os-tesla · session_01L9qibzC6RxMfB59EsgAoNN

席位核对

ACCEPT · seat domain:ui#1 · head 05e22529 · 2026-10-30T17:00Z · re-pins 6526955724 (head 43ba24a6)

The new head only merges origin/main at 70209b89, which includes #28193, the fix for main-red #28185 that turned Test UI (2/16) red at the old head. The delta against main is still the one file, ui/packages/app-shell/src/views/ObjectView.inviteOutcome-27797.test.tsx, +357/−0, so every reading in 6526955724 stands. At this head every check suite has completed, mergeable_state is clean, and skip-changeset is on. Landing as recorded there: the seat readies the PR and arms auto-merge.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 30, 2026 17:01
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 41095296286 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Test UI (2/16) — 失败步骤: Run the ui tests (shard 2/16)

    × the node cell and the Problems list both name the blank expression, in the same words 2530ms
    FAIL   dom  packages/app-shell/src/views/studio-design/AutomationsPillar.problemsAgree-27799.test.tsx > Automations page — Problems and the node agree on a blank expression (objectstack#27799) > the n
      ↳ 失败原因: AssertionError: expected 'flows[0].nodes[1].config.fields.id' to contain 'node \'write\''
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 5 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 30, 2026
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 86cf7ce Oct 30, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-tk3ydm branch October 30, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant