You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
automation: a flow started through the REST or action door carries the caller's positions and permission sets but not their posture rung #28099
Found by the #28070 card thread (PR #28098) and filed by the domain:server seat. Outside that PR's surface. ⛔ Not a claim.
What is wrong
PR #28098 makes a runAs: 'user' run whose grants the engine resolves (a record-change run, the segment after an approval decision) carry its user's posture rung (ExecutionContext.posture, ADR-0095 D2/D3). A run started through a door that forwards the caller's already-resolved grants does not get one:
the REST door, packages/runtime/src/domains/automation.ts (buildAutomationContext, ~L204-205), and
the action door, packages/runtime/src/action-execution.ts (the flow action's automation.execute context, ~L2077-2078),
both copy ec.positions / ec.permissions (and tenantId, locale), never ec.posture. Because the context carries its own grants, run setup does not re-resolve them, so the run has no rung. A platform administrator's manually-run flow is therefore served organization ledger rows only, not the deployment-level ones their request is served. It fails closed (fewer rows, never more).
Expected
A door-started run carries the rung its caller's request carries, the same way it carries the caller's positions and permission sets. Forwarding it reaches AutomationContext (packages/spec/src/contracts/automation-service.ts), or the door's extra-key shape, so the route is triage's.
Related: #28070, PR #28098 (its changeset's "Still without a rung" bullet and record-view-auditing.mdx name this case).
Granted (SKILL.md 跨域例外路径): the claim declares one optional member on AutomationContext (packages/spec/src/contracts/automation-service.ts). It owes Clause-②: yes (widening) on that contract type and a contract review.
Claim: PM loop · 2026-10-30T13:24Z · triage first touch 6523377748
Session: session_016WV4czNtyUvgvgGC1mdxrU (card thread; seat session_016WV4d1Np3hU7RQnA13YZcL)
Account: os-elon-musk
Branch: claude/project-thread-vyi88m
Worktree: objectstack-issue-28099
Domain: domain:server
Seat: domain:server#4
File surface: packages/runtime/src/domains/automation.ts (buildAutomationContext), packages/runtime/src/action-execution.ts (the flow action's automation.execute context only), packages/spec/src/contracts/automation-service.ts (one optional AutomationContext member, granted cross-domain by triage 6523377748), packages/services/service-automation/src/run-resume.ts and engine.ts only where run setup reads the forwarded rung (no other hunk), content/docs/permissions/record-view-auditing.mdx (the one sentence saying a door-started run is not yet served the deployment-level rows; amended 13:30Z), content/docs/automation/flows.mdx (the trigger route's Identity paragraph only; amended 15:31Z for contract-review should-fix S2 6526196044), their tests, .changeset/*; ⛔ no other packages/spec file, no governed path
Container & model: M, mode:thread, model: default (TIER_DEFAULT), effort: high; contract review owed (triage: Clause-②: yes (widening) on the contract type)
Clause-②: yes (widening) — one optional member on AutomationContext; the dev confirms from the diff
Metadata-protocol: none
Responsibility: a flow started through the REST or action door runs without its caller's posture rung, so a platform administrator's manual run is served fewer ledger rows than their own request (fails closed); the platform path that covers it is the door forwarding the caller's own already-resolved rung beside positions and permission sets, never derived from the flow's author and never raised; reached by every door-started run.
Thread-read: 6523377748
Premise: holds (card at origin/main47a8b588; #28070 closed, PR #28098 merged)
Serial constraints cleared: no open PR on these files right now; seat 4's PR #28110 (service-automation run-resume.ts, engine.ts docblock) is in the merge queue, so the thread starts from main after it lands or merges main before opening its PR.
{
"issue": 28099,
"status": "done",
"branch": "claude/project-thread-vyi88m",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28167",
"session": "session_016WV4czNtyUvgvgGC1mdxrU",
"premise_still_valid": true,
"summary": "AutomationContext (packages/spec/src/contracts/automation-service.ts) gains one optional member, posture?: ExecutionContext['posture'], documented beside positions/permissions. The REST trigger door (buildAutomationContext) and the action door (dispatchFlowAction) copy the request's own ec.posture when it is a non-empty string, as they copy locale: never derived from the flow's author, never raised, absent when the request has none; a body key named posture stays a flow param. seedRunGrants (run-resume.ts, one hunk): when run setup resolves the grants itself, that resolution's rung replaces a forwarded one, or the forwarded one is deleted, so a rung never stands beside grants it was not derived from. A context carrying its own grants keeps the forwarded rung; resolveRunDataContext already read context.posture via runPosture (#28070), so runtime-identity.ts is untouched. record-view-auditing.mdx sentence corrected (surface amended by the seat). Clause-②: yes (widening) on AutomationContext; Metadata-protocol: none. Contract review owed.",
"tests": "Measured on main 47a8b588 with the new pins: flow-run-posture.test.ts 5 red / 2 green (both trigger routes and the action door handed the engine no rung); real stack, the platform administrator's door-shaped envelope (grants, no rung) was served the organization ledger row only (kept as CONTROL). The engine already carried a context-supplied rung on main; only the 'forwarded rung without grants dropped when the resolution has none' cell was red. Head: runtime flow-run-posture.test.ts 7/7, service-automation runas-user-posture-rung.integration.test.ts 20/20. Ablations via scripts/ablation-replace.mjs, each restored blob == HEAD: A1 trigger door copy removed -> 4 red; A2 trigger door defaults MEMBER -> 2 red; A3 trigger door reads ctxBody.posture -> 2 red; A4 action door copy removed -> 1 red; A5 action door defaults -> 1 red; A6 seedRunGrants else-delete removed -> 1 red; A7 resolver rung seeded over carried grants -> 5 red; A8 no resolved rung seeded (#28070 case) -> 5 red. Full vitest after merging main: runtime 488 files / 8832 tests, service-automation 230 / 2912, spec src/contracts 50 / 469 (pre-merge); typecheck spec/runtime/service-automation exit 0 (runtime needs driver-turso dist in a fresh worktree).",
"gates": "dispatch-gates --commands derived 108 families (same list after the merge): 108 exit 0 (check:skill-examples and check:dual-build-cjs-loads exit 3 on the first pass, exit 0 after a whole-tree turbo build); --ran reconcile: 108 derived, 108 run, 0 NOT-MEASURED; pnpm lint exit 0; check:route-envelope exit 0; check-commit-card-trailers --range origin/main..HEAD exit 0. Head 0c325aab = bd3ac11c + plain merge of origin/main after PR #28110 landed.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0 — GitHub reads via gh api REST (issue, comments, PR #28110 state/files); no MCP write",
"api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls -> #28167), this comment (POST /repos/objectstack-ai/objectstack/issues/28099/comments); git push is not a REST write. PR carries no assignees and no reviewer request, per the dispatch order.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed — SeededRunContext.posture (service-automation/src/runtime-identity.ts) now restates the member it inherits from AutomationContext (same type); harmless, outside the surface",
"carrier: none · noted, not filed — content/docs/automation/flows.mdx trigger-route Identity paragraph lists the forwarded identity as 'user, positions, permissions, tenant'; incomplete, not false; outside the surface"
]
}
ACCEPT → PR #28167 comment 6527073143 · head b53b0297 · 2026-10-30T15:53Z · landing sent (contract review PASS, record 6526701502; both should-fixes taken in-PR).
Activity
objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 真挡得住的权限 | none | P②
Triage: p2 ·
domain:server·area:access· cross-domain exception · 2026-10-30T12:56Z⛔ Not a claim.
AutomationContext(packages/spec/src/contracts/automation-service.ts). It owesClause-②: yes (widening)on that contract type and a contract review.pm:queue.pm:retriageremoved.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
Claim: PM loop · 2026-10-30T13:24Z · triage first touch 6523377748
Session:
session_016WV4czNtyUvgvgGC1mdxrU(card thread; seatsession_016WV4d1Np3hU7RQnA13YZcL)Account:
os-elon-muskBranch:
claude/project-thread-vyi88mWorktree:
objectstack-issue-28099Domain:
domain:serverSeat:
domain:server#4File surface:
packages/runtime/src/domains/automation.ts(buildAutomationContext),packages/runtime/src/action-execution.ts(the flow action'sautomation.executecontext only),packages/spec/src/contracts/automation-service.ts(one optionalAutomationContextmember, granted cross-domain by triage 6523377748),packages/services/service-automation/src/run-resume.tsandengine.tsonly where run setup reads the forwarded rung (no other hunk),content/docs/permissions/record-view-auditing.mdx(the one sentence saying a door-started run is not yet served the deployment-level rows; amended 13:30Z),content/docs/automation/flows.mdx(the trigger route's Identity paragraph only; amended 15:31Z for contract-review should-fix S2 6526196044), their tests,.changeset/*; ⛔ no otherpackages/specfile, no governed pathContainer & model:
M,mode:thread,model: default (TIER_DEFAULT),effort: high; contract review owed (triage:Clause-②: yes (widening)on the contract type)Clause-②: yes (widening) — one optional member on
AutomationContext; the dev confirms from the diffMetadata-protocol: none
Responsibility: a flow started through the REST or action door runs without its caller's posture rung, so a platform administrator's manual run is served fewer ledger rows than their own request (fails closed); the platform path that covers it is the door forwarding the caller's own already-resolved rung beside positions and permission sets, never derived from the flow's author and never raised; reached by every door-started run.
Thread-read: 6523377748
Premise: holds (card at
origin/main47a8b588; #28070 closed, PR #28098 merged)Serial constraints cleared: no open PR on these files right now; seat 4's PR #28110 (service-automation
run-resume.ts,engine.tsdocblock) is in the merge queue, so the thread starts frommainafter it lands or mergesmainbefore opening its PR.objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
os-dev-report
{ "issue": 28099, "status": "done", "branch": "claude/project-thread-vyi88m", "pr": "https://github.com/objectstack-ai/objectstack/pull/28167", "session": "session_016WV4czNtyUvgvgGC1mdxrU", "premise_still_valid": true, "summary": "AutomationContext (packages/spec/src/contracts/automation-service.ts) gains one optional member, posture?: ExecutionContext['posture'], documented beside positions/permissions. The REST trigger door (buildAutomationContext) and the action door (dispatchFlowAction) copy the request's own ec.posture when it is a non-empty string, as they copy locale: never derived from the flow's author, never raised, absent when the request has none; a body key named posture stays a flow param. seedRunGrants (run-resume.ts, one hunk): when run setup resolves the grants itself, that resolution's rung replaces a forwarded one, or the forwarded one is deleted, so a rung never stands beside grants it was not derived from. A context carrying its own grants keeps the forwarded rung; resolveRunDataContext already read context.posture via runPosture (#28070), so runtime-identity.ts is untouched. record-view-auditing.mdx sentence corrected (surface amended by the seat). Clause-②: yes (widening) on AutomationContext; Metadata-protocol: none. Contract review owed.", "tests": "Measured on main 47a8b588 with the new pins: flow-run-posture.test.ts 5 red / 2 green (both trigger routes and the action door handed the engine no rung); real stack, the platform administrator's door-shaped envelope (grants, no rung) was served the organization ledger row only (kept as CONTROL). The engine already carried a context-supplied rung on main; only the 'forwarded rung without grants dropped when the resolution has none' cell was red. Head: runtime flow-run-posture.test.ts 7/7, service-automation runas-user-posture-rung.integration.test.ts 20/20. Ablations via scripts/ablation-replace.mjs, each restored blob == HEAD: A1 trigger door copy removed -> 4 red; A2 trigger door defaults MEMBER -> 2 red; A3 trigger door reads ctxBody.posture -> 2 red; A4 action door copy removed -> 1 red; A5 action door defaults -> 1 red; A6 seedRunGrants else-delete removed -> 1 red; A7 resolver rung seeded over carried grants -> 5 red; A8 no resolved rung seeded (#28070 case) -> 5 red. Full vitest after merging main: runtime 488 files / 8832 tests, service-automation 230 / 2912, spec src/contracts 50 / 469 (pre-merge); typecheck spec/runtime/service-automation exit 0 (runtime needs driver-turso dist in a fresh worktree).", "gates": "dispatch-gates --commands derived 108 families (same list after the merge): 108 exit 0 (check:skill-examples and check:dual-build-cjs-loads exit 3 on the first pass, exit 0 after a whole-tree turbo build); --ran reconcile: 108 derived, 108 run, 0 NOT-MEASURED; pnpm lint exit 0; check:route-envelope exit 0; check-commit-card-trailers --range origin/main..HEAD exit 0. Head 0c325aab = bd3ac11c + plain merge of origin/main after PR #28110 landed.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — GitHub reads via gh api REST (issue, comments, PR #28110 state/files); no MCP write", "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls -> #28167), this comment (POST /repos/objectstack-ai/objectstack/issues/28099/comments); git push is not a REST write. PR carries no assignees and no reviewer request, per the dispatch order.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — SeededRunContext.posture (service-automation/src/runtime-identity.ts) now restates the member it inherits from AutomationContext (same type); harmless, outside the surface", "carrier: none · noted, not filed — content/docs/automation/flows.mdx trigger-route Identity paragraph lists the forwarded identity as 'user, positions, permissions, tenant'; incomplete, not false; outside the surface" ] }objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
ACCEPT → PR #28167 comment 6527073143 · head
b53b0297· 2026-10-30T15:53Z · landing sent (contract review PASS, record 6526701502; both should-fixes taken in-PR).objectstack-fleet commentedon Oct 30, 2026
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL
Landed · 2026-10-30T16:39Z
7d846b5d(merge queue)completedbyFixes #28099State:
pm:dispatchedremoved in this stroke.