Skip to content

feat(security): ADR-0091 L2 — delegation of duty (职务代理) - #2810

Merged
os-zhuang merged 3 commits into
mainfrom
feat/adr-0091-l2-delegation
Jul 11, 2026
Merged

feat(security): ADR-0091 L2 — delegation of duty (职务代理)#2810
os-zhuang merged 3 commits into
mainfrom
feat/adr-0091-l2-delegation

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

ADR-0091 L2 (delegation half). Builds on the L1 validity substrate: a holder of a delegatable position may self-service hand off their own authority, time-boxed — the one branch of the D12 gate open to a non-administrator.

D3 — the self-service delegation branch

A non-admin (no adminScope, no tenant-superuser wildcard) hitting the D12 gate is normally denied. L2 adds a branch: a sys_user_positioninsert that stamps delegated_from is judged as a delegation and approved iff every invariant holds:

RuleEnforcement
delegated_from = the writeryou may only delegate authority you hold yourself
mandatory valid_until, future, ≤ 30-day ceilingan open-ended delegation is a permanent grant with extra steps
mandatory reasondual-audit substrate
writer holds the position directly (validity-filtered)a grant that itself arrived via delegation is not re-delegatable — chains cut
position is delegatable: trueopt-in (spec PositionSchema.delegatable, default false)
position distributes noadminScope-carrying setadministration is never self-delegated (D12 containment), fail-closed
insert-onlynot self-renewable — continuing past expiry needs a fresh delegation, leaving a new audit record

Dual audit: granted_by (writer) + delegated_from (authority source), both stamped/recorded.

Explain (D3 rule 5)

buildContextForUser surfaces delegation provenance; the principal layer attributes a delegated position "via delegation from X, until Y".

Proof (ADR-0054)

position.delegatable is registered as a bound high-risk class with an end-to-end dogfood proof (delegation-of-duty): a gated delegation write over the real HTTP API, then the delegate's grant resolving in-window and dying at valid_until via the real resolveAuthzContext — the L1 filter on the real persisted row. Access dies with no cleanup job.

Tests

SuiteResult
delegated-admin-gate (16 new delegation cases)38/38
explain-engine (provenance)14/14
spec (parse + proof-registry bindings)6688/6688
core security94/94
plugin-security (full)286/286
dogfood delegation-of-duty5/5

Liveness gate: bound proof resolves. check:role-word, check:authz-resolver, check-changeset-fixed all pass.

Not in this PR

Break-glass activation workflow and recertification campaigns stay enterprise (D7); their community shapes are the L1 substrate. Early revocation of a delegation is an admin/expiry concern, not a self-service affordance in L2.

🤖 Generated with Claude Code

https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H


Generated by Claude Code

A holder of a delegatable position may hand off their OWN authority,
time-boxed, WITHOUT being an administrator — the one self-service branch
of the D12 gate.
- spec: PositionSchema.delegatable (default false) + sys_position.delegatable
- D12 gate: self-service branch on sys_user_position insert — approves iff
the row is a well-formed delegation: delegated_from = writer, mandatory
valid_until (future, within the 30-day ceiling), mandatory reason, and the
writer holds the position DIRECTLY (validity-filtered; a delegated holding
is not re-delegatable — chains cut). Insert-only → not self-renewable. A
delegatable position distributing an adminScope set is rejected fail-closed
(administration is never self-delegated — D12 containment). Dual audit:
granted_by (writer) + delegated_from (authority source)
- explain: buildContextForUser surfaces delegation provenance; the principal
layer attributes a delegated position 'via delegation from X, until Y'
- proof (ADR-0054): position.delegatable is a bound high-risk class with an
end-to-end dogfood proof — a gated delegation write over the real HTTP API,
then the delegate's grant resolving in-window and dying at valid_until via
the real resolver
- docs: authorization.mdx delegation section; ADR-0091 phasing L2 landed
Tests: gate 38 (16 new delegation cases), explain 14, spec 6688, core 94,
plugin-security 286 — all green; dogfood delegation-of-duty 5/5; liveness gate
(bound proof resolves); role-word + authz-resolver guards pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H
@vercel

vercelBot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 11, 2026 2:45am

Request Review

…gistry conflicts
Both this branch and the merged ADR-0057 lifecycle work (#2791) appended a
HIGH_RISK_CLASSES entry and extended the BOUND_PROOF_PATHS expectation:
kept BOTH ('delegation' → position/delegatable, 'data-lifecycle' →
object/lifecycle). proof-registry tests and the spec-liveness gate pass on
the merged tree.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNBzMWmSECrbiEDdVzwBt3
@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/l labels Jul 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/dogfood, @objectstack/plugin-security, @objectstack/spec.

98 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via packages/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via packages/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/cli.mdx(via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via packages/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via packages/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/permissions/access-recipes.mdx(via packages/plugins/plugin-security)
  • content/docs/permissions/authorization.mdx(via packages/dogfood, packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx(via packages/dogfood)
  • content/docs/permissions/explain.mdx(via @objectstack/plugin-security)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx(via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)
  • content/docs/ui/audience-based-interfaces.mdx(via packages/plugins/plugin-security)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit f3035bd into mainJul 11, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the feat/adr-0091-l2-delegation branch July 11, 2026 02:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude