Repository navigation
Commit de6fbd4
test(qa-scenarios): add the requisition_to_receipt mid-tier scenario card (#30703)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} -->
_Requested by **Elon** · [project
thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9DGZeuomThCs6PH2x2FrJR8Q)_
Fixes #30480
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:新增「采购申请到收货」中档场景卡(8 个对象、按金额 5000 / 30000 分三档的多级审批、3 个角色其中 2
个按行限定、1 个采购支出报表、120 张采购申请跨 7–10 月、10 道问数、6 个写操作、5 个 agent
动作),并配一份只属于这张卡的真值测试。
- **为什么改**:落实 cloud#3600 九个场景中的采购场景,让 AI 建应用、问数、代办写操作都有一张能用代码判分的采购卡。
- **风险与回滚**:只加测试数据和测试,所在包私有、不发布,运行时零改动;回滚即删两个新文件。
- **先看**:① `docs/qa/scenarios/requisition_to_receipt.json` 的
`run.questions` 与 `run.operations`;②
`packages/qa/scenarios/test/requisition-to-receipt.test.ts` 的
`EXPECTED_TRUTHS` 及旁边的手算推导;③ 同一文件里的种子一致性用例。
- **两分钟验证**:`pnpm --filter @objectstack/scenarios test`,预期 5 个测试文件、69
个用例全绿。
- **需要你做的**:无,席位落地。
## What changes
- `docs/qa/scenarios/requisition_to_receipt.json` (new): the 采购申请到收货
requisition-to-receipt mid-tier card.
- Eight objects: `department`, `employee`, `supplier`,
`purchase_requisition` (the main object), `approval_step`,
`purchase_order`, `po_line` and `goods_receipt`.
- The amount-threshold approval: `approval_levels` is 1 up to 5,000, 2
up to 30,000 and 3 above (a formula on the amount). Level 1 goes to the
requester's department manager, level 2 to the finance controller, level
3 to the general manager. The seed holds all three levels, including a
requisition of exactly 5,000 at one level.
- Three personas: `requester` (own rows) and `dept_manager` (own
department) carry a row scope on all five transactional objects; `buyer`
is organization-wide. Department budgets are hidden from the requester
and the buyer, supplier bank accounts from the requester and the
manager.
- Seed: 120 requisitions dated July to October 2026, plus 184 approval
steps, 90 purchase orders, 117 order lines and 97 goods receipts. The
arithmetic rule that generated it is stated in the card's `$comment`, so
every truth can be worked by hand.
- Run half: 10 questions, 6 operations and 5 agent actions (one
confirm-gated); `iterate` adds supplier invoices with a three-way match.
- `packages/qa/scenarios/test/requisition-to-receipt.test.ts` (new):
this card's own test file.
- It pins all 10 computed truths and the 6 per-persona truths against
hand-worked values, with the derivations written next to the pins.
- It asserts the mid-tier floor and the seed's own consistency: a line
is quantity times unit price, an order totals its lines and equals its
requisition, the approval levels follow the thresholds, each level
routes to its approver, the steps match the status, and a received order
has every line fully received.
- It shows that a wrong seed cell or a wrong truth spec in a fixture
copy goes red against those pins.
## Why
The card is one of the six mid-tier scenarios ruled on
objectstack-ai/cloud#3600 (Q1 = v3). It gives the procurement domain a
scenario whose answers, permission boundaries and write outcomes are
graded by code.
## Tests
`pnpm --filter @objectstack/scenarios test`: 5 files, 69 tests passed.
`pnpm --filter @objectstack/scenarios typecheck`: exit 0, after building
the closure with `pnpm --filter '@objectstack/scenarios^...' build`;
`tsc --listFiles` includes the new test file.
## Acceptance notes
- **File name.** The card is `requisition_to_receipt.json`, not
`requisition-to-receipt.json` as the issue spells it. A card's `id` must
be a snake_case machine name equal to the file's basename, so a
hyphenated basename cannot load. The schema is unchanged.
- **`library.test.ts` untouched.** It names only the three control cards
and asserts the rest by "no refusal", so this card needs no line there.
- **No schema field for some floor items.** As on the travel-expense
card, three floor items have no field in the schema: an approval or
automation flow as a structural expectation, "declarative preferred",
and a report as distinct from a dashboard. The card states them in
`prompt.detailed` (zh and en) and in `capabilities`, seeds
`approval_step` as an expected object, and declares the report under
`expect.dashboards`. Nothing in the loader grades them.
- **Seven operation kinds, six operations.** `raise_po_from_text` covers
two of them: entry from free text with lines, and the multi-step chain
(raise the order, add two lines, send it, and the requisition becomes
ordered). `manager_approves_level_one` carries the workflow step and its
progress query in one ask; `pr_0111_waiting_on` asks the same
requisition's progress before the step.
- **Free-text lines matched by price.** The two lines
`raise_po_from_text` creates are matched by quantity and unit price
(41,500 and 6,500 are on no seeded line), not by the item text, so an
agent that spells the item differently still matches.
- **A value no seed row carries.** `cancel_sent_po` writes `status:
cancelled`. `expect.selectFields` asks `purchase_order.status` for at
least four options (draft, sent, received, cancelled); the loader checks
only that the field exists.
- **Capability tags.** The loader checks only the area half. The names
follow the travel-expense card; `approvals.dynamic-approver-routing` is
also a checklist item.
- **Reference not read.** `objectstack-ai/templates` is outside this
session's repository scope. The domain is designed from the card text
alone, and the rulings are applied as the card states them.
- **Seed generator.** The seed was generated by a scratch script kept
out of the PR. Its rule is the card's `$comment`. The pinned truths were
worked from that rule (the derivations are in the test file) and
cross-checked by an independent count. The loader matched every pin on
its first run.
## Verification
<details>
<summary>scenarios test + typecheck (head 1590b31)</summary>
```
Test Files 5 passed (5)
Tests 69 passed (69)
> tsc --noEmit
os-verify-lock: VERDICT command-exit 0
```
</details>
<details>
<summary>dispatch-gates --commands (50 commands, local, head
1590b31)</summary>
All 50 derived commands exit 0. The `--ran` reconciliation reads: 50
derived, 50 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero because every
line recorded its exit code.
The first sweep, on the pre-merge head 3d37abf, had four non-zero
exits, all from the local tree rather than the diff. Each cleared before
the second sweep:
- `check-plugin-teardown-shape.mjs --self-test` exit 3: the shallow
clone could not reach its pinned fixture commit; cleared by `git fetch
--unshallow origin main`.
- `check:doc-formula-expressions` exit 3 and
`check:dual-build-cjs-loads` exit 3 (PREREQUISITE NOT MET): a dist was
not built; cleared by a whole-tree `turbo run build` (119/119).
- `check:dts-closure` exit 1: it ran while a closure build of mine was
rebuilding `@objectstack/metadata`, so its declarations were briefly
absent; exit 0 once no build was running.
Changed lines: 1332 (+1332 / -0, 2 files), under the 3000 threshold.
`origin/main` was merged at `b77c160a02` before this PR opened; the
delta against `main` is still exactly the two new files.
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(No schema touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes (the new test file lints
clean with the repo config; the repo-wide run is CI's).
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset. (Nothing
publishes: `@objectstack/scenarios` is private, so `skip-changeset`.)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (Not touched.)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
---
_Generated by [Claude
Code](https://claude.ai/code/session_016WV4cwyCQLVbmVSgGXVBhc)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent bfb6e15 commit de6fbd4
2 files changed
Lines changed: 1332 additions & 0 deletions
File tree
- docs/qa/scenarios
- packages/qa/scenarios/test
0 commit comments