Skip to content

test(qa-scenarios): add the order_to_cash mid-tier scenario card - #30706

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-o6p52q
Nov 6, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-o6p52q

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread
Fixes #30477
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:新增「订单到收款」中档场景卡(8 个对象:员工、客户、产品、销售订单、订单明细、发票、收款、跟进活动;折扣审批加逾期催收自动化;3 个角色其中 2 个按行限定;1 张应收账龄报表;120 张订单跨 7–10 月;10 道问数、6 个写操作、5 个 agent 动作),并配一份只属于这张卡的真值测试。
  • 为什么改:落实 cloud#3600 九个场景中的订单到收款场景,让 AI 建应用、问数、代办写操作都有一张能用代码判分的销售到财务闭环卡。
  • 风险与回滚:只加测试数据和测试,所在包私有、不发布,运行时零改动,也不碰任何共享文件;回滚即删两个新文件。
  • 先看:① docs/qa/scenarios/order_to_cash.json 的 run.questions 与 run.operations;② packages/qa/scenarios/test/order-to-cash.test.ts 的 EXPECTED_TRUTHS 与 EXPECTED_PERSONA_TRUTHS;③ 同文件的种子一致性用例(发票、收款、账龄与催收规则)。
  • 两分钟验证:pnpm --filter @objectstack/scenarios test,预期 5 个测试文件、70 个用例全绿。
  • 需要你做的:无,席位落地。

What changes

  • docs/qa/scenarios/order_to_cash.json (new): the 订单到收款 order-to-cash mid-tier card.
    • Eight objects: employee, account, product, sales_order, order_line, invoice, payment and activity (the account's follow-up stream, its own records with lookups to the account, the invoice and the owner, never typed into the account).
    • The flows: an order with a line discounted above 10% is routed to the owner's sales manager (approver, approved_on), and an invoice 15 days past due and not fully paid gets a collection call for the AR clerk.
    • Three personas: sales_rep (e03, own accounts; no payment object, no product cost) and sales_manager (e01, team east; no payment bank reference) carry a row scope; ar_clerk (e09) sees everything but product cost.
    • Seed: 120 orders dated July to October 2026, plus 240 lines, 95 invoices, 72 payments and 64 activities. The arithmetic rule that generated it is stated in the card's $comment, so every truth can be worked by hand. Receivables are as of asOf 2026-10-31: one account has paid nothing, one pays half on the due date, one pays 20 days late.
    • Run half: 10 questions, 6 operations and 5 agent actions (one confirm-gated); iterate adds credit notes.
  • packages/qa/scenarios/test/order-to-cash.test.ts (new): this card's own test file.
    • It pins all 10 computed truths and the 8 per-persona truths against hand-worked values, with the derivations written beside the pins.
    • It asserts the mid-tier floor, and checks the seed against its own rule: line amounts, order totals, approval routing, one invoice per fulfilled order, the payment roll-up, balance, status and aging bucket, and the collection calls.
    • It checks that each write's declared outcome agrees with the seed (the targeted rows' state, the totals, the open balance the overpayment exceeds).
    • It shows that a wrong seed cell and a wrong truth spec in a fixture copy go red against those pins.

Tests

pnpm --filter @objectstack/scenarios test: 5 files, 70 tests passed (64 before this card, 6 new). pnpm --filter @objectstack/scenarios typecheck: exit 0, after building the closure with pnpm --filter '@objectstack/scenarios^...' build.

The pinned values were worked from the seed rule by a script that implements the business rule directly (it never reads the card's truth specs or calls the loader), then matched against the loader's computed truths: every pin agreed on the first run. The ranking, aging, subscription and per-persona derivations are written out by hand beside their pins.

Acceptance notes

  • File name. The card is order_to_cash.json, not order-to-cash.json as the issue spells it. A card's id must be a snake_case machine name and equal the file's basename, so a hyphenated basename cannot load. The test file follows the merged sibling's spelling, order-to-cash.test.ts.
  • No shared file touched. The travel-expense card's PR made test/library.test.ts assert only the three control cards and moved per-card pins to each card's own file, so this PR edits neither library.test.ts nor the README. Sibling cards no longer conflict with it.
  • README spelling. docs/qa/scenarios/README.md "Adding a card" step 3 names the pin file test/ID.test.ts, while its model and this card use a hyphenated basename. An observation only; the README is unchanged here.
  • No schema field for some floor items. The approval flow, the automation, "declarative preferred" and a report as distinct from a dashboard have no field in the schema. The card states them in prompt.detailed (zh and en) and in capabilities, seeds the approval on sales_order (approver, approved_on) and the automation's collection calls as activity rows, and declares the report under expect.dashboards. Nothing in the loader grades them.
  • Seven operation kinds, six operations. order_from_text covers two of them: entry from free text with lines, and the multi-step chain (create the order, add two lines, submit it, route it to the manager). The workflow step is approve_discount; its progress query is the question so_0120_waiting_on.
  • Two writes on SO-0110. rep_approves_own_discount (refused) is listed before approve_discount (applied). A refused write changes nothing, so both outcomes hold whether a runner grades each write against the seed or applies the writes in order.
  • Created rows matched by where. A where cannot name the new order's id, so order_from_text locates the order by account and today's date and each line by product, quantity and discount; no seeded row matches any of them. The lines are therefore not tied to the new order in the post-state.
  • Stored aging bucket. invoice.aging_bucket is a formula on today in the built app; the seed stores its value as of asOf, and the test holds every bucket to the due date.
  • Capability tags. approvals.dynamic-approver-routing and automation.time-relative-trigger are checklist items; the other tags follow the existing cards' wording. The loader checks the area half only.
  • Changeset. @objectstack/scenarios is private: true and nothing else moves, so this PR carries skip-changeset, as the travel-expense card's PR did.
  • Unreachable references. The domain is designed from the card text and general business knowledge alone; objectstack-ai/cloud#3567 was not read.

Verification

scenarios test + typecheck (head e44efca)
 Test Files  5 passed (5)
      Tests  70 passed (70)
> tsc --noEmit
os-verify-lock: VERDICT command-exit 0
dispatch-gates --commands (50 commands, local, head e44efca)

All 50 derived commands exit 0 on this head (the merge of main at e44efca), and on the pre-merge head 5d751a9 before it. The --ran reconciliation reads: 50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero because every line recorded its exit code.

On the first run two of them exited 3 (PREREQUISITE NOT MET) and exited 0 once the prerequisite was met:

  • check-plugin-teardown-shape.mjs --self-test, after fetching its pinned positive-control commit into the shallow clone;
  • check:dual-build-cjs-loads, after a full turbo run build (119 of 119 tasks).

After the merge of main (which moved packages/spec): pnpm --filter @objectstack/spec build then check:generated reported all 14 generated artifacts up to date.

Changed lines: 1379 (+1379 / -0, 2 files), under the 3000 threshold.


Generated by Claude Code

Adds docs/qa/scenarios/order_to_cash.json, the 订单到收款 order-to-cash
mid-tier card: eight objects (employee, account, product, sales_order,
order_line, invoice, payment, activity), a discount approval routed to
the owner's sales manager, a time-triggered collection-call automation,
three personas (two row-scoped), a receivables aging report, 120 orders
across July-October 2026, 10 questions, 6 operations and 5 agent
actions.

Adds packages/qa/scenarios/test/order-to-cash.test.ts, the card's own
truth pins: every computed truth over all rows and per persona against
hand-worked values, the mid-tier floor, the seed's consistency with the
rule in $comment, and two fixture copies (a wrong seed cell, a wrong
truth spec) that go red against the pins.

Claude-Session: https://claude.ai/code/session_016WV4d1Exmm9uiWTdqYBhqM
Co-authored-by: Claude <noreply@anthropic.com>
Both writes target SO-0110. Listed first, the refused self-approval
leaves the seed unchanged, so its outcome and the manager's applied
approval hold whether a runner grades each write against the seed or
applies them in order.

Claude-Session: https://claude.ai/code/session_016WV4d1Exmm9uiWTdqYBhqM
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 Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 4bf9a2d7eeeec7c07971aba1a8734c227acaaa3a → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:devx#3 · os-elon-musk · session_016WV4cz3RTQjLh7hZBLzgtZ

席位核对 · ACCEPT · e44efca5 · 2026-11-05T23:10Z

Head-sha: e44efca53f6787e7a362687feaf65145beedf199

  • Shape: 2 files, +1,379/−0 (< 3,000), both on the amended claim surface (docs/qa/scenarios/order_to_cash.json, packages/qa/scenarios/test/order-to-cash.test.ts). Not governed. Fixes #30477, Clause-②: no, Metadata-protocol: none at line start.
  • Premise measured: schema from feat(scenarios): scenario-card schema + loader (private packages/qa package) and nine open seed cards #30340 on main; test(qa-scenarios): add the travel_expense mid-tier scenario card #30600 left library.test.ts and the README card-agnostic, so no shared line is touched.
  • Gates: check-runs on this head read by the seat: 35 success, 18 skipped (path filter), 0 failed or pending. Dev's local dispatch-gates 50/50 exit 0, --ran 0 NOT-MEASURED.
  • Spot checks (seat's own arithmetic against the pinned truths): receivables_aging 61–90 = 4300 + 6800 + 1600 + 1000 = 13,700 ✓, 31–60 = 9300 + 5550 + 800 = 15,650 ✓, 1–30 = 4300 + 6800 + 1200 + 1600 + 1000 + 10200 = 25,100 ✓, current = 124,240 − 54,450 = 69,790 ✓ (ties to open_receivables); orders_by_status cancelled 4 + 3 = 7, fulfilled 86 + 9 = 95 ✓. The acceptance "a deliberately wrong truth goes red" is two cases (wrong seed cell, wrong truth spec).
  • Accepted deviations: snake_case basename (id = basename, as test(qa-scenarios): add the travel_expense mid-tier scenario card #30600); main moved after the dev's merge (spec-only, no overlap), not re-merged.
  • Out of scope: none. Skills-docs: n/a.
  • Changeset: skip-changeset, the package is private (as test(qa-scenarios): add the travel_expense mid-tier scenario card #30600).
  • Landing: non-governed; flips when the maintainer's landing word for this term is on record.

@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

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

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

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

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

  • Test Core (1/8) — 失败步骤: Run this shard's tests

    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > is green against a verbatim copy of the shipped ledgers
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > stays green when the missing path is attributed to ANOTHER repo
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > never bounds a citation attributed to ANOTHER repo
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > prints the citation count and how many are in range, in the documented two
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — symbol anchors (#12516) > stays GREEN on the drifted BEFORE-state — the honest residual this grammar e
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — symbol anchors (#12516) > prints the anchor count and how many resolve, equal on a green run
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the evidence-scan population (#13041) > stays GREEN when a `dead` entry carries the SAME rotted pointe
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the evidence-scan population (#13041) > declares every status either scanned or explicitly unscanned, 
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the live-elsewhere criteria (#13483) > is green on the shipped ledgers and publishes the population be
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the live-elsewhere criteria (#13483) > is green on a planted live-elsewhere row and counts it as carry
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the README state table (#7257) > is green against a verbatim copy, and says how many rows it checked
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the generated count artifact (#7377, sharded #20361) > is green against a verbatim copy, says the shar
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    

↳ 失败原因 是判读的关键:超时(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 队列共有 4 个失败构建(不含本次)。

分诊清单:

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

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:devx#3 · os-elon-musk · session_016WV4d1Exmm9uiWTdqYBhqM

Merge-queue triage: run 42160085799 is red from #30716, not from this PR


Generated by Claude Code

@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

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

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

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

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

  • Test Core (1/8) — 失败步骤: Run this shard's tests

    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > is green against a verbatim copy of the shipped ledgers
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > stays green when the missing path is attributed to ANOTHER repo
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > never bounds a citation attributed to ANOTHER repo
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — evidence pointers (#5623) > prints the citation count and how many are in range, in the documented two
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — symbol anchors (#12516) > stays GREEN on the drifted BEFORE-state — the honest residual this grammar e
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — symbol anchors (#12516) > prints the anchor count and how many resolve, equal on a green run
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the evidence-scan population (#13041) > stays GREEN when a `dead` entry carries the SAME rotted pointe
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the evidence-scan population (#13041) > declares every status either scanned or explicitly unscanned, 
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the live-elsewhere criteria (#13483) > is green on the shipped ledgers and publishes the population be
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the live-elsewhere criteria (#13483) > is green on a planted live-elsewhere row and counts it as carry
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the README state table (#7257) > is green against a verbatim copy, and says how many rows it checked
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    @objectstack/spec:test:  FAIL   local  scripts/liveness/check-liveness.test.ts > check:liveness — the generated count artifact (#7377, sharded #20361) > is green against a verbatim copy, says the shar
      ↳ 失败原因: @objectstack/spec:test: AssertionError: Spec liveness gate (registry-rooted) — governed types: object, field, flow, action, hook, permission, position, agent, tool, skill, dataset, page, view, report,
    

↳ 失败原因 是判读的关键:超时(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 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 8 个失败构建(不含本次)。

分诊清单:

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scenario library: mid-tier card — 订单到收款 order-to-cash (8–10 问数 + 4–6 write operations, row-scoped personas)

2 participants