Repository navigation
Description
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
Filing gate: ② follow-up from a contract review. Should-fixes S1 and S2 of the CONTRACT_REVIEW_TIER review 6683045112 on PR #30903 (#30882). That PR lands without them because neither causes a false grade today. ⛔ Not a claim. Triage sets the grade and the lane.
Business reason. The scenario runner is how the maintainer measures what an AI-built app gets right. PR #30903 makes the seed hand a user id to each owner field, and stops a refused seed row from failing questions it feeds. Two parts of that rest on inference rather than on what the card declares. A new card can be mis-seeded with no warning, and a refused row can hide more of the scorecard than it needs to.
S2: the handle fields are inferred, not declared
userHandleFields (packages/qa/scenarios/src/runner/orchestrate.ts, at PR #30903's head) treats as a person handle any direct persona-scope field that is not id and is in neither expect.lookups nor the select fields. That is right for all nine cards today: exactly account.owner, invoice.owner and task.assignee. A future card with a direct scope on an undeclared text or option field would be sent a user id in that field, and nothing at authoring time would refuse it.
Wanted:
- The card format declares the handle fields (for example a
userkind on the scope rule, or a list on the card). - The loader refuses a scope on a field that is neither declared a handle nor a known lookup or select.
- The run record lists the fields the seed rewrote.
- The loader is in flight in fix(scenarios): the loader refuses an operation its persona cannot reach, and two cards stop writing hidden fields #30846 (Scenario loader refuses an operation its persona cannot reach (row scope, hidden field or object); fix the three cards it catches #30802). Start after it lands.
S1: dependence on a refused row is object-level
seedDependence marks a question not measured whenever its object holds any refused row. On crm_account_with_contacts, refusing contact ct4 drops contacts_per_account as sdr, whose scope never reads ct4. This is never a false fail, and the scorecard cell shows the count, but it hides results the run could have graded.
Wanted: decide dependence by re-evaluating each question's truth over the seed minus the out rows, so that only turns whose expected answer changes are marked not measured. Pin it with the ct4 case.
Level: QA tooling only, Clause-②: no, Metadata-protocol: none.
Dedupe (open and closed): "userHandleFields" and "seedDependence" each hit only #30882, whose dev reports name them. New.
Related: #30882, PR #30903, #30913 (the sibling owner_id finding), #30802.
Reader: the domain:devx lane seat, from pm:queue, after PR #30903 and #30846 land.
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:devx· 2026-11-06T10:56Z⛔ Not a claim.
findingis removed.Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8
Scope added by ruling · 2026-11-07T13:35Z · The maintainer agreed at 2026-11-07T13:34Z to the analysis of #30913 (in the project files at
issue-30913/decision-analysis.md, §3 and §5). Its card-format half lands here, because this card already declares what a scope field holds.Added Wanted (S3),
personas[].record = { object, id }:asset_lifecycle,leave_balances,order_to_cash,requisition_to_receipt,travel_expense: for example e06, e05;service_desk: a02, a04, cus_03.userfield is fixed by name, not chosen per card.Serial: after #30932, which is in flight on the same
schema.ts,loader.tsand nine cards. #30913 restarts when this lands.objectstack-fleet commentedon Nov 7, 2026
domain:devx#3 · os-project-manager · session_01FEkQ5njkh3xbcDN6EtSfw7
Claim: PM loop round 1
Session:
session_01FEkQ5njkh3xbcDN6EtSfw7Account:
os-project-managerBranch:
claude/project-thread-kbxfnl(a project card thread,session_01FEkQ5nVm4yfBmbggVVSu4R; the thread can push only its harness branch, a measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-30914Domain:
domain:devxSeat:
domain:devx#3File surface:
packages/qa/scenarios/src/{schema.ts,loader.ts},src/runner/{prompts.ts,orchestrate.ts,seed.ts}and the run record type,docs/qa/scenarios/**cards (platform-checklist areas only if a loader change forces it), tests underpackages/qa/scenarios/test/**, the package README's card-format section, plus one changeset.Container & model:
M,mode:thread,model: default — dispatch-gates --tier: no path-derived mandate,effort: mediumClause-②: yes —
@objectstack/scenariosis published since PR #31221 and its.entry re-exportsschema.ts/loader.ts; the card widens the card schema (handle declaration,personas[].record) and narrows what the loader accepts. Contract review owed on the head before landing (in-seat, per Leehom 「你有 fable ,车道契约复审可以自己做」 2026-11-07T16:00Z); the face is read from the real diff.Metadata-protocol: none
Responsibility: n/a — QA tooling, no product door
Thread-read: 6707631426
Premise: holds. On main
bdefd49f3,userHandleFieldsinpackages/qa/scenarios/src/runner/prompts.ts(line 127) still infers handle fields from what the card does not declare, andseedDependenceinrunner/orchestrate.ts(line 339) is still object-level.Serial constraints cleared: PR #30903, #30846 and #30932 have landed. Runs beside #31159 (in flight on
runner/driver.ts/cli.ts); this card'sorchestrate.tsedit stays inseedDependenceand its callers, and a later-landing branch mergesorigin/main.Ruling-ref: 「p1 p2 处理完了,就可以处理 p3」 (maintainer, 2026-10-26T10:29Z); S3 added by the maintainer's ruling recorded at 6707631426 (2026-11-07T13:34Z).
Order:
pm-orders/devx/order-30914.md(project files), handed to the card thread in its opening message.Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:devx#3 · os-project-manager · session_01FEkQ5nVm4yfBmbggVVSu4R
os-dev-report
{
"issue": 30914,
"status": "done",
"branch": "claude/project-thread-kbxfnl",
"pr": "#31275",
"session": "session_01FEkQ5nVm4yfBmbggVVSu4R",
"premise_still_valid": true,
"summary": "Base bdefd49, head 4b4df50, 20 files +425/-89. S2:
run.userHandleFields: [{object, field}]declares the seed fields holding a user handle;userHandleFields(runner prompts.ts) reads only that list; the loader refuses a scope rule whose last field is none of id / declared lookup / declared select / declared handle, and a handle declaration on the row id, a lookup, a select, an unseeded object, a field no seed row carries, or declared twice;RunHalf.seed.rewrittenlists the fields the seed rewrote. Handle set before (inferred) and after (declared) is identical on the nine cards: crm account.owner, invoice invoice.owner, project task.assignee. S1:truthsOver(card, seed)(new export of., the loader's own rules) recomputes each question's truth over the seed less the refused rows and their children;seedDependence(scenario, refused).question(q, persona)marks not measured only the turns whose expected answer changes or stops being defined; ct4 pin:contacts_per_accountassdrstays measured. S3:personas[].record: {object, id}on six cards (asset_lifecycle e06/e05, leave_balances e07/e05, order_to_cash e03/e01, requisition_to_receipt e02/e13, travel_expense e02/e01, service_desk agent a02/a04 + customer cus_03); refused when it names no seeded row; required for a scoped persona unless a direct scope rule on a declared handle field names it (the three control cards), reading S3 together with ruling item 5 on #30913 (named in the PR acceptance notes);PERSON_USER_FIELD = 'user'; the runner does not readrecord. Card assignee not touched; no claim of my own.","tests": "
pnpm --filter @objectstack/scenarios exec vitest run --maxWorkers=2: 28/28 files, 571/571 tests pass; package typecheck exit 0; eslint on packages/qa/scenarios exit 0. New pins: 12 loader refusal cases + 2 controls (test/refusals.test.ts), declaration / nine-card handle-set / record-list / per-turn dependence cases (test/runner/units.test.ts), ct4 run 7/7 measured with 2 not measured, all-accounts-refused run 3/3 measured with 6 not measured,seed.rewritten(test/runner/orchestrate.test.ts). Ablations via scripts/ablation-replace.mjs, each put the refused behaviour back on disk and went red, then restored (git diff HEAD empty after all legs): A1 scope terminal field (2 failed), A2 handle on lookup/select/id (3), A3 handle object unseeded (1), A4 handle field not carried (1), A5 handle duplicate (1), A6 record names no row (2), A7 record required (2), A8 per-turn dependence back to per-object (4), A9 seed.rewritten dropped (2). Live model runs paused; none run.","gates": "Derived by
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the real diff: 62 commands, run from 33a2098 (the code head; 4b4df50 only edits the changeset sentence), each exit captured before any pipe;--ranreconciliation 62 derived, 61 run, 1 NOT-MEASURED; all run exit 0. NOT MEASURED:pnpm check:dual-build-cjs-loadsexit 3 PREREQUISITE NOT MET (reads every package's dist; only the scenarios closure was built), CI Lint & Repo Gates runs it. Changeset gates rerun on 4b4df50: check-changeset-no-major exit 0 (patch), ADR-0087 exit 0, empty-changeset exit 0. Roster/wide block: 47 commands, 43 exit 0, 4 PR-context gates refuse locally (exit 1/2) and are answered by CI; partof with PR_BODY exit 0. check:type-check-debt exit 0. check-plugin-teardown-shape --self-test exit 0 after fetching pinned 621a487. CI on 4b4df50: 48 check-runs, every one success or skipped, including Test Core and its 8 shards, Lint & Repo Gates, Check Changeset, Type Check workspace, PR-body guards, Governed Surface Queue Guard. Gate record: pm-orders/devx/30914-gates-ran.txt (project files).","dogfood_battery": "4b4df50a · VERDICT command-exit 0 (1779 s under the lock; closure build VERDICT command-exit 0) · Test Files 435/438 (3 skipped) · Tests 3609/3650 (41 skipped) · no failures",
"mcp_calls": "8 — read only: issue_read ×5 (get / get_comments on #30914 and #30913), pull_request_read ×3 (get #31214, get #31275, get_check_runs #31275). No write tool.",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create: #31275, draft, request fw-20261107T212415Z-22ca25, run 42415697821 success, read back identical 17604/17604 bytes, assignees none, no labels sent); POST /repos/objectstack-ai/objectstack/dispatches (relay comment: this os-dev-report on #30914 via post-stamped.mjs). Plus git push of 33a2098 and 4b4df50 (not REST writes).",
"deviations": [
"packages/qa/scenarios/src/runner/namespace.ts is outside the claimed file surface: the namespaced card must prefix run.userHandleFields[].object and personas[].record.object or the namespaced runner reads unprefixed names (6 lines, named in the PR body).",
"The order says the PR opens with its labels in the same act; os-dev.md rule 2 lists assignees in pr_create too. pr_create sent no labels key and no assignees; labels, if any, are the seat's.",
"Gate loop ran on 33a2098; the follow-up commit 4b4df50 touched only the changeset, whose three gates were rerun on 4b4df50. The dogfood battery ran on 4b4df50."
],
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:devx#3 · os-project-manager · session_01FEkQ5njkh3xbcDN6EtSfw7
Landed 2026-11-07T23:09Z · PR #31275 merged through the merge queue at 2026-11-07T23:09Z, as
c0f88b9a17fc74f7e46245590880d91a6df5b173.merged: true, merge commitc0f88b9a17, head reviewed4b4df50a30(contract review 6713691120 PASS, ACCEPT 6713698473)completedbyFixes #30914State change:
pm:dispatchedremoved (card closed). #30913 (on hold) can restart:personas[].recordis now in the card format and loader, and the runner's use of it is that card's half.