docs: record RDS DB subnet group owner extraction

This commit is contained in:
joshsiv-mulga
2026-10-08 10:03:17 +10:00
parent 17dc29251d
commit 11fab67247
2 changed files with 4 additions and 2 deletions
+2
View File
@@ -289,6 +289,7 @@ while the branch is in flight; they do not describe the umbrella repository's
| `4b0a4dd6b` | — | — | ACM characterization before registration: full-pipeline 400 MissingAction/InvalidAction envelopes, a 200 `ListCertificates` against a live NATS responder, dispatch and telemetry target-parser agreement, authorization before the NATS call (subject counter stays zero), 413 before dispatch, 503 when NATS is down (ACM's own nil-connection check is unreachable over HTTP), the action reaching throttle, trace and audit, and the nine-action inventory. Mutating the parser, the authorization call and the action table each failed tests. Test-only; full preflight passed. |
| `fdaf589ca` | `spinifex/gateway` (`ACM_Request`, `acmActions`, `acmActionFromTarget`, legacy `acm` entries) | `spinifex/domains/acm/awsapi` (`NewRegistration`, `OperationInventory`) | ACM registers its AWS JSON 1.1 control plane from its domain, wired only by the awsgw role; the dispatcher reproduces the old order (missing/unknown action, `InternalError` without an account, bounded body, resource ARNs, authorization, then nil-NATS and the action). The S4 composition invariant now covers every registered domain `awsapi` with the same named coverage-tool exception. Coverage output was byte-identical and the ACM integration conformance summary was identical at the parent and after. Mutating authorization order, the target parser, the inventory and gateway imports each failed tests. Temporary edge: `Deps.NATS` is a raw `*nats.Conn` because every ACM action function takes one. Full preflight passed. |
| `01276bf29` | — | — | RDS DB subnet group characterization before extraction (ADR-0003 S1, ADR-0004): repeat delete reports not found, name scoped to the account, modify never moves a placed instance, snapshots do not block delete, restore rejects an unknown group, tags reached through the ARN and gone with the group, persisted record field names. Present contract and gaps in `docs/package-boundary/rds-db-subnet-group-lifecycle.md`; no conformance claimed. |
| `17dc29251` | `spinifex/handlers/rds` (`DBSubnetGroupRecord`, `DBSubnetGroupSubnet`, `DBSubnetGroupKey`, `DBSubnetGroupsPrefix`, `getDBSubnetGroup`, `resolveGroupSubnets` and the create/modify/delete bodies) | `spinifex/domains/rds/subnetgroup` (`Owner`, `Record`, `Subnet`, `Key`, `Prefix`) | First ADR-0004 resource owner. The handler keeps AWS validation, projection and paging; delete reaches instances through the owner-declared `Dependants`, and instance placement reaches the group through the instance-declared `subnetGroupPlacement`. Stored shape unchanged; `docs/service-interfaces.yaml` lists the package with the RDS daemon. No conformance claimed; gaps in the lifecycle contract. |
The EC2 contract row is intentionally different from the directory moves: it creates
a compatibility boundary. `ec2.cmd.*` retains its deployed one-token NATS
@@ -385,6 +386,7 @@ These residuals were recorded by individual slices and must be resolved once the
- `domains/ec2/awsapi/instance` (dependency): imports `handlers/iam` (`IAMService` in `DescribeInstances.go`, `RunInstances.go` and `IamInstanceProfileAssociation.go`; `InstanceProfile` in the latter two), `runtime/compute/cache` (`NodeState`, `NodeUnknown`, `NodeLive`) and `runtime/compute/vm` (`VM`), both in `status_synthesis.go`. The IAM edge needs an IAM capability; the runtime edges are domain-to-runtime and need the instance record and node liveness exposed through an EC2-owned projection.
- `domains/ec2/awsapi/spotinstance` (dependency): imports `handlers/iam.IAMService` and `handlers/quota.Service` in `RequestSpotInstances.go`.
- Instance adapter consumers outside EC2: `gateway/rds/enginecatalog.go`, `daemon/eks_cp_control.go`, `daemon/rds_deps.go` and `handlers/quota/vcpu.go` call `domains/ec2/awsapi/instance` directly; each needs an EC2 capability rather than the AWS action adapter.
- `handlers/rds` → `domains/rds/subnetgroup` (legacy edges): `instanceReferences` binds `Dependants` by scanning instance records, and `tags.go` writes the group record through its generic tag registry. They clear when the RDS instance gains its own owner and RDS tagging moves to `domains/rds/awsapi`.
- Merge-time follow-up in the umbrella repository: the `Makefile` `invariants-check` target, the `docs-pr.yml` clause cross-check, `.claude/hooks/architecture-traps.sh` and a `check-invariants.sh` comment hard-code `spinifex/spinifex/network/invariants`. They must change with the pointer bump that brings in this branch, or the docs-pr cross-check silently skips. Live specs and proposals citing `spinifex/network/` will report unresolved citations until updated.
## ADR-0004 source inventory and first-resource ranking
@@ -16,7 +16,7 @@ The group's one external effect is indirect: instance create and restore read it
|---|---|---|
| Identity | `DBSubnetGroupName`, case-sensitive, immutable, `default` reserved. ARN `arn:aws:rds:{region}:{account}:subgrp:{name}`. | `handlers/rds/subnetgroup_test.go` `TestCreateDBSubnetGroup_RejectsMalformedRequests`, `handlers/rds/arn_test.go` |
| Scope | Account and Region: one record per name in the `rds-account-{account}` bucket. Not AZ-scoped; each member subnet carries the AZ recorded on the EC2 subnet. | `TestDBSubnetGroup_NameIsScopedToTheAccount`, `TestCreateDBSubnetGroup_AcceptsASingleSubnet` |
| Durable owner and record | `handlers/rds/subnetgroup.go` owns `db-subnet-groups/{name}` (`DBSubnetGroupRecord`). `tags.go` also writes the record's `Tags` field through CAS. | `TestDBSubnetGroupRecord_PersistedFieldNames`, `TestDBSubnetGroup_TagsAreReachedThroughItsARN` |
| Durable owner and record | `domains/rds/subnetgroup` (`Owner`) owns `db-subnet-groups/{name}` (`Record`). `handlers/rds/subnetgroup.go` is the AWS adapter: request validation, projection and paging. `handlers/rds/tags.go` also writes the record's `Tags` field through CAS. | `TestDBSubnetGroupRecord_PersistedFieldNames`, `TestDBSubnetGroup_TagsAreReachedThroughItsARN`, `domains/rds/subnetgroup/owner_test.go` |
| Desired state | Description, member subnets and their single VPC, and tags. Subnets are validated as the caller through EC2 `DescribeSubnets`: same account, one VPC, at most 20, no duplicates. | `TestCreateDBSubnetGroup_Rejects*`, `TestModifyDBSubnetGroup_RefusesAMoveToAnotherVPC` |
| Generation | None. Create is exclusive (`createJSON`); modify and tag writes retry against the KV revision so a concurrent write is not undone; delete is unconditional. | `TestCreateDBSubnetGroup_RejectsADuplicateName`, `TestTagWrites_ConcurrentAddsAndRemovesDoNotLoseEachOther` |
| Observed state | Not tracked separately. `SubnetGroupStatus` is always `Complete` and every member subnet reports `Active`. | `TestDescribeDBInstances_ReportsTheSubnetGroupTheInstanceWasPlacedFrom` |
@@ -30,7 +30,7 @@ The group's one external effect is indirect: instance create and restore read it
## Gaps
1. Delete is check-then-delete with no fence against a concurrent instance create or restore that has already read the group (`subnetgroup.go` `DeleteDBSubnetGroup`, `network.go` `resolvePlacement`), so an instance can name a deleted group. Its placement is already stored, so the endpoint keeps working; only the name dangles.
2. The in-use guard reads the instance's private records directly (`instancesUsingGroup`), and placement reads the group's private record directly (`getDBSubnetGroup` in `network.go`). Both cross the resource boundary ADR-0003 S4 forbids.
2. Both cross-resource reads now go through consumer-owned capabilities: the owner's `Dependants` for the in-use guard and the instance side's `subnetGroupPlacement` for placement. The `Dependants` binding in `handlers/rds/subnetgroup.go` (`instanceReferences`) still scans instance records directly until instances have their own owner, and `handlers/rds/tags.go` still writes the group's record directly. Both are temporary legacy edges.
3. `DescribeDBInstances` projects the group from the instance record alone, so its `DBSubnetGroup` carries no description or subnets (`describe.go`). AWS documents both fields on that response; not verified against live AWS.
4. Member subnets always report `Active`, even after the EC2 subnet is deleted. What AWS reports in that case is not verified.
5. Modify accepts a new subnet set that drops the subnet a placed instance sits in. Whether AWS refuses this is not verified.