10.2 Asset owners and impacted-owner approval
packs:change-governance
After this you can: declare subtree owners, require their approval through the all-of line, and hand ownership over.
Before you start — tick each one:
- Lesson 10.1 — Approval policies and the change funnel (
opschain learn 10.1)
In the GUI: Governance → Policies & owners — the approval policies beside the subtree owner declarations the funnel resolves approvers from; a held change's owner lines show in Reviews & approvals like any other line.
"Approval of each impacted asset owner" is the approval rule most change
boards actually want — and the one that cannot be spelled as a static
approver list, because who approves depends on what the change
touches. OpsChain makes ownership an authz-shaped fact declared on the
policy fabric, then resolves it per change at the create funnel. The
model reference is opschain docs change-governance; this lesson assumes
the funnel basics from lesson 10.1.
Licence entitlement. Asset-owner declarations and the
impacted_asset_ownersapprover kind rideChangeGovernanceService, so everything here requires thepacks:change-governanceentitlement (seeopschain docs entitlements).
The walkthrough uses the Lime Group demo estate: robert owns
core_banking, sarah owns payments_gateway, and internet_banking is
deliberately unowned.
1. Declare ownership
An asset owner declaration names a subtree root and its owner
identities (users and groups). Declaring is delegable exactly like the
metadata-writer role: writes are decided updatable on the reserved
/governance/owners<node path> rule-path family, sit on the step-up
floor, and are audited; reads ride readable on the same family,
404-on-deny. As a holder of that grant (elevated):
opschain governance owners declare /projects/limebank/environments/prod/assets/core_banking \
--owner-user robert
owners declared on /projects/limebank/environments/prod/assets/core_banking (01a2f5a0-3c1d-7e2f-8b4a-9d0e1f2a3b4c): robert
opschain governance owners list
NODE PATH OWNERS CREATED BY CREATED AT
/projects/limebank/environments/prod/assets/core_banking robert ryan 2026-10-27T09:30:12Z
/projects/limebank/environments/prod/assets/payments_gateway sarah ryan 2026-10-27T09:30:40Z
- A declaration covers its node and whole subtree on segment boundaries; the deepest covering declaration wins (inheritance).
- The subtree is immutable once declared: move ownership by remove +
declare, so the audit trail shows the handover
(
opschain audit --type-prefix api:asset_owners:).
2. The owner policy
A policy carrying the impacted_asset_owners approver kind resolves
declarations per change instead of naming anyone. The canonical row —
production × destroy — as the change governance administrator
(elevated):
opschain approval-policies create --name 'Production destroy control' \
--path-pattern '/projects/limebank/environments/prod/**' \
--action-pattern 'destroy*' \
--approver-kind impacted_asset_owners --require-step-up
approval policy "Production destroy control" created (01a2f5a1-6b2e-7f30-9c5b-0e1f2a3b4c5d) — path /projects/limebank/environments/prod/**, quorum 1
Named approvers and kinds compose: a policy may carry users, groups and/or kinds, but must carry at least one source.
3. The all-of owner line
As jessica (elevated — the policy also demands step-up), run
destroy_stack against an owned asset:
opschain runs create change /projects/limebank/environments/prod/assets/core_banking --action destroy_stack
created change 01a2f5a2-8d3f-7a41-ad6c-1f2a3b4c5d6e (destroy_stack on /projects/limebank/environments/prod/assets/core_banking) — pending_approval
opschain approvals show <run-id>
change 01a2f5a2-8d3f-7a41-ad6c-1f2a3b4c5d6e — destroy_stack on /projects/limebank/environments/prod/assets/core_banking
status: pending · requested by jessica at 2026-10-27T09:35:02Z
quorum deadline: 2026-11-03T09:35:02Z
lines:
Production destroy control — 0/1
waiting on robert
The change enters pending_approval with one all-of line per
resolved owner: quorum 1 per line, every owner line must satisfy —
all-of, not n-of-m — with the resolved subtree root frozen onto the
line (owner_path). Sarah cannot approve robert's line; robert
approves and the change releases:
opschain approvals approve <run-id>
approval recorded — the checklist completed and 01a2f5a2-8d3f-7a41-ad6c-1f2a3b4c5d6e was released to run
Self-approval exclusion and distinct-identity counting apply per owner line: an owner who requested the change cannot wave their own asset through.
4. The uncovered refusal
Run the same action against the unowned asset:
opschain runs create change /projects/limebank/environments/prod/assets/internet_banking --action destroy_stack
Error: The approval policy "Production destroy control" requires approval of each impacted asset owner, but no subtree owner is declared covering: /projects/limebank/environments/prod/assets/internet_banking — declare owners for every impacted target before this change can be created (a covered change is never approver-less; see: opschain docs change-governance)
An impacted target no declaration covers refuses the create loudly — a covered change is never created approver-less, and nothing is created at all. Fix it by declaring an owner (or an ancestor-level declaration that covers the gap), then re-run.
5. Handover, audited
Ownership changes are themselves governed facts:
opschain governance owners update <declaration-id> --owner-user sarah
owners updated on /projects/limebank/environments/prod/assets/core_banking (01a2f5a0-3c1d-7e2f-8b4a-9d0e1f2a3b4c): sarah
opschain audit --type-prefix api:asset_owners:
WHEN TYPE USER SOURCE NODE CORRELATION
2026-10-27T09:41:18Z api:asset_owners:update ryan - /projects/limebank/environments/prod/assets/core_banking 01a2f5a4-…
2026-10-27T09:30:12Z api:asset_owners:create ryan - /projects/limebank/environments/prod/assets/core_banking 01a2f5a0-…
The update event carries before/after owners. Removing a declaration
(opschain governance owners remove <declaration-id>) ends coverage —
any covered destroy against that subtree then refuses at create until
ownership is re-declared.
Check yourself
- Which refusal does the funnel print when an impacted subtree has no owner declared — and is a change created at all? Then: after robert approves his line, what does
opschain approvals showreport as the checklist status?
What you learned
- Ownership is declared per subtree on the reserved
/governance/owners<path>rule-path family — delegable, audited, step-up floored, deepest declaration wins, immutable subtree. - The
impacted_asset_ownerskind resolves owners per change over the frozen target set: one all-of checklist line per owner, self-approval excluded per line. - An uncovered impacted target refuses the create by name — fail closed, never approver-less.
Next: lesson 10.3 — The approval context (opschain learn 10.3), or back to your track (opschain learn).