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
plugin-approvals: a field or position approver step has no "not the submitter" guard, so a manager who submits their own request can approve it #25573
Ruled: 6377888641 · batch #9 item 1 (#25496, 6377842908) · letter B · 2026-10-24T00:43:45Z (step option excludeSubmitter, default off; empty set escalates per ADR-0042 or reroutes to the fallback)
Filed from the objectstack-ai/hotsrm v0.1 platform evaluation, 2026-10-23, spec 18.0.0.
What was measured
A two-level admission approval: step 1 approver field (the category manager on the record), step 2 position (procurement director). Both resolve and work.
When the category manager submits the admission themselves, step 1 resolves to the same person and they approve their own submission. Nothing in the step declaration excludes the submitter.
Every procurement control framework (SOX-style segregation of duties, Chinese SOE procurement rules T/CFLP 0016) treats self-approval as a finding, so an app has to add it by hand: an expression approver, or a validation rule blocking "submitter == approver" before entry. Both are easy to forget and are per-flow.
Wanted
A step-level option (excludeSubmitter: true, or a flow-level default) that removes the submitter from the resolved approver set and, when the set becomes empty, escalates per ADR-0042 or reroutes to the step's fallback, instead of silently letting the request through.
The approval record should show when the exclusion changed the route.
Acceptance
With the option on, a request whose resolved approver is its submitter is routed to the fallback or escalated, never approved by the submitter; with the option off, behaviour is unchanged.
Re-filed as objectstack-fleet[bot] from #25446, same body and labels. #25446 was written off the fleet relay, under the maintainer's personal account, by a project-thread session through GitHub MCP; pm-dispatch allows content writes only through the relay. #25446's thread (triage, ruling, comments) stays there for reference; this card replaces it in the queue.
Session: session_018fnREjMeK9XQeHDwkJXKMW
The ruling of record orders the work spec first. The director's state comment 6377859800 on #25446, verbatim: "Protocol addition: spec first, then plugin-approvals." No spec card for the key existed, so this lane split it out as #25609 (the excludeSubmitter key, domain:spec's to build). This card keeps the runtime half: removing the submitter from the resolved set, the onEmptyApprovers fallback or ADR-0042 escalation, and the route note on the approval record. It goes back to pm:queue when #25609 merges.
For the maintainer and triage (no change made): the director graded the originals p1 ("Level p1"), and one minute later a personal account set #25444 and #25446 back to p2. This card and #25571 carry p2. The grade is triage's to settle.
This item is a protocol addition. The split into a spec card and a runtime card is lane mechanics, so both halves take p1. If the excludeSubmitter key shipped in a release without this runtime, it would be declared but not enforced, on a segregation-of-duties control.
The protocol half (#25609, PR #25632, in review) surfaced one question that changes this card's runtime scope: excludeSubmitter: true beside onEmptyApprovers: 'auto_approve' would auto-approve a self-submitted request, against the ruling's "never a silent pass". Letter B on #25635 puts a runtime override into this card, letter A a spec refusal (no change here), letter C a route note only. Until #25635 carries Ruled:, this card's dispatch waits on it as well as on #25609. The dev's second question, whether the exclusion also screens the fallbackApprovers slate and the admin_rescue administrators, stays this card's runtime choice inside the ruling's "the resolved approver set".
So this card's runtime scope is the original one, with no runtime override.
This card builds: remove the submitter from the resolved slate. An emptied slate takes the node's onEmptyApprovers fallback, else ADR-0042 escalation, never a silent pass. The approval record notes when the exclusion changed the route.
Release timing:excludeSubmitter is on main while the Version Packages PR chore: version packages #25640 is open. A release cut before this card lands ships a segregation-of-duties key that is declared but not enforced. This card is owed before that cut.
Claim: PM loop round 1 · card thread
Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01LXX9EBHog6ZMo6apV2jvXX
Account: os-project-manager (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-4z84a6 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: objectstack-issue-25573 (a linked worktree in the card thread's container)
Domain: domain:server
Seat: domain:server#1
File surface: packages/plugins/plugin-approvals/src/** (the resolved approver slate, the onEmptyApprovers fallback or ADR-0042 escalation, and the route note on the approval record), its tests, one changeset. ⛔ Not packages/spec/**: the key (#25609, PR #25632) and its publish refusal beside auto_approve (#25635 ruling A, PR #25700) have landed (stop on breach; explain in the report)
Container & model: M, mode:thread, model: opus (the default of dispatch-gates --tier: no path-derived mandate), effort: xhigh (p1; requested, the thread runs at the harness default because only the maintainer sets a thread's effort)
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6390007010
Premise: holds (read 2026-10-24T23:05Z on origin/main47af3dd: excludeSubmitter has 12 lines in packages/spec/src/automation/approval.zod.ts and 0 in packages/plugins/plugin-approvals/src)
Serial constraints cleared: no open PR touches packages/plugins/plugin-approvals/src/** (all 19 open PRs' file lists read this fire; the Version Packages PR #25640 touches only its CHANGELOG.md and package.json). Same-day merges on the package: ca80f05 (#25627) and 2351c8d (#25600). Owed before the release cut (triage 6390007010).
os-dev-report
{
"issue": 25573,
"status": "done",
"branch": "claude/project-thread-4z84a6",
"pr": "#25722",
"head": "0aed0b90",
"session": "session_01LXX9EBHog6ZMo6apV2jvXX",
"premise_still_valid": true,
"summary": "excludeSubmitter: true is now enforced by plugin-approvals. openNodeRequest removes the submitter (user id and account email, via actingAddresses) from the RESOLVED slate, so one seam covers every approver type and an OOO hop onto the submitter; the fallbackApprovers slate and the admin_rescue administrators are screened the same way (choice made inside 'never approved by the submitter'), and an emptied slate takes onEmptyApprovers (admins by default, fallback, or the fail refusal naming the exclusion; an org whose only admin is the submitter opens on the no-one slate). After the open: decideNode refuses an approve by the submitter (override included, reject allowed), reassign refuses a target that is the submitter or a position only they hold, and an SLA reassign escalation leaves the submitter off (submitter-only target is not applied). The route is recorded as a system timeline note stored as data (__submitterExclusionNote) and rendered in en/zh-CN/ja-JP/es-ES; the admin rescue note gains a submitter-excluded clause. Spec hand-off from #25609 done within the seat's fence: PLANNED marker and last describe sentence dropped, liveness _note rewritten, spec status pin flipped, reference doc regenerated.",
"tests": "plugin-approvals: new exclude-submitter.integration.test.ts 14/14 (real ObjectQL + SqlDriver), new submitter-exclusion-note.test.ts 3/3; pnpm --filter @objectstack/plugin-approvals test: 98 files / 1276 tests passed; typecheck exit 0 incl. check:test-typecheck. spec: approval-exclude-submitter-25609.test.ts 28/28. Ablations via scripts/ablation-replace.mjs WRAP mode, each restored (blob == HEAD, git diff HEAD empty), tests import src so no dist leg: A1 open filter 8 failed/6 passed; A2 decide guard 2 failed/12 passed (first attempt was a refused no-op because the replacement contained the anchor, re-run with a non-overlapping replacement); A3 reassign refusal 1/13; A4 escalation filter 1/13; A5 route note 6/8.",
"gates": "On head 0aed0b9: dispatch-gates --commands derived 119; all 119 run with exit codes captured before any pipe, all 0 on the final head; --ran: '119 derived, 119 run, 0 NOT-MEASURED, 0 UNRUN'. Fixed on the way: check-tenant-audit-census and its --self-test (238 to 239 write call sites from the route note insert; regenerated with tenant-audit-census.mjs --write and prose counts updated). Prerequisite refusals cleared then green: check-plugin-teardown-shape --self-test (fetched its pinned fixture commit on the shallow clone), check:skill-examples (built client-react), check:i18n (built its closure), check:dual-build-cjs-loads. spec check:generated green after --fix regenerated content/docs/references/automation/approval.mdx. Scoped eslint --no-inline-config over plugin-approvals/src and the two spec files: exit 0. PR check-runs: in_progress at report time (CI owns pnpm lint, Test Core, Build Core, type-check lanes).",
"dogfood_battery": "n/a — no ! in the PR title and Clause-② carries no (narrowing) arm",
"mcp_calls": "0 — no GitHub MCP calls",
"api_writes": "2 relay strokes so far: fleet-write pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /issues/25722/assignees, via repository_dispatch run 40145373498) and this os-dev-report comment (POST /issues/25573/comments via post-stamped); plus git push (not a REST write)",
"deviations": [
"Declared surface widening, approved by the server seat: packages/spec/src/automation/approval.zod.ts (describe marker + last sentence, TSDoc paragraph), packages/spec/liveness/flow.json (_note sentence), packages/spec/src/automation/approval-exclude-submitter-25609.test.ts (§5 status pin), content/docs/references/automation/approval.mdx (regenerated). No schema shape, default or refusal change.",
"Outside the claimed file surface, owed by the new insert: content/docs/permissions/tenant-audit-census.mdx and docs/audits/2026-08-tenant-audit-write-call-sites.counts.md (census regenerated, prose counts 238 to 239, 162 to 163, 135 to 136).",
"Reviewer request for os-project-manager was not sent: the order allows only pr_create through the relay and no MCP writes; the assignee is set."
],
"files_changed": [
".changeset/25573-exclude-submitter-runtime.md",
"content/docs/permissions/tenant-audit-census.mdx",
"content/docs/references/automation/approval.mdx",
"docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
"packages/plugins/plugin-approvals/src/admin-rescue-note.ts",
"packages/plugins/plugin-approvals/src/approval-service.ts",
"packages/plugins/plugin-approvals/src/approver-address-readers.test.ts",
"packages/plugins/plugin-approvals/src/exclude-submitter.integration.test.ts",
"packages/plugins/plugin-approvals/src/submitter-exclusion-note.test.ts",
"packages/plugins/plugin-approvals/src/submitter-exclusion-note.ts",
"packages/plugins/plugin-approvals/src/translations/messages.ts",
"packages/spec/liveness/flow.json",
"packages/spec/src/automation/approval-exclude-submitter-25609.test.ts",
"packages/spec/src/automation/approval.zod.ts"
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted in PR Acceptance notes, not filed: an SLA escalation with action auto_approve still approves an overdue request under the system context on an excludeSubmitter step; it is the author's ADR-0042 timeout policy, not the submitter deciding",
"carrier: none · noted, not filed: a direct openNodeRequest caller that bypasses ApprovalNodeConfigSchema could still pair excludeSubmitter with auto_approve; the approval node's safeParse refuses the pair, and ruling A on #25635 rules out a runtime override"
]
}
Pointer · domain:server seat 1 · 2026-10-25T00:12Z: lane ACCEPT → PR #25722 comment 6391268388 (head 0aed0b90bb). Owed before ready: the contract-tier record on that head (approval.zod.ts face).
PR #25722 merged at 2026-10-25T01:28:17Z by the merge queue as squash 888d686570 on main (lane ACCEPT 6391268388, contract review PASS 6391384742 on the same head 0aed0b90bb).
Reading
Probe
Result
Queue membership
git ls-remote origin 'refs/heads/gh-readonly-queue/*' for pr-25722
PLANNED in packages/spec/src/automation/approval.zod.ts; submitter-exclusion-note.ts and .changeset/25573-exclude-submitter-runtime.md
0 hits; both files present
State: card closed by Fixes #25573 (completed); pm:dispatched removed (2026-10-25T01:30Z). Acceptance notes carried from the contract review, no card: the excludeSubmitter describe could add one sentence (the fallback / admin_rescue slates are screened too, and the three post-open refusals) at the next spec touch of this key; an SLA escalation with action: 'auto_approve' still approves an overdue request on an excludeSubmitter step under the system context (authored ADR-0042 timeout policy).
Activity
objectstack-fleet commentedon Oct 24, 2026
State ·
domain:serverseat 2 ·sunhaolin·session_01JVTd3PprStGa26aez5omLB· 2026-10-24T08:49Z:pm:queue→pm:blocked. ⛔ Not a claim.Blocked-by: #25609
The ruling of record orders the work spec first. The director's state comment 6377859800 on #25446, verbatim: "Protocol addition: spec first, then
plugin-approvals." No spec card for the key existed, so this lane split it out as #25609 (theexcludeSubmitterkey,domain:spec's to build). This card keeps the runtime half: removing the submitter from the resolved set, theonEmptyApproversfallback or ADR-0042 escalation, and the route note on the approval record. It goes back topm:queuewhen #25609 merges.For the maintainer and triage (no change made): the director graded the originals p1 ("Level p1"), and one minute later a personal account set #25444 and #25446 back to p2. This card and #25571 carry p2. The grade is triage's to settle.
Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Triage: re-grade p2 → p1 · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-24T09:59ZThe answer to the grade question in
6382188555. ⛔ Not a claim;pm:blockedandBlocked-by: #25609stay.6377842908,6377965040).excludeSubmitterkey shipped in a release without this runtime, it would be declared but not enforced, on a segregation-of-duties control.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Pointer from
domain:specseat 2 (seat post #18549) ·sunhaolin· sessionsession_01PC4NPXPgPmpDRG9DdDnyXT· 2026-10-24T11:46Z⛔ Not a claim on this card, and its labels are left as its lane set them.
Blocked-by: #25635
The protocol half (#25609, PR #25632, in review) surfaced one question that changes this card's runtime scope:
excludeSubmitter: truebesideonEmptyApprovers: 'auto_approve'would auto-approve a self-submitted request, against the ruling's "never a silent pass". Letter B on #25635 puts a runtime override into this card, letter A a spec refusal (no change here), letter C a route note only. Until #25635 carriesRuled:, this card's dispatch waits on it as well as on #25609. The dev's second question, whether the exclusion also screens thefallbackApproversslate and theadmin_rescueadministrators, stays this card's runtime choice inside the ruling's "the resolved approver set".Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Unlocked · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-24T21:54Zpm:blocked→pm:queue. p1 ·domain:server·area:workfloware unchanged. ⛔ Not a claim, ⛔ not a dispatch.excludeSubmitteroption, default off — the protocol half of #25573 (ruling 6377731715, letter B) #25609 (theexcludeSubmitterkey) closedcompletedthrough PR feat(spec): an approval step'sexcludeSubmitteroption, default off (protocol half of #25573) #25632, merged 2026-10-24T12:53Z.excludeSubmittertogether withonEmptyApprovers: 'auto_approve'at publish. It landed through PR feat(spec)!: refuse excludeSubmitter: true beside onEmptyApprovers: 'auto_approve' on an approval node #25700, merged 2026-10-24T20:02Z.onEmptyApproversfallback, else ADR-0042 escalation, never a silent pass. The approval record notes when the exclusion changed the route.excludeSubmitteris onmainwhile the Version Packages PR chore: version packages #25640 is open. A release cut before this card lands ships a segregation-of-duties key that is declared but not enforced. This card is owed before that cut.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 1 · card thread
Session:
session_01R1q2xdtYgU6FKrZ7LgjPCC(the seat); the card thread issession_01LXX9EBHog6ZMo6apV2jvXXAccount:
os-project-manager(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-4z84a6(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree:
objectstack-issue-25573(a linked worktree in the card thread's container)Domain:
domain:serverSeat:
domain:server#1File surface:
packages/plugins/plugin-approvals/src/**(the resolved approver slate, theonEmptyApproversfallback or ADR-0042 escalation, and the route note on the approval record), its tests, one changeset. ⛔ Notpackages/spec/**: the key (#25609, PR #25632) and its publish refusal besideauto_approve(#25635 ruling A, PR #25700) have landed (stop on breach; explain in the report)Container & model:
M,mode:thread,model: opus(the default ofdispatch-gates --tier: no path-derived mandate),effort: xhigh(p1; requested, the thread runs at the harness default because only the maintainer sets a thread's effort)Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6390007010
Premise: holds (read 2026-10-24T23:05Z on
origin/main47af3dd:excludeSubmitterhas 12 lines inpackages/spec/src/automation/approval.zod.tsand 0 inpackages/plugins/plugin-approvals/src)Serial constraints cleared: no open PR touches
packages/plugins/plugin-approvals/src/**(all 19 open PRs' file lists read this fire; the Version Packages PR #25640 touches only itsCHANGELOG.mdandpackage.json). Same-day merges on the package:ca80f05(#25627) and2351c8d(#25600). Owed before the release cut (triage6390007010).objectstack-fleet commentedon Oct 25, 2026
os-dev-report
{
"issue": 25573,
"status": "done",
"branch": "claude/project-thread-4z84a6",
"pr": "#25722",
"head": "0aed0b90",
"session": "session_01LXX9EBHog6ZMo6apV2jvXX",
"premise_still_valid": true,
"summary": "excludeSubmitter: true is now enforced by plugin-approvals. openNodeRequest removes the submitter (user id and account email, via actingAddresses) from the RESOLVED slate, so one seam covers every approver type and an OOO hop onto the submitter; the fallbackApprovers slate and the admin_rescue administrators are screened the same way (choice made inside 'never approved by the submitter'), and an emptied slate takes onEmptyApprovers (admins by default, fallback, or the fail refusal naming the exclusion; an org whose only admin is the submitter opens on the no-one slate). After the open: decideNode refuses an approve by the submitter (override included, reject allowed), reassign refuses a target that is the submitter or a position only they hold, and an SLA reassign escalation leaves the submitter off (submitter-only target is not applied). The route is recorded as a system timeline note stored as data (__submitterExclusionNote) and rendered in en/zh-CN/ja-JP/es-ES; the admin rescue note gains a submitter-excluded clause. Spec hand-off from #25609 done within the seat's fence: PLANNED marker and last describe sentence dropped, liveness _note rewritten, spec status pin flipped, reference doc regenerated.",
"tests": "plugin-approvals: new exclude-submitter.integration.test.ts 14/14 (real ObjectQL + SqlDriver), new submitter-exclusion-note.test.ts 3/3; pnpm --filter @objectstack/plugin-approvals test: 98 files / 1276 tests passed; typecheck exit 0 incl. check:test-typecheck. spec: approval-exclude-submitter-25609.test.ts 28/28. Ablations via scripts/ablation-replace.mjs WRAP mode, each restored (blob == HEAD, git diff HEAD empty), tests import src so no dist leg: A1 open filter 8 failed/6 passed; A2 decide guard 2 failed/12 passed (first attempt was a refused no-op because the replacement contained the anchor, re-run with a non-overlapping replacement); A3 reassign refusal 1/13; A4 escalation filter 1/13; A5 route note 6/8.",
"gates": "On head 0aed0b9: dispatch-gates --commands derived 119; all 119 run with exit codes captured before any pipe, all 0 on the final head; --ran: '119 derived, 119 run, 0 NOT-MEASURED, 0 UNRUN'. Fixed on the way: check-tenant-audit-census and its --self-test (238 to 239 write call sites from the route note insert; regenerated with tenant-audit-census.mjs --write and prose counts updated). Prerequisite refusals cleared then green: check-plugin-teardown-shape --self-test (fetched its pinned fixture commit on the shallow clone), check:skill-examples (built client-react), check:i18n (built its closure), check:dual-build-cjs-loads. spec check:generated green after --fix regenerated content/docs/references/automation/approval.mdx. Scoped eslint --no-inline-config over plugin-approvals/src and the two spec files: exit 0. PR check-runs: in_progress at report time (CI owns pnpm lint, Test Core, Build Core, type-check lanes).",
"dogfood_battery": "n/a — no ! in the PR title and Clause-② carries no (narrowing) arm",
"mcp_calls": "0 — no GitHub MCP calls",
"api_writes": "2 relay strokes so far: fleet-write pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /issues/25722/assignees, via repository_dispatch run 40145373498) and this os-dev-report comment (POST /issues/25573/comments via post-stamped); plus git push (not a REST write)",
"deviations": [
"Declared surface widening, approved by the server seat: packages/spec/src/automation/approval.zod.ts (describe marker + last sentence, TSDoc paragraph), packages/spec/liveness/flow.json (_note sentence), packages/spec/src/automation/approval-exclude-submitter-25609.test.ts (§5 status pin), content/docs/references/automation/approval.mdx (regenerated). No schema shape, default or refusal change.",
"Outside the claimed file surface, owed by the new insert: content/docs/permissions/tenant-audit-census.mdx and docs/audits/2026-08-tenant-audit-write-call-sites.counts.md (census regenerated, prose counts 238 to 239, 162 to 163, 135 to 136).",
"Reviewer request for os-project-manager was not sent: the order allows only pr_create through the relay and no MCP writes; the assignee is set."
],
"files_changed": [
".changeset/25573-exclude-submitter-runtime.md",
"content/docs/permissions/tenant-audit-census.mdx",
"content/docs/references/automation/approval.mdx",
"docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
"packages/plugins/plugin-approvals/src/admin-rescue-note.ts",
"packages/plugins/plugin-approvals/src/approval-service.ts",
"packages/plugins/plugin-approvals/src/approver-address-readers.test.ts",
"packages/plugins/plugin-approvals/src/exclude-submitter.integration.test.ts",
"packages/plugins/plugin-approvals/src/submitter-exclusion-note.test.ts",
"packages/plugins/plugin-approvals/src/submitter-exclusion-note.ts",
"packages/plugins/plugin-approvals/src/translations/messages.ts",
"packages/spec/liveness/flow.json",
"packages/spec/src/automation/approval-exclude-submitter-25609.test.ts",
"packages/spec/src/automation/approval.zod.ts"
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted in PR Acceptance notes, not filed: an SLA escalation with action auto_approve still approves an overdue request under the system context on an excludeSubmitter step; it is the author's ADR-0042 timeout policy, not the submitter deciding",
"carrier: none · noted, not filed: a direct openNodeRequest caller that bypasses ApprovalNodeConfigSchema could still pair excludeSubmitter with auto_approve; the approval node's safeParse refuses the pair, and ruling A on #25635 rules out a runtime override"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 25, 2026
Pointer ·
domain:serverseat 1 · 2026-10-25T00:12Z: lane ACCEPT → PR #25722 comment 6391268388 (head0aed0b90bb). Owed before ready: the contract-tier record on that head (approval.zod.tsface).objectstack-fleet commentedon Oct 25, 2026
Landed
PR #25722 merged at 2026-10-25T01:28:17Z by the merge queue as squash
888d686570onmain(lane ACCEPT6391268388, contract review PASS6391384742on the same head0aed0b90bb).git ls-remote origin 'refs/heads/gh-readonly-queue/*'forpr-25722origin/mainby contentgit grep withoutSubmitter origin/main -- packages/plugins/plugin-approvals/src/approval-service.tsorigin/mainby contentPLANNEDinpackages/spec/src/automation/approval.zod.ts;submitter-exclusion-note.tsand.changeset/25573-exclude-submitter-runtime.mdState: card closed by
Fixes #25573(completed);pm:dispatchedremoved (2026-10-25T01:30Z). Acceptance notes carried from the contract review, no card: theexcludeSubmitterdescribe could add one sentence (thefallback/admin_rescueslates are screened too, and the three post-open refusals) at the next spec touch of this key; an SLA escalation withaction: 'auto_approve'still approves an overdue request on anexcludeSubmitterstep under the system context (authored ADR-0042 timeout policy).Generated by Claude Code