Skip to content

test(dogfood): re-point the runAs and anonymous-guest flow pins to flow start admission's record rule - #29451

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-3bruef
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-3bruef

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread

Fixes #29426

维护者速读

  • 改了什么:只改两个 dogfood 测试文件和一个测试 fixture,让它们按 fix(runtime): every flow start door judges a start input against the object the flow's definition reads it from #29365 已落地的规则断言;运行时代码一行未动。
  • 为什么改:fix(runtime): every flow start door judges a start input against the object the flow's definition reads it from #29365 之后 main 的 Dogfood Regression Gate 一直红,这四个用例断言的是该规则有意改掉的旧行为(dogfood 分片在 PR 和合并队列里不跑,所以落地前没暴露)。
  • 风险与回滚:仅测试面,无发布内容(skip-changeset);回滚即 revert 本 PR,main 会重新变红。
  • 先看:packages/qa/dogfood/test/fixtures/flow-runas-fixture.ts(新增只读策略与"定义自选行"的读流程)、packages/qa/dogfood/test/flow-runas.dogfood.test.ts(拒收断言与读写提权证明)、packages/qa/dogfood/test/declarative-endpoint-anonymous-guest.dogfood.test.ts。
  • 两分钟验证:构建 dogfood 依赖闭包后运行 cd packages/qa/dogfood && pnpm exec vitest run test/flow-runas.dogfood.test.ts test/declarative-endpoint-anonymous-guest.dogfood.test.ts,预期 17/17 通过。
  • 需要你做的:无,席位落地。

What changes

The rule these pins now follow: a start input the definition reads as a record id is judged as the caller, for every runAs, before the run exists (#29365). Four dogfood cases asserted the behaviour that rule deliberately replaced. They are re-pointed, and the proofs they carried are kept with inputs the rule admits.

flow-runas-fixture.ts (shared with flow-runas-schedule.dogfood.test.ts, which is unaffected):

  • A select-only RLS policy (runas_note_shared_read) makes an admin note whose status is shared readable to the member. No write policy admits it, so the member still cannot write it.
  • Three new flows: runas_system_read_sealed, runas_user_read_sealed and runas_system_read_sealed_via_parent. Their definition fixes the row with a literal name filter and takes no start input.
  • viaParent gains an option to hand no input.

flow-runas.dogfood.test.ts:

  • Write elevation and de-elevation now use a shared admin note, which the member can read but not write. The runAs: 'system' child writes it. The runAs: 'user' run fails on its node with 400 FLOW_FAILED. Because the member can read the row, the node's refusal is now the record layer's access refusal: update_record(runas_note) failed with details.innerRefusal.code PERMISSION_DENIED. It used to be the read door's not-found.
  • Read elevation now uses the sealed flows. The elevated run returns the admin note, and the user-mode run returns nothing.
  • New case: a member can read the note, and a read flow returns it under either runAs.
  • New precondition: the member can read a shared note but its direct write is refused.
  • Re-pointed refusals (two cases, write and read): a member start that hands an unreadable note id to the runAs: 'system' child (through the user-mode parent's subflow) or to the runAs: 'user' flow gets this full answer:
    • 404 RECORD_NOT_FOUND in the ADR-0112 envelope;
    • no data, and no field of the note in the body (the id in the message is the caller's own input);
    • no run recorded for the started flow or its child;
    • the note unchanged.

declarative-endpoint-anonymous-guest.dogfood.test.ts:

  • The executor-is-handed-the-guest pin now uses a start that names no row. Admission has nothing to load, so the executor is reached and the user-less runAs: 'user' refusal answers, as before.
  • New case: a guest start that names the seeded row gets 404 RECORD_NOT_FOUND before the run exists. The executor is never called, the seeded row's name is not in the body, every engine call the door's load made carries the guest context (principalKind: 'guest', isSystem: false), and the driver is never reached.

Forced test edits (each one named): memberTriggerExpectingAccessRefusal's message assertion (not-found → access refusal plus innerRefusal.code); the rows the four elevation and de-elevation legs use; the guest flow pin's start params ({ noteId } → {}).

Tests

All on head b237bdc7b (origin/main f95d0dbad merged in), with the dogfood closure rebuilt (turbo run build --filter='./packages/**', 78/78), under scripts/pm/os-verify-lock.sh:

  • The two files: cd packages/qa/dogfood && pnpm exec vitest run test/flow-runas.dogfood.test.ts test/declarative-endpoint-anonymous-guest.dogfood.test.ts gives 17/17 passed. On main d93acbbe before this change it gave 4 failed and 8 passed.
  • Every dogfood file that starts a flow or declares runAs (grep -l "/automation/\|runAs" packages/qa/dogfood/test/*.test.ts, 42 files, including flow-runas-schedule, which shares the fixture) gives Test Files 42/42, Tests 428/428 passed.
  • pnpm --filter @objectstack/dogfood typecheck exits 0. Root eslint --no-inline-config on the three files exits 0.
Ablations (one per negative pin family; each leg mutated through scripts/ablation-replace.mjs, rebuilt, proved in dist/ by scripts/ablation-dist-preflight.mjs, restored and proved absent)
  1. Flow start admission off (refuseUnreadableFlowStartRecords returns at once, @objectstack/runtime): 3 failed | 14 passed. Red: both member refusal cases and the guest refusal case. Restored: git diff HEAD empty, marker absent from dist.
  2. De-elevation off (resolveRunDataContext treats runAs: 'user' as system, @objectstack/service-automation): 2 failed | 15 passed. Red: the user-mode write leg (no longer 400 FLOW_FAILED) and the user-mode sealed read (returned the row). Restored the same way.

Acceptance notes

Verification


Generated by Claude Code

…ow start admission's record rule

A start input the definition reads as a record id is judged as the caller,
for every runAs, before the run exists (#29365). The runAs proofs now hand
the flows rows that rule admits (a note the member may read but not write;
a row the definition fixes by a literal), and the refusal is pinned as
404 RECORD_NOT_FOUND with no run recorded and nothing disclosed.

Claude-Session: https://claude.ai/code/session_01ADHkmSoKQWHgd1oZe8j7Pu
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json eb123b7ccc15831928da8f4bf115c73f8be23db1 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1

维护者速读

席位意见:四例都属于规则有意改变的预期,测量结果与本席判断一致。提权证明改用调用者可读的输入后保留,拒收断言的是完整拒收。

席位核对

ACCEPT · domain:server seat 5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1 · 2026-11-02T15:47Z · head b237bdc7b0 · Fixes #29426 (claim 6580005113)

  1. Shape: draft against main, Fixes #29426, skip-changeset: test files only, nothing publishes. 234 changed lines, 3 files under packages/qa/dogfood/test.
  2. Against the order: each of the four cases is classified (a), an expectation the ruled fix(runtime): every flow start door judges a start input against the object the flow's definition reads it from #29365 rule deliberately changes. Each re-pointed case pins the full refusal: 404 RECORD_NOT_FOUND, no run recorded, the row unchanged, no record field in the body. The elevation and de-elevation proofs are kept with inputs the rule admits. No runtime change and no revert.
  3. Accepted deviations: main was merged mid-verification and everything re-ran on the merged head. The PR body points to the report for its gate readings.
  4. Gates: the dev reports, on this head under the lock, both files 17/17, all 42 dogfood files that start flows or declare runAs 428/428, dogfood typecheck 0 and lint 0, and dispatch gates 51/51. Ablations: admission off gives 3 red, user-as-system gives 2 red, both restored. The seat readies the PR only when no check-run on this head is red or running.
  5. Out of scope: none.
  6. Landing: pr_ready + automerge_enable through the relay.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 15:48
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 2, 2026 15:48
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 6af3d29 Nov 2, 2026
52 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-3bruef branch November 2, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

main red: Dogfood Regression Gate fails on main since #29365 (dfbe34d8) — flow-runas and declarative-endpoint-anonymous-guest dogfood files

1 participant