Skip to content

Scenario library: mid-tier card — 差旅报销 travel expense (8–10 问数 + 4–6 write operations, row-scoped personas) #30476

Closed

Description

@objectstack-fleet

epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu

Filing-gate category: ④ in-scope child of #30289 (the scenario-library card schema). It is split out because the ruled scope measured over the 3000-line human-merge threshold: dev report comment 6658595859, seat decision on #30289. Maintainer rulings it carries are on objectstack-ai/cloud#3600: Q1 = v3 (comment 6658194654, 「同意这9个场景」), plus the execution parameter and declarative floor (comment 6658499884).

Blocked-by: #30340

Scope: one mid-tier scenario card, 差旅报销 travel expense (finance)

Write docs/qa/scenarios/travel-expense.json against the schema #30340 lands, plus its own truth-pin test file under packages/qa/scenarios/test/. A test file per card keeps the six card PRs from conflicting.

  • Domain: trip request, claim + claim lines, grade-based travel standard; a 2-step approval; an over-standard line requires a reason.
  • Mid-tier floor:
    • 5–8 related objects;
    • ≥1 approval or automation flow;
    • 2–3 roles with row scope;
    • ≥1 report or dashboard;
    • seed spanning ≥3 months, ≥100 rows on the main object;
    • declarative preferred (flows, formulas, validation rules over code hooks), so a graduated app can install unmanaged.
  • Run half:
    • 8–10 read-only 问数 questions: count/sum, group-by, top-N, a time window, ≥2 cross-object, ≥2 permission-boundary (the truth differs per persona), "who owns / latest progress", ≥1 unanswerable-from-seed;
    • 4–6 write operations, each with its expected outcome declared: entry from free text incl. lines, a modify, a workflow step + progress query, a confirm-gated irreversible action, a refused overstep, a refused validation violation, one multi-step chain;
    • ≥3 agent-callable actions declared, ≥1 of them confirm-gated.
  • Iterate: one sentence, with its expected delta.
  • Reference: objectstack-ai/templates/packages/expense (domain design only; ⛔ never its v15 code).
  • ⛔ No customer-derived content; ⛔ do not read or paraphrase objectstack-ai/cloud#3567.

Acceptance

  • The card loads with zero refusals. Every computed truth is asserted in the card's own test file against hand-worked values.
  • A deliberately wrong truth in a fixture copy goes red.
  • The PR stays under 3000 changed lines.

Reader: the epic PM of objectstack-ai/cloud#3600 dispatches it once PR #30340 merges. The six siblings are dispatched in parallel.


Generated by Claude Code

Activity

  1. added
    domain:devxDomain lane — seat card indexed by label:pm:seat
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    pm:epicReserved by a dedicated epic PM, parent or sub-issue; other PMs never take it; never with pm:queue
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    on Nov 5, 2026
  2. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:devx · epic child · 2026-11-05T14:06Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    priority:p1High: required for production / M2
    and removed
    pm:epicReserved by a dedicated epic PM, parent or sub-issue; other PMs never take it; never with pm:queue
    on Nov 5, 2026
  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu

    Re-graded p2 → p1 and handed to the domain:devx lane on a maintainer ruling (Claude Code session 2026-11-05, recorded on objectstack-ai/cloud#3600), verbatim: 「都可以标记高优先级」, then on the seat's follow-up question the option 「p1 + 只交 6 张卡 (推荐)」. pm:epic removed in this stroke; pm:blocked stays on Blocked-by: #30340. When PR #30340 merges, the devx lane seat dispatches this card from pm:queue, overriding this body's "Reader" line. The card's body, and the rulings it cites, are the spec. Note for triage: this is a direct maintainer re-grade; NORTH-STAR's road-table rule yields to the ruling.

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 5, 2026
  6. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu

    Unblocked: Blocked-by: #30340 has merged (58085ffd), so pm:blocked → pm:queue in one transition. This card is the domain:devx lane's to claim and dispatch (p1). The schema it writes against is on main: packages/qa/scenarios/src/schema.ts; worked examples are the three control cards in docs/qa/scenarios/.

  7. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 5, 2026
  8. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8

    Claim: PM loop round 1
    Session: session_017ihL2ebbZkr2QAEG1x7UC8
    Account: marchtian
    Branch: claude/issue-30476-travel-expense-card
    Worktree: objectstack-issue-30476
    Domain: domain:devx
    Seat: domain:devx#2
    File surface: docs/qa/scenarios/travel-expense.json (new) and one new truth-pin test file under packages/qa/scenarios/test/, written against packages/qa/scenarios/src/schema.ts at origin/main (PR #30340, 58085ffd), following the three control cards in docs/qa/scenarios/. If a library-wide test or README index must list the new card, the seat touches only that card's own line there. ⛔ No change to schema.ts, loader.ts or truth.ts; no customer-derived content; not objectstack-ai/cloud#3567; objectstack-ai/templates/packages/expense is a domain-design reference only (never its v15 code).
    Container & model: S, mode:subagent, model: default tier, effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — QA scenario card
    Thread-read: 6662234245
    Premise: holds (Blocked-by: #30340 merged 58085ffd; no docs/qa/scenarios/travel-expense.json at origin/main 2ffdb64977).
    Serial constraints cleared: the six sibling cards (#30476–#30481) each write their own card file and test file; no open PR touches docs/qa/scenarios/travel-expense.json.

  9. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
    os-dev-report

    {
     "issue": 30476,
     "pr": 30600,
     "head": "130acb8292736934df9717c4ad0ec8298f0acee7",
     "gates": {
      "scenarios_test": "pnpm --filter @objectstack/scenarios test :: exit 0 · Test Files 4 passed (4) · Tests 64 passed (64)",
      "scenarios_typecheck": "pnpm --filter @objectstack/scenarios typecheck :: exit 0 (after pnpm --filter '@objectstack/scenarios^...' build)",
      "loader_refusals": 0,
      "dispatch_gates_commands": "50 derived · 50 exit 0",
      "prerequisite_reruns": [
       "check:doc-formula-expressions exit 3 -> 0 after building formula + lint",
       "check:lean-entry-closure exit 3 -> 0 after building objectql",
       "check:dual-build-cjs-loads exit 3 -> 0 after a full turbo run build"
      ],
      "ran_reconciliation": "50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN (derived zero: every line carries its exit code)",
      "merge_origin_main": "already up to date at 2ffdb64977",
      "ci": "in_progress at report time"
     },
     "files_changed": [
      "docs/qa/scenarios/travel_expense.json",
      "packages/qa/scenarios/test/travel-expense.test.ts",
      "packages/qa/scenarios/test/library.test.ts"
     ],
     "changed_lines": {
      "total": 1337,
      "additions": 1336,
      "deletions": 1,
      "threshold": 3000
     },
     "changeset": "none: @objectstack/scenarios is private; skip-changeset label sent with pr_create",
     "floor": {
      "objects_5_to_8": "expect.objects (7)",
      "approval_flow": "run.seed.approval_step (steps 1 and 2) + expect.objects[6] + capabilities[5] approvals.multi-step-approval + run.operations[2]",
      "roles_with_row_scope": "run.personas[0].scope (employee) + run.personas[1].scope (dept_manager); run.personas[2] finance_officer is org-wide, hidden.objects trip_request",
      "report_or_dashboard": "expect.dashboards[0] travel_spend_by_department (+ expect.appNavTargets[3])",
      "seed_span_and_size": "run.seed.expense_claim: 120 rows, claim_date 2026-07..2026-10 (4 months)",
      "declarative_preferred": "prompt.detailed.zh / prompt.detailed.en + capabilities[1..3,6] (roll-up-summary, formula-field, validation-rule, record-triggered-flow); no schema field grades it",
      "questions_8_to_10": "run.questions (10)",
      "operations_4_to_6": "run.operations (6)",
      "agent_actions_3_plus_1_confirm": "run.agentActions (4); run.agentActions[3] pay_claim confirm true",
      "iterate": "iterate.change + iterate.expectDelta (objects travel_advance; lookups travel_advance.trip, expense_claim.advance)"
     },
     "run_half": {
      "questions": 10,
      "question_kinds": {
       "count_sum": [
        "run.questions[0] paid_reimbursement (sum)",
        "run.questions[3] claimed_last_month (sum)"
       ],
       "group_by": [
        "run.questions[1] claims_by_status",
        "run.questions[4] over_standard_by_department",
        "run.questions[6] trips_by_status",
        "run.questions[8] department_budgets"
       ],
       "top_n": [
        "run.questions[2] top_claimants"
       ],
       "time_window": [
        "run.questions[3] claimed_last_month (calendar previous_month)"
       ],
       "cross_object": [
        "run.questions[4] over_standard_by_department (claim.claimant.department)",
        "run.questions[5] sales_paid_hotel (claim.claimant.department, claim.status)"
       ],
       "permission_boundary": [
        "run.questions[0] (employee, dept_manager)",
        "run.questions[1] (dept_manager)",
        "run.questions[6] (employee, finance_officer withheld)",
        "run.questions[8] (employee withheld, dept_manager)"
       ],
       "who_owns_latest_progress": [
        "run.questions[7] ec_0093_waiting_on"
       ],
       "unanswerable": [
        "run.questions[9] recoverable_vat"
       ]
      },
      "operations": 6,
      "operation_kinds": {
       "entry_from_free_text_incl_lines": "run.operations[0] file_and_submit_from_text (applied)",
       "modify": "run.operations[1] fix_meal_days (applied)",
       "workflow_step": "run.operations[2] manager_approves_step_one (applied; progress query run.questions[7])",
       "confirm_gated_irreversible": "run.operations[3] pay_claim (pending_confirmation)",
       "refused_overstep": "run.operations[4] employee_approves_colleague (refused PERMISSION_DENIED)",
       "refused_validation": "run.operations[5] over_standard_without_reason (refused VALIDATION_FAILED)",
       "multi_step_chain": "run.operations[0] file_and_submit_from_text (file, two lines, submit, route)"
      },
      "agent_actions": 4,
      "agent_actions_confirm_gated": 1,
      "personas": 3,
      "guardrails": 5
     },
     "truths_pinned": {
      "all_rows": 10,
      "per_persona": 7,
      "file": "packages/qa/scenarios/test/travel-expense.test.ts"
     },
     "wrong_truth_red": [
      "fixture copy, seed c009.total_amount +1: assertPinned throws; paid_reimbursement 145801, top_claimants e09 20551",
      "fixture copy, top_claimants filter value ['paid']: assertPinned throws; top_claimants differs"
     ],
     "deviations": [
      "file name travel_expense.json, not travel-expense.json: schema MachineNameSchema and the loader's id-equals-basename check refuse a hyphen; schema unchanged",
      "library.test.ts: one line (the exact loaded-id list gains 'travel_expense'); its test title still reads 'holds exactly the three control cards'",
      "7 named operation kinds over the 6-operation cap: run.operations[0] carries entry-from-free-text and multi-step-chain",
      "schema cannot express an approval flow, 'declarative preferred' or a report distinct from a dashboard as graded structure; stated in prompt + capabilities",
      "run.operations[0] post-state omits the routed step-1 approval row: a where cannot name the new claim id and step 1 / e01 / pending also matches a seeded row",
      "objectstack-ai/templates and objectstack-ai/cloud answer 403 from this session: domain designed from the card text; cloud#3600 rulings applied as the card states them",
      "seed generated by a scratch script kept out of the PR; its rule is in the card's $comment"
     ],
     "mcp_calls": 0,
     "api_writes": {
      "count": 2,
      "endpoints": [
       "relay pr_create: POST /repos/objectstack-ai/objectstack/pulls + POST /repos/objectstack-ai/objectstack/issues/30600/labels",
       "post-stamped: POST /repos/objectstack-ai/objectstack/issues/30476/comments (this comment)"
      ]
     },
     "security_findings": "none",
     "out_of_scope_findings": [
      "carrier: seat · noted, not filed · docs/qa/scenarios/README.md 'Adding a card' step 3 says to add truths to test/library.test.ts; mid-tier cards pin in their own test file",
      "carrier: seat · noted, not filed · every sibling mid-tier card must edit the same library.test.ts loaded-id line, so the six PRs conflict on it in turn",
      "carrier: seat · noted, not filed · schema gaps: no expect key for a flow or approval process, nor for a report distinct from a dashboard"
     ]
    }
  10. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8

    Landed · PR #30600 merged as b6ae87c29c · 2026-11-05T18:31Z. The mid-tier 差旅报销 card is docs/qa/scenarios/travel_expense.json (7 objects, 3 personas, 10 questions, 6 operations, 4 agent actions, one iterate step), with its hand-worked truths in packages/qa/scenarios/test/travel-expense.test.ts. ACCEPT 6665586934. For the sibling cards (#30477–#30481): test/library.test.ts now names only the three control cards, so a new card adds its own test/<id>.test.ts and never edits that file (README "Adding a card" step 3 says so). A card's id must be snake_case and equal its file's basename. The card closed through Fixes; pm:dispatched comes off in this stroke.

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions