Skip to content

Commit de3996b

Browse files
feat(scenarios): every Build check traces to the build prompt (#31185)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"} --> _Requested by **Leehom** · [project thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X93oALNL86RLkdGBScHovs1)_ Fixes #31144 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:场景跑测的建造提示词现在按名写明 Build 半场逐条检查的结构(查找字段指向、单选字段最少选项数、仪表盘名、应用导航目标),迭代提示词同样写明新增对象与字段;五张把审批历史当普通数据种入的卡片改为“审批即数据”,去掉 `approvals.*` 标签并在描述里说清楚;带行内编辑标签的卡片在描述里写明明细在主表单上内联编辑。 - 为什么改:首次完整中档跑测里,忠实按描述建造的应用因为猜不中仪表盘名、选项个数、审批引擎而丢分;原则是每条 Build 检查都必须能在提示词里找到出处。 - 风险与回滚:只动私有包 `@objectstack/scenarios` 与 `docs/qa/scenarios` 卡片,不发布;回滚即 revert 本 PR。代价是开放卡库暂时没有一张卡考察平台审批引擎(三条审批标签行保留在表里)。 - 先看:`packages/qa/scenarios/src/runner/prompts.ts`(`structureLines` / `changeContract`)、`packages/qa/scenarios/test/runner/prompt-trace.test.ts`、`docs/qa/scenarios/order_to_cash.json` 的描述与标签。 - 两分钟验证:`pnpm --filter @objectstack/scenarios exec vitest run test/runner/prompt-trace.test.ts`,预期 40 个用例全绿。 - 需要你做的:无,席位落地。 ## What changes **The rule.** Every Build check traces to text the build prompt carries; otherwise a faithful build fails for not guessing a name. 1. **Item 1, dashboard / report names: the route chosen is "state each name in the data contract".** `dataContract` (`packages/qa/scenarios/src/runner/prompts.ts`) gains a `Structure:` block, rendered by the new `structureLines`, that names every `expect` row the exact-name scorer (`scoreGraph`) checks beyond the seed: each lookup's target, each single-choice field with its minimum option count, each dashboard, and each app navigation target. Why this route and not "check by function": - The counted Build score is the exact-name scorer; the name-agnostic one (`scoreGraphShape`) is reported, not counted. Every other `expect` row already traces by name (objects and fields through the seed, persona sets as `NAMESPACE_PERSONA`); dashboards and nav targets were the only rows that did not. - "By function" already exists where it belongs: the `dashboards.report` and `dashboards.widget-measures` tag rows judge a report or widget over an object the card names. A functional `expect.dashboards` would duplicate them and change the card schema, the loader's gallery floor, `appNavTargets` resolution, the iterate delta and the screenshot exporter (`export/screenshots.ts` picks the card's dashboard by name). - The cost is that a card prescribes the name. The naming rule already prescribes the prefix of every item, and the run showed builds follow contract names verbatim (every persona set was built by its contract name). - Measured on main `8ef4d309`: six cards pin a dashboard and its nav entry, not three. `requisition_to_receipt` pins `purchasing_spend_by_department` and `service_desk` pins `support_performance`, besides the three the card names. The rule applies to all six. 2. **Item 2, option minimums: the route chosen is "state the minimum in the contract".** Each `expect.selectFields` row is stated as a single-choice field with its count, for example `` `demopurchase_supplier.category` (4) ``. On a card carrying `records-forms.select-options`, one more line states that tag's check: every other single-choice field the build declares offers two options or more. That is the check behind the `asset_category.depreciation_method` failure: it is the tag row `select:asset_category.depreciation_method->options>=2`, not an `expect` row. Every row is kept: in five rows the minimum is above what the seed shows (`leave_day.portion` 3/2, `invoice.status` 4/3, `invoice.aging_bucket` 5/4, `purchase_order.status` 4/3, `escalation_rule.priority` 4/3), and the prose names each extra option (afternoon, written off, over 90, cancelled, low). 3. **Item 3, approval tags: all five cards model approvals as data.** I decided each card separately; the table is in Acceptance notes. The card's stop condition does not apply, because modelling approvals as data keeps every approval-history question answerable. For `asset_lifecycle`, `leave_balances`, `order_to_cash`, `requisition_to_receipt` and `travel_expense`: - **Tags:** `approvals.approval-flow`, `approvals.multi-step-approval` and `approvals.dynamic-approver-routing` come off the cards. - **Prose (zh and en):** says where each decision is recorded (an approval step record, or the approver and decision date on the request) and that deciding updates that record. It no longer lists "an approval process" among the preferred declarative tools. - **Seed:** unchanged. It already modelled approvals this way. 4. **Item 4, `master-detail-inline-edit`: it is stated in the prompt.** The prose of every card carrying the tag now says the lines are details of their master, edited inline on its form: `order_to_cash`, `leave_balances`, `requisition_to_receipt` and `travel_expense`, plus the control card `invoice_with_line_items` (one clause). `project_with_tasks` already said it. 5. **Bounded in-place fix in the same class: the iterate prompts.** `iteratePrompt` and `templateIteratePrompt` now append `changeContract`. The iterate re-score checked `iterate.expectDelta` names that the iterate prompt never stated (`demoorder_credit_note`, `demoasset_asset_transfer.to_department`, …). The prompts now state the new objects (with the card's field minimum) and the delta's lookups and option fields. The fix meets all four in-place conditions: the same defect class, the renderer from item 1, `prompts.ts` held by this claim, and the same gate family. 6. **Docs:** - `docs/qa/scenarios/README.md` gains "Build checks trace to the prompt" (names, tags, approvals). - The package README gains a "Structure contract" bullet. ## Why The first complete mid-tier run (cloud#3600, main `5f003744`) lost Build points on checks the build was never told about: dashboard names, option counts, an approval engine the cards' own data never runs through, and inline edit. ## Tests - New `packages/qa/scenarios/test/runner/prompt-trace.test.ts` (40 tests). It reads the exact-name checks off the scorer itself, as `scoreGraph` over an empty graph, and requires each to name text in the build prompt (or in both iterate prompts, for the delta's checks) for all 9 cards. A check kind the contract does not know is reported as untraced. It also pins the two-option floor line where the tag is carried, the inline-edit clause in each language of a tagged card, and that a card seeding a decision date (`decided_on` / `approved_on`) carries no `approvals.*` tag and asks for no approval process. - `test/score/scenario-tags.test.ts`: the library pin "each row is declared by a card" now exempts the two approval-engine rows, which no open card declares, and says why. The rows stay in the table. - Ablations, run through `scripts/ablation-replace.mjs`. Each mutation landed on disk, was restored, and the blob equals HEAD (`4dee8b93ba84`, `git diff HEAD` empty): - With the `Structure:` block emptied, the suite read 18 failed of 40 (the build trace for 9 cards and the select floor for 9). - With `changeContract`'s structure rows emptied, it read 18 failed of 40 (the iterate trace and the floor). ## Acceptance notes <details><summary>Item 3: the per-card approval reading</summary> | Card | Approval history in the seed | 问数 reading it | Operations grading approval | Under the engine route | Decision | |:--|:--|:--|:--|:--|:--| | asset_lifecycle | `disposal_request.approver`, `decided_on`, `status` | `dr_0005_waiting_on` | `manager_approves_scrap`, `employee_approves_own_scrap` update the request | the waiting-on question loses its rows; the approver is an `employee` row, not a user | data | | leave_balances | `approval_step` (141 rows) | `lr_0105_waiting_on`, `pending_by_approver` | `manager_approves_step_one` updates an approval step | the approval step object leaves the seed, with two questions and two persona scopes | data | | order_to_cash | `sales_order.approver`, `approved_on`, `status` | `so_0120_waiting_on` | `approve_discount`, `rep_approves_own_discount` update the order | the approver is an `employee` lookup, which an engine approver cannot route to | data | | requisition_to_receipt | `approval_step` (184 rows) | `pr_0111_waiting_on` | `manager_approves_level_one`, `manager_approves_finance_level` update an approval step | the same as leave_balances | data | | travel_expense | `approval_step` (204 rows) | `ec_0093_waiting_on` | `manager_approves_step_one`, `employee_approves_own_claim` update an approval step | the same as leave_balances | data | Each card's `agentActions` also decide approvals on the data object: `decide_approval_step`, `decide_scrap_request`, `decide_discount_approval`. </details> - **No open card exercises the platform approval engine now.** The three tag rows stay in `CAPABILITY_TAG_CHECKS`, judged and tested, for a card written for the engine: approvers as users, no seeded engine history, and approving through the engine's decide door. Writing such a card is outside this card. - **The control card `invoice_with_line_items` now differs from its corpus case.** Its prose gains ", inline on its form". The golden case in `packages/cli/src/lint/corpus.ts` keeps its wording: the card's `provenance` derives only `expect` from it, and `scenario-cards.test.ts` pins only that. - **Card premise readings:** - The `select:…>=Nopts` spelling is real for `expect` rows. The fourth example the card gives is the tag row's spelling `select:OBJECT.FIELD->options>=2`. - The PM hypothesis "requisition_to_receipt may pin none" is disproved: it pins one dashboard. - **Out of scope:** the runner's `owner_id` and seed logic (#30914 / #30913), and #31145's run-grading items. ## Verification - Head `115474c9`, base `8ef4d309`. - `pnpm --filter @objectstack/scenarios test`: Test Files 24/24, Tests 495/495 on head `115474c9` (after `pnpm --filter '@objectstack/scenarios^...' build` and the package build). - `pnpm --filter @objectstack/scenarios typecheck` (`tsc --noEmit`, its `include` covers `test/**`): exit 0. - `node --stack-size=4000 node_modules/eslint/bin/eslint.js packages/qa/scenarios --no-inline-config` (the root `pnpm lint` command, scoped; the package has no lint script, and the cards are JSON, which the config does not lint): exit 0. - **Not measured:** - A recorded-driver replay. No recording is in this container, and the recorded driver replays turns by card, mode and phase, not by prompt. - A live model run. Live runs are paused by the maintainer. <details><summary>Derived gates (dispatch-gates --commands on head, 52 commands)</summary> ```text node scripts/check-adr-links.mjs :: exit 0 node scripts/check-adr-links.mjs --self-test :: exit 0 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-adoption.mjs :: exit 0 node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0 node scripts/check-comment-mask-corpus.mjs :: exit 0 node scripts/check-dts-emitted.mjs --self-test :: exit 0 node scripts/check-issue-citations.mjs :: exit 0 node scripts/check-plugin-teardown-shape.mjs :: exit 0 node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0 node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0 node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0 node scripts/docs-audit/check-affected-docs.mjs :: exit 0 node scripts/docs-audit/check-drift-comment.mjs :: exit 0 pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0 pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0 pnpm check:ci-filter-parity :: exit 0 pnpm check:closed-ceremony-text :: exit 0 pnpm check:cross-package-test-inputs :: exit 0 pnpm check:doc-authoring :: exit 0 pnpm check:driver-memory-census :: exit 0 pnpm check:dts-closure :: exit 0 pnpm check:dual-build-cjs-loads :: exit 3 pnpm check:engine-double-contract :: exit 0 pnpm check:gitlink-declared :: exit 0 pnpm check:issue-citations :: exit 0 pnpm check:keyed-text-bounds :: exit 0 pnpm check:lean-entry-closure :: exit 0 pnpm check:logger-receiver-detach :: exit 0 pnpm check:nul-bytes :: exit 0 pnpm check:objectql-double-limit :: exit 0 pnpm check:org-identifier :: exit 0 pnpm check:page-declaration-shape :: exit 0 pnpm check:platform-object-tenancy-census :: exit 0 pnpm check:published-files :: exit 0 pnpm check:query-options-erasure :: exit 0 pnpm check:refd-timer-probe :: exit 0 pnpm check:registry-log-declared :: exit 0 pnpm check:rest-log-spy-declared :: exit 0 pnpm check:slot-lookup :: exit 0 pnpm check:sourcemap-no-sources-content :: exit 0 pnpm check:system-context-census :: 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:vouch-for-reference-callers :: exit 0 pnpm check:watch-hint-literal :: exit 0 pnpm check:where-matcher :: exit 0 node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0 ``` - `dispatch-gates --ran`: 52 derived, 51 run, 1 NOT MEASURED (`check:dual-build-cjs-loads` exit 3, PREREQUISITE NOT MET: it needs every package's `dist/`), 0 unrun. - `check-plugin-teardown-shape.mjs --self-test` first answered exit 3 on the shallow clone; after `git fetch --depth=1 origin 621a487…` it answered exit 0 (48 cases). - Every CI-run family is read from this PR's check-runs. </details> <details><summary>The rendered structure block, order_to_cash</summary> ```text Structure: besides the objects and fields above, the build is checked for these, by the exact names shown: - Lookups, each referencing the object shown: `demoorder_employee.manager` → `demoorder_employee`, `demoorder_account.owner` → `demoorder_employee`, `demoorder_sales_order.account` → `demoorder_account`, `demoorder_sales_order.owner` → `demoorder_employee`, `demoorder_sales_order.approver` → `demoorder_employee`, `demoorder_order_line.order` → `demoorder_sales_order`, `demoorder_order_line.product` → `demoorder_product`, `demoorder_invoice.order` → `demoorder_sales_order`, `demoorder_invoice.account` → `demoorder_account`, `demoorder_payment.invoice` → `demoorder_invoice`, `demoorder_activity.account` → `demoorder_account`, `demoorder_activity.invoice` → `demoorder_invoice`, `demoorder_activity.owner` → `demoorder_employee`. - Single-choice (select) fields, each offering at least the number of options shown: `demoorder_employee.role` (4), `demoorder_employee.team` (3), `demoorder_account.payment_terms` (2), `demoorder_product.category` (3), `demoorder_sales_order.status` (5), `demoorder_invoice.status` (4), `demoorder_invoice.aging_bucket` (5), `demoorder_payment.method` (3), `demoorder_activity.type` (4). - Every other single-choice field you declare offers at least two options: a field with one option is no choice. - Dashboards, each a dashboard named exactly: `demoorder_receivables_aging_report`. A report the description asks for may be shown on one; it does not stand in for it. - The app's navigation has an entry for each of: `demoorder_account`, `demoorder_sales_order`, `demoorder_invoice`, `demoorder_payment`, `demoorder_activity`, `demoorder_receivables_aging_report`. ---ITERATE--- Add credit notes for returns and allowances: a credit note is issued against an invoice and reduces its balance. The change is checked for these, by the exact names shown: - New objects, named exactly: `demoorder_credit_note`, each with at least 4 fields. - Lookups, each referencing the object shown: `demoorder_credit_note.invoice` → `demoorder_invoice`, `demoorder_credit_note.account` → `demoorder_account`. - Every single-choice field you declare offers at least two options: a field with one option is no choice. ``` </details> ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (untouched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes (scoped to the touched paths; 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: this one does not publish (`@objectstack/scenarios` is `private`), `skip-changeset`. - [x] 6. `packages/spec` touched: no. - [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 (the 维护者速读 block is the lane's Chinese summary). --- _Generated by [Claude Code](https://claude.ai/code/session_01FEkQ5n81cbmj4ZjYYxQQAs)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent bd81a7a commit de3996b

11 files changed

Lines changed: 255 additions & 25 deletions

File tree

‎docs/qa/scenarios/README.md‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ question's computed truth; a card that does not load is red in CI.
3131
| Layer | Key | What it states |
3232
|:---|:---|:---|
3333
| 1 | `prompt` | `{ short, detailed }`, each `{ zh?, en? }` with at least one language. |
34-
| 2 | `expect` | The structural expectation the deterministic scorer reads, field for field: `objects`, `minFieldsPerObject?`, `selectFields?` (`{ object, field, minOptions }`), `lookups?` (`{ object, field, to }`), `dashboards?`, `appNavTargets?`. |
34+
| 2 | `expect` | The structural expectation the deterministic scorer reads, field for field: `objects`, `minFieldsPerObject?`, `selectFields?` (`{ object, field, minOptions }`), `lookups?` (`{ object, field, to }`), `dashboards?`, `appNavTargets?`. The runner's build prompt states every row by name ([Build checks trace to the prompt](#build-checks-trace-to-the-prompt)). |
3535
| 3 | `capabilities`, `businessFunctions` | Tags `<area>.<name>`, where `<area>` is a closed set: the basenames of `docs/qa/platform-checklist/areas/*.json`, read from the tree. `businessFunctions` is the marketplace taxonomy's business-function facet, read from `@objectstack/spec/marketplace` (`MarketplaceBusinessFunctionsSchema`, defined once in `packages/spec/src/marketplace/taxonomy.zod.ts`): 1-3 distinct values, the primary one first — the card is classified the way the template it graduates into will be listed. |
3636
| 4 | `run.seed`, `run.questions`, `run.personas` | Seed rows per object; at least five read-only questions, each with a **declarative** truth spec; at least two personas, each a role, the objects or fields it must NOT see, and optionally a row `scope`. |
3737
| 5 | `run.operations`, `run.guardrails`, `run.agentActions?` | At least two writes, each acting as a persona and declaring its `outcome`; the five guardrail checks; optionally the agent-callable business actions. |
@@ -210,6 +210,27 @@ the loader enforces; each card's own test pins the rest:
210210
action, a refused overstep, a refused validation violation and one multi-step chain;
211211
- at least three agent actions, one of them confirm-gated.
212212

213+
## Build checks trace to the prompt
214+
215+
Every Build check must trace to text the build prompt carries; otherwise a faithful build fails
216+
for not guessing a name.
217+
218+
- **Names.** The runner's data contract states the seed (objects and fields), each persona's
219+
permission set and every `expect` row by name: lookup targets, option fields with their
220+
minimum option counts, dashboards and app navigation targets. The iterate prompt does the
221+
same for `iterate.expectDelta`. A card therefore picks its dashboard names knowing the build
222+
is told them.
223+
- **Tags.** A capability tag whose check reads something the seed does not show is asked for
224+
in the card's prose: `records-forms.master-detail-inline-edit` names the detail edited inline
225+
on its master, in every language the prompt carries.
226+
- **Approvals.** A card either exercises the platform approval engine or models approvals as
227+
data, never both. A card that seeds approval history as rows (an approval step object, or an
228+
approver and decision date on the record) and grades approving as a data write models them
229+
as data: its prose says each decision is a record it updates, asks for no approval process,
230+
and it carries no `approvals.*` tag, whose checks read the engine's Approval node. The engine
231+
keeps its own history, which no seed row can preload. Every open card models approvals as
232+
data today.
233+
213234
## Adding a card
214235

215236
1. Write `<id>.json` here; `id` equals the basename, `code` is one no other card uses, and

‎docs/qa/scenarios/asset_lifecycle.json‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"en": "Build a fixed-asset lifecycle app: an asset register, checkout and return, repairs, monthly depreciation and a scrap approval."
1313
},
1414
"detailed": {
15-
"zh": "固定资产全生命周期应用。资产按类别登记(笔记本电脑、显示器、手机、办公椅),每个类别规定使用月数和折旧方法(直线法,无残值);每项资产记录资产编号、序列号、类别、所属部门、采购日期和采购成本。资产管理员把资产领用给员工,一次可以领用多件;领用单记录领用日期、应还日期(长期配发不填)、归还日期和归还时的状况。领用后资产状态自动变为使用中、保管人为领用人,归还后保管人清空;只有在库的资产才能领用,否则不能保存。资产损坏时开维修单(故障描述、状态、维修费用),维修期间资产状态为维修中。每月最后一天由定时流程给每项未报废的资产计提一个月折旧(采购当月不计提);资产的累计折旧汇总它的折旧记录,账面价值 = 采购成本 − 累计折旧。报废要走审批:报废申请由资产所属部门的经理审批,批准后由资产管理员执行报废;执行报废不可撤销,资产变为已报废、剩余账面价值核销,此后不再计提折旧。员工只能看到自己保管的资产,以及自己的领用单、自己报修的维修单和自己提交的报废申请,看不到采购成本、累计折旧、账面价值、折旧记录和部门资产预算;部门经理能看到本部门的资产、本部门员工的领用单,以及本部门资产的维修单、报废申请和折旧记录;资产管理员能看到全部资产,但看不到部门资产预算;员工的家庭住址(用于寄送设备)只有资产管理员可见。需要一个按类别和部门统计资产数量和账面价值的报表。尽量用声明式配置(公式字段、汇总字段、校验规则、审批流程、定时流程)而不是代码钩子,以便应用能以非托管方式安装。",
16-
"en": "A fixed-asset lifecycle app. Assets are registered by category (laptop, monitor, mobile phone, office chair); each category sets a useful life in months and a depreciation method (straight line, no salvage value), and each asset records its asset tag, serial number, category, owning department, purchase date and purchase cost. The asset administrator checks assets out to employees, several at once if needed; a checkout records the checkout date, a due date (none for a permanent assignment), the return date and the condition on return. A checkout sets the asset in use with the employee as its custodian, and a return clears the custodian; only an asset in stock can be checked out, otherwise the checkout cannot be saved. A damaged asset gets a repair order (the fault, a status and the repair cost) and is in repair until it is fixed. On the last day of each month a scheduled flow posts one month of depreciation for every asset not disposed of (nothing for the purchase month); an asset's accumulated depreciation sums its depreciation entries, and its book value is the purchase cost minus the accumulated depreciation. Scrapping needs an approval: the manager of the asset's department decides a scrap request, and once it is approved the asset administrator disposes of the asset; a disposal cannot be undone, sets the asset disposed, writes off its remaining book value and stops its depreciation. An employee sees only the assets they hold and their own checkouts, the repairs they reported and the scrap requests they filed, and sees no purchase cost, accumulated depreciation, book value, depreciation entry or department asset budget; a department manager sees their department's assets, their own people's checkouts, and the repairs, scrap requests and depreciation of their department's assets; the asset administrator sees every asset but no department's asset budget; an employee's home address (used to ship equipment) is visible to the asset administrator only. Add a report of asset count and book value by category and department. Prefer declarative configuration (formula and roll-up fields, validation rules, an approval process, a scheduled flow) over code hooks, so the app can be installed unmanaged."
15+
"zh": "固定资产全生命周期应用。资产按类别登记(笔记本电脑、显示器、手机、办公椅),每个类别规定使用月数和折旧方法(直线法,无残值);每项资产记录资产编号、序列号、类别、所属部门、采购日期和采购成本。资产管理员把资产领用给员工,一次可以领用多件;领用单记录领用日期、应还日期(长期配发不填)、归还日期和归还时的状况。领用后资产状态自动变为使用中、保管人为领用人,归还后保管人清空;只有在库的资产才能领用,否则不能保存。资产损坏时开维修单(故障描述、状态、维修费用),维修期间资产状态为维修中。每月最后一天由定时流程给每项未报废的资产计提一个月折旧(采购当月不计提);资产的累计折旧汇总它的折旧记录,账面价值 = 采购成本 − 累计折旧。报废要走审批:报废申请由资产所属部门的经理审批,审批人、状态和审批日期都记在报废申请本身上(审批就是更新这条申请),批准后由资产管理员执行报废;执行报废不可撤销,资产变为已报废、剩余账面价值核销,此后不再计提折旧。员工只能看到自己保管的资产,以及自己的领用单、自己报修的维修单和自己提交的报废申请,看不到采购成本、累计折旧、账面价值、折旧记录和部门资产预算;部门经理能看到本部门的资产、本部门员工的领用单,以及本部门资产的维修单、报废申请和折旧记录;资产管理员能看到全部资产,但看不到部门资产预算;员工的家庭住址(用于寄送设备)只有资产管理员可见。需要一个按类别和部门统计资产数量和账面价值的报表。尽量用声明式配置(公式字段、汇总字段、校验规则、定时流程)而不是代码钩子,以便应用能以非托管方式安装。",
16+
"en": "A fixed-asset lifecycle app. Assets are registered by category (laptop, monitor, mobile phone, office chair); each category sets a useful life in months and a depreciation method (straight line, no salvage value), and each asset records its asset tag, serial number, category, owning department, purchase date and purchase cost. The asset administrator checks assets out to employees, several at once if needed; a checkout records the checkout date, a due date (none for a permanent assignment), the return date and the condition on return. A checkout sets the asset in use with the employee as its custodian, and a return clears the custodian; only an asset in stock can be checked out, otherwise the checkout cannot be saved. A damaged asset gets a repair order (the fault, a status and the repair cost) and is in repair until it is fixed. On the last day of each month a scheduled flow posts one month of depreciation for every asset not disposed of (nothing for the purchase month); an asset's accumulated depreciation sums its depreciation entries, and its book value is the purchase cost minus the accumulated depreciation. Scrapping needs an approval: the manager of the asset's department decides a scrap request, which records its own approver, status and decision date (deciding it updates the request), and once it is approved the asset administrator disposes of the asset; a disposal cannot be undone, sets the asset disposed, writes off its remaining book value and stops its depreciation. An employee sees only the assets they hold and their own checkouts, the repairs they reported and the scrap requests they filed, and sees no purchase cost, accumulated depreciation, book value, depreciation entry or department asset budget; a department manager sees their department's assets, their own people's checkouts, and the repairs, scrap requests and depreciation of their department's assets; the asset administrator sees every asset but no department's asset budget; an employee's home address (used to ship equipment) is visible to the asset administrator only. Add a report of asset count and book value by category and department. Prefer declarative configuration (formula and roll-up fields, validation rules, a scheduled flow) over code hooks, so the app can be installed unmanaged."
1717
}
1818
},
1919
"expect": {
@@ -59,7 +59,6 @@
5959
"records-forms.roll-up-summary",
6060
"records-forms.validation-rule",
6161
"records-forms.select-options",
62-
"approvals.dynamic-approver-routing",
6362
"automation.record-triggered-flow",
6463
"automation.scheduled-flow",
6564
"access-security.row-level-security",

‎docs/qa/scenarios/invoice_with_line_items.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"prompt": {
99
"short": {"en": "Build an invoicing app with invoices and their line items."},
1010
"detailed": {
11-
"en": "Model an invoicing app: an invoice with multiple line items (product, quantity, unit price, amount). The invoice total should sum its line amounts, and line items are entered together with the invoice."
11+
"en": "Model an invoicing app: an invoice with multiple line items (product, quantity, unit price, amount). The invoice total should sum its line amounts, and line items are entered together with the invoice, inline on its form."
1212
}
1313
},
1414
"expect": {

0 commit comments

Comments
 (0)