Repository navigation
Description
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
Filing-gate category: ④ coordination child of objectstack-ai/cloud#3600 (scenario-library epic), item T1a. Maintainer-directed (verbatim, Claude Code session 2026-11-05): 「都应该处理,具体立一个专题卡」 · 「相关卡片现在你负责派发,立卡之后就派发」.
Business rationale: inherited from the parent. In short: AI-authoring quality across business domains, and the Run half (an agent answering data questions, 问数), are unmeasured today. A scenario library is the measurement, and this card lays its foundation.
Ruling carried
D1 on cloud#3600 (maintainer, verbatim): 「同意」. It accepts this layout:
- the open main library lives in this repo under
docs/qa/scenarios/; - the schema and loader live in a private
packages/qa/*package (devx, notpackages/spec, so the format carries no protocol obligation); - a private cloud overlay holds the held-out and customer-derived cards. That overlay is out of scope here.
⛔ No customer-derived scenario ever lands in this repo as-is.
Scope
- New private workspace package under
packages/qa/for the scenario-card schema (zod) and loader.- Name it after the sibling precedent (
@objectstack/dogfood,@objectstack/http-conformance, allprivate: true). Measure that precedent before naming.
- Name it after the sibling precedent (
- Card format, six layers:
prompt:{ short, detailed }, each{ zh?, en? }with at least one language.expect: the structural expectation. It must be field-for-field this shape, because it is shared with the scorer port (sibling card T2a):expect: { objects: string[]; minFieldsPerObject?: number; selectFields?: { object: string; field: string; minOptions: number }[]; lookups?: { object: string; field: string; to: string }[]; dashboards?: string[]; appNavTargets?: string[]; }
capabilitiesandcategory.capabilitiesis a list of tags<area>.<name>. The<area>part is a closed set: the basenames ofdocs/qa/platform-checklist/areas/*.json, read from the tree. An unknown area is refused loudly, with the file and the path.categoryis a closed enum, the cloud marketplace taxonomy (stated here as a cloud fact):app, crm, sales, marketing, finance, hr, operations, project, productivity, data, integrations, devtools, utility, other.
run.questions(the 问数 half).- Seed rows per object.
- Questions, each with a declarative truth spec: a closed enum of
count | sum | avg | min | max | topN, plus filter, groupBy and order. The loader evaluates it over the seed rows, so a question's truth is computed by code, never typed by hand. - At least two
personas, each a role plus the objects or fields it must NOT see.
run.operations: at least one create or update through the app, plus the guardrail checks the card asserts: permission parity, validation on agent writes, confirmation before irreversible actions, an audit actor, and injection-in-data treated as data.iterate: a one-sentence change request plus the expectedexpectdelta.
- Loader.
- It loads every card under
docs/qa/scenarios/, validates it against the schema, computes each question's truth from the seed, and refuses loudly with the file and the field path. - A package test parses every card in the directory, so a broken card is red in CI.
- It loads every card under
- Nine seed cards, each with a full Run half (seed rows, at least 3 questions, 2 personas):
- The 5 golden cases in
packages/cli/src/lint/corpus.ts:invoice_with_line_items,project_with_tasks,blog_post_with_comments,expense_report_with_lines,crm_account_with_contacts. Deriveexpectfrom each fixture. - The 4 generic build cases of cloud's private eval dataset. Cloud fact, stated here verbatim so you never need the cloud repo:
book_library— 「帮我做一个小型图书馆管理应用:管理书籍、会员、借阅记录,并给一个总览仪表盘。」- objects
book, member, loan; minFieldsPerObject 4; - selects
book.status≥2 andloan.status≥2; - lookups
loan.book→bookandloan.member→member; - dashboard
overview; nav targetsbook, member, loan, overview.
- objects
tickets_select_dense— "Build a support-ticket tracker with priority and status."- object
ticket; minFieldsPerObject 4; - selects
ticket.priority≥3 andticket.status≥3.
- object
leave_system— 「做一个请假申请系统:员工档案 + 请假申请(含请假天数、状态、审批人),再加一个按状态统计的仪表盘。」- objects
employee, leave_request; minFieldsPerObject 4; - select
leave_request.status≥2; - lookup
leave_request.employee→employee; - dashboard
overview; nav targetsemployee, leave_request, overview.
- objects
purchase_master_detail— "Create a purchase order app: orders with multiple line items."- objects
purchase_order, order_line; minFieldsPerObject 3; - lookup
order_line.purchase_order→purchase_order.
- objects
- The 5 golden cases in
docs/qa/scenarios/README.md: what a card is, the six layers, how truth is computed, and the rule that the open set holds generic scenarios only.
Out of scope
Each of these is a sibling card under cloud#3600:
- the scorer (T2a);
- capability-tag checks and CLI wiring;
- the local runner;
- the cloud overlay;
- customer-derived cards.
Acceptance
- The package exists,
private: true, and its tests pass. - All 9 seed cards load, and their computed truths are asserted in a test.
- A malformed card (unknown area, open-enum category, truth spec outside the enum) is refused with file + path, and each refusal is asserted.
- No
packages/specchange and no public-surface change.
Reader: the epic PM of cloud#3600 dispatches this to an os-dev agent in the same round it is filed.
Dedup: see the parent's dedup table. Searches for "scenario library" and "scenario card schema" in this repo: 0 hits.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 5, 2026
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
Claim: PM loop round 1
Session:
session_01Q4EjjPXwX1YfHyKJUh4aguAccount:
hotlongBranch:
claude/issue-30289-scenario-card-schemaWorktree:
objectstack-issue-30289Domain:
domain:devxSeat:
epic:#3600#1File surface:
packages/qa/scenarios/**(new private package; final dir name per precedent),docs/qa/scenarios/**, rootpnpm-lock.yaml/workspace entries the new package needs,.changeset/30289-scenario-card-schema.md(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: TIER_DEFAULT(dispatch-gates --tier: "no path-derived mandate"),effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: none
Premise: holds
Serial constraints cleared: none — the 33 open
pm:dispatchedcards' claimed file surfaces were read and none touchespackages/cli/src/lint,packages/qaordocs/qa/scenarios; sibling #30289/#30290 surfaces are disjointRouting audit (maintainer direct-dispatch channel):
domain:devx+area:devpath+pm:epicwere set at filing by the epic PM of objectstack-ai/cloud#3600, not by triage. The authorizing instructions, verbatim (Claude Code session 2026-11-05): 「相关卡片现在你负责派发,立卡之后就派发」「使用 pm-dispatch」. Domain read from the landing paths:packages/qa/**anddocs/qa/**are devx. Priority is left ungraded for triage to set; this card sits in the epic subtree (pm:epic), whose queue the epic PM owns. Seat-account override: see cloud#3600 comment 6650372672.objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p2 · epic child ·
domain:devxkept · 2026-11-05T05:59Z⛔ Not a claim.
packages/qapackage, plus 9 seed cards. Dev-path tooling, so p2. Scenario library T2b: capability-tag checks in the ported scorer +os lint --evalreads scenario cards #30291 and Scenario library T3/T4: local Claude Code runner — Build, Run (问数 + operations per persona over the app's MCP), Iterate — writing run records, zero cloud-billed tokens #30292 wait on it.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
os-dev-report
{ "issue": 30289, "status": "done", "branch": "claude/issue-30289-scenario-card-schema", "pr": "https://github.com/objectstack-ai/objectstack/pull/30340", "session": "session_01Q4EjjPXwX1YfHyKJUh4agu", "premise_still_valid": true, "summary": "New private package @objectstack/scenarios (packages/qa/scenarios; private, exports at src, no build, zod only) holds the scenario-card zod schema (six strict layers; the expect shape is exactly the one the card fixes, with nothing renamed and no optional key added), a truth evaluator and loadScenarios(dir, {areas}). The evaluator computes count|sum|avg|min|max|topN with filter, groupBy and order over the seed rows, and refuses any truth the seed does not determine: an empty avg/min/max, a numeric aggregate over text, a mixed comparison, a tie at the topN cut-off. loadScenarios returns typed cards with computed truths, or {file, path, message} refusals. Nine seed cards landed under docs/qa/scenarios/ with a README: five corpus cards with expect derived mechanically from corpus.ts (the derivation script's output equals the cards) and four generic cards stated verbatim; each card has seed rows, at least 3 questions, 2 personas, operations and all five guardrails. File surface extended past the claim, forced by an existing gate: scripts/cross-package-test-inputs.mjs + turbo.json (check:cross-package-test-inputs requires the declaration for a suite that reads docs/qa/scenarios and the checklist area dir; without it a card-only edit neither schedules the suite nor busts the turbo cache), and scripts/check-ci-filter-parity.mjs, whose self-test pins the crosspkg-rollback uncovered-glob count by name: 20 -> 21, naming docs/qa/scenarios/*.json. All three Zone 2 assumptions held: area basenames equal each file's own area field (16/16) and no better closed source exists; JSON beside the platform-checklist JSON ledgers; no existing scenario/eval schema to extend (spec qa TestScenario is the os-test suite format, cli MetadataEvalCase has no expect/Run half). Resumed after a rate-limit stop; no work was redone.", "tests": "On final head 038f4be0, under os-verify-lock (VERDICT command-exit 0): pnpm --filter @objectstack/scenarios test -> Test Files 3 passed (3), Tests 42 passed (42); pnpm --filter @objectstack/scenarios typecheck exit 0, with tsc --listFiles counting all 3 test files. library.test.ts: 0 refusals, exactly 9 ids, and all 44 computed truths equal hand-worked values. refusals.test.ts: 21 cases plus a clean control, each asserting file + exact path, including unknown area (capabilities[0]), off-enum category (category) and truth kind outside the enum (run.questions[0].truth.kind). truth.test.ts: evaluator semantics. One ablation through scripts/ablation-replace.mjs (no dist involved; tests import ../src): avg / rows.length instead of / values.length, anchor 1 -> 0, blob 0afa46f9 -> a6a44d3e; truth.test.ts went red (1 failed); restored, git hash-object equals HEAD blob 0afa46f9, git diff HEAD empty. test:repo is not run locally (no test:repo file touched; declared to CI).", "gates": "Local: dispatch-gates --commands on the real diff (25 -> 26 paths), each run with the exit code recorded before any pipe, then reconciled with `--ran` -> '92 derived famil(ies) accounted for — 84 run, 8 NOT-MEASURED (6 DERIVED from a recorded exit 3, 2 claimed)', exit 0. All 84 run exit 0. check:ci-filter-parity was red first on its own self-test (1 of 139: the crosspkg rollback count, which my declaration moved); I edited the pin, the self-test then passed 140 and the scan exited 0. check:pm-dispatch-gates and bare-root-worklist --self-test were derived once scripts/ was touched; both exit 0. NOT MEASURED, exit 3 PREREQUISITE NOT MET (no dist in this worktree; the diff builds no package): check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content, @objectstack/lint check:doc-formula-expressions. check-plugin-teardown-shape --self-test needs an unshallowed clone and exits 3 on the shared checkout too. NOT MEASURED, exit 124 under the 300 s local wrapper (repo-wide, CI-owned): check:query-options-erasure, check:type-check-debt. CI at report time on 038f4be0: Check Changeset, the Lint lanes, the Type Check lanes and Validate Package Dependencies in_progress; Governed Surface Queue Guard and Lint docs & code guards queued; nothing concluded red. Changed lines 2823 (under the 3000 human-merge line).", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — relay pr_create (repository_dispatch -> POST /repos/objectstack-ai/objectstack/pulls, draft, no labels, no assignees; read-back identical 11597 bytes), and this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/30289/comments). git push is not a REST write.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: CLI-wiring sibling card under cloud#3600 · noted, not filed: the five corpus cards' expect is derived once and is not pinned equal to packages/cli/src/lint/corpus.ts (a pin would make a private qa package import CLI internals; corpus.ts is not exported). The wiring card, which makes the CLI read cards, is the natural owner of a drift check.", "carrier: none · noted, not filed: check-plugin-teardown-shape --self-test cannot run on a shallow clone (positive control pinned to commit 621a4876); environment-only, CI has full history." ] }objectstack-fleet commentedon Nov 5, 2026
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
File-surface amendment for the claim above, recorded by the seat at review of PR #30340:
scripts/cross-package-test-inputs.mjs(one@objectstack/scenariosrow),turbo.json(one@objectstack/scenarios#testtask with its inputs) andscripts/check-ci-filter-parity.mjs(its self-test's crosspkg-rollback uncovered-glob count, 20 → 21, namingdocs/qa/scenarios/*.json).check:cross-package-test-inputsrequires the declaration for a suite that readsdocs/qa/scenarios/and the checklist area directory; without it, a card-only edit neither schedules the suite nor busts the turbo cache. The parity self-test pins that count by name.objectstack-fleet commentedon Nov 5, 2026
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
ACCEPT → PR #30340 (head
038f4be0), landing held. Waits-on: objectstack-ai/cloud#3600 decision Q1 (comment 6651166095). Since: this comment.objectstack-fleet commentedon Nov 5, 2026
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
Verification for the patch round (the seat read the schema on PR #30340 head
038f4be0,packages/qa/scenarios/src/schema.ts). The maintainer's 8–10 问数 directive on objectstack-ai/cloud#3600 (comment 6651865232) needs four things the current truth spec cannot express:object, andfilter/groupByread that object's own fields only (FILTER_OPS= eq ne gt gte lt lte in). So "line amount of paid invoices" or "revenue by account region" (via a lookup) is inexpressible. Needs a relation path onfilterandgroupBy(e.g.invoice.status) resolved through the seed rows' lookup ids.asOfdate plus relative-window filters, so a truth stays deterministic.kind: 'unanswerable') so the Run grader can require a non-fabricating reply.These join the PR #30340 patch round once decision Q1 v2 is ruled. They extend closed enums and shapes; they do not loosen them.