Repository: kubernetes-sigs/cluster-api
Pull request #9778 (2023-11-27 19:13:49)

🌱 Drop unused runtime features for the in-memory provider
**What this PR does / why we need it**:
When we envisioned the in-memory provider we were thinking of adding some special behavior to it to create a sort of Chaos agent. Given that this idea has been on hold for a couple of months now, I'm cleaning up the part of the codebase we created to make this possible which is now un-used.

We can eventually re-introduce them back later if necessary

/area testing

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please ask for approval from [fabriziopandini](https://github.com/fabriziopandini). For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcluster-api).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/cluster-api/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["fabriziopandini"]} -->
vincepri: lgtm pending linter
sbueringer: Same. Interesting, didn't realize there is that much that we don't use

Patch:
diff --git a/.github/ISSUE_TEMPLATE/release_tracking.md b/.github/ISSUE_TEMPLATE/release_tracking.md
index 9a815602b..5c09abd3c 100644
--- a/.github/ISSUE_TEMPLATE/release_tracking.md
+++ b/.github/ISSUE_TEMPLATE/release_tracking.md
@@ -14,11 +14,14 @@ Please see the corresponding section in [release-tasks.md](https://github.com/ku
 
 **Notes**:
 * Weeks are only specified to give some orientation.
-* The following is based on the v1.6 release cycle. Modify according to the tracked release cycle.
+* The following is based on the v1.4 release cycle. Modify according to the tracked release cycle.
+
+Week -3 to 1:
+* [ ] [Release Lead] [Set a tentative release date for the minor release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#set-a-tentative-release-date-for-the-minor-release)
+* [ ] [Release Lead] [Assemble release team](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#assemble-release-team)
 
 Week 1:
 * [ ] [Release Lead] [Finalize release schedule and team](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#finalize-release-schedule-and-team)
-* [ ] [Release Lead] [Add/remove release team members](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#addremove-release-team-members)
 * [ ] [Release Lead] [Prepare main branch for development of the new release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#prepare-main-branch-for-development-of-the-new-release)
 * [ ] [Communications Manager] [Add docs to collect release notes for users and migration notes for provider implementers](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#add-docs-to-collect-release-notes-for-users-and-migration-notes-for-provider-implementers)
 * [ ] [Communications Manager] [Update supported versions](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#update-supported-versions)
@@ -27,42 +30,39 @@ Week 1 to 4:
 * [ ] [Release Lead] [Track] [Remove previously deprecated code](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#track-remove-previously-deprecated-code)
 
 Week 6:
-* [ ] [Release Lead] [Cut the v1.5.1 & v1.4.6 releases](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [Release Lead] [Cut the v1.3.1 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
 
 Week 9:
-* [ ] [Release Lead] [Cut the v1.5.2 & v1.4.7 releases](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [Release Lead] [Cut the v1.3.2 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
 
 Week 11 to 12:
 * [ ] [Release Lead] [Track] [Bump dependencies](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#track-bump-dependencies)
 
 Week 13:
-* [ ] [Release Lead] [Cut the v1.6.0-beta.0 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
-* [ ] [Release Lead] [Cut the v1.5.3 & v1.4.8 releases](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [Release Lead] [Cut the v1.4.0-beta.0 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [Release Lead] [Cut the v1.3.3 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
 * [ ] [Release Lead] [Create a new GitHub milestone for the next release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#create-a-new-github-milestone-for-the-next-release)
 * [ ] [Communications Manager] [Communicate beta to providers](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#communicate-beta-to-providers)
 
 Week 14:
-* [ ] [Release Lead] [Cut the v1.6.0-beta.1 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
-* [ ] [Release Lead] [Set a tentative release date for the next minor release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#set-a-tentative-release-date-for-the-next-minor-release)
-* [ ] [Release Lead] [Assemble next release team](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#assemble-next-release-team)
+* [ ] [Release Lead] [Cut the v1.4.0-beta.1 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
 * [ ] [Release Lead] Select release lead for the next release cycle
 
 Week 15:
+* [ ] [Release Lead] [Create the release-1.4 release branch](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#create-a-release-branch)
+* [ ] [Release Lead] [Cut the v1.4.0-rc.0 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [CI Manager] [Setup jobs and dashboards for the release-1.4 release branch](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#setup-jobs-and-dashboards-for-a-new-release-branch)
+* [ ] [Communications Manager] [Ensure the book for the new release is available](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#ensure-the-book-for-the-new-release-is-available)
 
-* KubeCon idle week
+Week 15 to 17:
+* [ ] [Communications Manager] [Polish release notes](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#polish-release-notes)
 
 Week 16:
-* [ ] [Release Lead] [Cut the v1.6.0-rc.0 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
-* [ ] [Release Lead] [Update milestone applier and GitHub Actions](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#update-milestone-applier-and-github-actions)
-* [ ] [CI Manager] [Setup jobs and dashboards for the release-1.6 release branch](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#setup-jobs-and-dashboards-for-a-new-release-branch)
-* [ ] [Communications Manager] [Ensure the book for the new release is available](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#ensure-the-book-for-the-new-release-is-available)
+* [ ] [Release Lead] [Cut the v1.4.0-rc.1 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
 
 Week 17:
-* [ ] [Release Lead] [Cut the v1.6.0-rc.1 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
-
-Week 18:
-* [ ] [Release Lead] [Cut the v1.6.0 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
-* [ ] [Release Lead] [Cut the v1.5.4 & v1.4.9 releases](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [Release Lead] [Cut the v1.4.0 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
+* [ ] [Release Lead] [Cut the v1.3.4 release](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#repeatedly-cut-a-release)
 * [ ] [Release Lead] Organize release retrospective
 * [ ] [Communications Manager] [Change production branch in Netlify to the new release branch](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#change-production-branch-in-netlify-to-the-new-release-branch)
 * [ ] [Communications Manager] [Update clusterctl links in the quickstart](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#update-clusterctl-links-in-the-quickstart)
@@ -81,4 +81,3 @@ Continuously:
 If and when necessary:
 * [ ] [Release Lead] [Track] [Bump the Cluster API apiVersion](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#optional-track-bump-the-cluster-api-apiversion)
 * [ ] [Release Lead] [Track] [Bump the Kubernetes version](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#optional-track-bump-the-kubernetes-version)
-* [ ] [Release Lead] [Track Release and Improvement tasks](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/release/release-tasks.md#optional-track-release-and-improvement-tasks)
\ No newline at end of file
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 57768ed76..5742ea2e2 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -22,7 +22,7 @@ jobs:
           fetch-depth: 0
       - name: Get changed files
         id: changed-files
-        uses: tj-actions/changed-files@1c938490c880156b746568a518594309cfb3f66b # tag=v40.2.1
+        uses: tj-actions/changed-files@25ef3926d147cd02fc7e931c1ef50772bbb0d25d # tag=v40.1.1
       - name: Get release version
         id: release-version
         run: |
diff --git a/CHANGELOG/v1.6.0-rc.1.md b/CHANGELOG/v1.6.0-rc.1.md
deleted file mode 100644
index 32b10b8b4..000000000
--- a/CHANGELOG/v1.6.0-rc.1.md
+++ /dev/null
@@ -1,314 +0,0 @@
-🚨 This is a RELEASE CANDIDATE. Use it only for testing purposes. If you find any bugs, file an [issue](https://github.com/kubernetes-sigs/cluster-api/issues/new).
-
-## Highlights
-
-* MachinePools are now supported in ClusterClass Clusters
-* Metrics, profiling and other diagnostics are now served securely by default
-* Types in `ipam.cluster.x-k8s.io` have graduated to `v1beta1`
-
-## Deprecation Warning
-
-- The API version `v1alpha4` is no longer served in this release.
-  - [Version migration guide](https://main.cluster-api.sigs.k8s.io/developer/providers/version-migration.html)
-  - [GitHub issue #8038](https://github.com/kubernetes-sigs/cluster-api/issues/8038)
-  - [API deprecation details](https://main.cluster-api.sigs.k8s.io/contributing#removal-of-v1alpha3--v1alpha4-apiversions)
-- The API version `v1alpha3` has been completely removed in this release.
-- Flag `--metrics-bind-addr` is [deprecated](https://github.com/kubernetes-sigs/cluster-api/pull/9264) for all controllers
-
-## Changes since v1.6.0-rc.0
-## :chart_with_upwards_trend: Overview
-- 2 new commits merged
-- 1 bug fixed 🐛
-
-## :bug: Bug Fixes
-- ClusterResourceSet: Requeue after 1 minute if ErrClusterLocked got hit (#9788)
-
-## :seedling: Others
-- e2e: Improve output of exec.KubectlApply (#9761)
-
-<details>
-<summary>More details about the release</summary>
-
-:warning: **RELEASE CANDIDATE NOTES** :warning:
-
-## 👌 Kubernetes version support
-
-- Management Cluster: v1.25.x -> v1.28.x
-- Workload Cluster: v1.23.x -> v1.28.x
-
-[More information about version support can be found here](https://cluster-api.sigs.k8s.io/reference/versions.html)
-
-## Changes since v1.5.0
-## :chart_with_upwards_trend: Overview
-- 387 new commits merged
-- 6 breaking changes :warning:
-- 15 feature additions ✨
-- 35 bugs fixed 🐛
-
-## :memo: Proposals
-- Community meeting: Add proposal for karpenter integration feature group (#9571)
-
-## :warning: Breaking Changes
-- API: Remove v1alpha3 API Version (#8997)
-- API: Stop serving v1alpha4 API Versions (#8996)
-- clusterctl: Improve Context handling in clusterctl (#8939)
-- Dependency: Bump to controller-runtime v0.16 (#8999)
-- Metrics/Logging: Implement secure diagnostics (metrics, pprof, log level changes) (#9264)
-- util: Remove go-vcs dependency from releaselink tool (#9288)
-
-## :sparkles: New Features
-- API: Add validation to nested ObjectMeta fields (#8431)
-- CAPD: Add config maps to CAPD RBAC (#9528)
-- CAPD: Add MachinePool Machine implementation to CAPD components (#8842)
-- CAPD: Allow adding custom HA proxy config for CAPD load balancer (#8785)
-- CAPD: Initialize configmap object before getting it (#9529)
-- ClusterClass: Add topology-owned label to MachineHealthChecks. (#9191)
-- ClusterClass: Introduce NamingStrategy and allow generating names using go templates (#9340)
-- ClusterClass: Update API with ClusterClass MachinePool support (#8820)
-- clusterctl: Add RKE2 bootstrap provider to clusterctl (#9720)
-- clusterctl: Block move with annotation (#8690)
-- IPAM: Promote IPAM types to v1beta1 (#9525)
-- MachinePool: Add MachinePool workers support in ClusterClass (#9016)
-- MachineSet: Adjust preflight check to allow kubelet version skew of 3 for clusters running v1.28 and above (#9222)
-- Release: Add automation to create release branch and tags (#9111)
-- Testing/Documentation: V1.28: Prepare quickstart, capd and tests for the new release including kind bump (#9160)
-
-## :bug: Bug Fixes
-- CAPBK: Certificate paths in cloud-init scripts should not use a platform-dependent path separator (#9167)
-- CAPD: Delete container after failed start to work around port allocation issues (#9125)
-- CAPD: Fix DockerMachine panic (#9673)
-- CI: Fix reporting bug in verify-container-image script (#9676)
-- ClusterClass: Fix ClusterClass enqueue for ExtensionConfig (#9133)
-- ClusterClass: Topology: fix namingstrategy webhook to not use uppercase characters for testing the template and align unit test to e2e test (#9425)
-- clusterctl: Fix provider namespace secret not included in clusterctl move (#9694)
-- ClusterResourceSet: Requeue after 1 minute if ErrClusterLocked got hit (#9788)
-- Dependency: Bump golang.org/x/net to v0.13.0 (#9121)
-- Dependency: Bump to docker v24.0.5-0.20230714235725-36e9e796c6fc (#9038)
-- Devtools: Adding metrics container port in tilt-prepare only if it's missing (#9308)
-- Devtools: Allow duplicate objects in Tiltfile (#9302)
-- Devtools: Change tilt debug base image to golang (#9070)
-- Devtools: Fix tilt-prepare leader-elect setting (#9315)
-- Devtools: Pin Plantuml version (#9424)
-- Devtools: Tilt: ensure .tiltbuild/bin directory is created early enough, add tilt troubleshooting guide (#9165)
-- e2e: Drop MachinePools from Dualstack tests (#9477)
-- e2e: Fix autoscaler image repo (#9353)
-- e2e: Test: pin conformance image to a version which includes a fix for the dualstack tests (#9252)
-- KCP: Allow dropping patches KubeadmControlPlane KubeadmConfig (#9698)
-- KCP: Allow to drop useExperimentalRetryJoin field from KubeadmControlPlane.kubeadmConfigSpec (#9170)
-- KCP: Fix KCP Controller reconcile always return error when workload cluster is unreachable (#9342)
-- KCP: Requeue KCP object if ControlPlaneComponentsHealthyCondition is not yet true (#9032)
-- Machine: Retry Node delete when CCT is locked (#9570)
-- MachineDeployment: MD controller: use regular random suffix for MachineSets, ensure max length 63 (#9298)
-- MachineHealthCheck: Fix excessive trace logging in the machine health check controller (#9419)
-- MachinePool: Fix bug where MachinePool Machine ownerRefs weren't updating (#9619)
-- Release: Alphabetically sorting release tool output (#9055)
-- Release: Deduplicating area in pr title in release notes (#9186)
-- Release: Fix go install path for kpromo v4.0.4 (#9336)
-- Release: Generate warning when release notes can not be generated (#9163)
-- Release: Hack/release-notes: ensure relase notes tool can be used for external projects again (#9018)
-- Release: Reverts pull request from cahillsf/improve-release-speed (#9465)
-- Runtime SDK: Set User Agent for test extension correctly (#9748)
-- util: Fix AddAnnotations for unstructured.Unstructured (#9164)
-
-## :seedling: Others
-- API: Add ClusterClass column to Cluster CRD (#9120)
-- API: Add verify-import-restrictions to enforce import restrictions (#9407)
-- API: Enforce import restrictions in all API packages (#9461)
-- API: Ensure we generate all webhook manifests.yaml (#9621)
-- API: Move API v1beta1 webhooks to a separate package (#9047)
-- API: Move docker infrastructure API v1beta1 webhooks to separate package (#9458)
-- API: Move docker infrastructure experimental API v1beta1 webhooks to separate package (#9460)
-- API: Move experimental addons API v1beta1 webhooks to separate package (#9438)
-- API: Move experimental API v1beta1 webhooks to separate package (#9417)
-- API: Move inmemory infrastructure API v1beta1 webhooks to separate package (#9459)
-- API: Move Kubeadm API v1beta1 webhooks to separate package (#9410)
-- API: Remove files and markers for Kubebuilder (#9344)
-- API: Remove reliance on controller-runtime scheme builder (#9045)
-- API: Remove reliance on controller-runtime scheme builder for experimental APIs (#9185)
-- API: Remove reliance on controller-runtime scheme builder for remaining API groups (#9266)
-- API: Remove the dependency on cluster-api/utils from addons API (#9482)
-- API: Test and document controller ownerReferences (#9153)
-- CAPBK: Remove Kubeadm upstream v1beta1 types (#9345)
-- CAPD: Fix multi error handling in RunContainer (#9139)
-- CAPD: Set Condition, if creating external LB failed. (#9697)
-- CI: Add colored-line-number output for golangci-lint action (#9147)
-- CI: Add dependabot for test and hack/tools module (#9041)
-- CI: Add exclude for Kustomize API to dependabot config (#9059)
-- CI: Add licence-scan for pull requests (#9184)
-- CI: Add loggercheck linter and fix findings (#9446)
-- CI: Add verify-govulncheck and verify-vulnerabilities targets and integrate to scan action (#9144)
-- CI: Bump actions/cache from 3.3.1 to 3.3.2 (#9395)
-- CI: Bump actions/checkout from 4.1.0 to 4.1.1 (#9611)
-- CI: Bump actions/github-script from 7.0.0 to 7.0.1 (#9738)
-- CI: Bump actions/setup-go from 4.0.1 to 4.1.0 (#9187)
-- CI: Bump apidiff to v0.7.0 (#9472)
-- CI: Bump golangci-lint to v1.54.1 (#9174)
-- CI: Bump golangci/golangci-lint-action from 3.6.0 to 3.7.0 (#9261)
-- CI: Bump tj-actions/changed-files from 40.1.0 to 40.1.1 (#9714)
-- CI: Bump Trivy to v0.45.1 (#9445)
-- CI: Fix .golangci.yml comments (#9499)
-- CI: Ginkgolinter: forbid focus container (#9320)
-- CI: Github: add edited and reopened as triggers for the GH workflow approval (#9259)
-- CI: Github: add workflow to auto-approve golangci-lint if ok-to-test label is set (#9244)
-- CI: Go.mod reformat to have only two require blocks (#9192)
-- CI: Golangci-lint: replace deprecated local-prefixes setting for gci (#9339)
-- CI: Make GO_ARCH explicit in verify_containter script (#9341)
-- CI: Update actions for 1.5 and make names consistent (#9115)
-- CI: Verify plantuml image generation in CI (#9363)
-- ClusterCacheTracker: Add separate concurrency flag for cluster cache tracker (#9116)
-- ClusterCacheTracker: Ensure Get/List calls are not getting stuck when apiserver is unreachable (#9028)
-- ClusterCacheTracker: Fix accessor deletion on health check failure (#9025)
-- ClusterClass: Add additional test cases for nested variable defaulting (#9728)
-- ClusterClass: Add ownerRefs to BootstrapConfig/InfraMachinePool in classy Clusters (#9389)
-- ClusterClass: Embed ssa.FilterObjectInput into HelperOption to remove duplication (#9512)
-- ClusterClass: Fix some nits in Cluster topology engine tests (#9464)
-- ClusterClass: Improve Cluster variable defaulting/validation errors (#9452)
-- ClusterClass: Improve message for TopologyReconciledCondition (#9400)
-- ClusterClass: Make ClusterClass generated object names consistent (#9254)
-- ClusterClass: Minor fixes for CC+MP implementation (#9318)
-- clusterctl: Check resource blocking clusterctl move during discovery (#9246)
-- clusterctl: Propagate ctx to retryWithExponentialBackoff in clusterctl (#9437)
-- clusterctl: Use goproxy to check version in clusterctl (#9237)
-- clusterctl: Use http get to download files from GitHub in clusterctl (#9236)
-- Dependency: Bump cert-manager to v1.13.2 (#9653)
-- Dependency: Bump cloud.google.com/go/storage from 1.34.1 to 1.35.1 in /hack/tools (#9727)
-- Dependency: Bump controller tools to v1.13.0 (#9221)
-- Dependency: Bump controller-runtime to v0.16.3 (#9592)
-- Dependency: Bump conversion-gen to v0.28 (#9267)
-- Dependency: Bump corefile-migration library to v1.0.21 (#9307)
-- Dependency: Bump docker to v24.0.5 (#9064)
-- Dependency: Bump envtest binaries to 1.28 (#9268)
-- Dependency: Bump github.com/blang/semver to v4 (#9189)
-- Dependency: Bump github.com/docker/distribution (#9544)
-- Dependency: Bump github.com/docker/docker from 24.0.6+incompatible to 24.0.7+incompatible in /test (#9652)
-- Dependency: Bump github.com/emicklei/go-restful/v3 from 3.10.2 to 3.11.0 in /test (#9272)
-- Dependency: Bump github.com/evanphx/json-patch/v5 from 5.6.0 to 5.7.0 (#9397)
-- Dependency: Bump github.com/fatih/color from 1.15.0 to 1.16.0 (#9681)
-- Dependency: Bump github.com/go-logr/logr from 1.2.4 to 1.3.0 (#9644)
-- Dependency: Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 (#9562)
-- Dependency: Bump github.com/onsi/ginkgo/v2 from 2.13.0 to 2.13.1 (#9716)
-- Dependency: Bump github.com/onsi/gomega from 1.29.0 to 1.30.0 (#9717)
-- Dependency: Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0 (#9517)
-- Dependency: Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#9679)
-- Dependency: Bump github.com/spf13/viper from 1.16.0 to 1.17.0 (#9561)
-- Dependency: Bump Go version to v1.20.11 (#9683)
-- Dependency: Bump go-github dependency to version v53 (#8995)
-- Dependency: Bump go.etcd.io/etcd/api/v3 from 3.5.9 to 3.5.10 (#9642)
-- Dependency: Bump go.etcd.io/etcd/client/v3 from 3.5.9 to 3.5.10 (#9646)
-- Dependency: Bump go.opentelemetry.io/* dependencies (#9598)
-- Dependency: Bump golang.org/grpc to v1.59.0 (#9626)
-- Dependency: Bump golang.org/x/net from 0.15.0 to 0.17.0 in /test (#9537)
-- Dependency: Bump golang.org/x/oauth2 from 0.13.0 to 0.14.0 (#9715)
-- Dependency: Bump golang.org/x/text from 0.13.0 to 0.14.0 (#9680)
-- Dependency: Bump golangci-lint to v1.55.2 (#9740)
-- Dependency: Bump gomodules.xyz/jsonpatch/v2 from 2.3.0 to 2.4.0 (#9188)
-- Dependency: Bump google.golang.org/api from 0.149.0 to 0.150.0 in /hack/tools (#9691)
-- Dependency: Bump google.golang.org/grpc from 1.58.2 to 1.58.3 (#9607)
-- Dependency: Bump kpromo to v4.0.4 (#9241)
-- Dependency: Bump opentelemetry to fix CVEs (#9709)
-- Dependency: Bump sigs.k8s.io/yaml from 1.3.0 to 1.4.0 (#9645)
-- Dependency: Bump some dependencies in Makefile (#9549)
-- Dependency: Bump the kubernetes group in /hack/tools with 2 updates (#9420)
-- Dependency: Bump the kubernetes group in /hack/tools with 2 updates (#9574)
-- Dependency: Bump the kubernetes group with 2 updates (#9606)
-- Dependency: Bump the kubernetes group with 4 updates (#9326)
-- Dependency: Bump the kubernetes group with 4 updates (#9455)
-- Dependency: Bump the kubernetes group with 4 updates (#9739)
-- Dependency: Bump Trivy to v0.47.0 (#9671)
-- Dependency: Replace hashicorp/go-multierror with kerrors (#9175)
-- Dependency: Update ensure-kubectl.sh to 1.28 (#9275)
-- Devtools: Add .PHONY for doctoc target (#9148)
-- Devtools: Allow non-provider Deployments in Tilt (#9404)
-- Devtools: Bump CAPI visualizer to v1.2.0 (#9195)
-- Devtools: Drop duplicate pprof and unused linter excludes (#9156)
-- Devtools: Improve Performance dashboard (#9387)
-- Devtools: Make dev cluster networking configurable (#9183)
-- Devtools: Makefile: run doctoc only once (#9182)
-- Devtools: Move tilt-prepare and log-push to tools/internal (#9020)
-- Devtools: Observability: move metrics to config and use sidecar in kube-state-metrics (#9390)
-- Devtools: Refactor docker-push* Makefile targets so users can control with ALL_DOCKER_BUILD which images are pushed (#8586)
-- Devtools: Tiltfile: rename deploy_kustomizations to additional_kustomizations (#9439)
-- e2e: Add back flavor to Waiter interface (#9166)
-- e2e: Add CRS re-reconcile to ownerReference test (#9296)
-- e2e: Add log level for kube components patch to ClusterClass (#9493)
-- e2e: Add MachinePools to Topology Quickstart E2E Templates (#9393)
-- e2e: Add MP timeouts to cluster upgrade tests (#9723)
-- e2e: Add test for ownerReference apiVersion update (#9269)
-- e2e: Add test for scale testing machinery (#9510)
-- e2e: Bump autoscaler to v1.28.0 (#9349)
-- e2e: Drop PR-Informing test tag and job description (#9362)
-- e2e: Dump all pods in e2e test clusters (#9441)
-- e2e: Dump all resource information for self-hosted tests (#9547)
-- e2e: Ensure finalizers are resilient on reconciliation (#9471)
-- e2e: Fail tests if test env version check fails (#9388)
-- e2e: Fix broken e2e test clusterclass (#9506)
-- e2e: Improve labels/annotations in CAPD test ClusterClass (#9469)
-- e2e: Improve logging for self-hosted e2e test (#9637)
-- e2e: Improve output of exec.KubectlApply (#9761)
-- e2e: Refactor e2e ownerRef test utils (#9313)
-- e2e: Test/conformance: add variables to overwrite parralelization of kubetest runs (#9667)
-- e2e: Test/e2e: structure resources by namespace/kind again (#9462)
-- e2e: Use existing value of `SKIP_RESOURCE_CLEANUP` if set in environment (#9152)
-- IPAM: Add age also to v1beta1 IPAM types (#9729)
-- IPAM: Add age column to kubectl output (#9521)
-- IPAM: Enforce IPAM import alias (#9730)
-- KCP: Controlplane: add a test case for syncMachines where the InfraMachine does not exist. (#8992)
-- KCP: Remove disableInPlacePropagation field in KCP controller (#9099)
-- KCP: Remove redundant GetRESTConfig in KCP Management.GetWorkloadCluster (#9448)
-- KCP: Support admin config for Kubeadm v1.29 (#9682)
-- Logging: Change default log level to 2 (#9093)
-- Logging: Fix patch errors not being logged (#9224)
-- Logging: Set controller-runtime logger for clusterctl (#9107)
-- MachinePool: Add MachinePool Builders (#9346)
-- MachinePool: Add util function to get MachinePool by label (#9219)
-- Metrics: Hack/observability: add capi_machine_status_certificatesexpirydate metric (#9084)
-- Metrics: Hack: bump kube-state-metrics and prometheus charts (#9352)
-- Release: Add additional blocks to release note generation (#9247)
-- Release: Add adilGhaffarDev to release-team owner alias (#9718)
-- Release: Add Release Team OWNERS file to docs/release folder (#9294)
-- Release: Avoid cd'ing into test folders when building Docker images (#9744)
-- Release: Bump kubebuilder tools to v0.4.2 (#9665)
-- Release: Bump PR title checker github action to v0.4.1 (#9650)
-- Release: Capitalize area prefix in release notes by default (#9614)
-- Release: Capitalized title in release notes (#9086)
-- Release: Clarify release team vs k8s/k8s-SIGs org membership (#9089)
-- Release: Exclude release trigger PRs from release notes (#9444)
-- Release: Format Community meeting area in release notes (#9648)
-- Release: Format MachineHealthCheck area in release notes (#9500)
-- Release: Give permissions for release notes tool to release team (#9563)
-- Release: Hack: add weekly update script for Slack (#9343)
-- Release: Improve multiple areas PRs with user friendly subs (#9071)
-- Release: Improve release notes formatting (#9337)
-- Release: Improve release speed (#9392)
-- Release: Improve release staging build speed (#9536)
-- Release: Prepare main branch for v1.6 development (#9097)
-- Release: Remove auto-labelling for clusterctl (#8990)
-- Release: Remove extra separator after title in release notes (#9605)
-- Release: Revert "Improve release staging build speed" (#9753)
-- Release: Update instructions checklist to generate release notes (#9443)
-- Release: Update kubebuilder-release-tools to v0.4.0 (#9531)
-- Release: Update release-notes make target + corresponding doc (#9573)
-- Runtime SDK: Improve ClusterClass watch for ExtensionConfigs (#9338)
-- Testing: Add MachinePool test cases (#9474)
-- Testing: Add MachinePool test cases to engine tests (#9373)
-- Testing: Add MachinePool test cases to variables tests (#9372)
-- Testing: Add MachinePools to Runtime SDK and Rollout tests (#9703)
-- Testing: Add MachinePools to topology upgrade test (#9502)
-- Testing: Add test for required properties in clusterclass variables (#9113)
-- Testing: Add unit tests for CC MP blueprint, current_state, & desired_state (#9348)
-- Testing: Add unit tests for reconcile_state, cluster_controller, & conditions (#9380)
-- Testing: Add WaitForMachinePoolToBeUpgraded to self-hosted test (#9540)
-- Testing: Extend test/framework to collect workload cluster nodes (#9416)
-- Testing: Follow-up fixes: Add MachinePools to Runtime SDK and Rollout tests (#9719)
-- Testing: Replacing gomega.Equal with gomega.BeComparableTo (#9015)
-- util: Adjust naming in SortForCreate implementation (#9311)
-- util: Move `internal.labels` to `format` package for use by providers (#9002)
-- util: Refactor SortForCreate to use sort.Slice (#9251)
-- util: Remove previously deprecated code (#9136)
-
-:book: Additionally, there have been 55 contributions to our documentation and book. (#8260, #8500, #8678, #8819, #8988, #9001, #9013, #9014, #9024, #9029, #9080, #9081, #9087, #9112, #9119, #9141, #9146, #9150, #9161, #9173, #9208, #9209, #9213, #9214, #9232, #9270, #9286, #9291, #9305, #9328, #9364, #9386, #9403, #9415, #9429, #9433, #9463, #9487, #9488, #9490, #9511, #9513, #9514, #9527, #9550, #9559, #9565, #9572, #9577, #9590, #9593, #9613, #9635, #9654, #9706) 
-
-</details>
-<br/>
-
-_Thanks to all our contributors!_ 😊
diff --git a/Makefile b/Makefile
index 1c9c5ea84..008050da0 100644
--- a/Makefile
+++ b/Makefile
@@ -1098,15 +1098,11 @@ release-alias-tag: ## Add the release alias tag to the last build tag
 
 .PHONY: release-notes-tool
 release-notes-tool:
-	go build -o bin/notes -tags tools sigs.k8s.io/cluster-api/hack/tools/release/notes
-
-.PHONY: test-release-notes-tool
-test-release-notes-tool:
-	go test -v -tags tools,integration sigs.k8s.io/cluster-api/hack/tools/release/notes
+	go build -o bin/notes hack/tools/release/notes/main.go
 
 .PHONY: release-weekly-update-tool
 release-weekly-update-tool:
-	go build -o bin/weekly -tags tools sigs.k8s.io/cluster-api/hack/tools/release/weekly
+	go build -o bin/weekly hack/tools/release/weekly/main.go
 
 .PHONY: promote-images
 promote-images: $(KPROMO)
diff --git a/api/v1beta1/machineset_types.go b/api/v1beta1/machineset_types.go
index f10e44f4f..843b343a4 100644
--- a/api/v1beta1/machineset_types.go
+++ b/api/v1beta1/machineset_types.go
@@ -41,22 +41,9 @@ type MachineSetSpec struct {
 
 	// Replicas is the number of desired replicas.
 	// This is a pointer to distinguish between explicit zero and unspecified.
-	//
-	// Defaults to:
-	// * if the Kubernetes autoscaler min size and max size annotations are set:
-	//   - if it's a new MachineSet, use min size
-	//   - if the replicas field of the old MachineSet is < min size, use min size
-	//   - if the replicas field of the old MachineSet is > max size, use max size
-	//   - if the replicas field of the old MachineSet is in the (min size, max size) range, keep the value from the oldMS
-	// * otherwise use 1
-	// Note: Defaulting will be run whenever the replicas field is not set:
-	// * A new MachineSet is created with replicas not set.
-	// * On an existing MachineSet the replicas field was first set and is now unset.
-	// Those cases are especially relevant for the following Kubernetes autoscaler use cases:
-	// * A new MachineSet is created and replicas should be managed by the autoscaler
-	// * An existing MachineSet which initially wasn't controlled by the autoscaler
-	//   should be later controlled by the autoscaler
+	// Defaults to 1.
 	// +optional
+	// +kubebuilder:default=1
 	Replicas *int32 `json:"replicas,omitempty"`
 
 	// MinReadySeconds is the minimum number of seconds for which a Node for a newly created machine should be ready before considering the replica available.
diff --git a/api/v1beta1/zz_generated.openapi.go b/api/v1beta1/zz_generated.openapi.go
index 073de884b..d49f8303a 100644
--- a/api/v1beta1/zz_generated.openapi.go
+++ b/api/v1beta1/zz_generated.openapi.go
@@ -2877,7 +2877,7 @@ func schema_sigsk8sio_cluster_api_api_v1beta1_MachineSetSpec(ref common.Referenc
 					},
 					"replicas": {
 						SchemaProps: spec.SchemaProps{
-							Description: "Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified.\n\nDefaults to: * if the Kubernetes autoscaler min size and max size annotations are set:\n  - if it's a new MachineSet, use min size\n  - if the replicas field of the old MachineSet is < min size, use min size\n  - if the replicas field of the old MachineSet is > max size, use max size\n  - if the replicas field of the old MachineSet is in the (min size, max size) range, keep the value from the oldMS\n* otherwise use 1 Note: Defaulting will be run whenever the replicas field is not set: * A new MachineSet is created with replicas not set. * On an existing MachineSet the replicas field was first set and is now unset. Those cases are especially relevant for the following Kubernetes autoscaler use cases: * A new MachineSet is created and replicas should be managed by the autoscaler * An existing MachineSet which initially wasn't controlled by the autoscaler\n  should be later controlled by the autoscaler",
+							Description: "Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1.",
 							Type:        []string{"integer"},
 							Format:      "int32",
 						},
diff --git a/config/crd/bases/cluster.x-k8s.io_machinesets.yaml b/config/crd/bases/cluster.x-k8s.io_machinesets.yaml
index e01642f07..d670ba9ae 100644
--- a/config/crd/bases/cluster.x-k8s.io_machinesets.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_machinesets.yaml
@@ -487,22 +487,10 @@ spec:
                 format: int32
                 type: integer
               replicas:
-                description: "Replicas is the number of desired replicas. This is
-                  a pointer to distinguish between explicit zero and unspecified.
-                  \n Defaults to: * if the Kubernetes autoscaler min size and max
-                  size annotations are set: - if it's a new MachineSet, use min size
-                  - if the replicas field of the old MachineSet is < min size, use
-                  min size - if the replicas field of the old MachineSet is > max
-                  size, use max size - if the replicas field of the old MachineSet
-                  is in the (min size, max size) range, keep the value from the oldMS
-                  * otherwise use 1 Note: Defaulting will be run whenever the replicas
-                  field is not set: * A new MachineSet is created with replicas not
-                  set. * On an existing MachineSet the replicas field was first set
-                  and is now unset. Those cases are especially relevant for the following
-                  Kubernetes autoscaler use cases: * A new MachineSet is created and
-                  replicas should be managed by the autoscaler * An existing MachineSet
-                  which initially wasn't controlled by the autoscaler should be later
-                  controlled by the autoscaler"
+                default: 1
+                description: Replicas is the number of desired replicas. This is a
+                  pointer to distinguish between explicit zero and unspecified. Defaults
+                  to 1.
                 format: int32
                 type: integer
               selector:
diff --git a/controlplane/kubeadm/internal/controllers/controller.go b/controlplane/kubeadm/internal/controllers/controller.go
index c6cb714b6..f71bdec07 100644
--- a/controlplane/kubeadm/internal/controllers/controller.go
+++ b/controlplane/kubeadm/internal/controllers/controller.go
@@ -375,7 +375,7 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, controlPl
 
 	// Aggregate the operational state of all the machines; while aggregating we are adding the
 	// source ref (reason@machine/name) so the problem can be easily tracked down to its source machine.
-	conditions.SetAggregate(controlPlane.KCP, controlplanev1.MachinesReadyCondition, controlPlane.Machines.ConditionGetters(), conditions.AddSourceRef())
+	conditions.SetAggregate(controlPlane.KCP, controlplanev1.MachinesReadyCondition, controlPlane.Machines.ConditionGetters(), conditions.AddSourceRef(), conditions.WithStepCounterIf(false))
 
 	// Updates conditions reporting the status of static pods and the status of the etcd cluster.
 	// NOTE: Conditions reporting KCP operation progress like e.g. Resized or SpecUpToDate are inlined with the rest of the execution.
@@ -528,7 +528,7 @@ func (r *KubeadmControlPlaneReconciler) reconcileDelete(ctx context.Context, con
 	// source ref (reason@machine/name) so the problem can be easily tracked down to its source machine.
 	// However, during delete we are hiding the counter (1 of x) because it does not make sense given that
 	// all the machines are deleted in parallel.
-	conditions.SetAggregate(controlPlane.KCP, controlplanev1.MachinesReadyCondition, controlPlane.Machines.ConditionGetters(), conditions.AddSourceRef())
+	conditions.SetAggregate(controlPlane.KCP, controlplanev1.MachinesReadyCondition, controlPlane.Machines.ConditionGetters(), conditions.AddSourceRef(), conditions.WithStepCounterIf(false))
 
 	// Gets all machines, not just control plane machines.
 	allMachines, err := r.managementCluster.GetMachinesForCluster(ctx, controlPlane.Cluster)
diff --git a/docs/book/src/developer/architecture/controllers/machine-set.md b/docs/book/src/developer/architecture/controllers/machine-set.md
index 58ba11383..4b46e6ad9 100644
--- a/docs/book/src/developer/architecture/controllers/machine-set.md
+++ b/docs/book/src/developer/architecture/controllers/machine-set.md
@@ -19,7 +19,7 @@ Changes to the following fields of MachineSet are propagated in-place to the Mac
 - `.spec.template.spec.nodeVolumeDetachTimeout`
 
 Changes to the following fields of MachineSet are propagated in-place to the InfrastructureMachine and BootstrapConfig:
-- `.spec.template.metadata.labels`
-- `.spec.template.metadata.annotations`
+- `.spec.machineTemplate.metadata.labels`
+- `.spec.machineTemplate.metadata.annotations`
 
-Note: Changes to these fields will not be propagated to Machines that are marked for deletion (example: because of scale down).
+Note: Changes to these fields will not be propagated to Machines that are marked for deletion (example: because of scale down).
\ No newline at end of file
diff --git a/docs/book/src/tasks/automated-machine-management/autoscaling.md b/docs/book/src/tasks/automated-machine-management/autoscaling.md
index 442152b71..ca8dbca37 100644
--- a/docs/book/src/tasks/automated-machine-management/autoscaling.md
+++ b/docs/book/src/tasks/automated-machine-management/autoscaling.md
@@ -12,17 +12,17 @@ from the [Autoscaler project documentation](https://github.com/kubernetes/autosc
 
 <aside class="note warning">
 
-<h1>Defaulting of the MachineDeployment, MachineSet replicas field</h1>
+<h1>Defaulting of the MachineDeployment replicas field</h1>
 
-Please note that the MachineDeployment and MachineSet replicas field has special defaulting logic to provide a smooth integration with the autoscaler.
-The replica field is defaulted based on the autoscaler min and max size annotations.The goal is to pick a default value which is inside
+Please note that the MachineDeployment replicas field has special defaulting logic to provide a smooth integration with the autoscaler.
+The replica field is defaulted based on the autoscaler min and max size annotations.The goal is to pick a default value which is inside 
 the (min size, max size) range so the autoscaler can take control of the replicase field.
 
 The defaulting logic is as follows:
 * if the autoscaler min size and max size annotations are set:
-  * if it's a new MachineDeployment or MachineSet, use min size
-  * if the replicas field of the old MachineDeployment or MachineSet is < min size, use min size
-  * if the replicas field of the old MachineDeployment or MachineSet is > max size, use max size
-  * if the replicas field of the old MachineDeployment or MachineSet is in the (min size, max size) range, keep the value from the oldMD or oldMS
+  * if it's a new MachineDeployment, use min size
+  * if the replicas field of the old MachineDeployment is < min size, use min size
+  * if the replicas field of the old MachineDeployment is > max size, use max size
+  * if the replicas field of the old MachineDeployment is in the (min size, max size) range, keep the value from the oldMD
 * otherwise, use 1
 </aside>
diff --git a/docs/book/src/tasks/bootstrap/microk8s-bootstrap.md b/docs/book/src/tasks/bootstrap/microk8s-bootstrap.md
index 5dfc80503..65734b5fe 100644
--- a/docs/book/src/tasks/bootstrap/microk8s-bootstrap.md
+++ b/docs/book/src/tasks/bootstrap/microk8s-bootstrap.md
@@ -85,7 +85,7 @@ Some of the configuration options available via `MicroK8sConfig` are:
 
 ### How does CABPM work?
 
-The main purpose of the MicroK8s bootstrap provider is to translate the users needs to a number of cloud-init files applicable for each type of cluster nodes. There are three types of cloud-inits:
+The main purpose of the MicroK8s bootstrap provider is to translate the users needs to the a number of cloud-init files applicable for each type of cluster nodes. There are three types of cloud-inits:
 
   - The first node cloud-init. That node will be a control plane node and will be the one where the addons are enabled.
   - The control plane node cloud-init. The control plane nodes need to join a cluster and contribute to its HA.
diff --git a/docs/proposals/20230407-flexible-managed-k8s-endpoints.md b/docs/proposals/20230407-flexible-managed-k8s-endpoints.md
index 3ff08ba06..9b3e1b706 100644
--- a/docs/proposals/20230407-flexible-managed-k8s-endpoints.md
+++ b/docs/proposals/20230407-flexible-managed-k8s-endpoints.md
@@ -24,6 +24,16 @@
       - [Core Cluster API Controllers changes](#core-cluster-api-controllers-changes)
       - [Provider controller changes](#provider-controller-changes)
     - [Guidelines for infra providers implementation](#guidelines-for-infra-providers-implementation)
+  - [Background work](#background-work)
+    - [EKS in CAPA](#eks-in-capa)
+      - [AKS in CAPZ](#aks-in-capz)
+      - [GKE in CAPG](#gke-in-capg)
+      - [Learnings from original Proposal: Two kinds with a Managed Control Plane & Managed Infra Cluster adhering to the current CAPI contracts](#learnings-from-original-proposal-two-kinds-with-a-managed-control-plane--managed-infra-cluster-adhering-to-the-current-capi-contracts)
+    - [Two New Flows](#two-new-flows)
+      - [Flow 1: `<Infra>Cluster` and `<Infra>ControlPlane`, with `ControlPlaneEndpoint` reported via `<Infra>ControlPlane`](#flow-1-infracluster-and-infracontrolplane-with-controlplaneendpoint-reported-via-infracontrolplane)
+      - [Flow 2: Change CAPI to make `<Infra>Cluster` optional](#flow-2-change-capi-to-make-infracluster-optional)
+      - [Alternative Option: Introduce a new Managed Kubernetes provider type (with contract)](#alternative-option-introduce-a-new-managed-kubernetes-provider-type-with-contract)
+  - [Recommendations](#recommendations)
   - [Implementation History](#implementation-history)
 
 <!-- END doctoc generated TOC please keep comment here to allow auto update -->
diff --git a/docs/proposals/YYYYMMDD-template.md b/docs/proposals/YYYYMMDD-template.md
index 3f88ae61d..60efe124a 100644
--- a/docs/proposals/YYYYMMDD-template.md
+++ b/docs/proposals/YYYYMMDD-template.md
@@ -159,7 +159,7 @@ considerations for performance, reliability and security.
 - What are some important details that didn't come across above.
 - What are the caveats to the implementation?
 - Go in to as much detail as necessary here.
-- Talk about core concepts and how they relate.
+- Talk about core concepts and how they releate.
 
 ### Security Model
 
diff --git a/docs/release/release-tasks.md b/docs/release/release-tasks.md
index dd6fa9ee6..924c12eb8 100644
--- a/docs/release/release-tasks.md
+++ b/docs/release/release-tasks.md
@@ -15,29 +15,27 @@ This document details the responsibilities and tasks for each role in the releas
 - [Release Lead](#release-lead)
   - [Responsibilities](#responsibilities)
   - [Tasks](#tasks)
-    - [Finalize release schedule and team](#finalize-release-schedule-and-team)
+    - [Set a tentative release date for the minor release](#set-a-tentative-release-date-for-the-minor-release)
+    - [Assemble release team](#assemble-release-team)
     - [Add/remove release team members](#addremove-release-team-members)
+    - [Finalize release schedule and team](#finalize-release-schedule-and-team)
     - [Prepare main branch for development of the new release](#prepare-main-branch-for-development-of-the-new-release)
     - [Create a new GitHub milestone for the next release](#create-a-new-github-milestone-for-the-next-release)
     - [[Track] Remove previously deprecated code](#track-remove-previously-deprecated-code)
     - [[Track] Bump dependencies](#track-bump-dependencies)
-    - [Set a tentative release date for the next minor release](#set-a-tentative-release-date-for-the-next-minor-release)
-    - [Assemble next release team](#assemble-next-release-team)
-    - [Update milestone applier and GitHub Actions](#update-milestone-applier-and-github-actions)
+    - [Create a release branch](#create-a-release-branch)
     - [[Continuously] Maintain the GitHub release milestone](#continuously-maintain-the-github-release-milestone)
     - [[Continuously] Bump the Go version](#continuously-bump-the-go-version)
     - [[Repeatedly] Cut a release](#repeatedly-cut-a-release)
     - [[Optional] Public release session](#optional-public-release-session)
     - [[Optional] [Track] Bump the Cluster API apiVersion](#optional-track-bump-the-cluster-api-apiversion)
     - [[Optional] [Track] Bump the Kubernetes version](#optional-track-bump-the-kubernetes-version)
-    - [[Optional] Track Release and Improvement tasks](#optional-track-release-and-improvement-tasks)
 - [Communications/Docs/Release Notes Manager](#communicationsdocsrelease-notes-manager)
   - [Responsibilities](#responsibilities-1)
   - [Tasks](#tasks-1)
     - [Add docs to collect release notes for users and migration notes for provider implementers](#add-docs-to-collect-release-notes-for-users-and-migration-notes-for-provider-implementers)
     - [Update supported versions](#update-supported-versions)
     - [Ensure the book for the new release is available](#ensure-the-book-for-the-new-release-is-available)
-    - [Generate weekly PR updates to post in Slack](#generate-weekly-pr-updates-to-post-in-slack)
     - [Create PR for release notes](#create-pr-for-release-notes)
     - [Change production branch in Netlify to the new release branch](#change-production-branch-in-netlify-to-the-new-release-branch)
     - [Update clusterctl links in the quickstart](#update-clusterctl-links-in-the-quickstart)
@@ -50,6 +48,10 @@ This document details the responsibilities and tasks for each role in the releas
     - [[Continuously] Monitor CI signal](#continuously-monitor-ci-signal)
     - [[Continuously] Reduce the amount of flaky tests](#continuously-reduce-the-amount-of-flaky-tests)
     - [[Continuously] Bug triage](#continuously-bug-triage)
+- [Maintainer](#maintainer)
+  - [Responsibilities](#responsibilities-3)
+  - [Tasks](#tasks-3)
+    - [[Repeatedly] Publish the release](#repeatedly-publish-the-release)
 
 <!-- END doctoc generated TOC please keep comment here to allow auto update -->
 
@@ -63,9 +65,9 @@ This document details the responsibilities and tasks for each role in the releas
   * Create and maintain the GitHub release milestone
   * Track tasks needed to add support for new Kubernetes versions in upcoming releases
   * Ensure a retrospective happens
-  * Ensure one of the [maintainers](https://github.com/kubernetes-sigs/cluster-api/blob/main/OWNERS_ALIASES) is available when a release needs to be cut.
+  * Ensure a maintainer is available when a release needs to be cut.
 * Staffing:
-  * Assemble the release team for the next release cycle
+  * Assemble the release team for the current release cycle
   * Ensure a release lead for the next release cycle is selected and trained
   * Set a tentative release date for the next release cycle
 * Cutting releases:
@@ -75,18 +77,26 @@ This document details the responsibilities and tasks for each role in the releas
 
 ### Tasks
 
-#### Finalize release schedule and team
+#### Set a tentative release date for the minor release
 
-1. Finalize release schedule and team in the [docs/release/releases](../../docs/release/releases), e.g. [release-1.4.md](../../docs/release/releases/release-1.4.md).
-2. Update @cluster-api-release-team Slack user group and GitHub team accordingly.
-   <br>Prior art: https://github.com/kubernetes-sigs/cluster-api/issues/7476
-3. Update @cluster-api-release-lead and @cluster-api-release-team aliases in root OWNERS_ALIASES file with Release Team members.
-4. Announce the _release team_ and _release schedule_ to the mailing list.
+1. Set a tentative release date for the release and document it by creating a `release-1.4.md`.
+
+#### Assemble release team
+
+There is currently no formalized process to assemble the release team.
+As of now we ask for volunteers in Slack and office hours.
 
 #### Add/remove release team members
 
 If necessary, the release lead can adjust the release team during the cycle to handle unexpected changes in staffing due to personal/professional issues, no-shows, or unplanned work spikes. Adding/removing members can be done by opening a PR to update the release team members list for the release cycle in question.
 
+#### Finalize release schedule and team
+
+1. Finalize release schedule and team in the [docs/release/releases](../../docs/release/releases), e.g. [release-1.4.md](../../docs/release/releases/release-1.4.md).
+2. Update @cluster-api-release-team Slack user group and GitHub team accordingly.
+   <br>Prior art: https://github.com/kubernetes-sigs/cluster-api/issues/7476
+3. Announce the _release team_ and _release schedule_ to the mailing list.
+
 #### Prepare main branch for development of the new release
 
 The goal of this issue is to bump the versions on the main branch so that the upcoming release version
@@ -149,26 +159,17 @@ We should take a look at the following dependencies:
 * Go dependencies in `go.mod` files.
 * Tools used in our Makefile (e.g. kustomize).
 
-#### Set a tentative release date for the next minor release
-
-1. Set a tentative release date for the next minor release and document it by creating a `release-X.Y.md` in [docs/release/releases](../../docs/release/releases).
-   <br>Prior art: https://github.com/kubernetes-sigs/cluster-api/pull/9635
+#### Create a release branch
 
-#### Assemble next release team
-
-There is currently no formalized process to assemble the release team.
-As of now we ask for volunteers in Slack and office hours.
-
-#### Update milestone applier and GitHub Actions
-
-Once release branch is created by GitHub Automation, the goal of this task would be to ensure we have the milestone
-applier that applies milestones accordingly and to update GitHub actions to work with new release version.
+The goal of this task is to ensure we have a release branch and the milestone applier applies milestones accordingly.
 From this point forward changes which should land in the release have to be cherry-picked into the release branch.
+
+1. Ask the [Maintainer](#maintainer) to create a new release branch.
   
-1. Update the [milestone applier config](https://github.com/kubernetes/test-infra/blob/0b17ef5ffd6c7aa7d8ca1372d837acfb85f7bec6/config/prow/plugins.yaml#L371) accordingly (e.g. `release-1.4: v1.4` and `main: v1.5`)
+2. Update the [milestone applier config](https://github.com/kubernetes/test-infra/blob/0b17ef5ffd6c7aa7d8ca1372d837acfb85f7bec6/config/prow/plugins.yaml#L371) accordingly (e.g. `release-1.4: v1.4` and `main: v1.5`)
    <br>Prior art: [cluster-api: update milestone applier config for v1.3](https://github.com/kubernetes/test-infra/pull/26631)
 
-2. Update the GitHub Actions to work with the new release version.
+3. Update the GitHub Actions to work with the new release version.
    <br>Prior art: [Update actions for 1.5 and make names consistent](https://github.com/kubernetes-sigs/cluster-api/pull/9115)
 
 #### [Continuously] Maintain the GitHub release milestone
@@ -228,10 +229,7 @@ to a newer Go minor version according to our [backport policy](./../../CONTRIBUT
          ```
 
 4. Publish the release in GitHub:
-   1. Reach out to one of the maintainers over the Slack to publish the release in GitHub.
-      * **NOTE:** clusterctl will have issues installing providers between the time the release tag is cut and the Github release is published. See [issue 7889](https://github.com/kubernetes-sigs/cluster-api/issues/7889) for more details.
-      * The draft release should be automatically created via the [Create Release GitHub Action](https://github.com/kubernetes-sigs/cluster-api/actions/workflows/release.yaml) with release notes previously committed to the repo by the release team. Ensure by reminding the maintainer that release is flagged as `pre-release` for all `beta` and `rc` releases or `latest` for a new release in the most recent release branch.
-   
+   1. Ask the [Maintainer](#maintainer) to publish the release in GitHub.
 5. Publish `clusterctl` to Homebrew by bumping the version in [clusterctl.rb](https://github.com/Homebrew/homebrew-core/blob/master/Formula/c/clusterctl.rb).
    <br>**Notes**:
     * This is only done for new latest stable releases, not for beta / RC releases and not for previous release branches.
@@ -279,20 +277,6 @@ Additional information:
 1. Create an issue for the new Kubernetes version via: [New Issue: Kubernetes bump](https://github.com/kubernetes-sigs/cluster-api/issues/new/choose).
 2. Track the issue to ensure the work is completed in time.
 
-#### [Optional] Track Release and Improvement tasks
-
-1. Create an issue for easier tracking of all the tasks for the release cycle in question.
-   <br>Prior art: [Tasks for v1.6 release cycle](https://github.com/kubernetes-sigs/cluster-api/issues/9094)
-2. Create a release improvement tasks [GitHub Project Board](https://github.com/orgs/kubernetes-sigs/projects/55) to track 
-   the current status of all improvement tasks planned for the release, their priorities, status (i.e `Done`/`In Progress`)
-   and to distribute the work among the Release Team members.
-
-   **Notes**:
-   * At the beginning of the cycle, Release Team Lead should prepare the improvement tasks board for the ongoing release cycle.
-     The following steps can be taken:
-      - Edit improvement tasks board name for current cycle (e.g. `CAPI vX.Y release improvement tasks`)
-      - Add/move all individual missing issues to the board
-
 ## Communications/Docs/Release Notes Manager
 
 ### Responsibilities
@@ -329,8 +313,8 @@ The goal of this task to make the book for the current release available under e
 
 1. Add a DNS entry for the book of the new release (should be available under e.g. `https://release-1-4.cluster-api.sigs.k8s.io`).
    <br>Prior art: [Add DNS for CAPI release-1.2 release branch](https://github.com/kubernetes/k8s.io/pull/3872)
-2. Open `https://release-1-4.cluster-api.sigs.k8s.io/` and verify that the certificates are valid.  If they are not, talk to someone with access to Netlify, they have to [click the `renew certificate` button](https://app.netlify.com/sites/kubernetes-sigs-cluster-api/settings/domain#https) in the Netlify UI.
-    - To add new subdomains to the certificate config, checkout the email snippet [template](https://github.com/kubernetes-sigs/cluster-api/issues/6017#issuecomment-1823306891) for reference.
+2. Open `https://release-1-4.cluster-api.sigs.k8s.io/` and verify that the certificates are valid
+   If they are not, talk to someone with access to Netlify, they have to [click the `renew certificate` button](https://app.netlify.com/sites/kubernetes-sigs-cluster-api/settings/domain#https) in the Netlify UI.
 3. Update references in introduction.md only on the main branch (drop unsupported versions, add the new release version).
    <br>Prior art: [Add release 1.2 book link](https://github.com/kubernetes-sigs/cluster-api/pull/6697)
 
@@ -542,4 +526,25 @@ The goal of bug triage is to triage incoming issues and if necessary flag them w
 and add them to the milestone of the current release.
 
 We probably have to figure out some details about the overlap between the bug triage task here, release leads
-and Cluster API maintainers.
\ No newline at end of file
+and Cluster API maintainers.
+
+## Maintainer
+
+The Maintainer must be a person with write access to the Cluster API repo. They can hold another role in the release team. The Maintainer need only be involved in the release as required on days when releases are cut. They are not expected to take part in release team meetings or other activities, but should feel free to do so.
+
+### Responsibilities
+
+* Be available on release day in case the release team needs help with tag creation.
+* Publish the release.
+* Ensure a substitute is nominated if they are not available.
+
+### Tasks
+
+#### [Repeatedly] Publish the release
+
+**NOTE:** clusterctl will have issues installing providers between the time the release tag is cut and the Github release is published. See [issue 7889](https://github.com/kubernetes-sigs/cluster-api/issues/7889) for more details
+
+Publish the release.
+
+   1. The draft release should be automatically created via the [Create Release GitHub Action](https://github.com/kubernetes-sigs/cluster-api/actions/workflows/release.yml) with release notes previously committed to the repo by the release team.
+   2. Publish the release. Ensure release is flagged as `pre-release` for all `beta` and `rc` releases or `latest` for a new release in the most recent release branch.
diff --git a/docs/release/release-team.md b/docs/release/release-team.md
index 36bbef0ed..cf2422b16 100644
--- a/docs/release/release-team.md
+++ b/docs/release/release-team.md
@@ -12,7 +12,6 @@
   - [Team Selection](#team-selection)
     - [Selection Criteria](#selection-criteria)
   - [Time Commitment](#time-commitment)
-  - [Release Team/Day Meetings](#release-teamday-meetings)
   - [Suggestions for Team Leads](#suggestions-for-team-leads)
   - [Why should I volunteer?](#why-should-i-volunteer)
   - [Cluster API release team vs kubernetes/kubernetes-SIG membership](#cluster-api-release-team-vs-kuberneteskubernetes-sig-membership)
@@ -71,7 +70,8 @@ As noted above, making changes to  the CAPI release cadence is out of scope for
 - **Communications/Docs/Release Notes Manager**: Responsible for communicating key dates to the community, improving release process documentation, and polishing release notes. Also responsible for ensuring the user-facing Netlify book and provider upgrade documentation are up to date.
 - **CI Signal/Bug Triage/Automation Manager**: Assumes the responsibility of the quality gate for the release and makes sure blocking issues and bugs are triaged and dealt with in a timely fashion. Helps improve release automation and tools.
 - **Team member**: Any Release Team lead or manager may select one or more additional members to help with their tasks. These team members will help fulfill future Release Team staffing requirements and continue to grow the CAPI community in general.
-*Note*: This is also documented in [Release tasks](./release-tasks.md) together with a mapping to specific tasks.
+- **Maintainer**: Responsible for tasks which require write access to the Cluster API repo including creating release tags and creating a release branch. This role must be filled by someone on the [`cluster-api-maintainers` list](https://github.com/kubernetes-sigs/cluster-api/blob/main/OWNERS_ALIASES).
+*Note*: This is also documented in [Release tasks](./release-tasks.md) together with a mapping to specific tasks.  
 
 ## Team repo permissions
 - Release notes (`CHANGELOG` folder)
@@ -110,27 +110,9 @@ While we don't anticipate individuals to be available every week during the rele
 
 Before you volunteer to be part of a CAPI release team, please make certain that your employer is aware and supportive of your commitment to the release team.
 
-## Release Team/Day Meetings
-
-Release Team Members meet and share team specific updates, news and all release specific items in the Release Team Meetings.
-
-- Release Team Meetings happen once a week every Wednesday, half an hour before office hours using the CAPI meeting zoom [link](https://zoom.us/j/861487554?pwd=dTVGVVFCblFJc0VBbkFqQlU0dHpiUT09). 
-- Release Team Meeting notes can be found [here](https://docs.google.com/document/d/1AUiuvapS3ldYVJfKucDhIoH6IJIPS009jqwnSTwS0EI).
-- Reach out to maintainers to get the zoom meeting host key to be able to share the screen when office hours zoom link is used.
-
-*Note:* For now, we don't have a calendar invite for Release Team Meetings to be sent out to all Release Team Members. Create a recurring calendar invite for the period of whole release cycle and send it to all Release Team Members.
-
-Release Day meetings is used to cut the releases as a group following the release cycle timeline.
-
-- Release Day Meetings happen on the release date specified in the release timeline document, using the CAPI meeting zoom [link](https://zoom.us/j/861487554?pwd=dTVGVVFCblFJc0VBbkFqQlU0dHpiUT09) at the time depending on the Release Team Members timezone and availability.
-
 ## Suggestions for Team Leads
 
   * In the first week of the release cycle, organize an onboarding session with members of your team (i.e CI Lead with CI team members) to go over the general responsibilities and expectations.
-  * Public communication should be default: all the Release Team specific topics, issues, discussion have to be public and discussed openly in the communication channels the Release Team uses. It gives visibility on the work being done, it is inclusive and track of record. All other communication
-  within the Release Team Members can de carried out using a private group/chat.
-  * For Release Lead: Inform Release Team Members about the upcoming release, a day prior to the actual release cutting date over a common communication
-  channel (usually Cluster API Slack) and ask for team specific updates from Team Leads (i.e status of CI signal from CI Team Lead or preparing a PR for release notes with new desired tag in advance) to ensure smoother release cutting process and avoid unexpected surprises. 
   * Clearly communicate with the team members you are responsible for, that the majority of the work during the release cycle will be a collaborative effort.
   * Establish an ownership rotation policy in consultation with respective team members.
   * Provide opportunities for team members to take the lead in cutting a release within the cycle, based on feasibility.
diff --git a/docs/release/releases/release-1.6.md b/docs/release/releases/release-1.6.md
index 9ed95b04a..61d2987b1 100644
--- a/docs/release/releases/release-1.6.md
+++ b/docs/release/releases/release-1.6.md
@@ -16,13 +16,13 @@ The following table shows the preliminary dates for the `v1.6` release cycle.
 | *v1.4.x & v1.5.x released*                           | Release Lead | Tuesday 24th October 2023   | week 13  |
 | v1.6.0-beta.x released                               | Release Lead | Tuesday 31st October 2023   | week 14  |
 | KubeCon idle week                                    |      -       | 6th - 10th November 2023    | week 15  |
-| release-1.6 branch created (**Begin [Code Freeze]**) | Release Lead | Tuesday 21st November 2023  | week 17  |
-| v1.6.0-rc.0 released                                 | Release Lead | Tuesday 21st November 2023  | week 17  |
-| release-1.6 jobs created                             | CI Manager   | Tuesday 21st November 2023  | week 17  |
-| v1.6.0-rc.x released                                 | Release Lead | Tuesday 28th November 2023  | week 18  |
-| **v1.6.0 released**                                  | Release Lead | Tuesday 5th December 2023   | week 19  |
-| *v1.4.x & v1.5.x released*                           | Release Lead | Tuesday 5th December 2023   | week 19  |
-| Organize release retrospective                       | Release Lead | TBC                         | week 19  |
+| release-1.6 branch created (**Begin [Code Freeze]**) | Release Lead | Tuesday 14th November 2023  | week 16  |
+| v1.6.0-rc.0 released                                 | Release Lead | Tuesday 14th November 2023  | week 16  |
+| release-1.6 jobs created                             | CI Manager   | Tuesday 14th November 2023  | week 16  |
+| v1.6.0-rc.x released                                 | Release Lead | Tuesday 21st November 2023  | week 17  |
+| **v1.6.0 released**                                  | Release Lead | Tuesday 28th November 2023  | week 18  |
+| *v1.4.x & v1.5.x released*                           | Release Lead | Tuesday 28th November 2023  | week 18  |
+| Organize release retrospective                       | Release Lead | TBC                         | week 18  |
 
 After the `.0` release monthly patch release will be created.
 
diff --git a/docs/release/releases/release-1.7.md b/docs/release/releases/release-1.7.md
index 7c7f1a968..62e434d5f 100644
--- a/docs/release/releases/release-1.7.md
+++ b/docs/release/releases/release-1.7.md
@@ -6,22 +6,22 @@ The following table shows the preliminary dates for the `v1.7` release cycle.
 
 | **What**                                             | **Who**      | **When**                    | **Week** |
 |------------------------------------------------------|--------------|-----------------------------|----------|
-| Start of Release Cycle                               | Release Lead | Monday 11th December 2023   | week 1   |
-| Schedule finalized                                   | Release Lead | Friday 15th December 2023   | week 1   |
-| Team finalized                                       | Release Lead | Friday 15th December 2023   | week 1   |
-| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 16th January 2024   | week 6   |
-| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 13th February 2024  | week 10  |
-| v1.7.0-beta.0 released                               | Release Lead | Tuesday 12th March 2024     | week 14  |
-| Communicate beta to providers                        | Comms Manager| Tuesday 12th March 2024     | week 14  |
-| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 12th March 2024     | week 14  |
-| KubeCon idle week                                    |      -       | 19th - 22nd March 2024      | week 15  |
-| v1.7.0-beta.x released                               | Release Lead | Tuesday 26th March 2024     | week 16  |
-| release-1.7 branch created (**Begin [Code Freeze]**) | Release Lead | Tuesday 2nd April 2024      | week 17  |
-| v1.7.0-rc.0 released                                 | Release Lead | Tuesday 2nd April 2024      | week 17  |
-| release-1.7 jobs created                             | CI Manager   | Tuesday 2nd April 2024      | week 17  |
-| v1.7.0-rc.x released                                 | Release Lead | Tuesday 9th April 2024      | week 18  |
-| **v1.7.0 released**                                  | Release Lead | Tuesday 16th April 2024     | week 19  |
-| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 16th April 2024     | week 19  |
+| Start of Release Cycle                               | Release Lead | Monday 4th December 2023    | week 1   |
+| Schedule finalized                                   | Release Lead | Friday 8th December 2023    | week 1   |
+| Team finalized                                       | Release Lead | Friday 8th December 2023    | week 1   |
+| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 9th January 2024    | week 6   |
+| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 6th February 2024   | week 10  |
+| v1.7.0-beta.0 released                               | Release Lead | Tuesday 5th March 2024      | week 14  |
+| Communicate beta to providers                        | Comms Manager| Tuesday 5th March 2024      | week 14  |
+| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 5th March 2024      | week 14  |
+| v1.7.0-beta.x released                               | Release Lead | Tuesday 12th March 2024     | week 15  |
+| KubeCon idle week                                    |      -       | 19th - 22nd March 2024      | week 16  |
+| release-1.7 branch created (**Begin [Code Freeze]**) | Release Lead | Tuesday 26th March 2024     | week 17  |
+| v1.7.0-rc.0 released                                 | Release Lead | Tuesday 26th March 2024     | week 17  |
+| release-1.7 jobs created                             | CI Manager   | Tuesday 26th March 2024     | week 17  |
+| v1.7.0-rc.x released                                 | Release Lead | Tuesday 2nd April 2024      | week 18  |
+| **v1.7.0 released**                                  | Release Lead | Tuesday 9th April 2024      | week 19  |
+| *v1.5.x & v1.6.x released*                           | Release Lead | Tuesday 9th April 2024      | week 19  |
 | Organize release retrospective                       | Release Lead | TBC                         | week 19  |
 
 After the `.0` release monthly patch release will be created.
@@ -32,4 +32,5 @@ After the `.0` release monthly patch release will be created.
 |-------------------------------------------|-------------------------------------------------------------------------------------------|----------------------------------------|
 | Release Lead                              | TBD | TBD                                    |
 | Communications/Docs/Release Notes Manager | TBD | TBD                                    |
-| CI Signal/Bug Triage/Automation Manager   | TBD | TBD                                    |
\ No newline at end of file
+| CI Signal/Bug Triage/Automation Manager   | TBD | TBD                                    |
+| Maintainer                                | TBD | TBD                                    |
\ No newline at end of file
diff --git a/exp/addons/internal/controllers/clusterresourceset_controller.go b/exp/addons/internal/controllers/clusterresourceset_controller.go
index 0eb41a6b4..3e30f5d75 100644
--- a/exp/addons/internal/controllers/clusterresourceset_controller.go
+++ b/exp/addons/internal/controllers/clusterresourceset_controller.go
@@ -166,9 +166,7 @@ func (r *ClusterResourceSetReconciler) Reconcile(ctx context.Context, req ctrl.R
 
 	// Requeue if ErrClusterLocked was returned for one of the clusters.
 	if errClusterLockedOccurred {
-		// Requeue after a minute to not end up in exponential delayed requeue which
-		// could take up to 16m40s.
-		return ctrl.Result{RequeueAfter: time.Minute}, nil
+		return ctrl.Result{Requeue: true}, nil
 	}
 
 	return ctrl.Result{}, nil
diff --git a/exp/internal/controllers/machinepool_controller.go b/exp/internal/controllers/machinepool_controller.go
index 2a4f7a120..6c11686e5 100644
--- a/exp/internal/controllers/machinepool_controller.go
+++ b/exp/internal/controllers/machinepool_controller.go
@@ -55,11 +55,6 @@ import (
 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io;bootstrap.cluster.x-k8s.io,resources=*,verbs=get;list;watch;create;update;patch;delete
 // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools;machinepools/status;machinepools/finalizers,verbs=get;list;watch;create;update;patch;delete
 
-var (
-	// machinePoolKind contains the schema.GroupVersionKind for the MachinePool type.
-	machinePoolKind = clusterv1.GroupVersion.WithKind("MachinePool")
-)
-
 const (
 	// MachinePoolControllerName defines the controller used when creating clients.
 	MachinePoolControllerName = "machinepool-controller"
diff --git a/exp/internal/controllers/machinepool_controller_phases.go b/exp/internal/controllers/machinepool_controller_phases.go
index 93878e189..cbd9c8a35 100644
--- a/exp/internal/controllers/machinepool_controller_phases.go
+++ b/exp/internal/controllers/machinepool_controller_phases.go
@@ -413,7 +413,7 @@ func (r *MachinePoolReconciler) createOrUpdateMachines(ctx context.Context, mp *
 			log.Info("Creating new Machine for infraMachine", "infraMachine", klog.KObj(infraMachine))
 			machine := computeDesiredMachine(mp, infraMachine, nil)
 
-			if err := ssa.Patch(ctx, r.Client, MachinePoolControllerName, machine); err != nil {
+			if err := r.Client.Create(ctx, machine); err != nil {
 				errs = append(errs, errors.Wrapf(err, "failed to create new Machine for infraMachine %q in namespace %q", infraMachine.GetName(), infraMachine.GetNamespace()))
 				continue
 			}
@@ -445,7 +445,7 @@ func computeDesiredMachine(mp *expv1.MachinePool, infraMachine *unstructured.Uns
 		ObjectMeta: metav1.ObjectMeta{
 			Name: names.SimpleNameGenerator.GenerateName(fmt.Sprintf("%s-", mp.Name)),
 			// Note: by setting the ownerRef on creation we signal to the Machine controller that this is not a stand-alone Machine.
-			OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(mp, machinePoolKind)},
+			OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(mp, mp.GroupVersionKind())},
 			Namespace:       mp.Namespace,
 			Labels:          make(map[string]string),
 			Annotations:     make(map[string]string),
diff --git a/go.mod b/go.mod
index f35458455..5fd1ce90d 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/google/go-github/v53 v53.2.0
 	github.com/google/gofuzz v1.2.0
 	github.com/olekukonko/tablewriter v0.0.5
-	github.com/onsi/ginkgo/v2 v2.13.2
+	github.com/onsi/ginkgo/v2 v2.13.1
 	github.com/onsi/gomega v1.30.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.17.0
@@ -31,7 +31,7 @@ require (
 	github.com/valyala/fastjson v1.6.4
 	go.etcd.io/etcd/api/v3 v3.5.10
 	go.etcd.io/etcd/client/v3 v3.5.10
-	golang.org/x/oauth2 v0.15.0
+	golang.org/x/oauth2 v0.14.0
 	golang.org/x/text v0.14.0
 	gomodules.xyz/jsonpatch/v2 v2.4.0
 	google.golang.org/grpc v1.59.0
@@ -156,12 +156,12 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.25.0 // indirect
 	go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
-	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/crypto v0.15.0 // indirect
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
-	golang.org/x/net v0.19.0 // indirect
+	golang.org/x/net v0.18.0 // indirect
 	golang.org/x/sync v0.4.0 // indirect
-	golang.org/x/sys v0.15.0 // indirect
-	golang.org/x/term v0.15.0 // indirect
+	golang.org/x/sys v0.14.0 // indirect
+	golang.org/x/term v0.14.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.14.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
diff --git a/go.sum b/go.sum
index 821e76533..d8012dfe8 100644
--- a/go.sum
+++ b/go.sum
@@ -433,8 +433,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
-github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
+github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU=
+github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
 github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
 github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -627,8 +627,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
-golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
+golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -707,8 +707,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
-golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
+golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -718,8 +718,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
-golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
+golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
+golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -786,14 +786,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
-golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
+golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
+golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/hack/generate-doctoc.sh b/hack/generate-doctoc.sh
index d4b8ee40a..ddd26e3d6 100755
--- a/hack/generate-doctoc.sh
+++ b/hack/generate-doctoc.sh
@@ -28,4 +28,4 @@ if [[ -z "$(command -v doctoc)" ]]; then
   exit 0
 fi
 
-doctoc ./CONTRIBUTING.md docs/release/release-tasks.md docs/release/release-team-onboarding.md docs/release/release-team.md docs/scope-and-objectives.md docs/staging-use-cases.md docs/proposals
+doctoc ./CONTRIBUTING.md docs/release/release-tasks.md docs/release/release-team-onboarding.md docs/scope-and-objectives.md docs/staging-use-cases.md docs/proposals
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 24ff4c13e..9ef6f6fa0 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -9,18 +9,16 @@ replace sigs.k8s.io/cluster-api/test => ../../test
 require (
 	cloud.google.com/go/storage v1.35.1
 	github.com/blang/semver/v4 v4.0.0
-	github.com/onsi/gomega v1.30.0
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/pflag v1.0.5
 	github.com/valyala/fastjson v1.6.4
-	google.golang.org/api v0.152.0
+	google.golang.org/api v0.150.0
 	k8s.io/api v0.28.4
 	k8s.io/apiextensions-apiserver v0.28.4
 	k8s.io/apimachinery v0.28.4
 	k8s.io/client-go v0.28.4
 	k8s.io/klog/v2 v2.100.1
 	k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9
-	k8s.io/kubectl v0.28.4
 	k8s.io/utils v0.0.0-20230406110748-d93618cff8a2
 	sigs.k8s.io/cluster-api v0.0.0-00010101000000-000000000000
 	sigs.k8s.io/cluster-api/test v0.0.0-00010101000000-000000000000
@@ -32,11 +30,10 @@ require (
 )
 
 require (
-	cloud.google.com/go v0.110.10 // indirect
-	cloud.google.com/go/compute v1.23.3 // indirect
+	cloud.google.com/go v0.110.8 // indirect
+	cloud.google.com/go/compute v1.23.1 // indirect
 	cloud.google.com/go/compute/metadata v0.2.3 // indirect
-	cloud.google.com/go/iam v1.1.5 // indirect
-	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
+	cloud.google.com/go/iam v1.1.3 // indirect
 	github.com/MakeNowJust/heredoc v1.0.0 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.0 // indirect
@@ -48,10 +45,8 @@ require (
 	github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
-	github.com/chai2010/gettext-go v1.0.2 // indirect
 	github.com/cloudflare/circl v1.3.3 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
-	github.com/daviddengcn/go-colortext v1.0.0 // indirect
 	github.com/distribution/reference v0.5.0 // indirect
 	github.com/docker/distribution v2.8.3+incompatible // indirect
 	github.com/docker/docker v24.0.7+incompatible // indirect
@@ -61,10 +56,7 @@ require (
 	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
 	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
 	github.com/evanphx/json-patch/v5 v5.7.0 // indirect
-	github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
-	github.com/fatih/camelcase v1.0.0 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
-	github.com/fvbommel/sortorder v1.1.0 // indirect
 	github.com/go-errors/errors v1.4.2 // indirect
 	github.com/go-logr/logr v1.3.0 // indirect
 	github.com/go-openapi/jsonpointer v0.19.6 // indirect
@@ -74,7 +66,6 @@ require (
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
-	github.com/google/btree v1.0.1 // indirect
 	github.com/google/cel-go v0.16.1 // indirect
 	github.com/google/gnostic-models v0.6.8 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
@@ -82,74 +73,59 @@ require (
 	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/s2a-go v0.1.7 // indirect
-	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
 	github.com/google/uuid v1.4.0 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
 	github.com/googleapis/gax-go/v2 v2.12.0 // indirect
-	github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/huandu/xstrings v1.3.3 // indirect
 	github.com/imdario/mergo v0.3.13 // indirect
-	github.com/inconshreveable/mousetrap v1.1.0 // indirect
-	github.com/jonboulle/clockwork v0.2.2 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
-	github.com/lithammer/dedent v1.1.0 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
-	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
-	github.com/moby/spdystream v0.2.0 // indirect
-	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
-	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+	github.com/onsi/gomega v1.30.0 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
 	github.com/pelletier/go-toml/v2 v2.1.0 // indirect
-	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
 	github.com/prometheus/client_golang v1.17.0 // indirect
 	github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
 	github.com/prometheus/common v0.44.0 // indirect
 	github.com/prometheus/procfs v0.11.1 // indirect
-	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/sagikazarmark/locafero v0.3.0 // indirect
 	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 	github.com/shopspring/decimal v1.3.1 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
 	github.com/spf13/afero v1.10.0 // indirect
 	github.com/spf13/cast v1.5.1 // indirect
-	github.com/spf13/cobra v1.8.0 // indirect
 	github.com/spf13/viper v1.17.0 // indirect
 	github.com/stoewer/go-strcase v1.2.0 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
-	github.com/xlab/treeprint v1.2.0 // indirect
 	go.opencensus.io v0.24.0 // indirect
-	go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
 	go.uber.org/multierr v1.11.0 // indirect
-	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/crypto v0.15.0 // indirect
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
 	golang.org/x/mod v0.13.0 // indirect
-	golang.org/x/net v0.19.0 // indirect
-	golang.org/x/oauth2 v0.15.0 // indirect
+	golang.org/x/net v0.18.0 // indirect
+	golang.org/x/oauth2 v0.14.0 // indirect
 	golang.org/x/sync v0.5.0 // indirect
-	golang.org/x/sys v0.15.0 // indirect
-	golang.org/x/term v0.15.0 // indirect
+	golang.org/x/sys v0.14.0 // indirect
+	golang.org/x/term v0.14.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
-	golang.org/x/time v0.5.0 // indirect
+	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.14.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
+	google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
 	google.golang.org/grpc v1.59.0 // indirect
 	google.golang.org/protobuf v1.31.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
@@ -157,13 +133,9 @@ require (
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/apiserver v0.28.4 // indirect
-	k8s.io/cli-runtime v0.28.4 // indirect
 	k8s.io/cluster-bootstrap v0.28.4 // indirect
 	k8s.io/component-base v0.28.4 // indirect
-	k8s.io/component-helpers v0.28.4 // indirect
-	k8s.io/metrics v0.28.4 // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
-	sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 // indirect
 	sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
 )
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index ee24b4f23..5fdaed1bd 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -17,22 +17,22 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
 cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
 cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
 cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
-cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
-cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic=
+cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
+cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
 cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
 cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
 cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
-cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
+cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0=
+cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
-cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
+cloud.google.com/go/iam v1.1.3 h1:18tKG7DzydKWUnLjonWcJO6wjSCAtzh4GcRKlH/Hrzc=
+cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -47,7 +47,6 @@ cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB/
 cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
-github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
@@ -66,7 +65,6 @@ github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
 github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
 github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
 github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -77,8 +75,6 @@ github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7N
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
-github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -91,15 +87,11 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/coredns/caddy v1.1.0 h1:ezvsPrT/tA/7pYDBZxu0cT0VmWk75AfIaf6GSYCNMf0=
 github.com/coredns/corefile-migration v1.0.21 h1:W/DCETrHDiFo0Wj03EyMkaQ9fwsmSgqTCQDHpceaSsE=
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/daviddengcn/go-colortext v1.0.0 h1:ANqDyC0ys6qCSvuEK7l3g5RaehL/Xck9EX8ATG8oKsE=
-github.com/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c=
 github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
 github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
@@ -124,15 +116,9 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv
 github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc=
 github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
-github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
-github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
-github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
-github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
-github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
-github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
 github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
 github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -183,15 +169,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
-github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A=
-github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE=
-github.com/golangplus/testing v1.0.0 h1:+ZeeiKZENNOMkTTELoSySazi+XaEhVO0mb+eanrSEUQ=
-github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
-github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
 github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo=
 github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -236,8 +215,6 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
 github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
@@ -249,9 +226,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
 github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
@@ -263,10 +237,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
 github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
-github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
-github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
-github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -283,10 +253,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
-github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
-github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -296,32 +262,23 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr
 github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
 github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
-github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
-github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
 github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
-github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
 github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
-github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
-github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
 github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
+github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU=
 github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
 github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -330,8 +287,6 @@ github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7X
 github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
 github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
 github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
-github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
-github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@@ -348,13 +303,10 @@ github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwa
 github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
 github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
 github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
 github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
-github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
 github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -366,8 +318,6 @@ github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
 github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
@@ -376,7 +326,6 @@ github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ai
 github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -392,8 +341,6 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
 github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
-github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
-github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -407,8 +354,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
-go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
 go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
@@ -422,8 +367,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
-golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
+golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -497,8 +442,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
-golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
+golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -508,8 +453,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
-golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
+golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
+golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -560,22 +505,19 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
-golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
+golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
+golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -590,8 +532,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
-golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -671,8 +613,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
 google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
 google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY=
-google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
+google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE=
+google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -717,12 +659,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
-google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
-google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
-google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
+google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
+google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -790,24 +732,16 @@ k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
 k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
 k8s.io/apiserver v0.28.4 h1:BJXlaQbAU/RXYX2lRz+E1oPe3G3TKlozMMCZWu5GMgg=
 k8s.io/apiserver v0.28.4/go.mod h1:Idq71oXugKZoVGUUL2wgBCTHbUR+FYTWa4rq9j4n23w=
-k8s.io/cli-runtime v0.28.4 h1:IW3aqSNFXiGDllJF4KVYM90YX4cXPGxuCxCVqCD8X+Q=
-k8s.io/cli-runtime v0.28.4/go.mod h1:MLGRB7LWTIYyYR3d/DOgtUC8ihsAPA3P8K8FDNIqJ0k=
 k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
 k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
 k8s.io/cluster-bootstrap v0.28.4 h1:4MKNy1Qd9QY7pl47rSMGIORF+tm3CUaqC1M8U9bjn4Q=
 k8s.io/cluster-bootstrap v0.28.4/go.mod h1:/c4ro/R4yf4EtJgFgFtvnHkbDOHwubeKJXh5R1c89Bc=
 k8s.io/component-base v0.28.4 h1:c/iQLWPdUgI90O+T9TeECg8o7N3YJTiuz2sKxILYcYo=
 k8s.io/component-base v0.28.4/go.mod h1:m9hR0uvqXDybiGL2nf/3Lf0MerAfQXzkfWhUY58JUbU=
-k8s.io/component-helpers v0.28.4 h1:+X9VXT5+jUsRdC26JyMZ8Fjfln7mSjgumafocE509C4=
-k8s.io/component-helpers v0.28.4/go.mod h1:8LzMalOQ0K10tkBJWBWq8h0HTI9HDPx4WT3QvTFn9Ro=
 k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
 k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
 k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
 k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
-k8s.io/kubectl v0.28.4 h1:gWpUXW/T7aFne+rchYeHkyB8eVDl5UZce8G4X//kjUQ=
-k8s.io/kubectl v0.28.4/go.mod h1:CKOccVx3l+3MmDbkXtIUtibq93nN2hkDR99XDCn7c/c=
-k8s.io/metrics v0.28.4 h1:u36fom9+6c8jX2sk8z58H0hFaIUfrPWbXIxN7GT2blk=
-k8s.io/metrics v0.28.4/go.mod h1:bBqAJxH20c7wAsTQxDXOlVqxGMdce49d7WNr1WeaLac=
 k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
 k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
@@ -823,8 +757,6 @@ sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20211028165026-57688c578b5d h1:KL
 sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20211028165026-57688c578b5d/go.mod h1:NRdZafr4zSCseLQggdvIMXa7umxf+Q+PJzrj3wFwiGE=
 sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
 sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
-sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 h1:vq2TtoDcQomhy7OxXLUOzSbHMuMYq0Bjn93cDtJEdKw=
-sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3/go.mod h1:/d88dHCvoy7d0AKFT0yytezSGZKjsZBVs9YTkBHSGFk=
 sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
 sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
 sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
diff --git a/hack/tools/release/notes/main.go b/hack/tools/release/notes/main.go
index d4163c6ae..376870d78 100644
--- a/hack/tools/release/notes/main.go
+++ b/hack/tools/release/notes/main.go
@@ -96,7 +96,7 @@ var (
 		"machinehealthcheck":                "MachineHealthCheck",
 		"clusterctl":                        "clusterctl", // Preserve lowercase
 		"util":                              "util",       // Preserve lowercase
-		"community-meeting":                 "Community meeting",
+		"Community-meeting":                 "Community meeting",
 	}
 
 	releaseBackportMarker = regexp.MustCompile(`(?m)^\[release-\d\.\d\]\s*`)
@@ -143,7 +143,7 @@ const (
 	missingAreaLabelPrefix   = "MISSING_AREA"
 	areaLabelPrefix          = "area/"
 	multipleAreaLabelsPrefix = "MULTIPLE_AREAS["
-	documentationAreaLabel   = "Documentation"
+	documentationAreaLabel   = "documentation"
 )
 
 type githubPullRequest struct {
@@ -293,7 +293,7 @@ func run() int {
 	for result := range results {
 		if result.err != nil {
 			fmt.Println(result.err)
-			return -1
+			os.Exit(0)
 		}
 
 		if result.prEntry == nil || result.prEntry.title == "" {
diff --git a/internal/controllers/machineset/machineset_controller.go b/internal/controllers/machineset/machineset_controller.go
index a72cb00f0..c499808e7 100644
--- a/internal/controllers/machineset/machineset_controller.go
+++ b/internal/controllers/machineset/machineset_controller.go
@@ -942,7 +942,7 @@ func (r *Reconciler) updateStatus(ctx context.Context, cluster *clusterv1.Cluste
 
 	// Aggregate the operational state of all the machines; while aggregating we are adding the
 	// source ref (reason@machine/name) so the problem can be easily tracked down to its source machine.
-	conditions.SetAggregate(ms, clusterv1.MachinesReadyCondition, collections.FromMachines(filteredMachines...).ConditionGetters(), conditions.AddSourceRef())
+	conditions.SetAggregate(ms, clusterv1.MachinesReadyCondition, collections.FromMachines(filteredMachines...).ConditionGetters(), conditions.AddSourceRef(), conditions.WithStepCounterIf(false))
 
 	return nil
 }
diff --git a/internal/webhooks/machinedeployment.go b/internal/webhooks/machinedeployment.go
index ed7a9ca41..0e8e86377 100644
--- a/internal/webhooks/machinedeployment.go
+++ b/internal/webhooks/machinedeployment.go
@@ -42,8 +42,8 @@ import (
 )
 
 func (webhook *MachineDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error {
-	if webhook.decoder == nil {
-		webhook.decoder = admission.NewDecoder(mgr.GetScheme())
+	if webhook.Decoder == nil {
+		webhook.Decoder = admission.NewDecoder(mgr.GetScheme())
 	}
 
 	return ctrl.NewWebhookManagedBy(mgr).
@@ -58,7 +58,7 @@ func (webhook *MachineDeployment) SetupWebhookWithManager(mgr ctrl.Manager) erro
 
 // MachineDeployment implements a validation and defaulting webhook for MachineDeployment.
 type MachineDeployment struct {
-	decoder *admission.Decoder
+	Decoder *admission.Decoder
 }
 
 var _ webhook.CustomDefaulter = &MachineDeployment{}
@@ -83,7 +83,7 @@ func (webhook *MachineDeployment) Default(ctx context.Context, obj runtime.Objec
 	var oldMD *clusterv1.MachineDeployment
 	if req.Operation == v1.Update {
 		oldMD = &clusterv1.MachineDeployment{}
-		if err := webhook.decoder.DecodeRaw(req.OldObject, oldMD); err != nil {
+		if err := webhook.Decoder.DecodeRaw(req.OldObject, oldMD); err != nil {
 			return errors.Wrapf(err, "failed to decode oldObject to MachineDeployment")
 		}
 	}
diff --git a/internal/webhooks/machineset.go b/internal/webhooks/machineset.go
index f0f38f84e..b9156544a 100644
--- a/internal/webhooks/machineset.go
+++ b/internal/webhooks/machineset.go
@@ -19,18 +19,14 @@ package webhooks
 import (
 	"context"
 	"fmt"
-	"strconv"
 	"strings"
 
-	"github.com/pkg/errors"
-	v1 "k8s.io/api/admission/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/apimachinery/pkg/util/validation/field"
-	"k8s.io/utils/pointer"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -43,10 +39,6 @@ import (
 )
 
 func (webhook *MachineSet) SetupWebhookWithManager(mgr ctrl.Manager) error {
-	if webhook.decoder == nil {
-		webhook.decoder = admission.NewDecoder(mgr.GetScheme())
-	}
-
 	return ctrl.NewWebhookManagedBy(mgr).
 		For(&clusterv1.MachineSet{}).
 		WithDefaulter(webhook).
@@ -58,49 +50,23 @@ func (webhook *MachineSet) SetupWebhookWithManager(mgr ctrl.Manager) error {
 // +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1beta1-machineset,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinesets,versions=v1beta1,name=default.machineset.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
 
 // MachineSet implements a validation and defaulting webhook for MachineSet.
-type MachineSet struct {
-	decoder *admission.Decoder
-}
+type MachineSet struct{}
 
 var _ webhook.CustomDefaulter = &MachineSet{}
 var _ webhook.CustomValidator = &MachineSet{}
 
 // Default sets default MachineSet field values.
-func (webhook *MachineSet) Default(ctx context.Context, obj runtime.Object) error {
+func (webhook *MachineSet) Default(_ context.Context, obj runtime.Object) error {
 	m, ok := obj.(*clusterv1.MachineSet)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a MachineSet but got a %T", obj))
 	}
 
-	req, err := admission.RequestFromContext(ctx)
-	if err != nil {
-		return err
-	}
-
-	dryRun := false
-	if req.DryRun != nil {
-		dryRun = *req.DryRun
-	}
-
-	var oldMS *clusterv1.MachineSet
-	if req.Operation == v1.Update {
-		oldMS = &clusterv1.MachineSet{}
-		if err := webhook.decoder.DecodeRaw(req.OldObject, oldMS); err != nil {
-			return errors.Wrapf(err, "failed to decode oldObject to MachineSet")
-		}
-	}
-
 	if m.Labels == nil {
 		m.Labels = make(map[string]string)
 	}
 	m.Labels[clusterv1.ClusterNameLabel] = m.Spec.ClusterName
 
-	replicas, err := calculateMachineSetReplicas(ctx, oldMS, m, dryRun)
-	if err != nil {
-		return err
-	}
-	m.Spec.Replicas = pointer.Int32(replicas)
-
 	if m.Spec.DeletePolicy == "" {
 		randomPolicy := string(clusterv1.RandomMachineSetDeletePolicy)
 		m.Spec.DeletePolicy = randomPolicy
@@ -253,104 +219,3 @@ func validateSkippedMachineSetPreflightChecks(o client.Object) *field.Error {
 	}
 	return nil
 }
-
-// calculateMachineSetReplicas calculates the default value of the replicas field.
-// The value will be calculated based on the following logic:
-// * if replicas is already set on newMS, keep the current value
-// * if the autoscaler min size and max size annotations are set:
-//   - if it's a new MachineSet, use min size
-//   - if the replicas field of the old MachineSet is < min size, use min size
-//   - if the replicas field of the old MachineSet is > max size, use max size
-//   - if the replicas field of the old MachineSet is in the (min size, max size) range, keep the value from the oldMS
-//
-// * otherwise use 1
-//
-// The goal of this logic is to provide a smoother UX for clusters using the Kubernetes autoscaler.
-// Note: Autoscaler only takes over control of the replicas field if the replicas value is in the (min size, max size) range.
-//
-// We are supporting the following use cases:
-// * A new MS is created and replicas should be managed by the autoscaler
-//   - Either via the default annotation or via the min size and max size annotations the replicas field
-//     is defaulted to a value which is within the (min size, max size) range so the autoscaler can take control.
-//
-// * An existing MS which initially wasn't controlled by the autoscaler should be later controlled by the autoscaler
-//   - To adopt an existing MS users can use the default, min size and max size annotations to enable the autoscaler
-//     and to ensure the replicas field is within the (min size, max size) range. Without the annotations handing over
-//     control to the autoscaler by unsetting the replicas field would lead to the field being set to 1. This is very
-//     disruptive for existing Machines and if 1 is outside the (min size, max size) range the autoscaler won't take
-//     control.
-//
-// Notes:
-//   - While the min size and max size annotations of the autoscaler provide the best UX, other autoscalers can use the
-//     DefaultReplicasAnnotation if they have similar use cases.
-func calculateMachineSetReplicas(ctx context.Context, oldMS *clusterv1.MachineSet, newMS *clusterv1.MachineSet, dryRun bool) (int32, error) {
-	// If replicas is already set => Keep the current value.
-	if newMS.Spec.Replicas != nil {
-		return *newMS.Spec.Replicas, nil
-	}
-
-	log := ctrl.LoggerFrom(ctx)
-
-	// If both autoscaler annotations are set, use them to calculate the default value.
-	minSizeString, hasMinSizeAnnotation := newMS.Annotations[clusterv1.AutoscalerMinSizeAnnotation]
-	maxSizeString, hasMaxSizeAnnotation := newMS.Annotations[clusterv1.AutoscalerMaxSizeAnnotation]
-	if hasMinSizeAnnotation && hasMaxSizeAnnotation {
-		minSize, err := strconv.ParseInt(minSizeString, 10, 32)
-		if err != nil {
-			return 0, errors.Wrapf(err, "failed to caculate MachineSet replicas value: could not parse the value of the %q annotation", clusterv1.AutoscalerMinSizeAnnotation)
-		}
-		maxSize, err := strconv.ParseInt(maxSizeString, 10, 32)
-		if err != nil {
-			return 0, errors.Wrapf(err, "failed to caculate MachineSet replicas value: could not parse the value of the %q annotation", clusterv1.AutoscalerMaxSizeAnnotation)
-		}
-
-		// If it's a new MachineSet => Use the min size.
-		// Note: This will result in a scale up to get into the range where autoscaler takes over.
-		if oldMS == nil {
-			if !dryRun {
-				log.V(2).Info(fmt.Sprintf("Replica field has been defaulted to %d based on the %s annotation (MS is a new MS)", minSize, clusterv1.AutoscalerMinSizeAnnotation))
-			}
-			return int32(minSize), nil
-		}
-
-		// Otherwise we are handing over the control for the replicas field for an existing MachineSet
-		// to the autoscaler.
-
-		switch {
-		// If the old MachineSet doesn't have replicas set => Use the min size.
-		// Note: As defaulting always sets the replica field, this case should not be possible
-		// We only have this handling to be 100% safe against panics.
-		case oldMS.Spec.Replicas == nil:
-			if !dryRun {
-				log.V(2).Info(fmt.Sprintf("Replica field has been defaulted to %d based on the %s annotation (old MS didn't have replicas set)", minSize, clusterv1.AutoscalerMinSizeAnnotation))
-			}
-			return int32(minSize), nil
-		// If the old MachineSet replicas are lower than min size => Use the min size.
-		// Note: This will result in a scale up to get into the range where autoscaler takes over.
-		case *oldMS.Spec.Replicas < int32(minSize):
-			if !dryRun {
-				log.V(2).Info(fmt.Sprintf("Replica field has been defaulted to %d based on the %s annotation (old MS had replicas below min size)", minSize, clusterv1.AutoscalerMinSizeAnnotation))
-			}
-			return int32(minSize), nil
-		// If the old MachineSet replicas are higher than max size => Use the max size.
-		// Note: This will result in a scale down to get into the range where autoscaler takes over.
-		case *oldMS.Spec.Replicas > int32(maxSize):
-			if !dryRun {
-				log.V(2).Info(fmt.Sprintf("Replica field has been defaulted to %d based on the %s annotation (old MS had replicas above max size)", maxSize, clusterv1.AutoscalerMaxSizeAnnotation))
-			}
-			return int32(maxSize), nil
-		// If the old MachineSet replicas are between min and max size => Keep the current value.
-		default:
-			if !dryRun {
-				log.V(2).Info(fmt.Sprintf("Replica field has been defaulted to %d based on replicas of the old MachineSet (old MS had replicas within min size / max size range)", *oldMS.Spec.Replicas))
-			}
-			return *oldMS.Spec.Replicas, nil
-		}
-	}
-
-	// If neither the default nor the autoscaler annotations are set => Default to 1.
-	if !dryRun {
-		log.V(2).Info("Replica field has been defaulted to 1")
-	}
-	return 1, nil
-}
diff --git a/webhooks/alias.go b/webhooks/alias.go
index b1688d95c..ee0646bdc 100644
--- a/webhooks/alias.go
+++ b/webhooks/alias.go
@@ -19,6 +19,7 @@ package webhooks
 import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
 
 	"sigs.k8s.io/cluster-api/internal/webhooks"
 )
@@ -56,11 +57,15 @@ func (webhook *Machine) SetupWebhookWithManager(mgr ctrl.Manager) error {
 }
 
 // MachineDeployment implements a validating and defaulting webhook for MachineDeployment.
-type MachineDeployment struct{}
+type MachineDeployment struct {
+	Decoder *admission.Decoder
+}
 
 // SetupWebhookWithManager sets up MachineDeployment webhooks.
 func (webhook *MachineDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error {
-	return (&webhooks.MachineDeployment{}).SetupWebhookWithManager(mgr)
+	return (&webhooks.MachineDeployment{
+		Decoder: webhook.Decoder,
+	}).SetupWebhookWithManager(mgr)
 }
 
 // MachineSet implements a validating and defaulting webhook for MachineSet.


Test patch:
diff --git a/exp/internal/controllers/machinepool_controller_phases_test.go b/exp/internal/controllers/machinepool_controller_phases_test.go
index d30c22f9f..febc0c372 100644
--- a/exp/internal/controllers/machinepool_controller_phases_test.go
+++ b/exp/internal/controllers/machinepool_controller_phases_test.go
@@ -17,7 +17,6 @@ limitations under the License.
 package controllers
 
 import (
-	"fmt"
 	"testing"
 	"time"
 
@@ -29,7 +28,6 @@ import (
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/client-go/tools/record"
-	utilfeature "k8s.io/component-base/featuregate/testing"
 	"k8s.io/utils/pointer"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -40,7 +38,6 @@ import (
 	"sigs.k8s.io/cluster-api/controllers/external"
 	"sigs.k8s.io/cluster-api/controllers/remote"
 	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
-	"sigs.k8s.io/cluster-api/feature"
 	"sigs.k8s.io/cluster-api/internal/test/builder"
 	"sigs.k8s.io/cluster-api/internal/util/ssa"
 	"sigs.k8s.io/cluster-api/util/kubeconfig"
@@ -1068,39 +1065,131 @@ func TestReconcileMachinePoolInfrastructure(t *testing.T) {
 }
 
 func TestReconcileMachinePoolMachines(t *testing.T) {
-	t.Run("Reconcile MachinePool Machines", func(t *testing.T) {
-		// NOTE: MachinePool feature flag is disabled by default, thus preventing to create or update MachinePool.
-		// Enabling the feature flag temporarily for this test.
-		defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.MachinePool, true)()
-
-		g := NewWithT(t)
+	defaultCluster := clusterv1.Cluster{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      clusterName,
+			Namespace: metav1.NamespaceDefault,
+		},
+	}
 
-		ns, err := env.CreateNamespace(ctx, "test-machinepool-machines")
-		g.Expect(err).ToNot(HaveOccurred())
+	defaultMachinePool := expv1.MachinePool{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "machinepool-test",
+			Namespace: metav1.NamespaceDefault,
+			Labels: map[string]string{
+				clusterv1.ClusterNameLabel: defaultCluster.Name,
+			},
+		},
+		Spec: expv1.MachinePoolSpec{
+			ClusterName: defaultCluster.Name,
+			Replicas:    pointer.Int32(2),
+			Template: clusterv1.MachineTemplateSpec{
+				Spec: clusterv1.MachineSpec{
+					Bootstrap: clusterv1.Bootstrap{
+						ConfigRef: &corev1.ObjectReference{
+							APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
+							Kind:       "BootstrapConfig",
+							Name:       "bootstrap-config1",
+						},
+					},
+					InfrastructureRef: corev1.ObjectReference{
+						APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
+						Kind:       "InfrastructureConfig",
+						Name:       "infra-config1",
+					},
+				},
+			},
+		},
+	}
 
-		cluster := builder.Cluster(ns.Name, clusterName).Build()
-		g.Expect(env.Create(ctx, cluster)).To(Succeed())
+	infraMachine1 := unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"kind":       "InfrastructureMachine",
+			"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
+			"metadata": map[string]interface{}{
+				"name":      "infra-machine1",
+				"namespace": metav1.NamespaceDefault,
+				"labels": map[string]interface{}{
+					clusterv1.ClusterNameLabel:     defaultCluster.Name,
+					clusterv1.MachinePoolNameLabel: defaultMachinePool.Name,
+				},
+			},
+		},
+	}
 
-		t.Run("Should do nothing if machines already exist", func(t *testing.T) {
-			machinePool := getMachinePool(2, "machinepool-test-1", clusterName, ns.Name)
-			g.Expect(env.Create(ctx, &machinePool)).To(Succeed())
+	infraMachine2 := unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"kind":       "InfrastructureMachine",
+			"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
+			"metadata": map[string]interface{}{
+				"name":      "infra-machine2",
+				"namespace": metav1.NamespaceDefault,
+				"labels": map[string]interface{}{
+					clusterv1.ClusterNameLabel:     defaultCluster.Name,
+					clusterv1.MachinePoolNameLabel: defaultMachinePool.Name,
+				},
+			},
+		},
+	}
 
-			infraMachines := getInfraMachines(2, machinePool.Name, clusterName, ns.Name)
-			for i := range infraMachines {
-				g.Expect(env.Create(ctx, &infraMachines[i])).To(Succeed())
-			}
+	machine1 := clusterv1.Machine{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "machine1",
+			Namespace: metav1.NamespaceDefault,
+			Labels: map[string]string{
+				clusterv1.ClusterNameLabel:     defaultCluster.Name,
+				clusterv1.MachinePoolNameLabel: "machinepool-test",
+			},
+		},
+		Spec: clusterv1.MachineSpec{
+			ClusterName: clusterName,
+			InfrastructureRef: corev1.ObjectReference{
+				APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
+				Kind:       "InfrastructureMachine",
+				Name:       "infra-machine1",
+				Namespace:  metav1.NamespaceDefault,
+			},
+		},
+	}
 
-			machines := getMachines(2, machinePool.Name, clusterName, ns.Name)
-			for i := range machines {
-				g.Expect(env.Create(ctx, &machines[i])).To(Succeed())
-			}
+	machine2 := clusterv1.Machine{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "machine2",
+			Namespace: metav1.NamespaceDefault,
+			Labels: map[string]string{
+				clusterv1.ClusterNameLabel:     defaultCluster.Name,
+				clusterv1.MachinePoolNameLabel: "machinepool-test",
+			},
+		},
+		Spec: clusterv1.MachineSpec{
+			ClusterName: clusterName,
+			InfrastructureRef: corev1.ObjectReference{
+				APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
+				Kind:       "InfrastructureMachine",
+				Name:       "infra-machine2",
+				Namespace:  metav1.NamespaceDefault,
+			},
+		},
+	}
 
-			infraConfig := map[string]interface{}{
-				"kind":       builder.GenericInfrastructureMachinePoolKind,
+	testCases := []struct {
+		name                        string
+		bootstrapConfig             map[string]interface{}
+		infraConfig                 map[string]interface{}
+		machines                    []clusterv1.Machine
+		infraMachines               []unstructured.Unstructured
+		machinepool                 *expv1.MachinePool
+		expectError                 bool
+		supportsMachinePoolMachines bool
+	}{
+		{
+			name: "two infra machines, should create two machinepool machines",
+			infraConfig: map[string]interface{}{
+				"kind":       "InfrastructureConfig",
 				"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
 				"metadata": map[string]interface{}{
 					"name":      "infra-config1",
-					"namespace": ns.Name,
+					"namespace": metav1.NamespaceDefault,
 				},
 				"spec": map[string]interface{}{
 					"providerIDList": []interface{}{
@@ -1119,49 +1208,24 @@ func TestReconcileMachinePoolMachines(t *testing.T) {
 							"address": "10.0.0.2",
 						},
 					},
-					"infrastructureMachineKind": builder.GenericInfrastructureMachineKind,
+					"infrastructureMachineKind": "InfrastructureMachine",
 				},
-			}
-			g.Expect(env.Create(ctx, &unstructured.Unstructured{Object: infraConfig})).To(Succeed())
-
-			r := &MachinePoolReconciler{
-				Client:   env,
-				ssaCache: ssa.NewCache(),
-			}
-
-			err = r.reconcileMachines(ctx, &machinePool, &unstructured.Unstructured{Object: infraConfig})
-			r.reconcilePhase(&machinePool)
-			g.Expect(err).ToNot(HaveOccurred())
-
-			machineList := &clusterv1.MachineList{}
-			labels := map[string]string{
-				clusterv1.ClusterNameLabel:     clusterName,
-				clusterv1.MachinePoolNameLabel: machinePool.Name,
-			}
-			g.Expect(env.GetAPIReader().List(ctx, machineList, client.InNamespace(cluster.Namespace), client.MatchingLabels(labels))).To(Succeed())
-			g.Expect(machineList.Items).To(HaveLen(2))
-			for i := range machineList.Items {
-				machine := &machineList.Items[i]
-				_, err := external.Get(ctx, r.Client, &machine.Spec.InfrastructureRef, machine.Namespace)
-				g.Expect(err).ToNot(HaveOccurred())
-			}
-		})
-
-		t.Run("Should create two machines if two infra machines exist", func(t *testing.T) {
-			machinePool := getMachinePool(2, "machinepool-test-2", clusterName, ns.Name)
-			g.Expect(env.Create(ctx, &machinePool)).To(Succeed())
-
-			infraMachines := getInfraMachines(2, machinePool.Name, clusterName, ns.Name)
-			for i := range infraMachines {
-				g.Expect(env.Create(ctx, &infraMachines[i])).To(Succeed())
-			}
-
-			infraConfig := map[string]interface{}{
-				"kind":       builder.GenericInfrastructureMachinePoolKind,
+			},
+			infraMachines: []unstructured.Unstructured{
+				infraMachine1,
+				infraMachine2,
+			},
+			expectError:                 false,
+			supportsMachinePoolMachines: true,
+		},
+		{
+			name: "two infra machines and two machinepool machines, nothing to do",
+			infraConfig: map[string]interface{}{
+				"kind":       "InfrastructureConfig",
 				"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
 				"metadata": map[string]interface{}{
-					"name":      "infra-config2",
-					"namespace": ns.Name,
+					"name":      "infra-config1",
+					"namespace": metav1.NamespaceDefault,
 				},
 				"spec": map[string]interface{}{
 					"providerIDList": []interface{}{
@@ -1180,44 +1244,28 @@ func TestReconcileMachinePoolMachines(t *testing.T) {
 							"address": "10.0.0.2",
 						},
 					},
-					"infrastructureMachineKind": builder.GenericInfrastructureMachineKind,
+					"infrastructureMachineKind": "InfrastructureMachine",
 				},
-			}
-			g.Expect(env.Create(ctx, &unstructured.Unstructured{Object: infraConfig})).To(Succeed())
-
-			r := &MachinePoolReconciler{
-				Client:   env,
-				ssaCache: ssa.NewCache(),
-			}
-
-			err = r.reconcileMachines(ctx, &machinePool, &unstructured.Unstructured{Object: infraConfig})
-			r.reconcilePhase(&machinePool)
-			g.Expect(err).ToNot(HaveOccurred())
-
-			machineList := &clusterv1.MachineList{}
-			labels := map[string]string{
-				clusterv1.ClusterNameLabel:     clusterName,
-				clusterv1.MachinePoolNameLabel: machinePool.Name,
-			}
-			g.Expect(env.GetAPIReader().List(ctx, machineList, client.InNamespace(cluster.Namespace), client.MatchingLabels(labels))).To(Succeed())
-			g.Expect(machineList.Items).To(HaveLen(2))
-			for i := range machineList.Items {
-				machine := &machineList.Items[i]
-				_, err := external.Get(ctx, r.Client, &machine.Spec.InfrastructureRef, machine.Namespace)
-				g.Expect(err).ToNot(HaveOccurred())
-			}
-		})
-
-		t.Run("Should do nothing if machinepool does not support machinepool machines", func(t *testing.T) {
-			machinePool := getMachinePool(2, "machinepool-test-3", clusterName, ns.Name)
-			g.Expect(env.Create(ctx, &machinePool)).To(Succeed())
-
-			infraConfig := map[string]interface{}{
-				"kind":       builder.GenericInfrastructureMachinePoolKind,
+			},
+			machines: []clusterv1.Machine{
+				machine1,
+				machine2,
+			},
+			infraMachines: []unstructured.Unstructured{
+				infraMachine1,
+				infraMachine2,
+			},
+			expectError:                 false,
+			supportsMachinePoolMachines: true,
+		},
+		{
+			name: "machinepool does not support machinepool machines, nothing to do",
+			infraConfig: map[string]interface{}{
+				"kind":       "InfrastructureConfig",
 				"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
 				"metadata": map[string]interface{}{
-					"name":      "infra-config3",
-					"namespace": ns.Name,
+					"name":      "infra-config1",
+					"namespace": metav1.NamespaceDefault,
 				},
 				"spec": map[string]interface{}{
 					"providerIDList": []interface{}{
@@ -1237,27 +1285,66 @@ func TestReconcileMachinePoolMachines(t *testing.T) {
 						},
 					},
 				},
+			},
+			expectError:                 false,
+			supportsMachinePoolMachines: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			g := NewWithT(t)
+
+			if tc.machinepool == nil {
+				tc.machinepool = defaultMachinePool.DeepCopy()
+			}
+
+			objs := []client.Object{defaultCluster.DeepCopy()}
+			infraConfig := &unstructured.Unstructured{Object: tc.infraConfig}
+			objs = append(objs, tc.machinepool, infraConfig.DeepCopy())
+
+			for _, infraMachine := range tc.infraMachines {
+				objs = append(objs, infraMachine.DeepCopy())
+			}
+
+			for _, machine := range tc.machines {
+				objs = append(objs, machine.DeepCopy())
 			}
-			g.Expect(env.Create(ctx, &unstructured.Unstructured{Object: infraConfig})).To(Succeed())
 
 			r := &MachinePoolReconciler{
-				Client:   env,
+				Client:   fake.NewClientBuilder().WithObjects(objs...).Build(),
 				ssaCache: ssa.NewCache(),
 			}
 
-			err = r.reconcileMachines(ctx, &machinePool, &unstructured.Unstructured{Object: infraConfig})
-			r.reconcilePhase(&machinePool)
-			g.Expect(err).ToNot(HaveOccurred())
+			err := r.reconcileMachines(ctx, tc.machinepool, infraConfig)
+
+			r.reconcilePhase(tc.machinepool)
+			if tc.expectError {
+				g.Expect(err).To(HaveOccurred())
+			} else {
+				g.Expect(err).ToNot(HaveOccurred())
+
+				machineList := &clusterv1.MachineList{}
+				labels := map[string]string{
+					clusterv1.ClusterNameLabel:     defaultCluster.Name,
+					clusterv1.MachinePoolNameLabel: tc.machinepool.Name,
+				}
+				err := r.Client.List(ctx, machineList, client.InNamespace(tc.machinepool.Namespace), client.MatchingLabels(labels))
+				g.Expect(err).ToNot(HaveOccurred())
 
-			machineList := &clusterv1.MachineList{}
-			labels := map[string]string{
-				clusterv1.ClusterNameLabel:     clusterName,
-				clusterv1.MachinePoolNameLabel: machinePool.Name,
+				if tc.supportsMachinePoolMachines {
+					g.Expect(machineList.Items).To(HaveLen(len(tc.infraMachines)))
+					for i := range machineList.Items {
+						machine := &machineList.Items[i]
+						_, err := external.Get(ctx, r.Client, &machine.Spec.InfrastructureRef, machine.Namespace)
+						g.Expect(err).ToNot(HaveOccurred())
+					}
+				} else {
+					g.Expect(machineList.Items).To(BeEmpty())
+				}
 			}
-			g.Expect(env.GetAPIReader().List(ctx, machineList, client.InNamespace(cluster.Namespace), client.MatchingLabels(labels))).To(Succeed())
-			g.Expect(machineList.Items).To(BeEmpty())
 		})
-	})
+	}
 }
 
 func TestInfraMachineToMachinePoolMapper(t *testing.T) {
@@ -1738,89 +1825,3 @@ func TestReconcileMachinePoolScaleToFromZero(t *testing.T) {
 		g.Expect(env.Get(ctx, client.ObjectKeyFromObject(node), delNode)).To(Succeed())
 	})
 }
-
-func getInfraMachines(replicas int, mpName, clusterName, nsName string) []unstructured.Unstructured {
-	infraMachines := make([]unstructured.Unstructured, replicas)
-	for i := 0; i < replicas; i++ {
-		infraMachines[i] = unstructured.Unstructured{
-			Object: map[string]interface{}{
-				"kind":       builder.GenericInfrastructureMachineKind,
-				"apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1",
-				"metadata": map[string]interface{}{
-					"name":      fmt.Sprintf("%s-infra-%d", mpName, i),
-					"namespace": nsName,
-					"labels": map[string]interface{}{
-						clusterv1.ClusterNameLabel:     clusterName,
-						clusterv1.MachinePoolNameLabel: mpName,
-					},
-				},
-			},
-		}
-	}
-	return infraMachines
-}
-
-func getMachines(replicas int, mpName, clusterName, nsName string) []clusterv1.Machine {
-	machines := make([]clusterv1.Machine, replicas)
-	for i := 0; i < replicas; i++ {
-		machines[i] = clusterv1.Machine{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      fmt.Sprintf("%s-machine-%d", mpName, i),
-				Namespace: nsName,
-				Labels: map[string]string{
-					clusterv1.ClusterNameLabel:     clusterName,
-					clusterv1.MachinePoolNameLabel: mpName,
-				},
-			},
-			Spec: clusterv1.MachineSpec{
-				ClusterName: clusterName,
-				Bootstrap: clusterv1.Bootstrap{
-					ConfigRef: &corev1.ObjectReference{
-						APIVersion: builder.BootstrapGroupVersion.String(),
-						Kind:       builder.GenericBootstrapConfigKind,
-						Name:       fmt.Sprintf("bootstrap-config-%d", i),
-					},
-				},
-				InfrastructureRef: corev1.ObjectReference{
-					APIVersion: builder.InfrastructureGroupVersion.String(),
-					Kind:       builder.GenericInfrastructureMachineKind,
-					Name:       fmt.Sprintf("%s-infra-%d", mpName, i),
-				},
-			},
-		}
-	}
-	return machines
-}
-
-func getMachinePool(replicas int, mpName, clusterName, nsName string) expv1.MachinePool {
-	return expv1.MachinePool{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      mpName,
-			Namespace: nsName,
-			Labels: map[string]string{
-				clusterv1.ClusterNameLabel: clusterName,
-			},
-		},
-		Spec: expv1.MachinePoolSpec{
-			ClusterName: clusterName,
-			Replicas:    pointer.Int32(int32(replicas)),
-			Template: clusterv1.MachineTemplateSpec{
-				Spec: clusterv1.MachineSpec{
-					ClusterName: clusterName,
-					Bootstrap: clusterv1.Bootstrap{
-						ConfigRef: &corev1.ObjectReference{
-							APIVersion: builder.BootstrapGroupVersion.String(),
-							Kind:       builder.GenericBootstrapConfigKind,
-							Name:       "bootstrap-config1",
-						},
-					},
-					InfrastructureRef: corev1.ObjectReference{
-						APIVersion: builder.InfrastructureGroupVersion.String(),
-						Kind:       builder.GenericInfrastructureMachineKind,
-						Name:       "infra-config1",
-					},
-				},
-			},
-		},
-	}
-}
diff --git a/hack/tools/release/notes/release_notes_integration_test.go b/hack/tools/release/notes/release_notes_integration_test.go
deleted file mode 100644
index 457f1d19f..000000000
--- a/hack/tools/release/notes/release_notes_integration_test.go
+++ /dev/null
@@ -1,131 +0,0 @@
-//go:build tools && integration
-
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-	"flag"
-	"fmt"
-	"io"
-	"os"
-	"os/exec"
-	"testing"
-
-	. "github.com/onsi/gomega"
-	"k8s.io/kubectl/pkg/cmd"
-)
-
-func TestReleaseNotesIntegration(t *testing.T) {
-	testCases := []struct {
-		name                 string
-		previousRelease      string
-		releaseBranchForTest string
-		expected             string
-	}{
-		{
-			// This tests a patch release computing the PR list from previous patch tag
-			// to HEAD. Since v1.3 is out of support, we won't be backporting new PRs
-			// so the branch should remain untouched and the test valid.
-			name:                 "new patch",
-			previousRelease:      "v1.3.9",
-			releaseBranchForTest: "release-1.3",
-			expected:             "test/golden/v1.3.10.md",
-		},
-		{
-			// The release notes command computes everything from last tag
-			// to HEAD. Hence if we use the head of release-1.5, this test will
-			// become invalid everytime we backport some PR to release branch release-1.5.
-			// Here we cheat a little by poiting to worktree to v1.5.0, which is the
-			// release that this test is simulating, so it should not exist yet. But
-			// it represents accurately the HEAD of release-1.5 when we released v1.5.0.
-			name:                 "new minor",
-			previousRelease:      "v1.4.0",
-			releaseBranchForTest: "v1.5.0",
-			expected:             "test/golden/v1.5.0.md",
-		},
-	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			setupNotesTest(t, tc.previousRelease, tc.releaseBranchForTest)
-			g := NewWithT(t)
-
-			expectedOutput, err := os.ReadFile(tc.expected)
-			g.Expect(err).ToNot(HaveOccurred())
-
-			orgCurrentDir, err := os.Getwd()
-			g.Expect(err).To(Succeed())
-			t.Cleanup(func() {
-				g.Expect(os.Chdir(orgCurrentDir)).To(Succeed())
-			})
-			g.Expect(os.Chdir(tc.releaseBranchForTest)).To(Succeed())
-
-			// a two workers config is slow but it guarantees no rate limiting
-			os.Args = []string{os.Args[0], "--from", tc.previousRelease, "--workers", "2"}
-
-			old := os.Stdout // keep backup of the real stdout to restore later
-			r, w, err := os.Pipe()
-			g.Expect(err).To(Succeed())
-			os.Stdout = w
-
-			g.Expect(runReleaseNotesCmd()).To(Succeed())
-
-			w.Close()
-			output, err := io.ReadAll(r)
-			g.Expect(err).NotTo(HaveOccurred())
-			os.Stdout = old
-
-			g.Expect(string(output)).To(BeComparableTo(string(expectedOutput)))
-		})
-	}
-}
-
-func runReleaseNotesCmd() error {
-	// we replicate the main function here so we don't get os.Exit
-	flag.Parse()
-	if code := run(); code != 0 {
-		return fmt.Errorf("release notes command exited with code %d", code)
-	}
-
-	return nil
-}
-
-func setupNotesTest(tb testing.TB, previousRelease, releaseBranchForTest string) {
-	g := NewWithT(tb)
-
-	_, err := os.Stat(releaseBranchForTest)
-	if os.IsNotExist(err) {
-		runCommand(tb, exec.Command("git", "worktree", "add", releaseBranchForTest))
-	} else {
-		g.Expect(err).To(Succeed())
-	}
-
-	pull := exec.Command("git", "pull", "upstream", releaseBranchForTest)
-	pull.Dir = releaseBranchForTest
-	runCommand(tb, pull)
-
-	tb.Cleanup(func() {
-		runCommand(tb, cmd.Command("git", "worktree", "remove", releaseBranchForTest))
-	})
-}
-
-func runCommand(tb testing.TB, cmd *exec.Cmd) {
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		tb.Fatalf("Command %s failed: %s", cmd.Args, string(out))
-	}
-}
diff --git a/hack/tools/release/notes/test/golden/v1.3.10.md b/hack/tools/release/notes/test/golden/v1.3.10.md
deleted file mode 100644
index 282850019..000000000
--- a/hack/tools/release/notes/test/golden/v1.3.10.md
+++ /dev/null
@@ -1,34 +0,0 @@
-## 👌 Kubernetes version support
-
-- Management Cluster: v1.**X**.x -> v1.**X**.x
-- Workload Cluster: v1.**X**.x -> v1.**X**.x
-
-[More information about version support can be found here](https://cluster-api.sigs.k8s.io/reference/versions.html)
-
-## Highlights
-
-* REPLACE ME
-
-## Deprecation Warning
-
-REPLACE ME: A couple sentences describing the deprecation, including links to docs.
-
-* [GitHub issue #REPLACE ME](REPLACE ME)
-
-## Changes since v1.3.9
-## :chart_with_upwards_trend: Overview
-- 6 new commits merged
-- 2 bugs fixed 🐛
-
-## :bug: Bug Fixes
-- Dependency: Bump to docker v24.0.5-0.20230714235725-36e9e796c6fc (#9046)
-- KCP: Requeue KCP object if ControlPlaneComponentsHealthyCondition is not yet true (#9034)
-
-## :seedling: Others
-- ClusterCacheTracker: Ensure Get/List calls are not getting stuck when apiserver is unreachable (#9033)
-- Dependency: Bump docker to v24.0.5 (#9067)
-- Dependency: Bump google.golang.org/grpc to v1.55.0 (#8971)
-- Dependency: Change tilt debug base image to golang (#9075)
-
-
-_Thanks to all our contributors!_ 😊
diff --git a/hack/tools/release/notes/test/golden/v1.5.0.md b/hack/tools/release/notes/test/golden/v1.5.0.md
deleted file mode 100644
index 714da8a22..000000000
--- a/hack/tools/release/notes/test/golden/v1.5.0.md
+++ /dev/null
@@ -1,299 +0,0 @@
-## 👌 Kubernetes version support
-
-- Management Cluster: v1.**X**.x -> v1.**X**.x
-- Workload Cluster: v1.**X**.x -> v1.**X**.x
-
-[More information about version support can be found here](https://cluster-api.sigs.k8s.io/reference/versions.html)
-
-## Highlights
-
-* REPLACE ME
-
-## Deprecation Warning
-
-REPLACE ME: A couple sentences describing the deprecation, including links to docs.
-
-* [GitHub issue #REPLACE ME](REPLACE ME)
-
-## Changes since v1.4.0
-## :chart_with_upwards_trend: Overview
-- 335 new commits merged
-- 4 breaking changes :warning:
-- 19 feature additions ✨
-- 67 bugs fixed 🐛
-
-## :warning: Breaking Changes
-- API: Stop serving v1alpha3 API types (#8549)
-- CAPD: Use k8s v1.27.0 in quickstart docs and CAPD (#8518)
-- clusterctl: Follow XDG Directory standard for config/data/... files (#6913)
-- Dependency: Bump to CR v0.15.0 (#8007)
-
-## :sparkles: New Features
-- CAPBK: Use caching read for bootstrap config owner (#8867)
-- CAPIM: Enable Kubernetes upgrades in CAPIM (#8938)
-- ClusterClass: Add support or concurrent MD upgrades in classy clusters (#8432)
-- ClusterClass: Add webhook warning for missing ClusterClass (#8746)
-- clusterctl: Add in memory provider (#8799)
-- clusterctl: Add MachinePool Machine support in clusterctl discovery (#8836)
-- clusterctl: Add support for add-on providers in clusterctl (#8472)
-- clusterctl: Feat: accept resource mutators in Move operation (#7966)
-- clusterctl: Introduce possibility to create clusterctl plugins (#8957)
-- Devtools: Hack/observability bump kube-state-metrics chart to get version v2.9.2 (#8979)
-- Devtools: Hack/observability: Add Parca, Bump observability tools, Add Grafana scale dashboard (#8754)
-- Devtools: Hack/observability: improve dashboards (#8964)
-- e2e: Ci: collect debug information about leftover processes (#8734)
-- IPAM: Implements Getter interface for IPAddressClaim object (#8374)
-- Machine: Enable configuring the kubernetes rest client timeout for draining nodes (#8917)
-- MachinePool: Add MachinePool Machine implementation in core CAPI components (#8828)
-- MachineSet: MS preflight checks to improve cluster stability (#8595)
-- MULTIPLE_AREAS[KCP/Core/CAPD]: Add flags for configuring rate limits (#8579)
-- util: Move mergeMap to util (#8377)
-
-## :bug: Bug Fixes
-- API: All: only set finalizers if deletionTimestamp is not set (#8949)
-- API: Ensure ownerReference apiVersions are always up to date (#8256)
-- CAPBK: Ignition: start kubeadm after network.target (#8772)
-- CAPBK: Set uninitialized taint only on worker nodes (#8358)
-- CAPD: Add kind mapper (#8880)
-- CAPD: Change the haproxy entrypoint to prevent getting stopped immediately after start (#8685)
-- CAPD: Delegate CAPD port selection to the container runtime (#8642)
-- CAPD: Implement watch filter (#8789)
-- CAPD: Test/capd: fix kind mapper entry for v1.25.11 (#8914)
-- CAPD: Test/e2e fix fail-swap-on=false flag not being part of kind images anymore (#8767)
-- CAPIM: Fix cluster deletion in the in-memory API server (#8818)
-- CAPIM: Fix inmemory provider docker build (#8822)
-- CAPIM: Test/e2e/in-memory: set providerID after VM is provisioned (#8879)
-- CI: Always build Kind images for upgrade tests (#8859)
-- CI: Ensure ALWAYS_BUILD_KIND_IMAGES is defaulted correctly in ci script (#8873)
-- CI: Verifier: use pull_request instead of pull_request_target (#8635)
-- ClusterCacheTracker: Stop pod caching when checking workload cluster (#8850)
-- ClusterClass: Avoid errors when MHC and upgrade occur together in classy clusters (#8464)
-- ClusterClass: Drop uid from error messages (#8333)
-- ClusterClass: Topology controller should avoid unnecessary rollouts during upgrades (#8628)
-- ClusterClass: Update TopologyReconciled condition on cluster deletion (#8422)
-- ClusterClass: Validate variables in defaulting webhook (#8332)
-- clusterctl: Add soft ownership from clusters to ClusterResourceSetBinding (#8318)
-- clusterctl: Ensure all GitHub releases are fetched when searching provider versions (#8240)
-- clusterctl: Handle nil pointer in clusterctl describe (#8724)
-- clusterctl: Return early if release for latest tag does not exist yet (#8253)
-- clusterctl: Return error on infra cluster and control plane discovery (#8604)
-- clusterctl: Use local kustomize version in create-local-repository.py (#8414)
-- ClusterResourceSet: : Make sure the Kubernetes API Server service already created on remote cluster before applying ClusterResourceSets (#8048)
-- ClusterResourceSet: Continue applying when apply for a single cluster failed (#8611)
-- Dependency: Bump to docker v24.0.5-0.20230714235725-36e9e796c6fc (#9042)
-- Dependency: Update kindnetd and kindest/haproxy (#8469)
-- Devtools: Change tilt debug base image to golang (#9072)
-- Devtools: Tilt: fix build_engine setting when using podman (#8972)
-- Devtools: Tilt: set CR logger in tilt-prepare, fix allowed contexts (#8919)
-- Devtools: Update clean-charts make target for new paths (#8904)
-- e2e: Adjust machinepool helper e2e timeout (#8739)
-- e2e: Fix length check in MD helper (#8352)
-- e2e: Ignore cert annotation in rollout test (#8761)
-- e2e: Increase timeout for clusterclass rollout test (#8897)
-- e2e: Increased assertClusterObjects timeout (#8758)
-- e2e: Pin kindest/node images to known good versions in clusterctl upgrade tests (#8860)
-- e2e: Remove non-functioning ginkgo.no-color flag (#8703)
-- e2e: Revert "Add calico as e2e test CNI" (#8575)
-- e2e: Test/e2e check for machines being ready after provisioning on Runtime SDK test (#8625)
-- e2e: Test/e2e: use topology cluster-template for clusterctl upgrade mgmt cluster (#8311)
-- e2e: Test/framework fix docker pod log collector (#8634)
-- IPAM: Fix gateway being required for IPAddress (#8506)
-- KCP: Allow machine rollout if cert reconcile fails (#8711)
-- KCP: Enable updates from CloudInit (mostly ubuntu) based KCPs to Ignition (flatcar) based KCPs (#8339)
-- KCP: Ensure nil-pointer check in KCP syncMachines (#8481)
-- KCP: Prevent KCP to create many private keys for each reconcile (#8617)
-- KCP: Requeue KCP object if ControlPlaneComponentsHealthyCondition is not yet true (#9035)
-- Machine: Bug fix to set node interruptible label (#8297)
-- Machine: Fix node label propagation (#8427)
-- MachinePool: Add node watcher to MachinePool controller (#8443)
-- MachinePool: Always patch owned conditions, fix GetTypedPhase, doc fixes (#8627)
-- MachinePool: Fix MachinePool node taint patching (#8462)
-- MachinePool: Update MachinePool bootstrap dataSecretName when bootstrap config changes (#8667)
-- Release: Alphabetically sorting release tool output (#9060)
-- Release: Hack/release-notes: ensure relase notes tool can be used for external projects again (#9021)
-- Testing: Catch failure when fetching component URLs (#8455)
-- Testing: Fix flake in machine phases test (#8370)
-- Testing: Fix flaky wait in CRS test (#8334)
-- Testing: Internal/machine-controller fix flakes in phases test (#8576)
-- Testing: Machine-controller: fix phase tests race condition in tests on lastUpdated field (#8484)
-- Testing: Use CreateAndWait in MP ScaleFromZero test (#8927)
-
-## :seedling: Others
-- API: Deprecate v1alpha3 and v1alpha4 in CRDs (#8687)
-- CAPBK: Replace reflect deepequal in bootstrap kubeadm (#8266)
-- CAPD: Automatically set kubelet args for capd (#8881)
-- CAPD: Only ignore necessary kubeadm preflight errors (#7911)
-- CAPIM: Add ClusterClass support for in-memory provider (#8807)
-- CAPIM: Add startup timeout to the in memory provider (#8831)
-- CAPIM: Add watch to in-memory server multiplexer (#8851)
-- CAPIM: Enable update for coreDNS and kube-proxy (#8899)
-- CAPIM: Fix readme for in-memory provider (#8905)
-- CAPIM: Fixups for watch in in-memory apiServer (#8898)
-- CAPIM: Improve etcd management in CAPIM (#8906)
-- CAPIM: In-memory provider: add apiserver & etcd metrics (#8962)
-- CAPIM: Test/e2e/in-memory: enable unit tests (#8886)
-- CAPIM: Test/e2e/in-memory: improve locking, return errors instead of panic (#8945)
-- CAPIM: Test/e2e/in-memory: improve performance by fixing locking issues (#8895)
-- CAPIM: Test/e2e/in-memory: sync in-memory provider ClusterClass with test (#8892)
-- CAPIM: Test/infra/inmemory: rename controller files (#8830)
-- CI: Add area/dependency label for dependabot when bumping gomod (#8410)
-- CI: Add dependency label to github actions update (#8845)
-- CI: Switch cloudbuild.yaml to e2 machine type (#8428)
-- CI: Verifier: change back to pull_request_target to make it work again (#8637)
-- ClusterCacheTracker: Deprecate DefaultIndex usage and remove where not needed (#8855)
-- ClusterCacheTracker: Ensure Get/List calls are not getting stuck when apiserver is unreachable (#9030)
-- ClusterCacheTracker: Fix accessor deletion on health check failure (#9031)
-- ClusterCacheTracker: Improve error when workload cluster is not reachable (#8801)
-- ClusterCacheTracker: Use ClusterCacheTracker consistently (instead of NewClusterClient) (#8744)
-- ClusterCacheTracker: Use rest config from ClusterCacheTracker consistently (#8894)
-- ClusterClass: Cluster/topology: use cached Cluster get in Reconcile (#8936)
-- ClusterClass: Cluster/topology: use cached MD list in get current state (#8922)
-- ClusterClass: Deprecate rolloutAfter in cluster topology (#8324)
-- ClusterClass: Upgrading control plane should only be blocked if MD are upgrading (not just rolling out) (#8658)
-- clusterctl: Add labels to OWNERS file (#8342)
-- clusterctl: Add move annotation on objects for cluster move operation (#8322)
-- clusterctl: Bump controller-tools to v0.12 (#8581)
-- clusterctl: CAPIM: use consistent spelling for release artifacts (#8853)
-- clusterctl: Drop cgroup-driver patch for CAPD (#8921)
-- clusterctl: Fix spelling mistake in clusterctl comment (#8344)
-- clusterctl: Prepare main branch for v1.5 development (#8430)
-- clusterctl: Update cert-manager to v1.12.2 (#8883)
-- Core: Cache unstructured in Cluster, MD and MS controller (#8916)
-- Core: Remove unnecessary requeues (#8743)
-- Dependency: Bump actions/checkout from 3.3.0 to 3.4.0 (#8321)
-- Dependency: Bump actions/checkout from 3.4.0 to 3.5.0 (#8389)
-- Dependency: Bump actions/checkout from 3.5.0 to 3.5.2 (#8540)
-- Dependency: Bump actions/checkout from 3.5.2 to 3.5.3 (#8837)
-- Dependency: Bump actions/setup-go from 3.5.0 to 4.0.1 (#8664)
-- Dependency: Bump docker to v24.0.5 (#9065)
-- Dependency: Bump docker/distribution to v2.8.2 (#8645)
-- Dependency: Bump EndBug/add-and-commit from 9.1.1 to 9.1.2 (#8584)
-- Dependency: Bump EndBug/add-and-commit from 9.1.2 to 9.1.3 (#8621)
-- Dependency: Bump gcb-docker-gcloud from v20230424-910a2a439d to v20230522-312425ae46 (#8770)
-- Dependency: Bump gcb-docker-gcloud image (#8570)
-- Dependency: Bump github.com/emicklei/go-restful/v3  from 3.9.0 to 3.10.2 in /test (#9056)
-- Dependency: Bump github.com/go-logr/logr from 1.2.3 to 1.2.4 (#8461)
-- Dependency: Bump github.com/onsi/ginkgo/v2 from 2.10.0 to 2.11.0 (#8891)
-- Dependency: Bump github.com/onsi/ginkgo/v2 from 2.9.2 to 2.9.4 (#8622)
-- Dependency: Bump github.com/onsi/ginkgo/v2 from 2.9.4 to 2.9.5 (#8666)
-- Dependency: Bump github.com/onsi/ginkgo/v2 from 2.9.5 to 2.9.7 (#8792)
-- Dependency: Bump github.com/onsi/ginkgo/v2 from 2.9.7 to 2.10.0 (#8839)
-- Dependency: Bump github.com/onsi/gomega from 1.27.4 to 1.27.5 (#8390)
-- Dependency: Bump github.com/onsi/gomega from 1.27.6 to 1.27.7 (#8715)
-- Dependency: Bump github.com/onsi/gomega from 1.27.7 to 1.27.8 (#8841)
-- Dependency: Bump github.com/prometheus/client_golang from 1.14.0 to 1.15.0 (#8541)
-- Dependency: Bump github.com/prometheus/client_golang from 1.15.0 to 1.15.1 (#8623)
-- Dependency: Bump github.com/prometheus/client_golang from 1.15.1 to 1.16.0 (#8890)
-- Dependency: Bump github.com/spf13/cobra from 1.6.1 to 1.7.0 (#8502)
-- Dependency: Bump github.com/spf13/viper from 1.15.0 to 1.16.0 (#8791)
-- Dependency: Bump golang version (1.20.3 -> 1.20.4) (#8749)
-- Dependency: Bump golang.org/x/oauth2 from 0.6.0 to 0.7.0 (#8503)
-- Dependency: Bump golang.org/x/oauth2 from 0.7.0 to 0.8.0 (#8665)
-- Dependency: Bump golang.org/x/oauth2 from 0.8.0 to 0.9.0 (#8889)
-- Dependency: Bump golang.org/x/oauth2 from 0.9.0 to 0.10.0 (#8985)
-- Dependency: Bump golang.org/x/text from 0.8.0 to 0.9.0 (#8504)
-- Dependency: Bump golang.org/x/text from 0.9.0 to 0.10.0 (#8840)
-- Dependency: Bump golangci-lint to 1.52.1 and fix findings (#8331)
-- Dependency: Bump golangci-lint to v1.51.2 (#8312)
-- Dependency: Bump golangci/golangci-lint-action from 3.4.0 to 3.5.0 (#8790)
-- Dependency: Bump golangci/golangci-lint-action from 3.5.0 to 3.6.0 (#8838)
-- Dependency: Bump gomodules.xyz/jsonpatch/v2 from 2.2.0 to 2.3.0 (#8716)
-- Dependency: Bump kind to v0.19.0 (#8681)
-- Dependency: Bump kindnet and haproxy images to latest (#8676)
-- Dependency: Bump to Go 1.20.6 (#9058)
-- Dependency: Update cert manager to v1.11.1 (#8529)
-- Dependency: Update cert-manager to v1.11.2 (#8638)
-- Dependency: Update cert-manager to v1.12.0 (#8702)
-- Dependency: Update cert-manager to v1.12.1 (#8748)
-- Dependency: Update controller runtime to 0.14.6 (#8405)
-- Dependency: Update controller tools to v0.11.4 (#8547)
-- Dependency: Update conversion-gen version (v0.26.0 -> v0.27.1) (#8573)
-- Dependency: Update docker to v20.10.24 (#8475)
-- Dependency: Update golangci-lint to v1.53.3 (#8796)
-- Dependency: Update kind to v0.18.0 (#8433)
-- Dependency: Update KIND to v0.20.0 (#8908)
-- Dependency: Update kpromo to v3.5.2 (#8487)
-- Dependency: Update kpromo to v3.6.0 (#8680)
-- Dependency: Update kubebuilder envtest (1.26.0 -> 1.27.1) (#8599)
-- Dependency: Upgrade golang version (1.19.6 -> 1.20.3) (#8527)
-- Devtools: Add go.work to .gitignore and .dockerignore (#8155)
-- Devtools: Align kind registry script with upstream (#8731)
-- Devtools: All: Add flags to enable block profiling (#8934)
-- Devtools: Build golangci-lint locally (#8933)
-- Devtools: Bump containerd to 1.6.18 in hack/tools (#8523)
-- Devtools: Hack/observability: add apiserver request dashboards (#8978)
-- Devtools: Hack/observability: Add Grafana state dashboard, improve metrics (#8834)
-- Devtools: Hack/observability: add metrics-server chart (#8950)
-- Devtools: Hack/observability: add tempo (for traces) (#8920)
-- Devtools: Hack/observability: Bump Loki, Grafana and promtail charts (#7182)
-- Devtools: Hack/observability: disable unused loki-gateway (#8794)
-- Devtools: Hack/observability: improve Grafana dashboards (#8861)
-- Devtools: Hack/observability: move charts so they are ignored by go mod (#8795)
-- Devtools: Hack/observability: skip preload images on non-kind clusters (#8931)
-- Devtools: Hack/observability: use 20 Gi of storage for Prometheus (#8961)
-- Devtools: Pin delve to match go minor version (#8725)
-- Devtools: Protect well know registry from accidental push during tilt up (#8930)
-- e2e: Add E2E test for MachineSet Preflight checks (#8698)
-- e2e: Add improvements to scale e2e (#8910)
-- e2e: Add Scale e2e - development only (#8833)
-- e2e: Add SHA to default KIND image used in e2e tests (#8975)
-- e2e: Assert E2E error responses when waiting for MD nodes (#8501)
-- e2e: Autoscaler e2e test (#8514)
-- e2e: Disable fail-fast by default for e2e tests (#8548)
-- e2e: Improve gomega fail handling in clusterClass rollout (#8769)
-- e2e: Improve logging for MachinePool upgrade test (#8728)
-- e2e: Log leftover processes to eventually detect zombies (#8662)
-- e2e: Modify scale e2e test defaults (#8902)
-- e2e: Move ClusterClass quickstart test from e2e-informing to e2e-main (#8765)
-- e2e: Pin cgroup driver used in v0.3 and v0.4 templates (#8684)
-- e2e: Test/e2e: add field to scale test to deploy Clusters in separate namespace (#8963)
-- e2e: Test/e2e: also dump workload cluster kube-system pods (#8800)
-- e2e: Test/e2e: cleanup test files (#8557)
-- e2e: Test/e2e: Fixup dump kube-system pods (#8809)
-- e2e: Test/e2e: improve logging for a detected rollout (#8953)
-- e2e: Test/e2e: increase apply timeout to 1m (#8941)
-- e2e: Test/framework: add functions to collect infrastructure logs in tests (#8675)
-- e2e: Unhold CI packages before installing (#7910)
-- IPAM: Make IPAddressClaim.Status.AddressRef optional (#8493)
-- KCP: Avoid panic if etcd server misbehaves (#8862)
-- KCP: Cache secrets between LookupOrGenerate and ensureCertificatesOwnerRef (#8926)
-- KCP: Cache unstructured (#8913)
-- KCP: Change endpoints to endpoint in the etcd client (#8909)
-- KCP: Drop redundant get machines (#8912)
-- KCP: Fix noisy error log triggered by missing patch helper (#8863)
-- KCP: Improve error log on scale up when Machine doesn't have a nodeRef (#8564)
-- KCP: Kcp use one workload cluster for reconcile (#8900)
-- KCP: Log the reason of a Machine rollout (#8959)
-- KCP: Remove v1alpha2 adoption logic from KCP (#8328)
-- Machine: Controller/machine: use unstructured caching client (#8896)
-- Machine: Optimize `reconcileInterruptibleNodeLabel` of machine controller (#8852)
-- Machine: Use providerID string as-is (#8577)
-- MachineDeployment: Drop the first return value from FindOldMachineSets (#8415)
-- MachineSet: Add MachineFinalizer during machine computation (#8463)
-- MachineSet: Surface failed preflight checks on MachineSet in `MachinesCreated` condition (#8669)
-- MULTIPLE_AREAS[ClusterCacheTracker/KCP/CAPBK]: Cache secrets in KCP, CABPK and ClusterCacheTracker (#8940)
-- Release: Add area label lookup for prefixes to release notes tool (#8780)
-- Release: Add runtime extension components to release (#8438)
-- Release: Bump kpromo to v3.5.1 (#8301)
-- Release: Fixed grammatically incorrect plurals in release tools (#9054)
-- Release: Improve release notes formatting (#8826)
-- Release: Improve release notes output (#8928)
-- Release: Make release notes generation concurrent (#8817)
-- Runtime SDK: Update handler name validation rules (#8280)
-- Testing: Add calico as e2e test CNI (#8420)
-- Testing: Add dualstack e2e test (#8517)
-- Testing: Add unit test for health check during creation of a new cluster accessor (#8269)
-- Testing: Allow overriding gingko args in e2e tests (#8365)
-- Testing: Fix typos in phrase "to exist" (#8688)
-- Testing: Merge ownerReference tests with quick start (#8264)
-- Testing: Update e2e upgrade test versions (#8361)
-- Testing: Update version matrix for github workflows (#8398)
-- Testing: Validating the warnings in tests (#8778)
-- util: Cache list calls in cluster to objects mapper (#8918)
-- util: Move `internal.labels` to `format` package for use by providers (#9006)
-- util: Rename internal/util/ssa util functions for better naming consistency (#8423)
-
-:book: Additionally, there have been 72 contributions to our documentation and book. (#8252, #8279, #8284, #8288, #8293, #8307, #8308, #8309, #8319, #8327, #8351, #8355, #8363, #8375, #8383, #8397, #8416, #8419, #8439, #8446, #8447, #8454, #8508, #8509, #8510, #8511, #8520, #8521, #8552, #8554, #8559, #8580, #8587, #8593, #8596, #8597, #8612, #8613, #8630, #8632, #8651, #8661, #8673, #8686, #8699, #8701, #8712, #8719, #8729, #8740, #8753, #8760, #8762, #8763, #8775, #8779, #8781, #8782, #8787, #8798, #8802, #8805, #8812, #8843, #8854, #8901, #8924, #8932, #8955, #8956, #8958, #8960) 
-
-
-_Thanks to all our contributors!_ 😊
diff --git a/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go b/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go
index 1e716bc02..3cbea665c 100644
--- a/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go
+++ b/internal/controllers/machinehealthcheck/machinehealthcheck_controller_test.go
@@ -40,7 +40,6 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
 
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/api/v1beta1/index"
@@ -1250,9 +1249,7 @@ func TestMachineHealthCheck_Reconcile(t *testing.T) {
 				},
 			},
 		}
-
-		reqCtx := admission.NewContextWithRequest(ctx, admission.Request{})
-		g.Expect((&webhooks.MachineSet{}).Default(reqCtx, machineSet)).Should(Succeed())
+		g.Expect((&webhooks.MachineSet{}).Default(ctx, machineSet)).Should(Succeed())
 		g.Expect(env.Create(ctx, machineSet)).To(Succeed())
 
 		// Ensure machines have been created.
diff --git a/internal/controllers/topology/cluster/reconcile_state_test.go b/internal/controllers/topology/cluster/reconcile_state_test.go
index cdbda35e6..d9171c490 100644
--- a/internal/controllers/topology/cluster/reconcile_state_test.go
+++ b/internal/controllers/topology/cluster/reconcile_state_test.go
@@ -3241,8 +3241,9 @@ func newFakeMachineDeploymentTopologyState(name string, infrastructureMachineTem
 
 	scheme := runtime.NewScheme()
 	_ = clusterv1.AddToScheme(scheme)
-	if err := (&webhooks.MachineDeployment{}).
-		Default(admission.NewContextWithRequest(ctx, admission.Request{}), mdState.Object); err != nil {
+	if err := (&webhooks.MachineDeployment{
+		Decoder: admission.NewDecoder(scheme),
+	}).Default(admission.NewContextWithRequest(ctx, admission.Request{}), mdState.Object); err != nil {
 		panic(err)
 	}
 	return mdState
diff --git a/internal/webhooks/machinedeployment_test.go b/internal/webhooks/machinedeployment_test.go
index 34125b5b7..ff2823167 100644
--- a/internal/webhooks/machinedeployment_test.go
+++ b/internal/webhooks/machinedeployment_test.go
@@ -52,7 +52,7 @@ func TestMachineDeploymentDefault(t *testing.T) {
 	scheme := runtime.NewScheme()
 	g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed())
 	webhook := &MachineDeployment{
-		decoder: admission.NewDecoder(scheme),
+		Decoder: admission.NewDecoder(scheme),
 	}
 
 	reqCtx := admission.NewContextWithRequest(ctx, admission.Request{
@@ -404,7 +404,7 @@ func TestMachineDeploymentValidation(t *testing.T) {
 			scheme := runtime.NewScheme()
 			g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed())
 			webhook := MachineDeployment{
-				decoder: admission.NewDecoder(scheme),
+				Decoder: admission.NewDecoder(scheme),
 			}
 
 			if tt.expectErr {
@@ -476,7 +476,7 @@ func TestMachineDeploymentVersionValidation(t *testing.T) {
 			scheme := runtime.NewScheme()
 			g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed())
 			webhook := MachineDeployment{
-				decoder: admission.NewDecoder(scheme),
+				Decoder: admission.NewDecoder(scheme),
 			}
 
 			if tt.expectErr {
@@ -538,7 +538,7 @@ func TestMachineDeploymentClusterNameImmutable(t *testing.T) {
 			scheme := runtime.NewScheme()
 			g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed())
 			webhook := MachineDeployment{
-				decoder: admission.NewDecoder(scheme),
+				Decoder: admission.NewDecoder(scheme),
 			}
 
 			warnings, err := webhook.ValidateUpdate(ctx, oldMD, newMD)
@@ -590,7 +590,7 @@ func TestMachineDeploymentTemplateMetadataValidation(t *testing.T) {
 			scheme := runtime.NewScheme()
 			g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed())
 			webhook := MachineDeployment{
-				decoder: admission.NewDecoder(scheme),
+				Decoder: admission.NewDecoder(scheme),
 			}
 
 			if tt.expectErr {
diff --git a/internal/webhooks/machineset_test.go b/internal/webhooks/machineset_test.go
index d9779b799..8ee8ab916 100644
--- a/internal/webhooks/machineset_test.go
+++ b/internal/webhooks/machineset_test.go
@@ -17,15 +17,12 @@ limitations under the License.
 package webhooks
 
 import (
-	"context"
 	"strings"
 	"testing"
 
 	. "github.com/onsi/gomega"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/utils/pointer"
-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
 
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/internal/webhooks/util"
@@ -45,16 +42,10 @@ func TestMachineSetDefault(t *testing.T) {
 			},
 		},
 	}
+	webhook := &MachineSet{}
 
-	scheme := runtime.NewScheme()
-	g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed())
-	webhook := &MachineSet{
-		decoder: admission.NewDecoder(scheme),
-	}
-
-	reqCtx := admission.NewContextWithRequest(ctx, admission.Request{})
-	t.Run("for MachineSet", util.CustomDefaultValidateTest(reqCtx, ms, webhook))
-	g.Expect(webhook.Default(reqCtx, ms)).To(Succeed())
+	t.Run("for MachineSet", util.CustomDefaultValidateTest(ctx, ms, webhook))
+	g.Expect(webhook.Default(ctx, ms)).To(Succeed())
 
 	g.Expect(ms.Labels[clusterv1.ClusterNameLabel]).To(Equal(ms.Spec.ClusterName))
 	g.Expect(ms.Spec.DeletePolicy).To(Equal(string(clusterv1.RandomMachineSetDeletePolicy)))
@@ -63,169 +54,6 @@ func TestMachineSetDefault(t *testing.T) {
 	g.Expect(*ms.Spec.Template.Spec.Version).To(Equal("v1.19.10"))
 }
 
-func TestCalculateMachineSetReplicas(t *testing.T) {
-	tests := []struct {
-		name             string
-		newMS            *clusterv1.MachineSet
-		oldMS            *clusterv1.MachineSet
-		expectedReplicas int32
-		expectErr        bool
-	}{
-		{
-			name: "if new MS has replicas set, keep that value",
-			newMS: &clusterv1.MachineSet{
-				Spec: clusterv1.MachineSetSpec{
-					Replicas: pointer.Int32(5),
-				},
-			},
-			expectedReplicas: 5,
-		},
-		{
-			name:             "if new MS does not have replicas set and no annotations, use 1",
-			newMS:            &clusterv1.MachineSet{},
-			expectedReplicas: 1,
-		},
-		{
-			name: "if new MS only has min size annotation, fallback to 1",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-					},
-				},
-			},
-			expectedReplicas: 1,
-		},
-		{
-			name: "if new MS only has max size annotation, fallback to 1",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			expectedReplicas: 1,
-		},
-		{
-			name: "if new MS has min and max size annotation and min size is invalid, fail",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "abc",
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "if new MS has min and max size annotation and max size is invalid, fail",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-						clusterv1.AutoscalerMaxSizeAnnotation: "abc",
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "if new MS has min and max size annotation and new MS is a new MS, use min size",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			expectedReplicas: 3,
-		},
-		{
-			name: "if new MS has min and max size annotation and old MS doesn't have replicas set, use min size",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			oldMS:            &clusterv1.MachineSet{},
-			expectedReplicas: 3,
-		},
-		{
-			name: "if new MS has min and max size annotation and old MS replicas is below min size, use min size",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			oldMS: &clusterv1.MachineSet{
-				Spec: clusterv1.MachineSetSpec{
-					Replicas: pointer.Int32(1),
-				},
-			},
-			expectedReplicas: 3,
-		},
-		{
-			name: "if new MS has min and max size annotation and old MS replicas is above max size, use max size",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			oldMS: &clusterv1.MachineSet{
-				Spec: clusterv1.MachineSetSpec{
-					Replicas: pointer.Int32(15),
-				},
-			},
-			expectedReplicas: 7,
-		},
-		{
-			name: "if new MS has min and max size annotation and old MS replicas is between min and max size, use old MS replicas",
-			newMS: &clusterv1.MachineSet{
-				ObjectMeta: metav1.ObjectMeta{
-					Annotations: map[string]string{
-						clusterv1.AutoscalerMinSizeAnnotation: "3",
-						clusterv1.AutoscalerMaxSizeAnnotation: "7",
-					},
-				},
-			},
-			oldMS: &clusterv1.MachineSet{
-				Spec: clusterv1.MachineSetSpec{
-					Replicas: pointer.Int32(4),
-				},
-			},
-			expectedReplicas: 4,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			g := NewWithT(t)
-
-			replicas, err := calculateMachineSetReplicas(context.Background(), tt.oldMS, tt.newMS, false)
-
-			if tt.expectErr {
-				g.Expect(err).To(HaveOccurred())
-				return
-			}
-
-			g.Expect(err).ToNot(HaveOccurred())
-			g.Expect(replicas).To(Equal(tt.expectedReplicas))
-		})
-	}
-}
-
 func TestMachineSetLabelSelectorMatchValidation(t *testing.T) {
 	tests := []struct {
 		name      string
diff --git a/test/go.mod b/test/go.mod
index a95a49294..320e9d4de 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -13,7 +13,7 @@ require (
 	github.com/flatcar/ignition v0.36.2
 	github.com/go-logr/logr v1.3.0
 	github.com/google/go-cmp v0.6.0
-	github.com/onsi/ginkgo/v2 v2.13.2
+	github.com/onsi/ginkgo/v2 v2.13.1
 	github.com/onsi/gomega v1.30.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.17.0
@@ -21,7 +21,7 @@ require (
 	github.com/vincent-petithory/dataurl v1.0.0
 	go.etcd.io/etcd/api/v3 v3.5.10
 	go.etcd.io/etcd/client/v3 v3.5.10
-	golang.org/x/net v0.19.0
+	golang.org/x/net v0.18.0
 	google.golang.org/grpc v1.59.0
 	k8s.io/api v0.28.4
 	k8s.io/apiextensions-apiserver v0.28.4
@@ -133,12 +133,12 @@ require (
 	go.opentelemetry.io/proto/otlp v1.0.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.25.0 // indirect
-	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/crypto v0.15.0 // indirect
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
-	golang.org/x/oauth2 v0.15.0 // indirect
+	golang.org/x/oauth2 v0.14.0 // indirect
 	golang.org/x/sync v0.4.0 // indirect
-	golang.org/x/sys v0.15.0 // indirect
-	golang.org/x/term v0.15.0 // indirect
+	golang.org/x/sys v0.14.0 // indirect
+	golang.org/x/term v0.14.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.14.0 // indirect
diff --git a/test/go.sum b/test/go.sum
index b5f076062..88a2ba2a8 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -327,8 +327,8 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
-github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
+github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU=
+github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
 github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
 github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -474,8 +474,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
-golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
+golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -550,8 +550,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
-golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
+golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -561,8 +561,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
-golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
+golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
+golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -624,13 +624,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
-golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
+golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
+golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller.go b/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller.go
index d50281f49..e23f46b44 100644
--- a/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller.go
+++ b/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller.go
@@ -20,6 +20,7 @@ package controllers
 import (
 	"context"
 	"fmt"
+	"time"
 
 	"github.com/pkg/errors"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -42,7 +43,6 @@ import (
 	"sigs.k8s.io/cluster-api/controllers/remote"
 	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
 	utilexp "sigs.k8s.io/cluster-api/exp/util"
-	"sigs.k8s.io/cluster-api/internal/util/ssa"
 	"sigs.k8s.io/cluster-api/test/infrastructure/container"
 	infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
 	infraexpv1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/exp/api/v1beta1"
@@ -57,7 +57,8 @@ const (
 	// dockerMachinePoolLabel is the label used to identify the DockerMachinePool that is responsible for a Docker container.
 	dockerMachinePoolLabel = "docker.cluster.x-k8s.io/machine-pool"
 
-	dockerMachinePoolControllerName = "dockermachinepool-controller"
+	// requeueAfter is how long to wait before checking again to see if the DockerMachines are still provisioning or deleting.
+	requeueAfter = 10 * time.Second
 )
 
 // DockerMachinePoolReconciler reconciles a DockerMachinePool object.
@@ -70,7 +71,6 @@ type DockerMachinePoolReconciler struct {
 	// WatchFilterValue is the label value used to filter events prior to reconciliation.
 	WatchFilterValue string
 
-	ssaCache        ssa.Cache
 	recorder        record.EventRecorder
 	externalTracker external.ObjectTracker
 }
@@ -140,7 +140,7 @@ func (r *DockerMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Re
 
 	// Handle deleted machines
 	if !dockerMachinePool.ObjectMeta.DeletionTimestamp.IsZero() {
-		return ctrl.Result{}, r.reconcileDelete(ctx, cluster, machinePool, dockerMachinePool)
+		return r.reconcileDelete(ctx, cluster, machinePool, dockerMachinePool)
 	}
 
 	// Add finalizer and the InfrastructureMachineKind if they aren't already present, and requeue if either were added.
@@ -194,22 +194,21 @@ func (r *DockerMachinePoolReconciler) SetupWithManager(ctx context.Context, mgr
 		return errors.Wrap(err, "failed setting up with a controller manager")
 	}
 
-	r.recorder = mgr.GetEventRecorderFor(dockerMachinePoolControllerName)
+	r.recorder = mgr.GetEventRecorderFor("dockermachinepool-controller")
 	r.externalTracker = external.ObjectTracker{
 		Controller: c,
 		Cache:      mgr.GetCache(),
 	}
-	r.ssaCache = ssa.NewCache()
 
 	return nil
 }
 
-func (r *DockerMachinePoolReconciler) reconcileDelete(ctx context.Context, cluster *clusterv1.Cluster, machinePool *expv1.MachinePool, dockerMachinePool *infraexpv1.DockerMachinePool) error {
+func (r *DockerMachinePoolReconciler) reconcileDelete(ctx context.Context, cluster *clusterv1.Cluster, machinePool *expv1.MachinePool, dockerMachinePool *infraexpv1.DockerMachinePool) (ctrl.Result, error) {
 	log := ctrl.LoggerFrom(ctx)
 
 	dockerMachineList, err := getDockerMachines(ctx, r.Client, *cluster, *machinePool, *dockerMachinePool)
 	if err != nil {
-		return err
+		return ctrl.Result{}, err
 	}
 
 	if len(dockerMachineList.Items) > 0 {
@@ -230,9 +229,10 @@ func (r *DockerMachinePoolReconciler) reconcileDelete(ctx context.Context, clust
 		}
 
 		if len(errs) > 0 {
-			return kerrors.NewAggregate(errs)
+			return ctrl.Result{}, kerrors.NewAggregate(errs)
 		}
-		return nil
+
+		return ctrl.Result{RequeueAfter: requeueAfter}, nil
 	}
 
 	// Once there are no DockerMachines left, ensure there are no Docker containers left behind.
@@ -243,21 +243,21 @@ func (r *DockerMachinePoolReconciler) reconcileDelete(ctx context.Context, clust
 	// List Docker containers, i.e. external machines in the cluster.
 	externalMachines, err := docker.ListMachinesByCluster(ctx, cluster, labelFilters)
 	if err != nil {
-		return errors.Wrapf(err, "failed to list all machines in the cluster with label \"%s:%s\"", dockerMachinePoolLabel, dockerMachinePool.Name)
+		return ctrl.Result{}, errors.Wrapf(err, "failed to list all machines in the cluster with label \"%s:%s\"", dockerMachinePoolLabel, dockerMachinePool.Name)
 	}
 
 	// Providers should similarly ensure that all infrastructure instances are deleted even if the InfraMachine has not been created yet.
 	for _, externalMachine := range externalMachines {
 		log.Info("Deleting Docker container", "container", externalMachine.Name())
 		if err := externalMachine.Delete(ctx); err != nil {
-			return errors.Wrapf(err, "failed to delete machine %s", externalMachine.Name())
+			return ctrl.Result{}, errors.Wrapf(err, "failed to delete machine %s", externalMachine.Name())
 		}
 	}
 
 	// Once all DockerMachines and Docker containers are deleted, remove the finalizer.
 	controllerutil.RemoveFinalizer(dockerMachinePool, infraexpv1.MachinePoolFinalizer)
 
-	return nil
+	return ctrl.Result{}, nil
 }
 
 func (r *DockerMachinePoolReconciler) reconcileNormal(ctx context.Context, cluster *clusterv1.Cluster, machinePool *expv1.MachinePool, dockerMachinePool *infraexpv1.DockerMachinePool) (ctrl.Result, error) {
@@ -318,7 +318,11 @@ func (r *DockerMachinePoolReconciler) reconcileNormal(ctx context.Context, clust
 		return ctrl.Result{}, nil
 	}
 
-	return r.updateStatus(ctx, cluster, machinePool, dockerMachinePool, dockerMachineList.Items)
+	dockerMachinePool.Status.Ready = false
+	conditions.MarkFalse(dockerMachinePool, expv1.ReplicasReadyCondition, expv1.WaitingForReplicasReadyReason, clusterv1.ConditionSeverityInfo, "")
+
+	// if some machine is still provisioning, force reconcile in few seconds to check again infrastructure.
+	return ctrl.Result{RequeueAfter: requeueAfter}, nil
 }
 
 func getDockerMachines(ctx context.Context, c client.Client, cluster clusterv1.Cluster, machinePool expv1.MachinePool, dockerMachinePool infraexpv1.DockerMachinePool) (*infrav1.DockerMachineList, error) {
@@ -376,64 +380,6 @@ func dockerMachineToDockerMachinePool(_ context.Context, o client.Object) []ctrl
 	return nil
 }
 
-// updateStatus updates the Status field for the MachinePool object.
-// It checks for the current state of the replicas and updates the Status of the MachineSet.
-func (r *DockerMachinePoolReconciler) updateStatus(ctx context.Context, cluster *clusterv1.Cluster, machinePool *expv1.MachinePool, dockerMachinePool *infraexpv1.DockerMachinePool, dockerMachines []infrav1.DockerMachine) (ctrl.Result, error) {
-	log := ctrl.LoggerFrom(ctx)
-
-	// List the Docker containers. This corresponds to an InfraMachinePool instance for providers.
-	labelFilters := map[string]string{dockerMachinePoolLabel: dockerMachinePool.Name}
-	externalMachines, err := docker.ListMachinesByCluster(ctx, cluster, labelFilters)
-	if err != nil {
-		return ctrl.Result{}, errors.Wrapf(err, "failed to list all external machines in the cluster")
-	}
-
-	externalMachineMap := make(map[string]*docker.Machine)
-	for _, externalMachine := range externalMachines {
-		externalMachineMap[externalMachine.Name()] = externalMachine
-	}
-	// We can use reuse getDeletionCandidates to get the list of ready DockerMachines and avoid another API call, even though we aren't deleting them here.
-	_, readyMachines, err := r.getDeletionCandidates(ctx, dockerMachines, externalMachineMap, machinePool, dockerMachinePool)
-	if err != nil {
-		return ctrl.Result{}, err
-	}
-
-	readyReplicaCount := len(readyMachines)
-	desiredReplicas := int(*machinePool.Spec.Replicas)
-
-	switch {
-	// We are scaling up
-	case readyReplicaCount < desiredReplicas:
-		conditions.MarkFalse(dockerMachinePool, clusterv1.ResizedCondition, clusterv1.ScalingUpReason, clusterv1.ConditionSeverityWarning, "Scaling up MachineSet to %d replicas (actual %d)", desiredReplicas, readyReplicaCount)
-	// We are scaling down
-	case readyReplicaCount > desiredReplicas:
-		conditions.MarkFalse(dockerMachinePool, clusterv1.ResizedCondition, clusterv1.ScalingDownReason, clusterv1.ConditionSeverityWarning, "Scaling down MachineSet to %d replicas (actual %d)", desiredReplicas, readyReplicaCount)
-	default:
-		// Make sure last resize operation is marked as completed.
-		// NOTE: we are checking the number of machines ready so we report resize completed only when the machines
-		// are actually provisioned (vs reporting completed immediately after the last machine object is created). This convention is also used by KCP.
-		if len(dockerMachines) == readyReplicaCount {
-			if conditions.IsFalse(dockerMachinePool, clusterv1.ResizedCondition) {
-				log.Info("All the replicas are ready", "replicas", readyReplicaCount)
-			}
-			conditions.MarkTrue(dockerMachinePool, clusterv1.ResizedCondition)
-		}
-		// This means that there was no error in generating the desired number of machine objects
-		conditions.MarkTrue(dockerMachinePool, clusterv1.MachinesCreatedCondition)
-	}
-
-	getters := make([]conditions.Getter, 0, len(dockerMachines))
-	for i := range dockerMachines {
-		getters = append(getters, &dockerMachines[i])
-	}
-
-	// Aggregate the operational state of all the machines; while aggregating we are adding the
-	// source ref (reason@machine/name) so the problem can be easily tracked down to its source machine.
-	conditions.SetAggregate(dockerMachinePool, expv1.ReplicasReadyCondition, getters, conditions.AddSourceRef())
-
-	return ctrl.Result{}, nil
-}
-
 func patchDockerMachinePool(ctx context.Context, patchHelper *patch.Helper, dockerMachinePool *infraexpv1.DockerMachinePool) error {
 	conditions.SetSummary(dockerMachinePool,
 		conditions.WithConditions(
diff --git a/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller_phases.go b/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller_phases.go
index 414a44c16..1a7201c53 100644
--- a/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller_phases.go
+++ b/test/infrastructure/docker/exp/internal/controllers/dockermachinepool_controller_phases.go
@@ -33,7 +33,6 @@ import (
 
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
-	"sigs.k8s.io/cluster-api/internal/util/ssa"
 	infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
 	infraexpv1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/exp/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/docker"
@@ -143,22 +142,16 @@ func (r *DockerMachinePoolReconciler) reconcileDockerMachines(ctx context.Contex
 	// Create a DockerMachine for each Docker container so we surface the information to the user. Use the same name as the Docker container for the Docker Machine for ease of lookup.
 	// Providers should iterate through their infrastructure instances and ensure that each instance has a corresponding InfraMachine.
 	for _, machine := range externalMachines {
-		if existingMachine, ok := dockerMachineMap[machine.Name()]; ok {
-			log.V(2).Info("Patching existing DockerMachine", "name", existingMachine.Name)
-			desiredMachine := computeDesiredDockerMachine(machine.Name(), cluster, machinePool, dockerMachinePool, &existingMachine)
-			if err := ssa.Patch(ctx, r.Client, dockerMachinePoolControllerName, desiredMachine, ssa.WithCachingProxy{Cache: r.ssaCache, Original: &existingMachine}); err != nil {
-				return errors.Wrapf(err, "failed to update DockerMachine %q", klog.KObj(desiredMachine))
-			}
-
-			dockerMachineMap[desiredMachine.Name] = *desiredMachine
-		} else {
+		if _, ok := dockerMachineMap[machine.Name()]; !ok {
 			log.V(2).Info("Creating a new DockerMachine for Docker container", "container", machine.Name())
-			desiredMachine := computeDesiredDockerMachine(machine.Name(), cluster, machinePool, dockerMachinePool, nil)
-			if err := ssa.Patch(ctx, r.Client, dockerMachinePoolControllerName, desiredMachine); err != nil {
+			dockerMachine, err := r.createDockerMachine(ctx, machine.Name(), cluster, machinePool, dockerMachinePool)
+			if err != nil {
 				return errors.Wrap(err, "failed to create a new docker machine")
 			}
 
-			dockerMachineMap[desiredMachine.Name] = *desiredMachine
+			dockerMachineMap[dockerMachine.Name] = *dockerMachine
+		} else {
+			log.V(4).Info("DockerMachine already exists, nothing to do", "name", machine.Name())
 		}
 	}
 
@@ -240,15 +233,30 @@ func (r *DockerMachinePoolReconciler) reconcileDockerMachines(ctx context.Contex
 	return nil
 }
 
-// computeDesiredDockerMachine creates a DockerMachine to represent a Docker container in a DockerMachinePool.
+// createDockerMachine creates a DockerMachine to represent a Docker container in a DockerMachinePool.
 // These DockerMachines have the clusterv1.ClusterNameLabel and clusterv1.MachinePoolNameLabel to support MachinePool Machines.
-func computeDesiredDockerMachine(name string, cluster *clusterv1.Cluster, machinePool *expv1.MachinePool, dockerMachinePool *infraexpv1.DockerMachinePool, existingDockerMachine *infrav1.DockerMachine) *infrav1.DockerMachine {
+func (r *DockerMachinePoolReconciler) createDockerMachine(ctx context.Context, name string, cluster *clusterv1.Cluster, machinePool *expv1.MachinePool, dockerMachinePool *infraexpv1.DockerMachinePool) (*infrav1.DockerMachine, error) {
+	log := ctrl.LoggerFrom(ctx)
+
+	labels := map[string]string{
+		clusterv1.ClusterNameLabel:     cluster.Name,
+		clusterv1.MachinePoolNameLabel: format.MustFormatValue(machinePool.Name),
+	}
 	dockerMachine := &infrav1.DockerMachine{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace:   dockerMachinePool.Namespace,
 			Name:        name,
-			Labels:      make(map[string]string),
+			Labels:      labels,
 			Annotations: make(map[string]string),
+			OwnerReferences: []metav1.OwnerReference{
+				{
+					APIVersion: dockerMachinePool.APIVersion,
+					Kind:       dockerMachinePool.Kind,
+					Name:       dockerMachinePool.Name,
+					UID:        dockerMachinePool.UID,
+				},
+				// Note: Since the MachinePool controller has not created its owner Machine yet, we want to set the DockerMachinePool as the owner so it's not orphaned.
+			},
 		},
 		Spec: infrav1.DockerMachineSpec{
 			CustomImage:   dockerMachinePool.Spec.Template.CustomImage,
@@ -257,22 +265,13 @@ func computeDesiredDockerMachine(name string, cluster *clusterv1.Cluster, machin
 		},
 	}
 
-	if existingDockerMachine != nil {
-		dockerMachine.SetUID(existingDockerMachine.UID)
-		dockerMachine.SetOwnerReferences(existingDockerMachine.OwnerReferences)
+	log.V(2).Info("Creating DockerMachine", "dockerMachine", dockerMachine.Name)
+
+	if err := r.Client.Create(ctx, dockerMachine); err != nil {
+		return nil, errors.Wrap(err, "failed to create dockerMachine")
 	}
 
-	// Note: Since the MachinePool controller has not created its owner Machine yet, we want to set the DockerMachinePool as the owner so it's not orphaned.
-	dockerMachine.SetOwnerReferences(util.EnsureOwnerRef(dockerMachine.OwnerReferences, metav1.OwnerReference{
-		APIVersion: dockerMachinePool.APIVersion,
-		Kind:       dockerMachinePool.Kind,
-		Name:       dockerMachinePool.Name,
-		UID:        dockerMachinePool.UID,
-	}))
-	dockerMachine.Labels[clusterv1.ClusterNameLabel] = cluster.Name
-	dockerMachine.Labels[clusterv1.MachinePoolNameLabel] = format.MustFormatValue(machinePool.Name)
-
-	return dockerMachine
+	return dockerMachine, nil
 }
 
 // deleteMachinePoolMachine attempts to delete a DockerMachine and its associated owner Machine if it exists.
diff --git a/test/infrastructure/inmemory/internal/cloud/alias.go b/test/infrastructure/inmemory/internal/cloud/alias.go
index 3fc7b0d0d..51daceae1 100644
--- a/test/infrastructure/inmemory/internal/cloud/alias.go
+++ b/test/infrastructure/inmemory/internal/cloud/alias.go
@@ -19,7 +19,6 @@ package cloud
 import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
-	cbuilder "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/builder"
 	cclient "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/client"
 	cmanager "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/manager"
 )
@@ -37,7 +36,4 @@ type Manager cmanager.Manager
 var (
 	// NewManager returns a new Manager for creating Controllers.
 	NewManager = cmanager.New
-
-	// NewControllerManagedBy returns a new controller builder that will be started by the provided Manager.
-	NewControllerManagedBy = cbuilder.ControllerManagedBy
 )
diff --git a/test/infrastructure/inmemory/internal/cloud/doc.go b/test/infrastructure/inmemory/internal/cloud/doc.go
index ac60dfe74..a88deec31 100644
--- a/test/infrastructure/inmemory/internal/cloud/doc.go
+++ b/test/infrastructure/inmemory/internal/cloud/doc.go
@@ -27,7 +27,6 @@ We can't use controller-runtime directly for the following reasons:
 * data should be stored in-memory
 * we would like that objects in memory behave like Kubernetes objects (garbage collection)
 
-The Manager, is the object responsible for the lifecycle of objects; it also allows
-defining controllers.
+The Manager, is the object responsible for the lifecycle of objects.
 */
 package cloud
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/builder/builder.go b/test/infrastructure/inmemory/internal/cloud/runtime/builder/builder.go
deleted file mode 100644
index 9fd02e846..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/builder/builder.go
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package builder
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"strings"
-
-	"k8s.io/apimachinery/pkg/runtime/schema"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
-
-	ccontroller "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/controller"
-	"sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/handler"
-	cmanager "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/manager"
-	cpredicate "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/predicate"
-	creconciler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/reconcile"
-	csource "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/source"
-)
-
-// Builder builds a Controller.
-type Builder struct {
-	forInput         ForInput
-	watchesInput     []WatchesInput
-	mgr              cmanager.Manager
-	globalPredicates []cpredicate.Predicate
-	ctrl             ccontroller.Controller
-	ctrlOptions      ccontroller.Options
-	name             string
-}
-
-// ControllerManagedBy returns a new controller builder that will be started by the provided Manager.
-func ControllerManagedBy(m cmanager.Manager) *Builder {
-	return &Builder{mgr: m}
-}
-
-// ForInput represents the information set by For method.
-type ForInput struct {
-	object     client.Object
-	predicates []cpredicate.Predicate
-	err        error
-}
-
-// For defines the type of Object being *reconciled*, and configures the ControllerManagedBy to respond to create / delete /
-// update events by *reconciling the object*.
-func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder {
-	if blder.forInput.object != nil {
-		blder.forInput.err = fmt.Errorf("method For(...) should only be called once, could not assign multiple objects for reconciliation")
-		return blder
-	}
-	input := ForInput{object: object}
-	for _, opt := range opts {
-		opt.ApplyToFor(&input)
-	}
-
-	blder.forInput = input
-	return blder
-}
-
-// WatchesInput represents the information set by Watches method.
-type WatchesInput struct {
-	src          csource.Source
-	eventhandler handler.EventHandler
-	predicates   []cpredicate.Predicate
-}
-
-// Watches defines the type of Object to watch, and configures the ControllerManagedBy to respond to create / delete /
-// update events by *reconciling the object* with the given EventHandler.
-func (blder *Builder) Watches(src csource.Source, eventhandler handler.EventHandler, opts ...WatchesOption) *Builder {
-	input := WatchesInput{src: src, eventhandler: eventhandler}
-	for _, opt := range opts {
-		opt.ApplyToWatches(&input)
-	}
-
-	blder.watchesInput = append(blder.watchesInput, input)
-	return blder
-}
-
-// WithEventFilter sets the event filters, to filter which create/update/delete/generic events eventually
-// trigger reconciliations.  For example, filtering on whether the resource version has changed.
-// Given predicate is added for all watched objects.
-// Defaults to the empty list.
-func (blder *Builder) WithEventFilter(p cpredicate.Predicate) *Builder {
-	blder.globalPredicates = append(blder.globalPredicates, p)
-	return blder
-}
-
-// WithOptions overrides the controller options use in doController. Defaults to empty.
-func (blder *Builder) WithOptions(options ccontroller.Options) *Builder {
-	blder.ctrlOptions = options
-	return blder
-}
-
-// Named sets the name of the controller to the given name.  The name shows up
-// in metrics, among other things, and thus should be a prometheus compatible name
-// (underscores and alphanumeric characters only).
-//
-// By default, controllers are named using the lowercase version of their kind.
-func (blder *Builder) Named(name string) *Builder {
-	blder.name = name
-	return blder
-}
-
-// Complete builds the Application Controller.
-func (blder *Builder) Complete(r creconciler.Reconciler) error {
-	_, err := blder.Build(r)
-	return err
-}
-
-// Build builds the Application Controller and returns the Controller it created.
-func (blder *Builder) Build(r creconciler.Reconciler) (ccontroller.Controller, error) {
-	if r == nil {
-		return nil, fmt.Errorf("must provide a non-nil Reconciler")
-	}
-	if blder.mgr == nil {
-		return nil, fmt.Errorf("must provide a non-nil Manager")
-	}
-	if blder.forInput.err != nil {
-		return nil, blder.forInput.err
-	}
-
-	// Set the ControllerManagedBy
-	if err := blder.doController(r); err != nil {
-		return nil, err
-	}
-
-	// Set the Watch
-	if err := blder.doWatch(); err != nil {
-		return nil, err
-	}
-
-	return blder.ctrl, nil
-}
-
-func (blder *Builder) doWatch() error {
-	// Reconcile type
-	if blder.forInput.object != nil {
-		i, err := blder.mgr.GetCache().GetInformer(context.TODO(), blder.forInput.object)
-		if err != nil {
-			return err
-		}
-
-		src := &csource.Informer{Informer: i}
-		hdler := &handler.EnqueueRequestForObject{}
-		allPredicates := append(blder.globalPredicates, blder.forInput.predicates...)
-		if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
-			return err
-		}
-	}
-
-	// Do the watch requests
-	if len(blder.watchesInput) == 0 && blder.forInput.object == nil {
-		return errors.New("there are no watches configured, controller will never get triggered. Use For(), Owns() or Watches() to set them up")
-	}
-	for _, w := range blder.watchesInput {
-		allPredicates := append([]cpredicate.Predicate(nil), blder.globalPredicates...)
-		allPredicates = append(allPredicates, w.predicates...)
-
-		if err := blder.ctrl.Watch(w.src, w.eventhandler, allPredicates...); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
-	if blder.name != "" {
-		return blder.name, nil
-	}
-	if !hasGVK {
-		return "", errors.New("one of For() or Named() must be called")
-	}
-	return strings.ToLower(gvk.Kind), nil
-}
-
-func (blder *Builder) doController(r creconciler.Reconciler) error {
-	ctrlOptions := blder.ctrlOptions
-	if ctrlOptions.Reconciler == nil {
-		ctrlOptions.Reconciler = r
-	}
-
-	var gvk schema.GroupVersionKind
-	hasGVK := blder.forInput.object != nil
-	if hasGVK {
-		var err error
-		gvk, err = apiutil.GVKForObject(blder.forInput.object, blder.mgr.GetScheme())
-		if err != nil {
-			return err
-		}
-	}
-
-	// Setup concurrency.
-	if ctrlOptions.Concurrency <= 0 {
-		ctrlOptions.Concurrency = 1
-	}
-
-	controllerName, err := blder.getControllerName(gvk, hasGVK)
-	if err != nil {
-		return err
-	}
-
-	// Build the controller.
-	blder.ctrl, err = ccontroller.New(controllerName, ctrlOptions)
-	if err != nil {
-		return err
-	}
-
-	// Add the controller to the Manager.
-	if err := blder.mgr.AddController(blder.ctrl); err != nil {
-		return err
-	}
-	return err
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/builder/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/builder/doc.go
deleted file mode 100644
index e6015d6ee..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/builder/doc.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package builder provides a builder to build controllers.
-package builder
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/builder/options.go b/test/infrastructure/inmemory/internal/cloud/runtime/builder/options.go
deleted file mode 100644
index a8c4545a8..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/builder/options.go
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package builder
-
-import (
-	cpredicate "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/predicate"
-)
-
-// ForOption is some configuration that modifies options for a For request.
-type ForOption interface {
-	// ApplyToFor applies this configuration to the given for input.
-	ApplyToFor(*ForInput)
-}
-
-// WatchesOption is some configuration that modifies options for a watches request.
-type WatchesOption interface {
-	// ApplyToWatches applies this configuration to the given watches options.
-	ApplyToWatches(*WatchesInput)
-}
-
-// WithPredicates sets the given predicates list.
-func WithPredicates(predicates ...cpredicate.Predicate) Predicates {
-	return Predicates{
-		predicates: predicates,
-	}
-}
-
-// Predicates filters events before enqueuing the keys.
-type Predicates struct {
-	predicates []cpredicate.Predicate
-}
-
-// ApplyToFor applies this configuration to the given ForInput options.
-func (w Predicates) ApplyToFor(opts *ForInput) {
-	opts.predicates = w.predicates
-}
-
-// ApplyToWatches applies this configuration to the given WatchesInput options.
-func (w Predicates) ApplyToWatches(opts *WatchesInput) {
-	opts.predicates = w.predicates
-}
-
-var _ ForOption = &Predicates{}
-var _ WatchesOption = &Predicates{}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/cache/cache.go b/test/infrastructure/inmemory/internal/cloud/runtime/cache/cache.go
index b78e08534..78508a878 100644
--- a/test/infrastructure/inmemory/internal/cloud/runtime/cache/cache.go
+++ b/test/infrastructure/inmemory/internal/cloud/runtime/cache/cache.go
@@ -35,7 +35,6 @@ import (
 )
 
 // Cache implements an in-memory cache.
-// TODO: consider if to move to internal.
 type Cache interface {
 	Start(ctx context.Context) error
 
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/cache/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/cache/doc.go
index fe1f5ad8c..7b4b73aa1 100644
--- a/test/infrastructure/inmemory/internal/cloud/runtime/cache/doc.go
+++ b/test/infrastructure/inmemory/internal/cloud/runtime/cache/doc.go
@@ -18,10 +18,8 @@ limitations under the License.
 Package cache defines resource group aware Cache.
 
 The Cache implements sync loop and garbage collector inspired from the ones existing
-in Kubernetes, but in this case only finalizers are respected while currently there is not
-a concept of ownerReferences.
+in Kubernetes.
 
-Note: The cloud runtime is using a Cache for all the resource groups, so it will be possible
-to implement controllers processing request from all the resources groups.
+Note: The cloud runtime is using a Cache for all the resource groups.
 */
 package cache
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/controller/controller.go b/test/infrastructure/inmemory/internal/cloud/runtime/controller/controller.go
deleted file mode 100644
index 1e3690bfd..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/controller/controller.go
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package controller
-
-import (
-	"context"
-	"fmt"
-	"sync"
-	"sync/atomic"
-	"time"
-
-	"k8s.io/apimachinery/pkg/util/wait"
-	"k8s.io/client-go/util/workqueue"
-	ctrl "sigs.k8s.io/controller-runtime"
-
-	chandler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/handler"
-	cpredicate "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/predicate"
-	creconciler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/reconcile"
-	csource "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/source"
-)
-
-// Options are the arguments for creating a new Controller.
-type Options struct {
-	Concurrency int
-	Reconciler  creconciler.Reconciler
-}
-
-// Controller represents a controller.
-type Controller interface {
-	Watch(src csource.Source, evthdler chandler.EventHandler, prct ...cpredicate.Predicate) error
-	Start(ctx context.Context) error
-}
-
-// New returns a new Controller.
-func New(name string, options Options) (Controller, error) {
-	if name == "" {
-		return nil, fmt.Errorf("name cannot be empty")
-	}
-
-	if options.Reconciler == nil {
-		return nil, fmt.Errorf("reconciler cannot be nil")
-	}
-
-	if options.Concurrency < 1 {
-		return nil, fmt.Errorf("concurrency cannot be less then 1")
-	}
-
-	return &controller{
-		name:             name,
-		reconciler:       options.Reconciler,
-		concurrency:      options.Concurrency,
-		cacheSyncTimeout: 2 * time.Minute,
-	}, nil
-}
-
-type controller struct {
-	name             string
-	reconciler       creconciler.Reconciler
-	concurrency      int
-	cacheSyncTimeout time.Duration // TODO: make this an option
-
-	queue workqueue.RateLimitingInterface
-
-	lock         sync.Mutex
-	startWatches []watchDescription
-	started      bool
-
-	//nolint:containedctx
-	ctx context.Context
-}
-
-type watchDescription struct {
-	src        csource.Source
-	handler    chandler.EventHandler
-	predicates []cpredicate.Predicate
-}
-
-// Watch implements Controller.
-func (c *controller) Watch(src csource.Source, evthdler chandler.EventHandler, prct ...cpredicate.Predicate) error {
-	c.lock.Lock()
-	defer c.lock.Unlock()
-
-	if !c.started {
-		c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct})
-		return nil
-	}
-
-	log := ctrl.LoggerFrom(c.ctx)
-	log.Info("Starting EventSource", "source", src)
-	return src.Start(c.ctx, evthdler, c.queue, prct...)
-}
-
-// Start implements Controller.
-func (c *controller) Start(ctx context.Context) error {
-	if ctx == nil {
-		return fmt.Errorf("context cannot be nil")
-	}
-
-	if c.started {
-		return fmt.Errorf("controller started more than once")
-	}
-
-	c.lock.Lock()
-	defer c.lock.Unlock()
-
-	log := ctrl.LoggerFrom(ctx).WithValues("controller", c.name)
-	ctx = ctrl.LoggerInto(ctx, log)
-	c.ctx = ctx
-
-	log.Info("Starting controller queue")
-	c.queue = workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
-	go func() {
-		<-ctx.Done()
-		c.queue.ShutDown()
-	}()
-
-	for _, watch := range c.startWatches {
-		log.Info("Starting EventSource", "source", watch.src)
-		if err := watch.src.Start(ctx, watch.handler, c.queue, watch.predicates...); err != nil {
-			return err
-		}
-	}
-
-	c.startWatches = nil
-
-	var workers int64
-	go func() {
-		log.Info("Starting reconcile workers", "count", c.concurrency)
-		wg := &sync.WaitGroup{}
-		wg.Add(c.concurrency)
-		for i := 0; i < c.concurrency; i++ {
-			go func() {
-				atomic.AddInt64(&workers, 1)
-				defer wg.Done()
-				for c.processNextWorkItem(ctx) {
-				}
-			}()
-		}
-
-		<-ctx.Done()
-		wg.Wait()
-	}()
-
-	if err := wait.PollUntilContextTimeout(ctx, 50*time.Millisecond, 5*time.Second, false, func(ctx context.Context) (done bool, err error) {
-		if atomic.LoadInt64(&workers) < int64(c.concurrency) {
-			return false, nil
-		}
-		return true, nil
-	}); err != nil {
-		return fmt.Errorf("failed to start reconcile workers: %v", err)
-	}
-	c.started = true
-	return nil
-}
-
-func (c *controller) processNextWorkItem(ctx context.Context) bool {
-	obj, shutdown := c.queue.Get()
-	if shutdown {
-		return false
-	}
-
-	defer c.queue.Done(obj)
-
-	c.reconcileHandler(ctx, obj)
-	return true
-}
-
-func (c *controller) reconcileHandler(ctx context.Context, obj interface{}) {
-	req, ok := obj.(creconciler.Request)
-	if !ok {
-		c.queue.Forget(obj)
-		return
-	}
-
-	// TODO: Inject logger + add log on error
-
-	result, err := c.reconciler.Reconcile(ctx, req)
-	switch {
-	case err != nil:
-		c.queue.AddRateLimited(req)
-	case result.RequeueAfter > 0:
-		c.queue.Forget(obj)
-		c.queue.AddAfter(req, result.RequeueAfter)
-	case result.Requeue:
-		c.queue.AddRateLimited(req)
-	default:
-		c.queue.Forget(obj)
-	}
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/controller/controller_test.go b/test/infrastructure/inmemory/internal/cloud/runtime/controller/controller_test.go
deleted file mode 100644
index 6d6068415..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/controller/controller_test.go
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package controller
-
-import (
-	"context"
-	"testing"
-	"time"
-
-	. "github.com/onsi/gomega"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/types"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-
-	cloudv1 "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/api/v1alpha1"
-	ccache "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/cache"
-	chandler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/handler"
-	creconciler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/reconcile"
-	csource "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/source"
-)
-
-var scheme = runtime.NewScheme()
-
-func init() {
-	_ = cloudv1.AddToScheme(scheme)
-}
-
-type simpleReconciler struct {
-	processed chan creconciler.Request
-}
-
-func (r *simpleReconciler) Reconcile(_ context.Context, req creconciler.Request) (_ creconciler.Result, err error) {
-	r.processed <- req
-	return creconciler.Result{}, nil
-}
-
-func TestController_Queue(t *testing.T) {
-	g := NewWithT(t)
-	ctx, cancelFn := context.WithCancel(context.TODO())
-
-	r := &simpleReconciler{
-		processed: make(chan creconciler.Request),
-	}
-
-	c, err := New("foo", Options{
-		Concurrency: 1,
-		Reconciler:  r,
-	})
-	g.Expect(err).ToNot(HaveOccurred())
-
-	i := &fakeInformer{}
-
-	err = c.Watch(&csource.Informer{
-		Informer: i,
-	}, &chandler.EnqueueRequestForObject{})
-	g.Expect(err).ToNot(HaveOccurred())
-
-	err = c.Start(ctx)
-	g.Expect(err).ToNot(HaveOccurred())
-
-	i.InformCreate("foo", &cloudv1.CloudMachine{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "bar-create",
-		},
-	})
-
-	g.Eventually(func() bool {
-		r := <-r.processed
-		return r == creconciler.Request{
-			ResourceGroup:  "foo",
-			NamespacedName: types.NamespacedName{Name: "bar-create"},
-		}
-	}, 5*time.Second, 100*time.Millisecond).Should(BeTrue())
-
-	i.InformUpdate("foo", &cloudv1.CloudMachine{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "bar-update",
-		},
-	}, &cloudv1.CloudMachine{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "bar-update",
-		},
-	})
-
-	g.Eventually(func() bool {
-		r := <-r.processed
-		return r == creconciler.Request{
-			ResourceGroup:  "foo",
-			NamespacedName: types.NamespacedName{Name: "bar-update"},
-		}
-	}, 5*time.Second, 100*time.Millisecond).Should(BeTrue())
-
-	i.InformDelete("foo", &cloudv1.CloudMachine{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "bar-delete",
-		},
-	})
-
-	g.Eventually(func() bool {
-		r := <-r.processed
-		return r == creconciler.Request{
-			ResourceGroup:  "foo",
-			NamespacedName: types.NamespacedName{Name: "bar-delete"},
-		}
-	}, 5*time.Second, 100*time.Millisecond).Should(BeTrue())
-
-	i.InformGeneric("foo", &cloudv1.CloudMachine{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "bar-generic",
-		},
-	})
-
-	g.Eventually(func() bool {
-		r := <-r.processed
-		return r == creconciler.Request{
-			ResourceGroup:  "foo",
-			NamespacedName: types.NamespacedName{Name: "bar-generic"},
-		}
-	}, 5*time.Second, 100*time.Millisecond).Should(BeTrue())
-
-	close(r.processed)
-	cancelFn()
-}
-
-var _ ccache.Informer = &fakeInformer{}
-
-type fakeInformer struct {
-	handler ccache.InformEventHandler
-}
-
-func (i *fakeInformer) AddEventHandler(handler ccache.InformEventHandler) error {
-	i.handler = handler
-	return nil
-}
-
-func (i *fakeInformer) RemoveEventHandler(_ ccache.InformEventHandler) error {
-	i.handler = nil
-	return nil
-}
-
-func (i *fakeInformer) InformCreate(resourceGroup string, obj client.Object) {
-	i.handler.OnCreate(resourceGroup, obj)
-}
-
-func (i *fakeInformer) InformUpdate(resourceGroup string, oldObj, newObj client.Object) {
-	i.handler.OnUpdate(resourceGroup, oldObj, newObj)
-}
-
-func (i *fakeInformer) InformDelete(resourceGroup string, res client.Object) {
-	i.handler.OnDelete(resourceGroup, res)
-}
-
-func (i *fakeInformer) InformGeneric(resourceGroup string, res client.Object) {
-	i.handler.OnGeneric(resourceGroup, res)
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/controller/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/controller/doc.go
deleted file mode 100644
index 720567847..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/controller/doc.go
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-/*
-Package controller provides types and functions for building Controllers.
-*/
-package controller
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/event/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/event/doc.go
deleted file mode 100644
index b02d5d495..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/event/doc.go
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-/*
-Package event contains the definitions for the Event types produced by source.Sources and transformed into
-reconcile.Requests by handler.EventHandler.
-
-The implementation is derived from sigs.k8s.io/controller-runtime/pkg/event and the main difference is that
-events are resourceGroup aware.
-*/
-package event
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/event/event.go b/test/infrastructure/inmemory/internal/cloud/runtime/event/event.go
deleted file mode 100644
index 7570551fa..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/event/event.go
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package event
-
-import (
-	"sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// CreateEvent is an event where a cloud object was created.
-type CreateEvent struct {
-	ResourceGroup string
-	Object        client.Object
-}
-
-// UpdateEvent is an event where a cloud object was updated.
-type UpdateEvent struct {
-	ResourceGroup string
-	ObjectOld     client.Object
-	ObjectNew     client.Object
-}
-
-// DeleteEvent is an event where a cloud object was deleted.
-type DeleteEvent struct {
-	ResourceGroup string
-	Object        client.Object
-}
-
-// GenericEvent is an event where the operation type is unknown (e.g. periodic sync).
-type GenericEvent struct {
-	ResourceGroup string
-	Object        client.Object
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/handler/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/handler/doc.go
deleted file mode 100644
index 98079f23b..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/handler/doc.go
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-/*
-Package handler defines EventHandlers that enqueue reconcile.Requests in response to Create, Update, Deletion Events
-observed from Watching Kubernetes APIs.
-
-The implementation is derived from sigs.k8s.io/controller-runtime/pkg/handler and the main difference are:
-- event handlers are resourceGroup aware.
-- the package provide only one event handler implementation, EnqueueRequestForObject.
-*/
-package handler
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/handler/enqueue_object.go b/test/infrastructure/inmemory/internal/cloud/runtime/handler/enqueue_object.go
deleted file mode 100644
index 077a8dcb2..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/handler/enqueue_object.go
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package handler
-
-import (
-	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/client-go/util/workqueue"
-
-	cevent "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/event"
-	creconciler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/reconcile"
-)
-
-var _ EventHandler = &EnqueueRequestForObject{}
-
-// EnqueueRequestForObject enqueues a Request containing the ResourceGroup, Name and Namespace of the object that is the source of the Event.
-// handler.EnqueueRequestForObject is used by almost all Controllers that have associated Resources to reconcile.
-type EnqueueRequestForObject struct{}
-
-// Create implements EventHandler.
-func (e *EnqueueRequestForObject) Create(evt cevent.CreateEvent, q workqueue.RateLimitingInterface) {
-	if evt.Object == nil {
-		return
-	}
-	q.Add(creconciler.Request{
-		ResourceGroup: evt.ResourceGroup,
-		NamespacedName: types.NamespacedName{
-			Namespace: evt.Object.GetNamespace(),
-			Name:      evt.Object.GetName(),
-		},
-	})
-}
-
-// Update implements EventHandler.
-func (e *EnqueueRequestForObject) Update(evt cevent.UpdateEvent, q workqueue.RateLimitingInterface) {
-	switch {
-	case evt.ObjectNew != nil:
-		q.Add(creconciler.Request{
-			ResourceGroup: evt.ResourceGroup,
-			NamespacedName: types.NamespacedName{
-				Namespace: evt.ObjectNew.GetNamespace(),
-				Name:      evt.ObjectNew.GetName(),
-			},
-		})
-	case evt.ObjectOld != nil:
-		q.Add(creconciler.Request{
-			ResourceGroup: evt.ResourceGroup,
-			NamespacedName: types.NamespacedName{
-				Namespace: evt.ObjectOld.GetNamespace(),
-				Name:      evt.ObjectOld.GetName(),
-			},
-		})
-	}
-}
-
-// Delete implements EventHandler.
-func (e *EnqueueRequestForObject) Delete(evt cevent.DeleteEvent, q workqueue.RateLimitingInterface) {
-	if evt.Object == nil {
-		return
-	}
-	q.Add(creconciler.Request{
-		ResourceGroup: evt.ResourceGroup,
-		NamespacedName: types.NamespacedName{
-			Namespace: evt.Object.GetNamespace(),
-			Name:      evt.Object.GetName(),
-		},
-	})
-}
-
-// Generic implements EventHandler.
-func (e *EnqueueRequestForObject) Generic(evt cevent.GenericEvent, q workqueue.RateLimitingInterface) {
-	if evt.Object == nil {
-		return
-	}
-	q.Add(creconciler.Request{
-		ResourceGroup: evt.ResourceGroup,
-		NamespacedName: types.NamespacedName{
-			Namespace: evt.Object.GetNamespace(),
-			Name:      evt.Object.GetName(),
-		},
-	})
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/handler/handler.go b/test/infrastructure/inmemory/internal/cloud/runtime/handler/handler.go
deleted file mode 100644
index c655e0b00..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/handler/handler.go
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package handler
-
-import (
-	"k8s.io/client-go/util/workqueue"
-
-	cevent "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/event"
-)
-
-// EventHandler enqueues reconcile.Requests in response to events (e.g. object Create). EventHandlers map an Event
-// for one object to trigger Reconciles for either the same object or different objects - e.g. if there is an
-// Event for object with type Foo then reconcile one or more object(s) with type Bar.
-type EventHandler interface {
-	// Create is called in response to an create event - e.g. VM Creation.
-	Create(cevent.CreateEvent, workqueue.RateLimitingInterface)
-
-	// Update is called in response to an update event -  e.g. VM Updated.
-	Update(cevent.UpdateEvent, workqueue.RateLimitingInterface)
-
-	// Delete is called in response to a delete event - e.g. VM Deleted.
-	Delete(cevent.DeleteEvent, workqueue.RateLimitingInterface)
-
-	// Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or
-	// external trigger request - e.g. reconcile re-sync.
-	Generic(cevent.GenericEvent, workqueue.RateLimitingInterface)
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/manager/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/manager/doc.go
index a4d5bb448..401228e7c 100644
--- a/test/infrastructure/inmemory/internal/cloud/runtime/manager/doc.go
+++ b/test/infrastructure/inmemory/internal/cloud/runtime/manager/doc.go
@@ -18,6 +18,5 @@ limitations under the License.
 Package manager defines a Manager for resource groups.
 
 Resource groups are stored into an in-memory Cache, and objects via a client.
-The Manager also operate controllers automating objects lifecycle.
 */
 package manager
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/manager/manager.go b/test/infrastructure/inmemory/internal/cloud/runtime/manager/manager.go
index 19c584c49..07dd04614 100644
--- a/test/infrastructure/inmemory/internal/cloud/runtime/manager/manager.go
+++ b/test/infrastructure/inmemory/internal/cloud/runtime/manager/manager.go
@@ -24,12 +24,10 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 
 	ccache "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/cache"
-	ccontroller "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/controller"
 	cresourcegroup "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/resourcegroup"
 )
 
-// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
-// A Manager is required to create Controllers.
+// Manager initializes shared dependencies such as Caches and Clients.
 type Manager interface {
 	// TODO: refactor in resoucegroup.add/delete/get; make delete fail if rs does not exist
 	AddResourceGroup(name string)
@@ -41,8 +39,6 @@ type Manager interface {
 	// TODO: expose less (only get informers)
 	GetCache() ccache.Cache
 
-	AddController(ccontroller.Controller) error
-
 	Start(ctx context.Context) error
 }
 
@@ -51,17 +47,14 @@ var _ Manager = &manager{}
 type manager struct {
 	scheme *runtime.Scheme
 
-	cache ccache.Cache
-
-	controllers []ccontroller.Controller
-	started     bool
+	cache   ccache.Cache
+	started bool
 }
 
 // New creates a new manager.
 func New(scheme *runtime.Scheme) Manager {
 	m := &manager{
-		scheme:      scheme,
-		controllers: make([]ccontroller.Controller, 0),
+		scheme: scheme,
 	}
 	m.cache = ccache.NewCache(scheme)
 	return m
@@ -88,15 +81,6 @@ func (m *manager) GetCache() ccache.Cache {
 	return m.cache
 }
 
-func (m *manager) AddController(controller ccontroller.Controller) error {
-	if m.started {
-		return fmt.Errorf("cannot add controller to a manager already started")
-	}
-
-	m.controllers = append(m.controllers, controller)
-	return nil
-}
-
 func (m *manager) Start(ctx context.Context) error {
 	log := ctrl.LoggerFrom(ctx)
 
@@ -112,13 +96,6 @@ func (m *manager) Start(ctx context.Context) error {
 		return fmt.Errorf("failed to start cache: %v", err)
 	}
 
-	log.Info("Starting manager")
-	for _, c := range m.controllers {
-		if err := c.Start(ctx); err != nil {
-			return fmt.Errorf("failed to start controllers: %v", err)
-		}
-	}
-
 	m.started = true
 	log.Info("Manager successfully started!")
 	return nil
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/predicate/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/predicate/doc.go
deleted file mode 100644
index 9774ec873..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/predicate/doc.go
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-/*
-Package predicate defines Predicates used by Controllers to filter Events before they are provided to EventHandlers.
-
-The implementation is derived from sigs.k8s.io/controller-runtime/pkg/predicate and the main difference are:
-- predicates are resourceGroup aware.
-- the package doesn't provide predicates implementation out of the box.
-*/
-package predicate
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/predicate/predicate.go b/test/infrastructure/inmemory/internal/cloud/runtime/predicate/predicate.go
deleted file mode 100644
index 4afea8eef..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/predicate/predicate.go
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package predicate
-
-import (
-	cevent "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/event"
-)
-
-// Predicate filters events before enqueuing the keys.
-type Predicate interface {
-	// Create returns true if the Create event should be processed
-	Create(cevent.CreateEvent) bool
-
-	// Delete returns true if the Delete event should be processed
-	Delete(cevent.DeleteEvent) bool
-
-	// Update returns true if the Update event should be processed
-	Update(cevent.UpdateEvent) bool
-
-	// Generic returns true if the Generic event should be processed
-	Generic(cevent.GenericEvent) bool
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/reconcile/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/reconcile/doc.go
deleted file mode 100644
index 9d36e7beb..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/reconcile/doc.go
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-/*
-Package reconcile defines the Reconciler interface; Reconciler is provided
-to Controllers at creation time as the API implementation.
-
-The implementation is derived from sigs.k8s.io/controller-runtime/pkg/reconcile and the main difference is that
-Reconciler and Request are resourceGroup aware.
-*/
-package reconcile
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/reconcile/reconcile.go b/test/infrastructure/inmemory/internal/cloud/runtime/reconcile/reconcile.go
deleted file mode 100644
index ad35dd90e..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/reconcile/reconcile.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package reconcile
-
-import (
-	"context"
-
-	"k8s.io/apimachinery/pkg/types"
-	"sigs.k8s.io/controller-runtime/pkg/reconcile"
-)
-
-// Reconciler is provided to Controllers at creation time as the API implementation.
-type Reconciler interface {
-	// Reconcile performs a full reconciliation for the resource referred to by the Request.
-	// The Controller will requeue the Request to be processed again if an error is non-nil or
-	// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
-	Reconcile(context.Context, Request) (Result, error)
-}
-
-// Request contains the information necessary to reconcile a resource. This includes the
-// information to uniquely identify the resource - the resourceGroup it belongs to, its Name and Namespace.
-type Request struct {
-	ResourceGroup string
-	types.NamespacedName
-}
-
-func (r Request) String() string {
-	if r.ResourceGroup == "" {
-		return r.NamespacedName.String()
-	}
-	return r.ResourceGroup + string(types.Separator) + r.NamespacedName.String()
-}
-
-// Result contains the result of a Reconciler invocation.
-type Result = reconcile.Result
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/source/doc.go b/test/infrastructure/inmemory/internal/cloud/runtime/source/doc.go
deleted file mode 100644
index 80d41ef47..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/source/doc.go
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-/*
-Package source provides event streams to hook up to Controllers with Controller.Watch. Events are
-used with handler.EventHandlers to enqueue reconcile.Requests and trigger Reconciles for resources.
-
-The implementation is derived from sigs.k8s.io/controller-runtime/pkg/source  and the main difference are:
-- sources are resourceGroup aware.
-- the package provide only one sources implementation, Informer.
-*/
-package source
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/source/informer_source.go b/test/infrastructure/inmemory/internal/cloud/runtime/source/informer_source.go
deleted file mode 100644
index 68c7f87ca..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/source/informer_source.go
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package source
-
-import (
-	"context"
-	"fmt"
-
-	"k8s.io/client-go/util/workqueue"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-
-	ccache "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/cache"
-	cevent "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/event"
-	chandler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/handler"
-	cpredicate "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/predicate"
-)
-
-// Informer is used to provide a source of events originating from CRUD operations inside the resourceGroup (e.g. Resource Create).
-type Informer struct {
-	Informer ccache.Informer
-}
-
-var _ Source = &Informer{}
-
-// Start implements Source.
-func (is *Informer) Start(_ context.Context, handler chandler.EventHandler, queue workqueue.RateLimitingInterface, prct ...cpredicate.Predicate) error {
-	// Informer should have been specified by the user.
-	if is.Informer == nil {
-		return fmt.Errorf("must specify Informer.Informer")
-	}
-
-	return is.Informer.AddEventHandler(informerEventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
-}
-
-func (is *Informer) String() string {
-	return fmt.Sprintf("informer source: %p", is.Informer)
-}
-
-var _ ccache.InformEventHandler = informerEventHandler{}
-
-// informerEventHandler handle events originated by a source.
-type informerEventHandler struct {
-	EventHandler chandler.EventHandler
-	Queue        workqueue.RateLimitingInterface
-	Predicates   []cpredicate.Predicate
-}
-
-// OnCreate creates CreateEvent and calls Create on EventHandler.
-func (e informerEventHandler) OnCreate(resourceGroup string, obj client.Object) {
-	c := cevent.CreateEvent{
-		ResourceGroup: resourceGroup,
-		Object:        obj,
-	}
-	for _, p := range e.Predicates {
-		if !p.Create(c) {
-			return
-		}
-	}
-	e.EventHandler.Create(c, e.Queue)
-}
-
-// OnUpdate creates UpdateEvent and calls Update on EventHandler.
-func (e informerEventHandler) OnUpdate(resourceGroup string, oldObj, newObj client.Object) {
-	u := cevent.UpdateEvent{
-		ResourceGroup: resourceGroup,
-		ObjectOld:     oldObj,
-		ObjectNew:     newObj,
-	}
-	for _, p := range e.Predicates {
-		if !p.Update(u) {
-			return
-		}
-	}
-	e.EventHandler.Update(u, e.Queue)
-}
-
-// OnDelete creates DeleteEvent and calls Delete on EventHandler.
-func (e informerEventHandler) OnDelete(resourceGroup string, obj client.Object) {
-	d := cevent.DeleteEvent{
-		ResourceGroup: resourceGroup,
-		Object:        obj,
-	}
-	for _, p := range e.Predicates {
-		if !p.Delete(d) {
-			return
-		}
-	}
-	e.EventHandler.Delete(d, e.Queue)
-}
-
-// OnGeneric creates GenericEvent and calls Generic on EventHandler.
-func (e informerEventHandler) OnGeneric(resourceGroup string, obj client.Object) {
-	d := cevent.GenericEvent{
-		ResourceGroup: resourceGroup,
-		Object:        obj,
-	}
-	for _, p := range e.Predicates {
-		if !p.Generic(d) {
-			return
-		}
-	}
-	e.EventHandler.Generic(d, e.Queue)
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime/source/source.go b/test/infrastructure/inmemory/internal/cloud/runtime/source/source.go
deleted file mode 100644
index 09b87289e..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime/source/source.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package source
-
-import (
-	"context"
-
-	"k8s.io/client-go/util/workqueue"
-
-	chandler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/handler"
-	cpredicate "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/predicate"
-)
-
-// Source is a source of events (e.g. Create, Update, Delete operations on resources)
-// which should be processed by event.EventHandlers to enqueue reconcile.Requests.
-type Source interface {
-	// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
-	// to enqueue reconcile.Requests.
-	Start(context.Context, chandler.EventHandler, workqueue.RateLimitingInterface, ...cpredicate.Predicate) error
-}
diff --git a/test/infrastructure/inmemory/internal/cloud/runtime_test.go b/test/infrastructure/inmemory/internal/cloud/runtime_test.go
deleted file mode 100644
index cf4cc0c41..000000000
--- a/test/infrastructure/inmemory/internal/cloud/runtime_test.go
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-Copyright 2023 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package cloud
-
-import (
-	"context"
-	"testing"
-	"time"
-
-	. "github.com/onsi/gomega"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-
-	cloudv1 "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/api/v1alpha1"
-	creconciler "sigs.k8s.io/cluster-api/test/infrastructure/inmemory/internal/cloud/runtime/reconcile"
-)
-
-var scheme = runtime.NewScheme()
-
-func init() {
-	_ = cloudv1.AddToScheme(scheme)
-}
-
-type simpleReconciler struct {
-	mgr Manager
-}
-
-func (r *simpleReconciler) SetupWithManager(_ context.Context, mgr Manager) error {
-	return NewControllerManagedBy(mgr).
-		For(&cloudv1.CloudMachine{}).
-		Complete(r)
-}
-
-func (r *simpleReconciler) Reconcile(ctx context.Context, req creconciler.Request) (creconciler.Result, error) {
-	client := r.mgr.GetResourceGroup(req.ResourceGroup).GetClient()
-
-	obj := &cloudv1.CloudMachine{}
-	if err := client.Get(ctx, req.NamespacedName, obj); err != nil {
-		return creconciler.Result{}, err
-	}
-
-	obj.Annotations = map[string]string{"reconciled": "true"}
-	if err := client.Update(ctx, obj); err != nil {
-		return creconciler.Result{}, err
-	}
-	return creconciler.Result{}, nil
-}
-
-func TestController_Queue(t *testing.T) {
-	g := NewWithT(t)
-	ctx, cancelFn := context.WithCancel(context.TODO())
-
-	mgr := NewManager(scheme)
-	mgr.AddResourceGroup("foo")
-
-	c := mgr.GetResourceGroup("foo").GetClient()
-
-	err := (&simpleReconciler{
-		mgr: mgr,
-	}).SetupWithManager(ctx, mgr)
-	g.Expect(err).ToNot(HaveOccurred())
-
-	err = mgr.Start(ctx)
-	g.Expect(err).ToNot(HaveOccurred())
-
-	obj := &cloudv1.CloudMachine{
-		ObjectMeta: metav1.ObjectMeta{
-			Name: "bar-reconcile",
-		},
-	}
-	err = c.Create(ctx, obj)
-	g.Expect(err).ToNot(HaveOccurred())
-
-	g.Eventually(func() bool {
-		obj2 := &cloudv1.CloudMachine{}
-		if err := c.Get(ctx, client.ObjectKeyFromObject(obj), obj2); err != nil {
-			return false
-		}
-		return obj2.Annotations["reconciled"] == "true"
-	}, 5*time.Second, 100*time.Millisecond).Should(BeTrue())
-
-	cancelFn()
-}