# 1. cp9 purge tag assurance is limited to trusted parent proof

Status: Accepted

## Context

CP9 sessions can create child cloud resources through product permissions. Some
of those children may be missing the cp9 delete-scope tags (`cp9-owner`,
`cp9-session`) even though they are deterministically contained by a verified
cp9 parent such as a VPC, EKS cluster, tagged IAM role, or load balancer. The
aws-nuke filters are fail-closed and exclude untagged children, which can block
stable cleanup of their tagged parents.

A naive fix — tagging anything whose name resembles a session — would let cleanup
mutate or delete resources that CP9 cannot prove it owns.

## Decision

`cp9 purge` repairs missing cp9 scope tags **only** when it has trusted parent
proof. Trusted parents are:

- verified cp9-tagged VPCs (and their non-default children),
- verified cp9-tagged EKS clusters,
- tagged IAM roles (inline policies / attachments inherit only from the role),
- trusted load-balancer-derived Route53 exact selectors.

There is one narrow cross-service edge: a deterministic CP9 EKS service role
may prove an EKS cluster whose immutable `RoleArn` equals that role ARN. This
edge is trusted only when all of the following hold:

- IAM `GetRole` returns the exact deterministic role name for the requested
  session in the cleanup account;
- a fresh IAM `ListRoleTags` independently proves `cp9-managed=true` (or
  `terraform-substrate`) and the exact owner/session scope;
- EKS `DescribeCluster` proves the exact role ARN, the cluster carries
  `environment=cp9`, and any existing cleanup-scope tags do not conflict;
- nodegroups are included only through EKS `ListNodegroups` plus an exact
  `DescribeNodegroup.ClusterName` containment check and non-conflicting tags;
- the whole discovered EKS graph is validated before its first tag mutation,
  and dry-run, execution, and post-verification use the same proof predicate.

An IAM timeout or incomplete role/tag proof blocks this edge; it never degrades
to name inference or an empty-success result. Ordinary IAM roles still confer
scope only to their inline policies and attachments.

Name-only inference is rejected (see ADR 0004 partner and the glossary term
"Name-only inference"). A session-looking name may be logged as a clue but is
never proof for tag assurance. It is also never proof for deletion except the
two Recycle delete-path exceptions below. Conflicting `cp9-owner` /
`cp9-session` tags on a candidate block that candidate without overwriting tags.

The first implementation excludes CloudFormation stack reverse inference and
standalone tag assurance for resources without direct cp9 tags; account-wide
inventory and quarantine of weakly attributed resources is a separate boundary.

Two **delete-path** exceptions exist so Recycle can converge when session tags
are missing or a stack is `DELETE_FAILED`. They are not tag-assurance edges and
they do not reopen hyphen-token name matching. Cleanup stability (no leftover
survivors) outranks expanding blast radius for these two cases only.

1. **Ownerless EKS name.** When Recycle has a concrete owner and session, an
   `environment=cp9` EKS cluster or nodegroup with no `cp9-owner` may be
   adopted if its cluster name is exactly one of: the session name,
   `<session>-starter-regional`, or `dedicated-<session>-<region>-…` where
   session is the token between `dedicated-` and the last `-<region>-`.
   Conflicting non-empty owners still block. Remaining risk: a non-CP9 cluster
   in the same account that uses one of those shapes.
2. **DELETE_FAILED HostedZone on a session-tagged stack.** Emptying and
   deleting `AWS::Route53::HostedZone` children listed by `ListStackResources`
   on a stack already in the Recycle set is allowed so `DeleteStack` can
   finish. This is not account-wide zone discovery. Remaining risk: an
   imported or foreign zone listed on that stack.

Account-414 shared DNS is out of scope for these exceptions.

## Consequences

- Tag assurance is auditable and provably scoped to cp9-owned trees.
- The EKS service-role edge can recover a cluster that lost direct cleanup
  labels without treating a session-looking cluster name as ownership proof.
- Untagged standalone resources are out of scope for assurance and must go
  through inventory/quarantine instead.
- Cleanup converges on parents whose untagged children are now provably tagged.
- Recycle may still delete two weakly attributed leftover classes so scheduled
  cleanup can finish: ownerless EKS whose name is the session,
  `<session>-starter-regional`, or exact dedicated shape; and DELETE_FAILED
  HostedZones listed on a session-tagged stack.
