typekro 0.26.0 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/alchemy/kro-delete.d.ts +8 -0
  3. package/dist/alchemy/kro-delete.d.ts.map +1 -1
  4. package/dist/alchemy/kro-delete.js +34 -35
  5. package/dist/alchemy/kro-delete.js.map +1 -1
  6. package/dist/alchemy/resource-registration.d.ts +60 -0
  7. package/dist/alchemy/resource-registration.d.ts.map +1 -1
  8. package/dist/alchemy/resource-registration.js +290 -11
  9. package/dist/alchemy/resource-registration.js.map +1 -1
  10. package/dist/alchemy/types.d.ts +44 -0
  11. package/dist/alchemy/types.d.ts.map +1 -1
  12. package/dist/core/deployment/k8s-helpers.d.ts +12 -0
  13. package/dist/core/deployment/k8s-helpers.d.ts.map +1 -1
  14. package/dist/core/deployment/k8s-helpers.js +26 -1
  15. package/dist/core/deployment/k8s-helpers.js.map +1 -1
  16. package/dist/core/deployment/kro-factory.d.ts +248 -1
  17. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  18. package/dist/core/deployment/kro-factory.js +1060 -180
  19. package/dist/core/deployment/kro-factory.js.map +1 -1
  20. package/dist/core/deployment/kro-instance-safety.d.ts +209 -0
  21. package/dist/core/deployment/kro-instance-safety.d.ts.map +1 -1
  22. package/dist/core/deployment/kro-instance-safety.js +506 -24
  23. package/dist/core/deployment/kro-instance-safety.js.map +1 -1
  24. package/dist/core/deployment/kro-namespace-teardown.d.ts +248 -0
  25. package/dist/core/deployment/kro-namespace-teardown.d.ts.map +1 -0
  26. package/dist/core/deployment/kro-namespace-teardown.js +459 -0
  27. package/dist/core/deployment/kro-namespace-teardown.js.map +1 -0
  28. package/dist/core/deployment/rollback-manager.d.ts +32 -0
  29. package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
  30. package/dist/core/deployment/rollback-manager.js +69 -21
  31. package/dist/core/deployment/rollback-manager.js.map +1 -1
  32. package/dist/core/serialization/core.d.ts.map +1 -1
  33. package/dist/core/serialization/core.js +82 -8
  34. package/dist/core/serialization/core.js.map +1 -1
  35. package/dist/core/types/deployment.d.ts +20 -0
  36. package/dist/core/types/deployment.d.ts.map +1 -1
  37. package/dist/factories/apisix/types.js +11 -11
  38. package/dist/factories/apisix/types.js.map +1 -1
  39. package/dist/factories/caddy/types.js +2 -2
  40. package/dist/factories/caddy/types.js.map +1 -1
  41. package/dist/factories/cert-manager/types.js +6 -6
  42. package/dist/factories/cert-manager/types.js.map +1 -1
  43. package/dist/factories/cilium/compositions/cilium-bootstrap.js +6 -6
  44. package/dist/factories/cilium/compositions/cilium-bootstrap.js.map +1 -1
  45. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js +1 -1
  46. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js.map +1 -1
  47. package/dist/factories/clickhouse/types.js +8 -8
  48. package/dist/factories/clickhouse/types.js.map +1 -1
  49. package/dist/factories/clickstack/types.js +5 -5
  50. package/dist/factories/clickstack/types.js.map +1 -1
  51. package/dist/factories/cnpg/types.js +6 -6
  52. package/dist/factories/cnpg/types.js.map +1 -1
  53. package/dist/factories/dagster/types.js +14 -14
  54. package/dist/factories/dagster/types.js.map +1 -1
  55. package/dist/factories/external-dns/types.js +3 -3
  56. package/dist/factories/external-dns/types.js.map +1 -1
  57. package/dist/factories/inngest/types.js +8 -8
  58. package/dist/factories/inngest/types.js.map +1 -1
  59. package/dist/factories/ory/types.js +40 -40
  60. package/dist/factories/ory/types.js.map +1 -1
  61. package/dist/factories/rook/types.js +7 -7
  62. package/dist/factories/rook/types.js.map +1 -1
  63. package/dist/factories/searxng/types.js +2 -2
  64. package/dist/factories/searxng/types.js.map +1 -1
  65. package/dist/factories/valkey/types.js +4 -4
  66. package/dist/factories/valkey/types.js.map +1 -1
  67. package/dist/factories/webapp/types.js +8 -8
  68. package/dist/factories/webapp/types.js.map +1 -1
  69. package/dist/utils/string.d.ts +14 -0
  70. package/dist/utils/string.d.ts.map +1 -1
  71. package/dist/utils/string.js +22 -0
  72. package/dist/utils/string.js.map +1 -1
  73. package/package.json +1 -1
@@ -32,6 +32,14 @@ export interface KubernetesObjectCleanupApi {
32
32
  namespace?: string;
33
33
  };
34
34
  }): Promise<unknown>;
35
+ read(resource: {
36
+ apiVersion: string;
37
+ kind: string;
38
+ metadata: {
39
+ name: string;
40
+ namespace?: string;
41
+ };
42
+ }): Promise<unknown>;
35
43
  }
36
44
  export interface KubernetesObjectInstanceApi extends KubernetesObjectCleanupApi {
37
45
  read(resource: {
@@ -1 +1 @@
1
- {"version":3,"file":"kro-delete.d.ts","sourceRoot":"","sources":["../../src/alchemy/kro-delete.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kro-delete.d.ts","sourceRoot":"","sources":["../../src/alchemy/kro-delete.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { CRDInstanceError, ensureError } from '../core/errors.js';
2
+ import { createRollbackManager } from '../core/deployment/rollback-manager.js';
2
3
  import { createBunCompatibleCustomObjectsApi, createBunCompatibleKubernetesObjectApi } from '../core/kubernetes/bun-api-client.js';
3
4
  import { getComponentLogger } from '../core/logging/index.js';
4
5
  function getSchemaVersion(apiVersion) {
@@ -60,47 +61,45 @@ export async function hasKroInstances(kubeConfig, options) {
60
61
  }
61
62
  export async function deleteKroDefinition(kubeConfig, options, k8sApi = createBunCompatibleKubernetesObjectApi(kubeConfig)) {
62
63
  const logger = getComponentLogger('alchemy-kro-delete');
63
- const crdPlural = options.plural ?? await lookupCRDPlural(kubeConfig, options, k8sApi);
64
+ // ONE gating mechanism: the engine's rollback manager deletes then polls to a REAL 404
65
+ // and THROWS on timeout — the SAME primitive the imperative KRO teardown uses. A
66
+ // pre-existing 404 is treated as already-gone.
67
+ const rollback = createRollbackManager(k8sApi);
68
+ const timeout = options.timeout ?? 300000;
69
+ // The RGD delete is a HARD gate (throws on timeout).
64
70
  try {
65
- await k8sApi.delete({
66
- apiVersion: 'kro.run/v1alpha1',
67
- kind: 'ResourceGraphDefinition',
68
- metadata: { name: options.rgdName },
69
- });
71
+ await rollback.deleteResourceAndWait({ apiVersion: 'kro.run/v1alpha1', kind: 'ResourceGraphDefinition', name: options.rgdName }, { timeout });
70
72
  }
71
73
  catch (error) {
72
- if (getKubernetesErrorCode(error) !== 404) {
73
- logger.error('Alchemy KRO RGD cleanup failed', ensureError(error), {
74
- rgdName: options.rgdName,
75
- error: ensureError(error).message,
76
- });
77
- throw error;
78
- }
79
- }
80
- if (!crdPlural) {
81
- logger.debug('Alchemy KRO CRD already absent during RGD cleanup', {
82
- kind: options.kind,
74
+ logger.error('Alchemy KRO RGD cleanup failed', ensureError(error), {
83
75
  rgdName: options.rgdName,
76
+ error: ensureError(error).message,
84
77
  });
85
- return;
86
- }
87
- const crdName = `${crdPlural}.${getSchemaGroup(options)}`;
88
- try {
89
- await k8sApi.delete({
90
- apiVersion: 'apiextensions.k8s.io/v1',
91
- kind: 'CustomResourceDefinition',
92
- metadata: { name: crdName },
93
- });
94
- }
95
- catch (error) {
96
- if (getKubernetesErrorCode(error) !== 404) {
97
- logger.error('Alchemy KRO CRD cleanup failed', ensureError(error), {
98
- crdName,
99
- error: ensureError(error).message,
100
- });
101
- throw error;
102
- }
78
+ throw error;
103
79
  }
80
+ // FINDING #1 — DO NOT delete the generated CRD here (leave it for out-of-band GC).
81
+ //
82
+ // Under alchemy's reverse-topo teardown the hoisted workload Namespace is a SEPARATE
83
+ // resource deleted AFTER the RGD/instance (both `dependsOn` it): the order is
84
+ // instance → RGD → namespace. `deleteKroDefinition` runs during the instance/RGD
85
+ // delete, which is BEFORE the namespace resource's own delete step. If we deleted the
86
+ // CRD here, it would be Terminating while the namespace later drains — and a namespace
87
+ // controller stalls indefinitely enumerating a *Terminating* CRD's type (the
88
+ // apiextensions `customresourcecleanup` finalizer is slow/fragile even with zero
89
+ // instances, upstream kro #1171). That is the EXACT hang the imperative path avoids by
90
+ // deleting the CRD strictly AFTER the namespace.
91
+ //
92
+ // Alchemy cannot cheaply reorder the CRD delete to run after the (separate, later,
93
+ // possibly SHARED/deduped) namespace resource, so we choose the other invariant-safe
94
+ // option: NEVER delete the CRD in the alchemy path. It is never Terminating during
95
+ // namespace teardown, so a namespace can never hang against it. A leftover Active CRD
96
+ // with zero instances is harmless (KRO's default allowCRDDeletion=false already leaves
97
+ // it), cluster-scoped, and can be GC'd out-of-band. This is the accepted residual of the
98
+ // alchemy #1 fix — documented, not silent.
99
+ logger.debug('Alchemy KRO teardown: leaving the generated CRD for out-of-band GC (finding #1)', {
100
+ kind: options.kind,
101
+ rgdName: options.rgdName,
102
+ });
104
103
  }
105
104
  export async function deleteKroInstanceFinalizerSafe(kubeConfig, name, options) {
106
105
  return deleteKroInstanceFinalizerSafeWithApis(kubeConfig, name, options, {
@@ -1 +1 @@
1
- {"version":3,"file":"kro-delete.js","sourceRoot":"","sources":["../../src/alchemy/kro-delete.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kro-delete.js","sourceRoot":"","sources":["../../src/alchemy/kro-delete.ts"],"names":[],"mappings":"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"}
@@ -13,11 +13,14 @@
13
13
  * The Kubernetes machinery (`deployers`, `kro-delete`, client/deployer construction) is
14
14
  * alchemy-version-agnostic and reused verbatim; only the registration glue changed.
15
15
  */
16
+ import type { KubeConfig } from '@kubernetes/client-node';
16
17
  import { Effect } from 'effect';
17
18
  import * as ProviderMod from 'alchemy/Provider';
18
19
  import * as ResourceMod from 'alchemy/Resource';
19
20
  import type { Resource as ResourceT } from 'alchemy/Resource';
21
+ import { type TypeKroLogger } from '../core/logging/index.js';
20
22
  import { type ResourceScope } from '../core/metadata/index.js';
23
+ import { listNamespacesOwnedByRgd } from '../core/deployment/kro-namespace-teardown.js';
21
24
  import type { DeploymentOptions } from '../core/types/deployment.js';
22
25
  import type { Enhanced } from '../core/types/kubernetes.js';
23
26
  import type { KroDeletionOptions } from './kro-delete.js';
@@ -83,6 +86,63 @@ export declare function singletonDriftVerdict(expectedFingerprint: string, deplo
83
86
  drift: true;
84
87
  reason: string;
85
88
  };
89
+ /**
90
+ * The namespaces of EVERY existing instance of the shared RGD (finding #7, alchemy).
91
+ * Discovers the generated CRD from {@link TypeKroResourceProps.namespacePreHoistQuery},
92
+ * lists instances cluster-wide, and returns each instance's namespace.
93
+ *
94
+ * FAIL CLOSED: a CRD-discovery or instance-list FAILURE (RBAC/connectivity) is NOT proof
95
+ * of absence — it THROWS. Only a successful CRD list with no matching CRD (fresh cluster),
96
+ * or a definitive 404 listing instances, yields an empty set.
97
+ *
98
+ * NAMESPACE RESOLUTION (finding #1, v7 — per-instance exact or fail closed): each existing
99
+ * instance's namespaces are resolved EXACTLY and PER INSTANCE from that instance's OWN CR
100
+ * `typekro.io/hoisted-namespaces` record — the only per-instance proof. An instance that
101
+ * lacks its own record (a genuinely-legacy deployment) FAILS CLOSED (throws): the RGD-wide
102
+ * set of Namespaces carrying `typekro.io/created-by-rgd == props.namespaceOwnerRgd` is NOT
103
+ * per-instance proof — a DIFFERENT (modern) instance could have stamped it, so a non-empty
104
+ * RGD-wide set would MASK a legacy instance whose own — possibly different — namespace is
105
+ * then invisible and pruned. We never approximate from `metadata.namespace` / `spec.namespace`.
106
+ * The RGD-wide set IS unioned into the returned protected set (a superset catching leaked
107
+ * namespaces) — it just never SATISFIES the per-instance check. The incoming namespace is
108
+ * always checked directly by the caller regardless.
109
+ */
110
+ /**
111
+ * Injectable API surface for {@link _existingInstanceNamespacesAlchemy} — lets the
112
+ * deterministic unit test supply mocks instead of a live cluster. Production passes
113
+ * nothing and the Bun-compatible clients are constructed from the KubeConfig.
114
+ */
115
+ interface AlchemyPreHoistDeps {
116
+ objectApi?: {
117
+ list(apiVersion: string, kind: string): Promise<unknown>;
118
+ };
119
+ customApi?: {
120
+ listClusterCustomObject(request: {
121
+ group: string;
122
+ version: string;
123
+ plural: string;
124
+ }): Promise<{
125
+ items?: Array<{
126
+ metadata?: {
127
+ namespace?: unknown;
128
+ annotations?: Record<string, string>;
129
+ };
130
+ spec?: unknown;
131
+ }>;
132
+ }>;
133
+ };
134
+ /** The NamespaceListApi passed to {@link listNamespacesOwnedByRgd}. */
135
+ ownedNamespaceListApi?: Parameters<typeof listNamespacesOwnedByRgd>[2] extends infer O ? O extends {
136
+ k8sApi?: infer A;
137
+ } ? A : never : never;
138
+ }
139
+ declare function _existingInstanceNamespacesAlchemy<T extends Enhanced<unknown, unknown>>(props: TypeKroResourceProps<T>, kc: KubeConfig, logger: TypeKroLogger, deps?: AlchemyPreHoistDeps): Promise<Set<string>>;
140
+ /**
141
+ * Test-only export of the alchemy pre-hoist namespace resolver (finding #1, v7) so the
142
+ * deterministic unit test can prove the per-instance-exact-or-fail-closed behavior with
143
+ * injected API mocks (no cluster).
144
+ */
145
+ export declare const existingInstanceNamespacesAlchemyForTest: typeof _existingInstanceNamespacesAlchemy;
86
146
  declare function inferKroDeletionOptions<T extends Enhanced<unknown, unknown>>(props: TypeKroResourceProps<T>): KroDeletionOptions | undefined;
87
147
  /** Internal test hook for legacy Alchemy KRO state rehydration. */
88
148
  export declare const inferKroDeletionOptionsForTest: typeof inferKroDeletionOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"resource-registration.d.ts","sourceRoot":"","sources":["../../src/alchemy/resource-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,IAAI,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAO9D,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAGjF,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAsB,MAAM,6BAA6B,CAAC;AAOhF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EACV,0BAA0B,EAG1B,eAAe,EACf,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAoBpB,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,EAAG,qBAA8B,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,CAClC,OAAO,iBAAiB,EACxB,oBAAoB,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAChD,eAAe,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAC5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,yCAAwD,CAAC;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gFAgCvB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,OAAO,WAAW,EAC/B,YAAY,EAAE,SAAS,0BAA0B,EAAE,+DAoCpD;AAmED,0DAA0D;AAC1D,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACpD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,mBAAmB,EAAE,MAAM,EAC3B,aAAa,EAAE,OAAO,EACtB,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAYpD;AAsMD,iBAAS,uBAAuB,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACnE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC7B,kBAAkB,GAAG,SAAS,CAqDhC;AAED,mEAAmE;AACnE,eAAO,MAAM,8BAA8B,gCAA0B,CAAC;AAoBtE;;;;;;GAMG;AACH,iBAAe,iBAAiB,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACnE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,iDAAiD;AACjD,eAAO,MAAM,wBAAwB,0BAAoB,CAAC;AA6C1D,iBAAS,4BAA4B,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACxE,QAAQ,EAAE,CAAC,EACX,aAAa,CAAC,EAAE,aAAa,GAC5B,CAAC,CAaH;AAED,oEAAoE;AACpE,eAAO,MAAM,mCAAmC,qCAA+B,CAAC;AAEhF,wBAAgB,6BAA6B,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAChF,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC7B,iBAAiB,CAcnB"}
1
+ {"version":3,"file":"resource-registration.d.ts","sourceRoot":"","sources":["../../src/alchemy/resource-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,IAAI,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI9D,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAMlF,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EAIL,wBAAwB,EAGzB,MAAM,8CAA8C,CAAC;AAGtD,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAsB,MAAM,6BAA6B,CAAC;AAOhF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EACV,0BAA0B,EAG1B,eAAe,EACf,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAsBpB,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,EAAG,qBAA8B,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,CAClC,OAAO,iBAAiB,EACxB,oBAAoB,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAChD,eAAe,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAC5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,yCAAwD,CAAC;AAEjF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gFAgCvB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,OAAO,WAAW,EAC/B,YAAY,EAAE,SAAS,0BAA0B,EAAE,+DAoCpD;AAgFD,0DAA0D;AAC1D,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACpD,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,mBAAmB,EAAE,MAAM,EAC3B,aAAa,EAAE,OAAO,EACtB,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAYpD;AAwED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;;GAIG;AACH,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAC1D,CAAC;IACF,SAAS,CAAC,EAAE;QACV,uBAAuB,CAAC,OAAO,EAAE;YAC/B,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC;SAChB,GAAG,OAAO,CAAC;YACV,KAAK,CAAC,EAAE,KAAK,CAAC;gBACZ,QAAQ,CAAC,EAAE;oBAAE,SAAS,CAAC,EAAE,OAAO,CAAC;oBAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;iBAAE,CAAC;gBACzE,IAAI,CAAC,EAAE,OAAO,CAAC;aAChB,CAAC,CAAC;SACJ,CAAC,CAAC;KACJ,CAAC;IACF,uEAAuE;IACvE,qBAAqB,CAAC,EAAE,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,GAClF,CAAC,SAAS;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAA;KAAE,GAC5B,CAAC,GACD,KAAK,GACP,KAAK,CAAC;CACX;AAED,iBAAe,kCAAkC,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACpF,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAC9B,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAkHtB;AAED;;;;GAIG;AACH,eAAO,MAAM,wCAAwC,2CAAqC,CAAC;AAkR3F,iBAAS,uBAAuB,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACnE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC7B,kBAAkB,GAAG,SAAS,CAqDhC;AAED,mEAAmE;AACnE,eAAO,MAAM,8BAA8B,gCAA0B,CAAC;AAoBtE;;;;;;GAMG;AACH,iBAAe,iBAAiB,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACnE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CA8Df;AAED,iDAAiD;AACjD,eAAO,MAAM,wBAAwB,0BAAoB,CAAC;AAgD1D,iBAAS,4BAA4B,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EACxE,QAAQ,EAAE,CAAC,EACX,aAAa,CAAC,EAAE,aAAa,GAC5B,CAAC,CAaH;AAED,oEAAoE;AACpE,eAAO,MAAM,mCAAmC,qCAA+B,CAAC;AAEhF,wBAAgB,6BAA6B,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAChF,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC7B,iBAAiB,CAcnB"}
@@ -22,8 +22,9 @@ import { ensureError } from '../core/errors.js';
22
22
  import { createKubernetesClientProvider } from '../core/kubernetes/client-provider.js';
23
23
  import { getComponentLogger } from '../core/logging/index.js';
24
24
  import { CEL_EXPRESSION_BRAND } from '../core/constants/brands.js';
25
- import { createBunCompatibleKubernetesObjectApi } from '../core/kubernetes/index.js';
25
+ import { createBunCompatibleCustomObjectsApi, createBunCompatibleKubernetesObjectApi, } from '../core/kubernetes/index.js';
26
26
  import { getResourceScope } from '../core/metadata/index.js';
27
+ import { decideNamespaceOwnershipCreateFirst, deleteNamespaceIfEmpty, HOISTED_NAMESPACES_ANNOTATION, listNamespacesOwnedByRgd, NAMESPACE_OWNER_ANNOTATION, readHoistedNamespacesRecord, } from '../core/deployment/kro-namespace-teardown.js';
27
28
  import { SINGLETON_SPEC_FINGERPRINT_ANNOTATION } from '../core/deployment/resource-tagging.js';
28
29
  import { stableSerialize } from '../core/singleton/singleton.js';
29
30
  import { DirectTypeKroDeployer, KroTypeKroDeployer, ResourceGraphDefinitionDeletionDeferredError, } from './deployers.js';
@@ -120,27 +121,37 @@ export function materializeAlchemyResources(kroResource, declarations) {
120
121
  */
121
122
  async function deployKroResource(props) {
122
123
  const logger = getComponentLogger('alchemy-deployment').child({ alchemyType: KRO_RESOURCE_TYPE });
124
+ // Fail-closed PRE-HOIST guard on the ALCHEMY path (finding #7): before applying a
125
+ // typekro-hoisted workload Namespace, refuse to proceed if it is still a KRO ApplySet
126
+ // member from a pre-hoist RGD — rolling the new hoisted RGD over the old one would let
127
+ // KRO's prune delete it. Cluster-checked here since `toAlchemyResources` is cluster-free.
128
+ await _assertNoPreHoistNamespaceConflictAlchemy(props, logger);
123
129
  // Singleton-owner spec-drift protection (the declarative analog of `assertNoDeployedSingletonSpecDrift`
124
130
  // in the imperative deploy path): refuse to clobber a shared singleton that already exists with a
125
131
  // different spec. Cluster-checked here since `toAlchemyResources` is intentionally cluster-free.
126
132
  await _assertNoSingletonDrift(props, logger);
127
- const { deployer, dispose } = await _resolveDeployer(props, 'deployment');
133
+ // finding #2 (adopted-namespace): the hoisted workload Namespace is stamped
134
+ // owned-by-this-RGD at BUILD time (cluster-free). READ the live namespace here and
135
+ // KEEP that stamp ONLY when typekro actually creates it (404) or already owns it;
136
+ // otherwise strip it so teardown never deletes a namespace typekro merely adopted.
137
+ const effectiveProps = await _preserveHoistedNamespaceAdoption(props, logger);
138
+ const { deployer, dispose } = await _resolveDeployer(effectiveProps, 'deployment');
128
139
  try {
129
140
  // Direct mode: hand the deployer the live state of this resource's dependencies so the engine
130
141
  // resolves its cross-resource references + CEL expressions against them (the deps deployed
131
142
  // first via alchemy ordering). KRO docs are self-contained, so the seed is irrelevant there.
132
- const seedResources = _seedFromDependencies(props);
143
+ const seedResources = _seedFromDependencies(effectiveProps);
133
144
  // alchemy serializes props to state, flattening this resource's CEL refs to `${…}` STRINGS.
134
145
  // The engine resolver only evaluates CEL OBJECTS, so (direct mode, with dependency state to
135
146
  // resolve against) re-hydrate those strings into template CEL objects before deploying — but
136
147
  // ONLY strings that reference a known dependency id, so genuine `${…}` literals (e.g. a shell
137
148
  // `${HOME}` in an env var) are left untouched.
138
- let resourceForDeploy = props.resource;
139
- if (seedResources && props.deploymentStrategy === 'direct') {
140
- resourceForDeploy = _rehydrateCelStrings(props.resource, new Set(seedResources.map((s) => s.id)));
149
+ let resourceForDeploy = effectiveProps.resource;
150
+ if (seedResources && effectiveProps.deploymentStrategy === 'direct') {
151
+ resourceForDeploy = _rehydrateCelStrings(effectiveProps.resource, new Set(seedResources.map((s) => s.id)));
141
152
  }
142
- else if (props.deploymentStrategy === 'kro' &&
143
- props.resource.kind !== 'ResourceGraphDefinition') {
153
+ else if (effectiveProps.deploymentStrategy === 'kro' &&
154
+ effectiveProps.resource.kind !== 'ResourceGraphDefinition') {
144
155
  // KRO CR instance (the custom resource an RGD defines — not the RGD itself). After alchemy
145
156
  // serializes props to state, the resource is a plain manifest with no readiness evaluator, so a
146
157
  // `waitForReady` deploy throws "No readiness evaluator found for <Kind>". Re-wrap it with
@@ -148,7 +159,7 @@ async function deployKroResource(props) {
148
159
  // InstanceSynced) — the same KRO-instance readiness the imperative deploy path waits on. The RGD
149
160
  // is excluded (it carries its own evaluator via the resourceGraphDefinition factory).
150
161
  const { kroCustomResource } = await import('../factories/kro/kro-custom-resource.js');
151
- const r = props.resource;
162
+ const r = effectiveProps.resource;
152
163
  resourceForDeploy = kroCustomResource({
153
164
  apiVersion: r.apiVersion ?? '',
154
165
  kind: r.kind ?? '',
@@ -156,9 +167,11 @@ async function deployKroResource(props) {
156
167
  spec: (r.spec ?? {}),
157
168
  });
158
169
  }
159
- const deployProps = resourceForDeploy === props.resource ? props : { ...props, resource: resourceForDeploy };
170
+ const deployProps = resourceForDeploy === effectiveProps.resource
171
+ ? effectiveProps
172
+ : { ...effectiveProps, resource: resourceForDeploy };
160
173
  const { resourceProperties } = await _deployAndCreateResult(deployProps, deployer, seedResources);
161
- _logDeploymentSuccess(logger, KRO_RESOURCE_TYPE, props, resourceProperties);
174
+ _logDeploymentSuccess(logger, KRO_RESOURCE_TYPE, effectiveProps, resourceProperties);
162
175
  return resourceProperties;
163
176
  }
164
177
  catch (error) {
@@ -200,6 +213,226 @@ export function singletonDriftVerdict(expectedFingerprint, deployingSpec, live)
200
213
  * fires for resources carrying the singleton spec-fingerprint annotation (i.e. singleton instances);
201
214
  * a missing instance / absent CRD / unreachable cluster is treated as "nothing to drift from".
202
215
  */
216
+ /**
217
+ * Fail-closed PRE-HOIST detection for the ALCHEMY deploy path (finding #7). Runs ONLY
218
+ * for a typekro-hoisted workload Namespace (`namespaceEmptyGate`). If the live namespace
219
+ * is a KRO ApplySet member (carries `applyset.kubernetes.io/part-of` or any `kro.run/*`
220
+ * label from a pre-hoist RGD), applying the new hoisted RGD would let KRO's prune delete
221
+ * it — so THROW. A 404 (fresh) is safe; any OTHER read error FAILS CLOSED (throws).
222
+ */
223
+ async function _assertNoPreHoistNamespaceConflictAlchemy(props, logger) {
224
+ if (props.namespaceEmptyGate !== true)
225
+ return;
226
+ const incoming = props.resource.metadata?.name;
227
+ if (typeof incoming !== 'string' || incoming.length === 0)
228
+ return;
229
+ const kc = _createClientProvider(props, 'pre-hoist-check');
230
+ const api = createBunCompatibleKubernetesObjectApi(kc);
231
+ // The set of namespaces to check: the incoming one PLUS every EXISTING instance's
232
+ // namespace (finding #7). An upgrade prunes the ApplySet for ALL instances of the
233
+ // shared RGD at once, so missing one would let KRO delete it.
234
+ const namespacesToCheck = new Set([incoming]);
235
+ for (const ns of await _existingInstanceNamespacesAlchemy(props, kc, logger)) {
236
+ namespacesToCheck.add(ns);
237
+ }
238
+ for (const name of namespacesToCheck) {
239
+ let labels = {};
240
+ try {
241
+ const live = (await api.read({
242
+ apiVersion: 'v1',
243
+ kind: 'Namespace',
244
+ metadata: { name },
245
+ }));
246
+ labels = live.metadata?.labels ?? {};
247
+ }
248
+ catch (error) {
249
+ const k8sErr = error;
250
+ const code = k8sErr.statusCode ?? k8sErr.code ?? k8sErr.body?.code;
251
+ if (code === 404)
252
+ continue; // fresh namespace — nothing to migrate
253
+ // FAIL CLOSED: a non-404 read error means we cannot prove the namespace is safe.
254
+ throw new Error(`Pre-hoist safety check could not read Namespace "${name}" (${ensureError(error).message}). ` +
255
+ `Refusing to deploy: a hoist over an unreadable namespace could let KRO's ApplySet prune delete it.`);
256
+ }
257
+ const partOfKro = typeof labels['applyset.kubernetes.io/part-of'] === 'string' ||
258
+ Object.keys(labels).some((key) => key.startsWith('kro.run/'));
259
+ if (partOfKro) {
260
+ throw new Error(`Pre-hoist deployment detected: the live Namespace "${name}" is a KRO ApplySet member ` +
261
+ `(carries applyset.kubernetes.io/part-of and/or kro.run/* labels from a pre-hoist RGD). ` +
262
+ `typekro now HOISTS every owned Namespace out of the RGD, so applying the new RGD in place ` +
263
+ `would drop "${name}" from KRO's ApplySet and KRO's prune would DELETE it and its workloads. ` +
264
+ `This upgrade is not auto-migrated — see docs/advanced/migration.md.`);
265
+ }
266
+ }
267
+ logger.debug('Pre-hoist namespace check passed (alchemy)', {
268
+ namespaces: [...namespacesToCheck],
269
+ });
270
+ }
271
+ async function _existingInstanceNamespacesAlchemy(props, kc, logger, deps = {}) {
272
+ const result = new Set();
273
+ const query = props.namespacePreHoistQuery;
274
+ if (!query)
275
+ return result;
276
+ // STRICT CRD discovery — a list failure FAILS CLOSED (throws).
277
+ const objectApi = deps.objectApi ?? createBunCompatibleKubernetesObjectApi(kc);
278
+ const crds = (await objectApi.list('apiextensions.k8s.io/v1', 'CustomResourceDefinition'));
279
+ const match = crds?.items?.find((crd) => crd.spec?.group === query.group && crd.spec?.names?.kind === query.kind);
280
+ const plural = match?.spec?.names?.plural;
281
+ if (!plural)
282
+ return result; // definitively fresh — no CRD, so no existing instances
283
+ let items;
284
+ try {
285
+ const customApi = deps.customApi ??
286
+ createBunCompatibleCustomObjectsApi(kc);
287
+ const listResponse = await customApi.listClusterCustomObject({
288
+ group: query.group,
289
+ version: query.version,
290
+ plural,
291
+ });
292
+ items = listResponse.items ?? [];
293
+ }
294
+ catch (error) {
295
+ const k8sErr = error;
296
+ const status = k8sErr.statusCode ?? k8sErr.code ?? k8sErr.body?.code;
297
+ if (status === 404)
298
+ return result; // CRD/instances vanished — fresh
299
+ throw new Error(`Pre-hoist safety check could not list existing instances of the RGD's CRD ` +
300
+ `(${ensureError(error).message}). Refusing to deploy: another instance's namespace could ` +
301
+ `be pruned by the hoist without being checked.`);
302
+ }
303
+ if (items.length === 0)
304
+ return result;
305
+ // The RGD-wide record of every namespace this RGD created: namespaces carrying
306
+ // `typekro.io/created-by-rgd == props.namespaceOwnerRgd`. We union it into the PROTECTED set
307
+ // as a superset (it catches namespaces leaked by an interrupted teardown), but it is NOT
308
+ // used to satisfy the per-instance check below (finding #1, v7) — being RGD-wide it cannot
309
+ // prove a SPECIFIC instance's namespaces. A list error FAILS CLOSED.
310
+ const ownerRgd = props.namespaceOwnerRgd;
311
+ const ownedNamespaces = new Set();
312
+ if (typeof ownerRgd === 'string' && ownerRgd.length > 0) {
313
+ let owned;
314
+ try {
315
+ owned = await listNamespacesOwnedByRgd(kc, ownerRgd, {
316
+ logger,
317
+ ...(deps.ownedNamespaceListApi ? { k8sApi: deps.ownedNamespaceListApi } : {}),
318
+ });
319
+ }
320
+ catch (error) {
321
+ throw new Error(`Pre-hoist safety check could not list namespaces owned by RGD "${ownerRgd}" ` +
322
+ `(${ensureError(error).message}). Refusing to deploy: without the durable ownership ` +
323
+ `record we cannot prove the hoist won't prune an existing instance's namespace.`);
324
+ }
325
+ for (const ns of owned)
326
+ ownedNamespaces.add(ns);
327
+ for (const ns of ownedNamespaces)
328
+ result.add(ns);
329
+ }
330
+ for (const item of items) {
331
+ // Resolve THIS instance's namespaces from its OWN exact PER-INSTANCE record — the CR
332
+ // `typekro.io/hoisted-namespaces` annotation (finding #1, v7). It carries the instance's
333
+ // EXACT hoisted names (a name derived from an arbitrary spec field round-trips) and is the
334
+ // ONLY per-instance proof.
335
+ const record = readHoistedNamespacesRecord(item.metadata?.annotations?.[HOISTED_NAMESPACES_ANNOTATION]);
336
+ if (record.status === 'present') {
337
+ // A VALID record — including an explicit empty `[]` — is per-instance proof: this instance
338
+ // hoists exactly these namespaces (possibly none). Resolved; do NOT fail closed.
339
+ for (const ns of record.names)
340
+ result.add(ns);
341
+ continue;
342
+ }
343
+ // MISSING or MALFORMED record → NO per-instance exact record. FAIL CLOSED (finding #1, v7). We do NOT
344
+ // fall back to the RGD-wide `created-by-rgd` set: being RGD-wide it is not per-instance
345
+ // proof — a DIFFERENT (modern) instance could have stamped it, so a non-empty set would
346
+ // MASK this legacy instance whose own — possibly different — owned namespace is then
347
+ // invisible and pruned. Nor do we approximate from metadata.namespace / spec.namespace.
348
+ throw new Error(`Pre-hoist safety check found an existing instance with no per-instance namespace record — ` +
349
+ `its CR carries no "${HOISTED_NAMESPACES_ANNOTATION}" annotation. The RGD-wide ` +
350
+ `"${NAMESPACE_OWNER_ANNOTATION}${ownerRgd ? `=${ownerRgd}` : ''}" set is NOT per-instance ` +
351
+ `proof (another instance could have stamped it), so this instance's own owned namespace ` +
352
+ `could be pruned by the hoist unseen. Refusing to deploy: migrate it (redeploy with a ` +
353
+ `current TypeKro so its namespaces are recorded) and retry.`);
354
+ }
355
+ logger.debug('Enumerated existing-instance namespaces for the alchemy pre-hoist check', {
356
+ count: result.size,
357
+ });
358
+ return result;
359
+ }
360
+ /**
361
+ * Test-only export of the alchemy pre-hoist namespace resolver (finding #1, v7) so the
362
+ * deterministic unit test can prove the per-instance-exact-or-fail-closed behavior with
363
+ * injected API mocks (no cluster).
364
+ */
365
+ export const existingInstanceNamespacesAlchemyForTest = _existingInstanceNamespacesAlchemy;
366
+ /**
367
+ * finding #2 (alchemy adopted-namespace, mirrors the imperative `applyRetainedHoistedNamespace`
368
+ * create-vs-adopt logic): the hoisted workload Namespace carries a build-time
369
+ * `typekro.io/created-by-rgd` ownership stamp (added cluster-free in
370
+ * `buildHoistedNamespaceResource`). Applying it unconditionally would let the empty-gated
371
+ * teardown DELETE a namespace typekro merely ADOPTED. So READ the live namespace and keep
372
+ * the stamp ONLY when typekro truly creates it (404) or already owns it (stamp already ==
373
+ * this RGD); otherwise STRIP the stamp from the resource before apply so the live namespace
374
+ * never carries our ownership record and teardown retains it. `namespaceOwnerRgd` is KEPT on
375
+ * props either way — at delete time the empty-gate compares the LIVE annotation to it, and a
376
+ * stripped/adopted namespace (no matching annotation) is retained.
377
+ *
378
+ * Returns props unchanged for non-hoisted-namespace resources or when the stamp should
379
+ * stay; otherwise a shallow copy whose resource has the ownership annotation removed.
380
+ */
381
+ async function _preserveHoistedNamespaceAdoption(props, logger) {
382
+ if (props.namespaceEmptyGate !== true || props.namespaceOwnerRgd === undefined)
383
+ return props;
384
+ const name = props.resource.metadata?.name;
385
+ if (typeof name !== 'string' || name.length === 0)
386
+ return props;
387
+ const kc = _createClientProvider(props, 'ownership-check');
388
+ const api = createBunCompatibleKubernetesObjectApi(kc);
389
+ // CREATE-FIRST ownership (finding #3), matching the imperative path: attempt to CREATE
390
+ // the namespace WITH the build-time stamp. A 201 is atomic proof typekro created it
391
+ // (owned). A 409 means it already exists — owned ONLY if a prior create by this RGD
392
+ // stamped it; otherwise adopted. This replaces the raceable read→(404)→own decision:
393
+ // there is no window in which another actor creates the namespace between our read and
394
+ // our claim. The generic deployer still SSA-applies the full config afterwards
395
+ // (idempotent), so a 201 here is not the final apply — it is the ownership PROBE.
396
+ let ownsNamespace;
397
+ try {
398
+ const decision = await decideNamespaceOwnershipCreateFirst(api, props.resource, props.namespaceOwnerRgd);
399
+ ownsNamespace = decision.owned;
400
+ }
401
+ catch (error) {
402
+ // A non-conflict CREATE failure (or a failed conflict-read) — do NOT claim ownership
403
+ // (conservative: a namespace we cannot provably create/own must not be stampable, or
404
+ // teardown might delete an adopted one). The deployer's SSA apply below surfaces the
405
+ // real error if the cluster is genuinely broken.
406
+ logger.debug('Create-first ownership probe failed; treating as adopted (alchemy)', {
407
+ namespace: name,
408
+ rgd: props.namespaceOwnerRgd,
409
+ error: ensureError(error).message,
410
+ });
411
+ ownsNamespace = false;
412
+ }
413
+ if (ownsNamespace)
414
+ return props; // keep the build-time ownership stamp
415
+ logger.debug('Preserving namespace adoption — stripping build-time ownership stamp (alchemy)', {
416
+ namespace: name,
417
+ rgd: props.namespaceOwnerRgd,
418
+ });
419
+ return { ...props, resource: _stripNamespaceOwnerAnnotation(props.resource) };
420
+ }
421
+ /**
422
+ * Return a shallow copy of a Namespace resource with the `typekro.io/created-by-rgd`
423
+ * ownership annotation removed. Used by {@link _preserveHoistedNamespaceAdoption} to avoid
424
+ * stamping ownership onto an adopted namespace. By reconcile time alchemy has JSON-round-
425
+ * tripped props to state (no symbols/brands), so a shallow object copy is safe here.
426
+ */
427
+ function _stripNamespaceOwnerAnnotation(resource) {
428
+ const src = resource;
429
+ const annotations = { ...(src.metadata?.annotations ?? {}) };
430
+ delete annotations[NAMESPACE_OWNER_ANNOTATION];
431
+ return {
432
+ ...resource,
433
+ metadata: { ...(src.metadata ?? {}), annotations },
434
+ };
435
+ }
203
436
  async function _assertNoSingletonDrift(props, logger) {
204
437
  const resource = props.resource;
205
438
  const expected = resource.metadata?.annotations?.[SINGLETON_SPEC_FINGERPRINT_ANNOTATION];
@@ -308,6 +541,9 @@ function propsFromOutput(output) {
308
541
  deploymentStrategy: output.deploymentStrategy ?? 'kro',
309
542
  ...(output.kubeConfigOptions !== undefined && { kubeConfigOptions: output.kubeConfigOptions }),
310
543
  ...(output.kroDeletion !== undefined && { kroDeletion: output.kroDeletion }),
544
+ ...(output.retain === true && { retain: true }),
545
+ ...(output.namespaceEmptyGate === true && { namespaceEmptyGate: true }),
546
+ ...(output.namespaceOwnerRgd !== undefined && { namespaceOwnerRgd: output.namespaceOwnerRgd }),
311
547
  };
312
548
  }
313
549
  /**
@@ -423,6 +659,46 @@ async function _resolveDeployer(props, phase) {
423
659
  */
424
660
  async function deleteKroResource(props) {
425
661
  const logger = getComponentLogger('alchemy-deployment').child({ alchemyType: KRO_RESOURCE_TYPE });
662
+ // Retained (shared) resources — e.g. the KRO instance control-plane Namespace —
663
+ // must survive a single stack's teardown/prune: another stack targeting the same
664
+ // workload namespace may still have KRO instances inside it. Drop only the state
665
+ // entry (like the deferred shared-RGD delete below), leaving the object on-cluster.
666
+ if (props.retain === true) {
667
+ logger.debug('Skipping delete: resource is retained (shared); dropping state entry only', {
668
+ resourceName: props.resource.metadata?.name,
669
+ namespace: props.namespace,
670
+ });
671
+ return;
672
+ }
673
+ // Empty-gated Namespace teardown (findings #3 + #4): a typekro-hoisted workload
674
+ // Namespace is deleted ONLY if empty and RETAINED if another stack/user still has
675
+ // resources inside it. Alchemy's reverse-topo teardown runs this AFTER the RGD +
676
+ // instance that `dependsOn` it are gone; the instance is deleted FIRST and its delete
677
+ // waits for the CR's `kro.run/finalizer` to clear (KRO graph-deletes all children),
678
+ // so by the time this runs everything THIS instance owned has already drained from
679
+ // the namespace (finding #1's ordering, provided here by the dependency graph + the
680
+ // instance-drain wait rather than an in-line CRD-404 wait; the gate is fail-safe
681
+ // regardless). Replaces the old retain-by-name-equality distinction — runtime
682
+ // emptiness is the truth for both the instance's own namespace and a shared one.
683
+ if (props.namespaceEmptyGate === true) {
684
+ const namespaceName = props.resource.metadata?.name;
685
+ if (typeof namespaceName !== 'string' || namespaceName.length === 0) {
686
+ logger.warn('Empty-gated namespace teardown skipped: resource has no metadata.name', {
687
+ namespace: props.namespace,
688
+ });
689
+ return;
690
+ }
691
+ const kubeConfig = _createClientProvider(props, 'delete');
692
+ await deleteNamespaceIfEmpty(kubeConfig, namespaceName, {
693
+ logger,
694
+ // Ownership record (finding #4) + gated delete (finding #1): only delete a
695
+ // namespace this composition's RGD created, and gate it to a real 404.
696
+ ...(props.namespaceOwnerRgd !== undefined && { ownedByRgd: props.namespaceOwnerRgd }),
697
+ ...(props.options?.timeout !== undefined && { timeoutMs: props.options.timeout }),
698
+ context: { alchemyType: KRO_RESOURCE_TYPE },
699
+ });
700
+ return;
701
+ }
426
702
  const { deployer, dispose } = await _resolveDeployer(props, 'delete');
427
703
  try {
428
704
  await deployer.delete(props.resource, {
@@ -473,6 +749,9 @@ async function _deployAndCreateResult(props, deployer, seedResources) {
473
749
  deploymentStrategy: props.deploymentStrategy,
474
750
  ...(props.kubeConfigOptions !== undefined && { kubeConfigOptions: props.kubeConfigOptions }),
475
751
  ...(props.kroDeletion !== undefined && { kroDeletion: props.kroDeletion }),
752
+ ...(props.retain === true && { retain: true }),
753
+ ...(props.namespaceEmptyGate === true && { namespaceEmptyGate: true }),
754
+ ...(props.namespaceOwnerRgd !== undefined && { namespaceOwnerRgd: props.namespaceOwnerRgd }),
476
755
  deployedResource: cleanDeployedResource,
477
756
  ready: true,
478
757
  deployedAt: Date.now(),