diff --git a/docs/PACKAGE_BOUNDARY_MIGRATION.md b/docs/PACKAGE_BOUNDARY_MIGRATION.md index 46080262b..b62dc208f 100644 --- a/docs/PACKAGE_BOUNDARY_MIGRATION.md +++ b/docs/PACKAGE_BOUNDARY_MIGRATION.md @@ -315,6 +315,7 @@ while the branch is in flight; they do not describe the umbrella repository's | `8cd9cff75` | `spinifex/migrate/migrate_test.go` (the `Registry`/`RunKV` tests and their NATS helpers) | `spinifex/foundation/state/migrate/kv_test.go` | The KV migration engine's only tests lived in the operator upgrade package's test file. They move to the package that owns the engine before the workflow moves, so `operator/upgrade` does not hold another package's test suite. No test name, assertion or behaviour changed. | | `919d5bfa6` | `spinifex/migrate` | `spinifex/operator/upgrade` | Owner decision: the operator-driven config-file and object-store upgrade workflow behind `spx admin upgrade` belongs to `operator/upgrade`, distinct from `foundation/state/migrate`. Package renamed to `upgrade`; no registry types, migration names, versions, file formats or command names changed. It imports only `foundation/state/{kvutil,migrate}`, `providers/objectstore` and jetstream, so it carries no layering debt. `scripts/diff-coverage.sh` and `VERSIONS.md` point at the new path. Full preflight passed apart from the recorded Go 1.27.0 advisory exception. | | `5292bd22c` | — | — | ADR-0001 layering ratchet added, with the nine import edges it found missing from this record recorded below; it lives at `architecture/layering` beside `tests/`, outside the product tree. | +| `8bf162fb7` | `spinifex/utils/ec2_subject.go` (`SubjectEnsureDefaultVpc`) | `contracts/ec2/v1` (`EnsureDefaultVpcSubject`) | The default-VPC request/reply subject crosses the gateway–daemon process boundary, so its home is the EC2 contract. Only the subject moved; the request and reply bodies remain anonymous structs on each side, as the contract README states. | The EC2 contract row is intentionally different from the directory moves: it creates a compatibility boundary. `ec2.cmd.*` retains its deployed one-token NATS @@ -387,10 +388,10 @@ These residuals were recorded by individual slices and must be resolved once the - Domain → runtime: `domains/ochre/capacity.go:9` imports `runtime/compute/gpu`; `domains/ec2/volume/service_impl.go:30` and `volume_leak_reaper.go:8` import `runtime/compute/vm`; `domains/ec2/instance/status_selection.go:9` also imports `runtime/compute/vm`. Each reads VM or GPU runtime state directly instead of through a domain-owned projection. - `handlers/sts/oidc_jwks.go:14` imports `handlers/eks` for `AccountBucketName` (line 101) and `OIDCJWKSKey` (line 110), the Q-22 STS-to-EKS dependency ADR-0001 prohibits in its present form. Removal condition: an EKS-owned OIDC projection or an identity-owned contract that STS consumes instead of the EKS implementation package. - `handlers/elbv2/{agent_types,haproxy,health_checker,nginx}.go` import `lbagent` (`HealthReport`, `ServerStatus`, `CertDir`, `NginxPIDPath`, `NginxCertDir`), a domain reading an agent's implementation package rather than a declared wire contract. Removal condition: the health-report and cert/PID-path vocabulary moves behind a guest/controller contract the domain and the agent both consume. -- `handlers/iam/service_impl.go:30` imports `admin` for `GenerateAWSSecretKey`, `AccountID` and `AccountName`, a domain-to-operator edge. This is part of the already-recorded `admin` → `operator/admin` blocker (`GenerateAWSAccessKey`/`GenerateAWSSecretKey` need an IAM-credentials owner before `admin` can move). +- `handlers/iam/service_impl.go:30` imports `admin` for `GenerateAWSSecretKey` (line 641) only, a domain-to-operator edge; the `admin.AccountID`, `admin.AccountName` and `admin.EncryptedSecret` uses are fields of a local `*AdminBootstrapData` parameter, not the package. This is part of the already-recorded `admin` → `operator/admin` blocker (`GenerateAWSAccessKey`/`GenerateAWSSecretKey` need an IAM-credentials owner before `admin` can move). - `vpcd/imds_instance_state.go:10` imports `daemon` for `LocalState`, `ReadLocalState`, `LocalStatePath`, `NewJetStreamManager` and `InstanceStateBucket`, a guest-facing daemon component reading the daemon's own implementation rather than a declared local-state contract. Removal condition: a daemon-owned local-state capability or contract that vpcd consumes instead of the `daemon` package directly. - Advisory: 27 production files across `domains/{acm,dns,ec2/*,network/host,network/ovn,ochre}` import `bootstrap/config` directly rather than through typed constructor inputs, which ADR-0001's `config` row expects. `bootstrap/preflight/preflight.go:15` imports `runtime/host/command` and `services.go:13` imports `operator/host/systemd`; both are expected bootstrap-to-runtime/operator edges for startup validation and are not domain-rule violations. -- `admin` → `operator/admin` is blocked until its shared pieces have owners: `DefaultAccountID`/`DefaultAccountName` (IAM/account bootstrap), `GenerateAWSAccessKey`/`GenerateAWSSecretKey` (IAM credentials), `PromoteSystemImage` (EC2 image domain), and `GenerateCACert`/`GenerateSignedCert` (Spinifex certificate issuance, used by the NATS role and RDS). +- `admin` → `operator/admin` is blocked until its shared pieces have owners: `DefaultAccountID`/`DefaultAccountName` (IAM/account bootstrap), `GenerateAWSAccessKey`/`GenerateAWSSecretKey` (IAM credentials), `PromoteSystemImage` (EC2 image domain), and `GenerateCACert`/`GenerateSignedCert` (Spinifex certificate issuance). A later consumer check found the certificate functions have no production consumer outside `operator/cli` (the NATS role uses them only in `nats_test.go`, and `handlers/rds/servingcert.go` only mentions them in a comment), so only `DefaultAccountID`, the key generators and `PromoteSystemImage` still block. - `domains/dns`: imports `runtime/compute/vm` (domain-to-runtime), `domains/network/reconcile` for the reconcile lock and `bootstrap/config` for node configuration. - ACM: the IAM AES-GCM helper import (ACM relocation residual). - `runtime/roles/awsgw`: the quota reconcile loop belongs to `domains/admission/quota`, and the EKS token-verify responder belongs with STS or EKS identity. @@ -502,14 +503,14 @@ series above; "needs decision" is open. | `gateway/{ecs,eks,rds,iam,sts,elbv2}` | Each service's AWS action adapters and dispatch, not yet registered through ADR-0002. | Deferred: the ADR-0002 registration contract has only reached ECR and ACM so far; each service needs its own registration slice. | | `gateway/spx` | `promote_image.go` and `spx.go` dispatch (`storage.go` already consumes `contracts/operator/v1`). | Needs decision: which package owns operator-plane action dispatch registration — an `ingress/aws`-style seam for the operator plane, or `gateway` stays its home. | | `gateway/tagging` | The cross-service tagging API (`GetResources`) and its authorization. | Decided: a new `domains/tagging` boundary owns the cross-resource tagging API and aggregation; individual resource domains keep ownership of their own tag storage and expose narrow tagging capabilities. Stays debt until those per-domain capabilities exist; clears when `domains/tagging` aggregates only through them. | -| `services/viperblockd` | Role supervision and the Viperblock EBS provider adapter in one package. | Decided: the adapter moves to `providers/ebs/viperblock`; `services/viperblockd` keeps only role supervision. EC2 volume code continues to depend only on `providers/ebs`. Clears when the adapter lives at `providers/ebs/viperblock`. | -| `utils` | `vpcd_event.go`, `encryption.go` (`ec2_subject.go` moved to `contracts/ec2/v1` as `EnsureDefaultVpcSubject`; its request and reply bodies are still anonymous structs on each side). | Decided: `vpcd_event.go` is a serialised cross-process contract (its `natEvent` payload crosses a NATS request-reply boundary on `vpc.add-nat`/`vpc.delete-nat`), so `domains/network` owns its meaning and its versioned wire form goes under `contracts/network/v1`. `ec2_subject.go` (`SubjectEnsureDefaultVpc`, a NATS request/reply subject between the gateway and the daemon) has `domains/ec2` as its subject-semantics owner, with `contracts/ec2/v1` as its eventual home since it crosses a process boundary. `encryption.go` (the Viperblock master-key loader) joins the Viperblock adapter at `providers/ebs/viperblock`, not generic EBS or foundation code. | +| `services/viperblockd` | Role supervision and the Viperblock EBS provider adapter in one package. | Decided: the adapter moves to `providers/ebs/viperblock`; `services/viperblockd` keeps only role supervision. EC2 volume code continues to depend only on `providers/ebs`. Clears when the adapter lives at `providers/ebs/viperblock`. Read-only assessment: the cut is clean (all shared `Config` state is adapter-side; only `launchService` would become an exported entry point), but the adapter imports `services/viperblockd/vbwire`, a legacy package with no recorded owner (consumers: `daemon`, `operator/cli`), which rule 4 forbids a provider to import. Prerequisite: an owner for `vbwire`, either its subjects and payloads under `contracts/viperblockd` with the JetStream helpers in the adapter, or the whole package in the adapter. | +| `utils` | `vpcd_event.go`, `encryption.go` (`ec2_subject.go` moved to `contracts/ec2/v1` as `EnsureDefaultVpcSubject`; its request and reply bodies are still anonymous structs on each side). | Decided: `vpcd_event.go` is a serialised cross-process contract (its `natEvent` payload crosses a NATS request-reply boundary on `vpc.add-nat`/`vpc.delete-nat`), so `domains/network` owns its meaning and its versioned wire form goes under `contracts/network/v1`. `ec2_subject.go` (`SubjectEnsureDefaultVpc`, a NATS request/reply subject between the gateway and the daemon) has `domains/ec2` as its subject-semantics owner, with `contracts/ec2/v1` as its eventual home since it crosses a process boundary. `encryption.go` (the Viperblock master-key loader) joins the Viperblock adapter at `providers/ebs/viperblock`, not generic EBS or foundation code. Blocked on a capability decision: its only callers are `domains/ec2/{image,instance,volume}`, which test the key only to derive the AWS-visible `Encrypted` posture; moving it would make EC2 import a Viperblock-specific provider. It needs an encryption-posture field in the `providers/ebs` contract or an EC2-owned configuration predicate first. | | `vpcd` | `imds_instance_state.go` reads `daemon.LocalState`, `ReadLocalState`, `LocalStatePath`, `NewJetStreamManager` and `InstanceStateBucket` directly (recorded above). | Needs a daemon-owned local-state capability or contract vpcd can consume instead of the `daemon` package. | | `daemon` | Reserved as `runtime/daemon`'s home only; not split or moved. | Deferred: Q-28's write-side consolidation is a prerequisite ADR-0001 names explicitly. | -| `admin` | `DefaultAccountID`/`DefaultAccountName`, `GenerateAWSAccessKey`/`GenerateAWSSecretKey`, `PromoteSystemImage`, `GenerateCACert`/`GenerateSignedCert` (recorded above). | Deferred: each needs its target owner first — IAM/account bootstrap, IAM credentials, the EC2 image domain, and Spinifex certificate issuance respectively. | +| `admin` | Operator use cases (`email.go`, `telemetry.go`, `network_detect.go`, `image_import.go`, `images_remove.go`, `orphan_volumes.go`, most of `admin.go` including certificate issuance) consumed only by `operator/cli` and `operator/installer/ui`; plus `DefaultAccountID`/`DefaultAccountName` (consumed by `daemon`, `gateway`, `runtime/roles/awsgw`), `GenerateAWSAccessKey`/`GenerateAWSSecretKey` (`handlers/iam`) and `images_promote.go` (`daemon`, `gateway/spx`). | Partially movable: a read-only assessment found the operator-only files can move to `operator/admin` with no new forbidden edge, cycle or shim (it clears the `operator/installer/ui` → `admin` entry); `images_promote_test.go` shares fixtures with `images_remove_test.go`. Remaining pieces are deferred to their owners: IAM/account bootstrap, IAM credentials, and the existing `domains/ec2/image`. | | `accountteardown` | Direct calls into `domains/ec2/awsapi/*` action adapters (recorded above). | Deferred: the ADR's `accountteardown` row replaces this with domain-owned cleanup capabilities. | | `lbagent` | The whole package; `handlers/elbv2` imports it as a domain-to-agent implementation edge (recorded above). | Deferred: Q-30 reserves `agents/elbv2` as its destination but forbids moving it as an isolated rename ahead of the common-agent design. | -| `migrate` | Nothing: moved to `operator/upgrade` in `919d5bfa6` after its KV-engine tests moved to `foundation/state/migrate` in `8cd9cff75`. | Cleared. | +| `migrate` | Nothing at the old path. | Split, not an exact ADR row: ADR-0001 maps `migrate` to `foundation/state/migrate`, but the package held two responsibilities. The KV migration engine and its tests are in `foundation/state/migrate` (`8cd9cff75`); the config-file and object-store upgrade workflow moved to `operator/upgrade` (`919d5bfa6`) by owner decision. Needs an ADR-0001 map clarification before this row can be claimed as target conformance. | `runtime/roles/awsgw` carries two recorded residuals from its own move (`931d86d5c` above) that are not yet re-homed: `runQuotaReconcile`/`quotaKeyFor` belong to