@intentius/chant-lexicon-k8s 0.44.14 → 0.45.0

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 (56) hide show
  1. package/dist/codegen/docs.d.ts.map +1 -1
  2. package/dist/codegen/generate-lexicon.d.ts +15 -1
  3. package/dist/codegen/generate-lexicon.d.ts.map +1 -1
  4. package/dist/components/capability-plugin.d.ts.map +1 -1
  5. package/dist/crd/parser.d.ts +28 -1
  6. package/dist/crd/parser.d.ts.map +1 -1
  7. package/dist/deep-observe-hooks.d.ts +60 -4
  8. package/dist/deep-observe-hooks.d.ts.map +1 -1
  9. package/dist/deep-observe.d.ts +36 -61
  10. package/dist/deep-observe.d.ts.map +1 -1
  11. package/dist/integrity.json +6 -3
  12. package/dist/lint/audit-catalog.d.ts.map +1 -1
  13. package/dist/lint/post-synth/crd-schema-helpers.d.ts +49 -0
  14. package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -0
  15. package/dist/lint/post-synth/index.d.ts.map +1 -1
  16. package/dist/lint/post-synth/wk8501.d.ts +14 -0
  17. package/dist/lint/post-synth/wk8501.d.ts.map +1 -0
  18. package/dist/lint/post-synth/wk8502.d.ts +13 -0
  19. package/dist/lint/post-synth/wk8502.d.ts.map +1 -0
  20. package/dist/manifest.json +1 -1
  21. package/dist/meta.json +126 -63
  22. package/dist/okf/index.md +2 -0
  23. package/dist/okf/rules/WK8501.md +11 -0
  24. package/dist/okf/rules/WK8502.md +11 -0
  25. package/dist/rules/crd-schema-helpers.ts +228 -0
  26. package/dist/rules/wk8501.ts +40 -0
  27. package/dist/rules/wk8502.ts +39 -0
  28. package/dist/spec/parse.d.ts +32 -0
  29. package/dist/spec/parse.d.ts.map +1 -1
  30. package/dist/validate.d.ts.map +1 -1
  31. package/package.json +3 -3
  32. package/src/codegen/docs.ts +0 -1044
  33. package/src/codegen/generate-lexicon.ts +38 -2
  34. package/src/codegen/snapshot.test.ts +20 -0
  35. package/src/components/capability-plugin.test.ts +20 -0
  36. package/src/components/capability-plugin.ts +5 -2
  37. package/src/crd/cnpg.test.ts +1 -1
  38. package/src/crd/infisical.test.ts +1 -1
  39. package/src/crd/parser.test.ts +117 -1
  40. package/src/crd/parser.ts +71 -5
  41. package/src/crd/traefik.test.ts +1 -1
  42. package/src/deep-observe-hooks.ts +78 -16
  43. package/src/deep-observe.test.ts +145 -29
  44. package/src/deep-observe.ts +43 -85
  45. package/src/generated/lexicon-k8s.json +126 -63
  46. package/src/lint/audit-catalog.ts +2 -0
  47. package/src/lint/post-synth/crd-schema-helpers.ts +228 -0
  48. package/src/lint/post-synth/index.ts +4 -0
  49. package/src/lint/post-synth/post-synth.test.ts +156 -0
  50. package/src/lint/post-synth/wk8501.ts +40 -0
  51. package/src/lint/post-synth/wk8502.ts +39 -0
  52. package/src/list-map-key-table.test.ts +83 -0
  53. package/src/op/activities/kubectl.ts +2 -2
  54. package/src/serializer.test.ts +4 -4
  55. package/src/spec/parse.ts +33 -0
  56. package/src/validate.ts +7 -4
@@ -1 +1 @@
1
- {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqHH;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4iC9E"}
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqHH;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB9E"}
@@ -3,7 +3,7 @@
3
3
  * for all Kubernetes resource and property types.
4
4
  */
5
5
  import type { PropertyConstraints } from "@intentius/chant/codegen/json-schema";
6
- import type { K8sParseResult } from "../spec/parse.js";
6
+ import type { K8sParseResult, CrdFieldSchema } from "../spec/parse.js";
7
7
  import type { NamingStrategy } from "./naming.js";
8
8
  export interface K8sLexiconEntry {
9
9
  resourceType: string;
@@ -13,9 +13,23 @@ export interface K8sLexiconEntry {
13
13
  gvkKind?: string;
14
14
  deprecatedProperties?: string[];
15
15
  constraints?: Record<string, PropertyConstraints>;
16
+ /**
17
+ * Field schema of a custom resource's `spec` (chant #1372). Only CRD-derived
18
+ * kinds carry one; built-in kinds are typed by the `.d.ts`. Consumed by the
19
+ * WK8501/WK8502 post-synth checks and the MCP catalog.
20
+ */
21
+ specSchema?: CrdFieldSchema;
16
22
  }
17
23
  /**
18
24
  * Generate the lexicon-k8s.json content.
19
25
  */
20
26
  export declare function generateLexiconJSON(results: K8sParseResult[], naming: NamingStrategy): string;
27
+ /**
28
+ * Pretty-print the registry the way every lexicon does, but keep each
29
+ * `specSchema` on one line (chant #1372). A CRD schema nests deeply — an
30
+ * ApplicationSet or RayCluster embeds a whole PodTemplateSpec — and two-space
31
+ * indentation on that tree quadruples the file for no reader's benefit.
32
+ * Compact, the schemas add ~0.8 MB to the registry; pretty, ~3.9 MB.
33
+ */
34
+ export declare function serializeWithCompactSchemas(entries: Record<string, K8sLexiconEntry>): string;
21
35
  //# sourceMappingURL=generate-lexicon.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-lexicon.d.ts","sourceRoot":"","sources":["../../src/codegen/generate-lexicon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAO/C,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,MAAM,EAAE,cAAc,GACrB,MAAM,CAqCR"}
1
+ {"version":3,"file":"generate-lexicon.d.ts","sourceRoot":"","sources":["../../src/codegen/generate-lexicon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAO/C,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAClD;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,MAAM,EAAE,cAAc,GACrB,MAAM,CAwCR;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,MAAM,CAkB5F"}
@@ -1 +1 @@
1
- {"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../src/components/capability-plugin.ts"],"names":[],"mappings":"AAWA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAMzG,eAAO,MAAM,iBAAiB;;;CAKpB,CAAC;AAEX,eAAO,MAAM,mBAAmB,EAAE,gBAgBjC,CAAC"}
1
+ {"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../src/components/capability-plugin.ts"],"names":[],"mappings":"AAWA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAMzG,eAAO,MAAM,iBAAiB;;;CAKpB,CAAC;AAEX,eAAO,MAAM,mBAAmB,EAAE,gBAmBjC,CAAC"}
@@ -6,7 +6,7 @@
6
6
  * main K8s swagger parser. This enables CRD-based resources to integrate
7
7
  * with the full codegen pipeline.
8
8
  */
9
- import type { K8sParseResult } from "../spec/parse.js";
9
+ import type { K8sParseResult, CrdFieldSchema } from "../spec/parse.js";
10
10
  import type { CRDSpec } from "./types.js";
11
11
  /**
12
12
  * Parse a CRD YAML document string into K8sParseResult entries.
@@ -18,4 +18,31 @@ export declare function parseCRD(content: string): K8sParseResult[];
18
18
  * Extracts one result per served version with storage version preferred.
19
19
  */
20
20
  export declare function parseCRDSpec(spec: CRDSpec): K8sParseResult[];
21
+ interface OpenAPISchema {
22
+ type?: string;
23
+ description?: string;
24
+ properties?: Record<string, OpenAPISchema>;
25
+ required?: string[];
26
+ items?: OpenAPISchema;
27
+ additionalProperties?: boolean | OpenAPISchema;
28
+ enum?: string[];
29
+ format?: string;
30
+ minimum?: number;
31
+ maximum?: number;
32
+ minLength?: number;
33
+ maxLength?: number;
34
+ pattern?: string;
35
+ default?: unknown;
36
+ "x-kubernetes-preserve-unknown-fields"?: boolean;
37
+ "x-kubernetes-int-or-string"?: boolean;
38
+ }
39
+ /**
40
+ * Reduce an `openAPIV3Schema` node to the compact {@link CrdFieldSchema} the
41
+ * lexicon JSON ships. Walks the whole tree; drops descriptions, formats,
42
+ * defaults and numeric bounds. `allOf`/`oneOf`/`anyOf` are not modelled — a
43
+ * node that relies on them with no `type` of its own comes out untyped, which
44
+ * the validators treat as "anything goes".
45
+ */
46
+ export declare function toFieldSchema(node: OpenAPISchema): CrdFieldSchema;
47
+ export {};
21
48
  //# sourceMappingURL=parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/crd/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAwD,MAAM,eAAe,CAAC;AAC1G,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAKvC;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAqB1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,EAAE,CAoD5D"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/crd/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,cAAc,EAId,cAAc,EACf,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAKvC;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAqB1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,EAAE,CAyD5D;AAID,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,oBAAoB,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IAC/C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sCAAsC,CAAC,EAAE,OAAO,CAAC;IACjD,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAoLD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,CA0CjE"}
@@ -22,14 +22,18 @@
22
22
  * are sets addressed by a well-known identity (containers by name, ports by
23
23
  * containerPort+protocol). None of that needs a live object in hand.
24
24
  *
25
- * What does *not* live here is the managed-fields prunewhether one
26
- * specific field on one specific live object is chant-owned, foreign-owned,
27
- * or contested. That is inherently per-object (it depends on *that* object's
25
+ * What does *not* live here is the managed-fields ownership walk which
26
+ * manager owns one specific field on one specific live object. That is
27
+ * inherently per-object (it depends on *that* object's
28
28
  * `metadata.managedFields`, which the declared tree never carries and which
29
29
  * differs between two Deployments of the same type), so it cannot be
30
30
  * expressed as a fixed rule keyed only by entity type and path — the shape
31
31
  * every other hook in this file takes. `./deep-observe.ts` computes it once
32
- * per resource and layers it on top of the rules below.
32
+ * per resource and attaches it to the observation as `fieldOwners`. Since
33
+ * chant #1191 ownership no longer prunes anything: a foreign-owned field
34
+ * nobody declared is reported as `undeclared` drift, and the only static
35
+ * subtraction for foreign writes is `K8S_SYSTEM_METADATA_PRUNE_PATTERNS`
36
+ * (core's `managed-fields`), applied below.
33
37
  *
34
38
  * The *entity-type-agnostic* half of these rules — which fields every
35
39
  * Kubernetes API object carries regardless of kind, and the well-known
@@ -73,6 +77,57 @@ export declare const K8S_SERVICE_DEFAULTS: Record<string, Record<string, unknown
73
77
  * is still compared, only the purely server-filled appearance is noise.
74
78
  */
75
79
  export declare const K8S_SERVER_ASSIGNED_PATTERNS: Record<string, ReadonlySet<string>>;
80
+ /**
81
+ * The k8s lexicon's static noise rules: the generic Kubernetes object
82
+ * envelope (unconditional, by pattern, `@intentius/chant/managed-fields`) and
83
+ * Kubernetes-defaulted fields (gated on `counterpart === "absent"`), plus the
84
+ * array orderings.
85
+ *
86
+ * The orderings are now taken from the spec itself (chant #1441): codegen
87
+ * carries `x-kubernetes-list-type`/`x-kubernetes-list-map-keys` through into
88
+ * `./generated/list-map-keys.json`, and {@link schemaListMapOrderKey} reads
89
+ * it. The hand-written conventions in
90
+ * `@intentius/chant/managed-fields`'s `k8sListMapOrderKey` — containers by
91
+ * `name`, `env` by `name`, `volumes` by `name`, container/service `ports` by
92
+ * `containerPort`/`port` + `protocol` — remain as the fallback for lists the
93
+ * spec does not annotate, and for readers that have no generated table at all
94
+ * (GCP's Config Connector hooks).
95
+ *
96
+ * This is the object `k8sPlugin.deepNormalizationHooks` is. It is also what
97
+ * `./deep-observe.ts` layers its per-resource managed-fields prune on top of,
98
+ * so the two normalization passes (the reader's own, and core's later
99
+ * re-normalization of both the declared and the already-normalized live tree
100
+ * — see `packages/core/src/lifecycle/deep-observe.ts`) apply the identical
101
+ * entityType-keyed rules either way.
102
+ */
103
+ /** Property name → candidate key-field sets, generated from the spec (chant #1441). */
104
+ type ListMapKeyTable = Record<string, string[][]>;
105
+ /**
106
+ * Where the generated table lives: next to this module, resolved from
107
+ * `import.meta.url`. This module ships as ESM (tsx strips types from src/
108
+ * directly), where a bare `require` is not defined — the #1441 regression
109
+ * crashed `lifecycle diff --live` with `require is not defined` on every
110
+ * estate with a Deployment, and azure's apiVersion registry hit the same
111
+ * class of bug in #1581. A plain fs read has no module-system dependency.
112
+ */
113
+ export declare function listMapKeyTablePath(): string;
114
+ /**
115
+ * Load the spec-derived table once. A missing or unreadable file degrades to
116
+ * an EMPTY table, which routes every list through `k8sListMapOrderKey`'s
117
+ * hand-written conventions — the same fallback an unlisted property already
118
+ * takes. The empty table is cached by the caller too, so an absent artifact
119
+ * costs one failed read and one warning, not one per array element
120
+ * (chant #1476).
121
+ *
122
+ * Degrading is the right call here, unlike azure's apiVersion registry
123
+ * (#1581) where a silent fallback bypasses correctness-bearing pins. Without
124
+ * the table, drift detection narrows back to the six hardcoded properties:
125
+ * less coverage, never wrong answers. The warning names the regen command so
126
+ * the narrowing is not silent.
127
+ */
128
+ export declare function loadListMapKeyTable(path?: string): ListMapKeyTable;
129
+ /** Test hook: replace (or drop) the cached table so the next lookup reloads it. */
130
+ export declare function resetListMapKeyTableCache(table?: ListMapKeyTable): void;
76
131
  /**
77
132
  * Order an associative list's element by the identity the SPEC declares for it
78
133
  * (chant #1441), falling back to `@intentius/chant/managed-fields`'s hand-written
@@ -88,4 +143,5 @@ export declare const K8S_SERVER_ASSIGNED_PATTERNS: Record<string, ReadonlySet<st
88
143
  */
89
144
  export declare function schemaListMapOrderKey(element: DeepArrayElement): string | undefined;
90
145
  export declare const k8sDeepNormalizationHooks: DeepNormalizationHooks;
146
+ export {};
91
147
  //# sourceMappingURL=deep-observe-hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deep-observe-hooks.d.ts","sourceRoot":"","sources":["../src/deep-observe-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAY,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAanG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoCxE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAE5E,CAAC;AAiGF;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAYnF;AAMD,eAAO,MAAM,yBAAyB,EAAE,sBAmBvC,CAAC"}
1
+ {"version":3,"file":"deep-observe-hooks.d.ts","sourceRoot":"","sources":["../src/deep-observe-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAY,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAQnG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoCxE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAE5E,CAAC;AA+BF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,uFAAuF;AACvF,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;AAIlD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,MAA8B,GAAG,eAAe,CAWzF;AAeD,mFAAmF;AACnF,wBAAgB,yBAAyB,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAEvE;AAmCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAYnF;AAMD,eAAO,MAAM,yBAAyB,EAAE,sBA4BvC,CAAC"}
@@ -7,8 +7,7 @@
7
7
  * rather than the hand-maintained `ignoreDifferences` list every Argo user
8
8
  * keeps.
9
9
  *
10
- * ## Why this is not "the AWS reader, with `kubectl get` instead of Cloud
11
- * Control"
10
+ * ## What managedFields decides, and what it does not
12
11
  *
13
12
  * AWS, Azure and Temporal's rows all prune by a **static, entityType-keyed**
14
13
  * table: an ARN always looks like an ARN, `provisioningState` is always
@@ -17,65 +16,43 @@
17
16
  * what `./deep-observe-hooks.ts`'s `k8sDeepNormalizationHooks` is, and it
18
17
  * covers Kubernetes' *equivalent* static noise (`status`,
19
18
  * `metadata.{uid,resourceVersion,generation,creationTimestamp}`, a handful of
20
- * server-defaulted pod-spec fields).
19
+ * server-defaulted pod-spec fields, and the annotations and labels
20
+ * Kubernetes' own controllers stamp on every object of a kind —
21
+ * `K8S_SYSTEM_METADATA_PRUNE_PATTERNS` in `@intentius/chant/managed-fields`).
21
22
  *
22
- * managedFields is not that kind of rule. Whether `spec.replicas` is noise on
23
- * *this* Deployment depends on whether *this* Deployment's
24
- * `metadata.managedFields` says a controller owns it a fact that differs
25
- * between two Deployments of the same type, and that the declared tree never
26
- * carries at all (chant's source has no `managedFields` key to normalize).
27
- * `DeepNormalizationHooks.prune` cannot see the object it is walking, only a
28
- * path and a value, so this cannot be expressed as a fixed hook the way the
29
- * other three rows' entire contribution is. It has to be computed once per
30
- * resource, here, and layered on top of the static rules before the tree is
31
- * normalized.
23
+ * managedFields is a different kind of fact. Which manager owns
24
+ * `spec.replicas` on *this* Deployment differs between two Deployments of
25
+ * the same type, and the declared tree never carries it at all (chant's
26
+ * source has no `managedFields` key to normalize). It has to be resolved once
27
+ * per resource, here, against the object in hand.
32
28
  *
33
- * ## The contested-field rule, precisely
29
+ * Until chant #1191 that resolution *pruned*: a foreign-owned path nobody
30
+ * declared was dropped before the tree reached core, on the theory that it
31
+ * was controller noise. It silenced exactly the case the deep read exists
32
+ * for — `kubectl label deploy web team=platform` is foreign-owned
33
+ * (`kubectl-edit`) and undeclared, and never appeared in fieldDrift. The
34
+ * policy now (recorded on #1202) is:
34
35
  *
35
- * For every path on the live tree, three questions, each independent:
36
+ * 1. **Chant-owned** (`chant`, `chant:<stack>` chant #1075, matched on the
37
+ * family so a stack rename does not stop recognizing its own history) is
38
+ * always diffable.
39
+ * 2. **Declared, whoever owns it live** (a contested field) is always
40
+ * diffable: chant's source is a statement of intent independent of which
41
+ * write currently holds the field, and a foreign write that overrides a
42
+ * value chant's manifest asks for is the thing `lifecycle diff --live`
43
+ * exists to surface. It reports as `changed`.
44
+ * 3. **Foreign-owned and undeclared** is reported as `undeclared` drift,
45
+ * unless the accepted baseline already carries it at that value. The
46
+ * baseline (`--update-baseline`) is the noise valve: an HPA that owns
47
+ * `spec.replicas` on a Deployment whose source is silent about replicas
48
+ * reports once, gets accepted, and stays quiet until the value moves.
36
49
  *
37
- * 1. **Does any chant field manager (`chant`, `chant:<stack>` chant #1075,
38
- * matched on the family so a stack rename does not stop recognizing its
39
- * own history) own this path?** If so it is chant's business regardless of
40
- * what else is true always diffable, never pruned by this rule.
41
- * 2. **Does some *other* manager own this path, and chant does not?** That is
42
- * controller-managed noise HPA rewriting `spec.replicas`, a mutating
43
- * webhook defaulting a field, `kubectl-client-side-apply` from a human
44
- * operator — *provided* nobody declared it (next question). Prune it.
45
- * 3. **Does chant's own manifest *also* set this path?** — independent of
46
- * who currently owns it live. This is the case the issue calls out by
47
- * name: **a contested field chant declared is drift-relevant.** The
48
- * reasoning: chant's source is a statement of intent regardless of
49
- * whether a previous apply is what currently holds the field, and a
50
- * foreign write that overrides a value chant's manifest asks for is
51
- * exactly the thing `lifecycle diff --live` exists to surface — silencing
52
- * it because *something else* currently owns the field would hide the one
53
- * case where chant and the cluster disagree about a property chant is
54
- * actively declaring. So: foreign-owned *and* declared is never pruned by
55
- * this rule, whatever #2 would otherwise do.
56
- *
57
- * `counterpart: "unknown"` and why it does not help here: core's own
58
- * counterpart tri-state (`side === "live" && counterpart === "absent"`, what
59
- * {@link K8S_SERVICE_DEFAULTS} is gated on) answers "did the *declared tree*
60
- * carry this path at all" — which is exactly question 3, but it is computed
61
- * by *core*, from the raw declared and raw live trees, only on the **second**
62
- * normalization pass (`packages/core/src/lifecycle/deep-observe.ts`'s
63
- * `diffDeepObservation`). This reader's own call to
64
- * {@link normalizeDeepProperties} runs first, with no `counterpartPaths`
65
- * supplied — same as the other three rows — so `counterpart` is `"unknown"`
66
- * for every node here, and a rule gated on `"absent"` would never fire during
67
- * this read at all. That is fine for a table keyed only by entityType (AWS's
68
- * service defaults are subtracted on core's later pass, not this one), but it
69
- * is *not* fine for the managed-fields rule: if this reader left
70
- * `spec.replicas` in the tree waiting for core's second pass to prune it,
71
- * core would be normalizing with the *static* `k8sDeepNormalizationHooks`,
72
- * which has no managedFields for this object in hand either (this reader
73
- * already computed its ownership sets from data it read once and does not
74
- * return). So question 3 is answered **here**, directly against the declared
75
- * `props` this reader was handed — not via `counterpart` — and the result is
76
- * baked into what this reader returns: a foreign-owned, undeclared field is
77
- * gone from the tree before it ever reaches core, and a contested one is
78
- * still there for the ordinary declared-vs-live comparison to catch.
50
+ * So ownership decides nothing about *whether* a path is compared. What it
51
+ * contributes is `fieldOwners` (#1189): every reported drift names the
52
+ * manager that holds the field live, which is how an operator tells
53
+ * `hpa-controller` doing its job from somebody running `kubectl edit`. The
54
+ * only fields subtracted because a foreign manager wrote them are the
55
+ * well-known system ones on the static allowlist.
79
56
  *
80
57
  * ## Resolving a managedFields entry against a live array
81
58
  *
@@ -99,10 +76,8 @@
99
76
  * container that also sets no scalar sub-fields (unusual — a real apply
100
77
  * setting a container almost always sets `image`/`name` too) would not confer
101
78
  * ownership onto a sibling field nobody's `fieldsV1` entry lists explicitly.
102
- * That is the conservative direction: a path absent from every manager's
103
- * fields is treated as "no ownership information", which leaves it diffable
104
- * rather than silently pruned. Reported drift that turns out to be more
105
- * noise than expected is a tuning problem; drift silently dropped is not.
79
+ * A path absent from every manager's fields simply has no `owner` on its
80
+ * drift line; it is compared like any other.
106
81
  *
107
82
  * ## `buildOwnershipSets` lives in core now
108
83
  *
@@ -1 +1 @@
1
- {"version":3,"file":"deep-observe.d.ts","sourceRoot":"","sources":["../src/deep-observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqHG;AAGH,OAAO,KAAK,EAEV,qBAAqB,EAGtB,MAAM,0BAA0B,CAAC;AAIlC,OAAO,EAAE,kBAAkB,EAAoB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAC3G,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAQvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AASjE,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAuBD;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,qBAAqB,EAC9B,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,qBAAqB,CAAC,CAiHhC"}
1
+ {"version":3,"file":"deep-observe.d.ts","sourceRoot":"","sources":["../src/deep-observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4FG;AAGH,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,0BAA0B,CAAC;AAIlC,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAQvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AASjE,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAQD;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,qBAAqB,EAC9B,OAAO,GAAE,YAAkC,GAC1C,OAAO,CAAC,qBAAqB,CAAC,CAgHhC"}
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "5793f99bc43b1e32a3b9c58246e7c3e7781efb03ad8e13e05a5c6d980b8d61fd",
5
- "meta.json": "f568fb8a0cbd4adf041baccaa3e1164c2e3c5c0090186236f887f0084f5521a8",
4
+ "manifest.json": "d494ac9907d9da8ddb4456e697be2efe6e5d238df855db3c62abeb7d7036f406",
5
+ "meta.json": "6ec9419aa1aed8402b7957955f2a67e8c641861cfd3650886fb0898db5df14f6",
6
6
  "types/index.d.ts": "ef2c9df6a4d1ebfbe33f96c094fbbe3fc7909522ea38e086666fbf3c8ac477fd",
7
7
  "rules/argo-appset-single-project.ts": "afa9f310753aa2d475f35012b13135b2dfaebed2a35d44edbe185ebc07673674",
8
8
  "rules/argo-ast.ts": "f57b7d84fef9c9cd326a7cad0dff290914e01299415d64bdab48e2f6eb4181c3",
@@ -15,6 +15,7 @@
15
15
  "rules/argo002.ts": "d2f07daabfc7a4624d3d60ea151fd2380d43f1578dd6a17825f6f6e0ebc610ba",
16
16
  "rules/argo003.ts": "a61024fbd3db772eface6b2e4fee618a5818f12a1050faea8e358e0fdc992396",
17
17
  "rules/argo005.ts": "611ea489e005e3ead925013e636f0d7c6899fd0ce68c59a97541fc6fe4e8d25c",
18
+ "rules/crd-schema-helpers.ts": "62e8d3d3557f6046ead90cce7198aa1f59838acc7b4229c5dda0cf2a2893fec9",
18
19
  "rules/flux002.ts": "4269ce13121bc5b28c02aad06765dc85085a1c9ebcc936ae958663b85de07bc6",
19
20
  "rules/flux003.ts": "a174af9941bd2491a9bbf72039ab2fc4d4f4de388b2884ddf7123f05594d9d4e",
20
21
  "rules/k8s-helpers.ts": "d7d5020bc9b47bfb1827e8c8cb13ad1d406890d08a964a521c9fbcb93b230827",
@@ -44,6 +45,8 @@
44
45
  "rules/wk8401.ts": "860e5104d53158ebea790f5acc3d34b82d666c4808d8ee5de44b68c1c602af77",
45
46
  "rules/wk8402.ts": "91c58dc146c6aa44b93f167fd5ed8c16cb5dc95e9d99f40685d9d0acdf7eb474",
46
47
  "rules/wk8403.ts": "abf42e48d9539768856d71d365b5e6cbb9d4800b9f890809b70d181641a86b98",
48
+ "rules/wk8501.ts": "7de8c368ae0b0a2678441a97ec6bed8172f1f127bad6a8441b39ea8d1d4f1dd3",
49
+ "rules/wk8502.ts": "c13813543b4ec42b9b87d2ebfe20bae3e6e954a8d7c4e9387581a753484aa778",
47
50
  "skills/chant-k8s.md": "222268f9e6b19912ece4b066d8897f009b90a3fe6f14e9c5059d0717e7ee0f82",
48
51
  "skills/chant-k8s-patterns.md": "683148e9f0f9da6879bd65d97c82cc29dbff897e31bc11b3c1de654cd6baeea3",
49
52
  "skills/chant-k8s-deployment-strategies.md": "c4cc93cba064230567baa755b5a3493dc69bfc6e74a62e1990d12039ffaaf5f8",
@@ -54,5 +57,5 @@
54
57
  "skills/chant-k8s-argo.md": "b1a0b826559d8c5033a479c5781efaf650320f0aee4419d8841170bd3393cea5",
55
58
  "skills/chant-k8s-flux.md": "9670efc2e9854bd14686b5adeb707396b9030a4dcaee6529b30abf56efe2c50c"
56
59
  },
57
- "composite": "24d9f9ce05e0ea1994936c42632aea832968d17455afc5f041e40836771ce212"
60
+ "composite": "1594ddb769d445bb1e070ee0e591c94da0716f03f2a4681c6284992981cf616a"
58
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"audit-catalog.d.ts","sourceRoot":"","sources":["../../src/lint/audit-catalog.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAqD,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAElH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAgCpD,CAAC"}
1
+ {"version":3,"file":"audit-catalog.d.ts","sourceRoot":"","sources":["../../src/lint/audit-catalog.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAqD,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAElH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAkCpD,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Shared helpers for the custom-resource spec checks (WK8501, WK8502) — chant #1372.
3
+ *
4
+ * A CRD's constructor takes `spec: Record<string, unknown>`, so a misspelled
5
+ * or wrong-typed field type-checks, serializes, and is accepted by the API
6
+ * server (which prunes what the structural schema does not know) — the
7
+ * controller then runs with a default nobody chose. The generated lexicon JSON
8
+ * carries each CRD's `spec` field schema (`specSchema`); these helpers walk a
9
+ * synthesized manifest against it and report what the schema would reject.
10
+ *
11
+ * Excluded from check auto-discovery by the "helper" filename filter.
12
+ */
13
+ import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
14
+ import type { CrdFieldSchema } from "../../spec/parse.js";
15
+ import { type K8sManifest } from "./k8s-helpers.js";
16
+ export type { CrdFieldSchema };
17
+ /**
18
+ * Spec schemas of every CRD the lexicon ships, keyed by `apiVersion/kind`.
19
+ * Built-in kinds carry no `specSchema` and are never in the map.
20
+ */
21
+ export declare function getCrdSchemaRegistry(): Map<string, CrdFieldSchema>;
22
+ /** Test seam: replace the registry (pass `null` to reload from the lexicon JSON). */
23
+ export declare function setCrdSchemaRegistry(registry: Map<string, CrdFieldSchema> | null): void;
24
+ /** The schema for a manifest's `apiVersion`/`kind`, if the lexicon ships one. */
25
+ export declare function specSchemaFor(manifest: K8sManifest): CrdFieldSchema | undefined;
26
+ /** Every manifest in the build that has a shipped spec schema, with that schema. */
27
+ export declare function customResources(ctx: PostSynthContext): Array<{
28
+ manifest: K8sManifest;
29
+ schema: CrdFieldSchema;
30
+ }>;
31
+ export interface SpecFinding {
32
+ kind: "unknown-field" | "type-mismatch";
33
+ /** Dotted path under `spec`, e.g. `spec.source.s3bucket`. Array elements use `[i]`. */
34
+ path: string;
35
+ message: string;
36
+ }
37
+ /**
38
+ * Walk `value` against `schema` and report every field the schema does not
39
+ * list (unless the enclosing object is `open`) and every scalar whose type or
40
+ * enum membership the schema rejects. Untyped nodes pass anything.
41
+ */
42
+ export declare function validateSpec(value: unknown, schema: CrdFieldSchema, path?: string): SpecFinding[];
43
+ /** Levenshtein distance between two strings. */
44
+ export declare function levenshtein(a: string, b: string): number;
45
+ /** Closest known field within Levenshtein distance 3 (case-insensitive), if any. */
46
+ export declare function suggestField(unknown: string, known: string[]): string | undefined;
47
+ /** `metadata.name` or the kind, for diagnostics. */
48
+ export declare function resourceLabel(manifest: K8sManifest): string;
49
+ //# sourceMappingURL=crd-schema-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crd-schema-helpers.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/crd-schema-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAuC,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAEtF,YAAY,EAAE,cAAc,EAAE,CAAC;AAgB/B;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAkBlE;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,GAAG,IAAI,CAEvF;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,CAG/E;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,GAAG,KAAK,CAAC;IAAE,QAAQ,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAAC,CAS/G;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,GAAG,eAAe,CAAC;IACxC,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,SAAS,GAAG,WAAW,EAAE,CAIjG;AAgGD,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAcxD;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAWjF;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAE3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAiCvE,eAAO,MAAM,eAAe,EAAE,cAAc,EAgC3C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAmCvE,eAAO,MAAM,eAAe,EAAE,cAAc,EAkC3C,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * WK8501: Custom resource spec has a field its CRD schema does not declare
3
+ *
4
+ * A generated CRD class takes `spec: Record<string, unknown>`, so a misspelled
5
+ * field (`classname` for `className`) type-checks and serializes. The API
6
+ * server accepts the object and prunes the unknown field, the controller
7
+ * never sees it, and the resource runs with a default nobody chose. The
8
+ * lexicon ships each CRD's `spec` schema (chant #1372); this check flags any
9
+ * field that schema does not list, unless the enclosing object declares
10
+ * `x-kubernetes-preserve-unknown-fields` or `additionalProperties`.
11
+ */
12
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
13
+ export declare const wk8501: PostSynthCheck;
14
+ //# sourceMappingURL=wk8501.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wk8501.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/wk8501.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAG9G,eAAO,MAAM,MAAM,EAAE,cAwBpB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * WK8502: Custom resource spec field has the wrong type or an invalid enum value
3
+ *
4
+ * With `spec: Record<string, unknown>` on every generated CRD class, nothing
5
+ * at compile time stops `replicas: "2"` or `desiredState: "Runing"`. The API
6
+ * server rejects the first at apply and the controller ignores the second.
7
+ * The lexicon ships each CRD's `spec` schema (chant #1372); this check
8
+ * compares every scalar against its declared type and enum before apply.
9
+ * `x-kubernetes-int-or-string` and untyped nodes accept anything.
10
+ */
11
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
12
+ export declare const wk8502: PostSynthCheck;
13
+ //# sourceMappingURL=wk8502.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wk8502.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/wk8502.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAG9G,eAAO,MAAM,MAAM,EAAE,cAwBpB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "k8s",
3
- "version": "0.44.14",
3
+ "version": "0.45.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "K8s",
6
6
  "intrinsics": [],