@intentius/chant-lexicon-helm 0.46.0 → 0.50.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 (122) hide show
  1. package/dist/archive-render.d.ts +94 -0
  2. package/dist/archive-render.d.ts.map +1 -0
  3. package/dist/commands.d.ts +54 -0
  4. package/dist/commands.d.ts.map +1 -0
  5. package/dist/config.d.ts +135 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/deep-observe-hooks.d.ts +2 -0
  8. package/dist/deep-observe-hooks.d.ts.map +1 -0
  9. package/dist/deep-observe.d.ts +54 -0
  10. package/dist/deep-observe.d.ts.map +1 -0
  11. package/dist/describe-resources.d.ts +17 -0
  12. package/dist/describe-resources.d.ts.map +1 -0
  13. package/dist/index.d.ts +19 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/integrity.json +5 -3
  16. package/dist/lint/audit-catalog.d.ts.map +1 -1
  17. package/dist/lint/post-synth/index.d.ts.map +1 -1
  18. package/dist/lint/post-synth/whm503.d.ts +34 -0
  19. package/dist/lint/post-synth/whm503.d.ts.map +1 -0
  20. package/dist/lint/post-synth/whm504.d.ts +20 -0
  21. package/dist/lint/post-synth/whm504.d.ts.map +1 -0
  22. package/dist/manifest.json +25 -13
  23. package/dist/okf/index.md +2 -0
  24. package/dist/okf/rules/WHM503.md +15 -0
  25. package/dist/okf/rules/WHM504.md +11 -0
  26. package/dist/okf/types/Values.md +1 -0
  27. package/dist/op/activities/cluster-probe.d.ts +44 -0
  28. package/dist/op/activities/cluster-probe.d.ts.map +1 -0
  29. package/dist/op/activities/helm.d.ts +179 -5
  30. package/dist/op/activities/helm.d.ts.map +1 -1
  31. package/dist/op/activities/index.d.ts +4 -2
  32. package/dist/op/activities/index.d.ts.map +1 -1
  33. package/dist/op/builders.d.ts +47 -0
  34. package/dist/op/builders.d.ts.map +1 -0
  35. package/dist/pinnability/actions.d.ts +76 -0
  36. package/dist/pinnability/actions.d.ts.map +1 -0
  37. package/dist/pinnability/classify.d.ts +129 -0
  38. package/dist/pinnability/classify.d.ts.map +1 -0
  39. package/dist/pinnability/conditions.d.ts +109 -0
  40. package/dist/pinnability/conditions.d.ts.map +1 -0
  41. package/dist/pinnability/index.d.ts +17 -0
  42. package/dist/pinnability/index.d.ts.map +1 -0
  43. package/dist/pinnability/localize.d.ts +124 -0
  44. package/dist/pinnability/localize.d.ts.map +1 -0
  45. package/dist/pinnability/render-stream.d.ts +27 -0
  46. package/dist/pinnability/render-stream.d.ts.map +1 -0
  47. package/dist/pinnability/values.d.ts +69 -0
  48. package/dist/pinnability/values.d.ts.map +1 -0
  49. package/dist/plugin.d.ts.map +1 -1
  50. package/dist/release-observe.d.ts +109 -0
  51. package/dist/release-observe.d.ts.map +1 -0
  52. package/dist/render-diff.d.ts +192 -0
  53. package/dist/render-diff.d.ts.map +1 -0
  54. package/dist/render-digest.d.ts +135 -0
  55. package/dist/render-digest.d.ts.map +1 -0
  56. package/dist/render-store.d.ts +310 -0
  57. package/dist/render-store.d.ts.map +1 -0
  58. package/dist/render-wrapper.d.ts +140 -0
  59. package/dist/render-wrapper.d.ts.map +1 -0
  60. package/dist/render.d.ts +81 -0
  61. package/dist/render.d.ts.map +1 -1
  62. package/dist/rules/whm503.ts +101 -0
  63. package/dist/rules/whm504.ts +52 -0
  64. package/dist/skills/chant-helm.md +7 -0
  65. package/dist/values-probe.d.ts +177 -0
  66. package/dist/values-probe.d.ts.map +1 -0
  67. package/dist/wrapper-chart.d.ts +61 -0
  68. package/dist/wrapper-chart.d.ts.map +1 -0
  69. package/package.json +10 -4
  70. package/src/archive-render.test.ts +201 -0
  71. package/src/archive-render.ts +119 -0
  72. package/src/commands.test.ts +487 -0
  73. package/src/commands.ts +445 -0
  74. package/src/config.test.ts +130 -0
  75. package/src/config.ts +220 -0
  76. package/src/deep-observe-hooks.ts +20 -0
  77. package/src/deep-observe.test.ts +165 -0
  78. package/src/deep-observe.ts +121 -0
  79. package/src/describe-resources.test.ts +255 -0
  80. package/src/describe-resources.ts +198 -0
  81. package/src/index.ts +106 -2
  82. package/src/lifecycle-integration.test.ts +289 -0
  83. package/src/lint/audit-catalog.ts +2 -0
  84. package/src/lint/post-synth/index.ts +4 -0
  85. package/src/lint/post-synth/whm503.test.ts +134 -0
  86. package/src/lint/post-synth/whm503.ts +101 -0
  87. package/src/lint/post-synth/whm504.test.ts +105 -0
  88. package/src/lint/post-synth/whm504.ts +52 -0
  89. package/src/op/activities/cluster-probe.test.ts +66 -0
  90. package/src/op/activities/cluster-probe.ts +148 -0
  91. package/src/op/activities/helm.test.ts +824 -0
  92. package/src/op/activities/helm.ts +628 -5
  93. package/src/op/activities/index.ts +17 -2
  94. package/src/op/builders.test.ts +70 -0
  95. package/src/op/builders.ts +66 -0
  96. package/src/pinnability/actions.ts +263 -0
  97. package/src/pinnability/classify.ts +579 -0
  98. package/src/pinnability/conditions.ts +0 -0
  99. package/src/pinnability/index.ts +77 -0
  100. package/src/pinnability/localize.test.ts +234 -0
  101. package/src/pinnability/localize.ts +644 -0
  102. package/src/pinnability/pinnability.test.ts +560 -0
  103. package/src/pinnability/render-stream.ts +59 -0
  104. package/src/pinnability/values.ts +205 -0
  105. package/src/plugin.test.ts +3 -1
  106. package/src/plugin.ts +97 -12
  107. package/src/release-observe.ts +392 -0
  108. package/src/render-diff.test.ts +366 -0
  109. package/src/render-diff.ts +407 -0
  110. package/src/render-digest.test.ts +186 -0
  111. package/src/render-digest.ts +207 -0
  112. package/src/render-store.test.ts +412 -0
  113. package/src/render-store.ts +621 -0
  114. package/src/render-wrapper.test.ts +259 -0
  115. package/src/render-wrapper.ts +274 -0
  116. package/src/render.test.ts +383 -4
  117. package/src/render.ts +319 -8
  118. package/src/skills/chant-helm.md +7 -0
  119. package/src/values-probe.test.ts +400 -0
  120. package/src/values-probe.ts +627 -0
  121. package/src/wrapper-chart.test.ts +110 -0
  122. package/src/wrapper-chart.ts +124 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Render diffing (#1249 offline, #1250 live — epic #1228 Phase 6), the two
3
+ * halves of `chant helm diff` (./commands.ts).
4
+ *
5
+ * `diffRenders` (#1249) is the offline half: given two content digests
6
+ * already in the render store (render-store.ts), report what changed
7
+ * between them — no cluster, no credentials, no live read. This is the
8
+ * pre-flight question a pin, a chart bump, or a values change all raise:
9
+ * "what will this touch?"
10
+ *
11
+ * Pairing is document-level, keyed on `(kind, namespace, name)` — the same
12
+ * identity `RenderManifest.documents` already indexes (render-store.ts).
13
+ * That index exists precisely so two renders can be matched without
14
+ * reparsing a whole stream: a document present on both sides with the same
15
+ * per-document digest is unchanged and costs nothing further; one whose
16
+ * digest differs is parsed on both sides and diffed field by field.
17
+ *
18
+ * Field-level diffing reuses core's `flattenDeepProperties` /
19
+ * `deepValueEqual` (packages/core/src/deep-observation.ts) — the same
20
+ * path-flattening core's own live-drift diff (lifecycle/deep-diff.ts) is
21
+ * built on. This module does not reuse `diffDeep` itself for the offline
22
+ * path: that function's shape is declared/live/baseline/fieldOwners,
23
+ * tailored to a source tree vs a cluster read. A stored render has neither
24
+ * a baseline nor a field owner, and both sides here are equally "declared"
25
+ * — reusing the flatten/compare primitives without the three-way apparatus
26
+ * is the right cut for render-to-render.
27
+ *
28
+ * Duplicate documents (an aliased dependency emitting the same CRD twice,
29
+ * render-digest.ts's canonicalization note) are matched positionally within
30
+ * their `(kind, namespace, name)` group: first occurrence to first, second
31
+ * to second. A group with more entries on one side reports the surplus as
32
+ * added or removed rather than guessing which duplicate corresponds to
33
+ * which.
34
+ *
35
+ * A document neither side's manifest could index (unparseable, or missing
36
+ * `kind`/`metadata.name` — render-store.ts's `indexRenderDocuments`) cannot
37
+ * be paired by identity. It is never silently dropped: `unindexed` counts
38
+ * it on whichever side(s) it appears, so a diff over two renders that both
39
+ * carry unindexable documents does not quietly under-report.
40
+ *
41
+ * `diffRenderLive` (#1250) is the online complement: given a single
42
+ * `contentDigest` resolved from the render store, read the live property
43
+ * tree for every document the render recorded — by identity
44
+ * (kind/namespace/name), not by helm release — and diff each one against
45
+ * the render's own stored bytes with `lifecycle/deep-diff.ts`. This *does*
46
+ * reuse `diffDeep`'s three-way apparatus (via `diffDeepObservation`): the
47
+ * declared side is the render's stored documents, the live side is a
48
+ * cluster read, which is exactly that function's shape.
49
+ *
50
+ * The declared side for the live path is the render's stored documents,
51
+ * never a fresh `helm template` run and never a chant TS build. A digest
52
+ * not in the store — an unpinned render was never persisted
53
+ * (`render-store.ts`'s `persistHelmRender` refuses that) — has nothing to
54
+ * diff against and comes back `found: false`, never a false "no drift" over
55
+ * documents nobody has (epic AC: unpinned releases handled without false
56
+ * drift).
57
+ *
58
+ * The live side reuses the exact seam `observeResourcesDeepHelm` (#1247)
59
+ * uses — the k8s lexicon's typed client and normalization hooks — so a
60
+ * document this reads and one a release's `describeResources` reads compare
61
+ * under the same rules (secret masking, managed-fields ownership, pruning).
62
+ * Hook resources need no special handling here the way the release-scoped
63
+ * read needs a second `helm get hooks` channel: `helm template` (what
64
+ * produced the stored render) already includes hook manifests as ordinary
65
+ * documents, so they are simply rows in `manifest.documents` like any other.
66
+ */
67
+ import type { DeepDiffResult } from "@intentius/chant/lifecycle/deep-diff";
68
+ import type { K8sConnector } from "@intentius/chant-lexicon-k8s/api/connect";
69
+ import { type RenderManifest } from "./render-store.js";
70
+ /** How one field within a changed document differs between the two renders. */
71
+ export interface RenderFieldChange {
72
+ /** Path within the document's property tree (`spec.replicas`, `data.zeta`). */
73
+ path: string;
74
+ /**
75
+ * `changed` — both renders have the path, with different values.
76
+ * `added` — only the right-hand (`to`) render has it.
77
+ * `removed` — only the left-hand (`from`) render has it.
78
+ */
79
+ kind: "changed" | "added" | "removed";
80
+ /** Value on the `from` side. Absent for `added`. */
81
+ before?: unknown;
82
+ /** Value on the `to` side. Absent for `removed`. */
83
+ after?: unknown;
84
+ }
85
+ /** Identity of one document, for reporting — the same triple documents are paired on. */
86
+ export interface RenderDiffDocumentRef {
87
+ kind: string;
88
+ namespace: string | null;
89
+ name: string;
90
+ /** The `# Source:` origin path, when the document carried one. */
91
+ source: string | null;
92
+ }
93
+ /** A document present on only one side. */
94
+ export interface AddedOrRemovedDocument extends RenderDiffDocumentRef {
95
+ digest: string;
96
+ }
97
+ /** A document present on both sides with different content. */
98
+ export interface ChangedDocument extends RenderDiffDocumentRef {
99
+ /** Per-document digest on the `from` side. */
100
+ beforeDigest: string;
101
+ /** Per-document digest on the `to` side. */
102
+ afterDigest: string;
103
+ /** Field-level differences, sorted by path. Empty only if a document parses but yields no leaves. */
104
+ changes: RenderFieldChange[];
105
+ }
106
+ export interface RenderDiffResult {
107
+ from: {
108
+ contentDigest: string;
109
+ chart: string;
110
+ releaseName: string;
111
+ };
112
+ to: {
113
+ contentDigest: string;
114
+ chart: string;
115
+ releaseName: string;
116
+ };
117
+ /** Present only on `to`. Sorted by kind/namespace/name. */
118
+ added: AddedOrRemovedDocument[];
119
+ /** Present only on `from`. Sorted by kind/namespace/name. */
120
+ removed: AddedOrRemovedDocument[];
121
+ /** Present on both, different bytes. Sorted by kind/namespace/name. */
122
+ changed: ChangedDocument[];
123
+ /** Present on both with equal per-document digest — reported as identities only, no field pass run. */
124
+ unchanged: RenderDiffDocumentRef[];
125
+ /**
126
+ * Documents each manifest's index could not identify — present in the
127
+ * stream (`docCount`) but absent from `documents` (unparseable, or no
128
+ * `kind` + `metadata.name`). Never matched, never silently dropped.
129
+ */
130
+ unindexed: {
131
+ from: number;
132
+ to: number;
133
+ };
134
+ }
135
+ export interface DiffRendersOptions {
136
+ /** Render store root override; defaults to `renderStoreRoot()`. */
137
+ root?: string;
138
+ }
139
+ /**
140
+ * Diff two renders already in the store, by content digest. Offline: every
141
+ * byte compared comes from the archive (render-store.ts), never a cluster.
142
+ *
143
+ * Throws when either digest has no manifest — a diff over a render nobody
144
+ * persisted is a usage error, not an empty report.
145
+ */
146
+ export declare function diffRenders(from: string, to: string, options?: DiffRendersOptions): RenderDiffResult;
147
+ /** True when the diff found no added, removed, or changed documents. */
148
+ export declare function renderDiffIsEmpty(result: RenderDiffResult): boolean;
149
+ export interface RenderLiveDiffOptions {
150
+ /** The stored render to diff against the cluster — a `contentDigest` from `chant helm renders`. */
151
+ contentDigest: string;
152
+ /** The chant environment the live read targets — resolves the k8s cluster binding (`k8s.profiles.<environment>.context`), same as any other live read. */
153
+ environment: string;
154
+ /** Render store root override (tests); defaults to `renderStoreRoot()`. */
155
+ root?: string;
156
+ owned?: boolean;
157
+ }
158
+ export interface RenderLiveDiffDeps {
159
+ /** Forwarded to the k8s reader — a test passes a fake cluster's connector. */
160
+ connect?: K8sConnector;
161
+ }
162
+ export type RenderLiveDiffOutcome = {
163
+ found: true;
164
+ manifest: RenderManifest;
165
+ diff: DeepDiffResult;
166
+ }
167
+ /** No such render in the store — refuse the diff rather than report a false clean result. */
168
+ | {
169
+ found: false;
170
+ contentDigest: string;
171
+ };
172
+ /** Row key convention shared with the release-scoped reads (#1246/#1247): `<Kind>/<namespace>/<name>`, `cluster:<Kind>/<name>`. */
173
+ export declare function documentKey(kind: string, namespace: string | undefined, name: string): string;
174
+ /**
175
+ * A namespace-silent document defaults to the render's target namespace —
176
+ * the same rule a deployed release applies to its manifest (`helm apply
177
+ * -n <ns>` targets whatever a namespace-silent object's `.Release.Namespace`
178
+ * would have filled in) — unless the kind is cluster-scoped, in which case a
179
+ * missing namespace is never defaulted.
180
+ */
181
+ export declare function resolveDocumentNamespace(kind: string, declared: string | null, renderNamespace: string | null): string | undefined;
182
+ /**
183
+ * Diff one stored render's documents against the live cluster.
184
+ *
185
+ * `found: false` when `contentDigest` is not in the store — never fabricates
186
+ * a document, and never reports "no drift" over a render this has no bytes
187
+ * for. On a found render, every document indexed in its manifest becomes a
188
+ * synthetic declared entity (keyed like a release's rows), read live through
189
+ * the k8s lexicon's deep observer, and diffed property-by-property.
190
+ */
191
+ export declare function diffRenderLive(options: RenderLiveDiffOptions, deps?: RenderLiveDiffDeps): Promise<RenderLiveDiffOutcome>;
192
+ //# sourceMappingURL=render-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-diff.d.ts","sourceRoot":"","sources":["../src/render-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAM7E,OAAO,EAAoE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMvH,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACtC,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,yFAAyF;AACzF,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,2CAA2C;AAC3C,MAAM,WAAW,sBAAuB,SAAQ,qBAAqB;IACnE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,qGAAqG;IACrG,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,EAAE,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,2DAA2D;IAC3D,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAChC,6DAA6D;IAC7D,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,uEAAuE;IACvE,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,uGAAuG;IACvG,SAAS,EAAE,qBAAqB,EAAE,CAAC;IACnC;;;;OAIG;IACH,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AA8DD,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,gBAAgB,CA6DpG;AAaD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAEnE;AAMD,MAAM,WAAW,qBAAqB;IACpC,mGAAmG;IACnG,aAAa,EAAE,MAAM,CAAC;IACtB,0JAA0J;IAC1J,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE;AACjE,6FAA6F;GAC3F;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAS5C,mIAAmI;AACnI,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7F;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,eAAe,EAAE,MAAM,GAAG,IAAI,GAC7B,MAAM,GAAG,SAAS,CAIpB;AAYD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,EAC9B,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,qBAAqB,CAAC,CAqChC"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Render canonicalization and the contentDigest/inputDigest split
3
+ * (#1237, epic #1228 Phase 2).
4
+ *
5
+ * A pinned render's output is normalized to a canonical byte form before
6
+ * digesting, and two digests are recorded with different jobs:
7
+ *
8
+ * - `inputDigest` answers "same inputs?" cheaply — a `sha256:` over the
9
+ * canonical JSON of { chart reference, chart version, resolved values,
10
+ * capability profile }. It is the same digest `helmInstall` records in the
11
+ * release ledger (#1243), computed by the same helper, so a render and a
12
+ * deploy of the same inputs share an identity.
13
+ * - `contentDigest` answers "same bytes on the cluster?" — a `sha256:` over
14
+ * the canonical rendered bytes. It is the artifact identity.
15
+ *
16
+ * The two diverge exactly when rendering is unpinned or the chart is
17
+ * unstable: two renders with the same inputDigest but different
18
+ * contentDigests mean the render function is not a function of its declared
19
+ * inputs. That divergence is itself a signal — `renderStability` names it.
20
+ *
21
+ * Canonicalization scope (what the epic measured, not more):
22
+ * - Mapping key order is normalized (sorted) — YAML mappings are unordered
23
+ * in Kubernetes semantics, so key order is render noise. Sequence order is
24
+ * never touched; list order is meaningful to Kubernetes.
25
+ * - Document order is preserved, not sorted. The epic verified document
26
+ * ordering is already stable across renders (three renders, again with
27
+ * subcharts), so reordering would only destroy information.
28
+ * - Duplicate documents are preserved. An aliased dependency emits the same
29
+ * CRD twice (epic finding 11); helm dedupes on install, the artifact keeps
30
+ * both, and the digest stays stable because canonicalization is
31
+ * per-document and order-preserving.
32
+ * - The helm-inserted `# Source:` header is kept (it is the origin-routing
33
+ * key the archive wrapper builds on) and normalized to a single leading
34
+ * line. All other comments, trailing whitespace, CRLF line endings, and
35
+ * document-separator styling are render noise and are dropped or
36
+ * normalized.
37
+ */
38
+ import type { HelmRenderRecord } from "./render.js";
39
+ /**
40
+ * The declared inputs of a helm render or deploy, in the exact shape #1243
41
+ * digests for the release ledger. `helmInstallInputDigest`
42
+ * (op/activities/helm.ts) and `HelmRender`'s recorded `inputDigest` both
43
+ * delegate here, so the two cannot drift: the same chart reference, version,
44
+ * resolved values, and capability facts produce the same digest whether they
45
+ * reach helm through a render or a deploy.
46
+ */
47
+ export interface HelmInputDigestSource {
48
+ /** Chart reference — a local path, or `<repo-url>/<chart>` for repo-fetched charts. */
49
+ chart: string;
50
+ /** Pinned chart version. Digested as `null` when absent. */
51
+ chartVersion?: string;
52
+ /** Resolved values (file merged with overrides). Digested as `{}` when absent. */
53
+ values?: Record<string, unknown>;
54
+ /**
55
+ * Capability facts the render is pinned against. Only the facts join the
56
+ * digest — the profile's *name* is a label, not an input, so two profiles
57
+ * declaring the same cluster digest identically. `apiVersions` is sorted:
58
+ * it declares a set, not an order.
59
+ */
60
+ capabilityProfile?: {
61
+ kubeVersion?: string;
62
+ apiVersions?: string[];
63
+ };
64
+ }
65
+ /**
66
+ * The input-side identity of a helm render or deploy: `sha256:` over the
67
+ * canonical JSON (core's `canonicalJson`, RFC 8785 shape) of the declared
68
+ * inputs. Shared with #1243's release-ledger digest — see
69
+ * `HelmInputDigestSource`. Deliberately excludes the release name and
70
+ * namespace: those are baked into the rendered bytes but the ledger uses
71
+ * this digest as a cross-environment join key, and two environments
72
+ * deploying the same chart, version, and values must share it.
73
+ */
74
+ export declare function helmInputDigest(source: HelmInputDigestSource): string;
75
+ /**
76
+ * Normalize a `helm template` stream to its canonical byte form.
77
+ *
78
+ * Per document: the `# Source:` header (if any) becomes the single leading
79
+ * comment line, the YAML body is re-serialized with sorted mapping keys
80
+ * (sequences untouched), no line-width folding, and a trailing newline.
81
+ * Documents are emitted in render order, each introduced by a `---` line.
82
+ * CRLF endings, trailing whitespace, non-Source comments, and empty or
83
+ * comment-only documents are render noise and do not survive.
84
+ *
85
+ * A document that fails to parse as YAML is kept verbatim (trimmed) rather
86
+ * than dropped — the canonical form must never silently lose content, and a
87
+ * verbatim document still digests deterministically.
88
+ */
89
+ export declare function canonicalizeRender(rendered: string): string;
90
+ /**
91
+ * The content-side identity of a render: `sha256:` over the canonical bytes
92
+ * of the rendered stream (see `canonicalizeRender`). Unlike `inputDigest`,
93
+ * this changes whenever the bytes that would reach the cluster change — a
94
+ * chart upgrade with identical values, a helm version that renders
95
+ * differently, an unstable template.
96
+ */
97
+ export declare function helmContentDigest(rendered: string): string;
98
+ /** One inputDigest's renders and the distinct content identities they produced. */
99
+ export interface RenderStabilityGroup {
100
+ inputDigest: string;
101
+ /** Render names in this group, in record order. */
102
+ names: string[];
103
+ /** Distinct content digests observed, in first-seen order. */
104
+ contentDigests: string[];
105
+ }
106
+ export interface RenderStabilityReport {
107
+ /** Groups whose every render produced the same bytes. */
108
+ stable: RenderStabilityGroup[];
109
+ /**
110
+ * Groups where the same inputs produced different bytes: the render is
111
+ * not pinned down by its declared inputs — an unstable chart, or an input
112
+ * that escaped declaration. Every group here is a defect signal.
113
+ */
114
+ unstable: RenderStabilityGroup[];
115
+ /** Names of records carrying no digests (unpinned renders) — unassessable. */
116
+ unassessed: string[];
117
+ }
118
+ /**
119
+ * Group recorded renders by input identity and report whether the same
120
+ * inputs always produced the same bytes.
121
+ *
122
+ * Two renders with equal `inputDigest` and different `contentDigest` mean
123
+ * the render is not a function of its declared inputs — the chart is
124
+ * unstable (generated values, timestamps) or an input escaped declaration.
125
+ * That divergence is the signal this helper exists to name; a single render
126
+ * per input proves nothing and lands in `stable` by default.
127
+ *
128
+ * Grouping keys on `(inputDigest, name)` because the release name is a real
129
+ * render input baked into the bytes but deliberately absent from
130
+ * `inputDigest` (see `helmInputDigest`) — two differently named renders of
131
+ * the same chart legitimately differ in content and must not be read as
132
+ * instability.
133
+ */
134
+ export declare function renderStability(records: readonly HelmRenderRecord[]): RenderStabilityReport;
135
+ //# sourceMappingURL=render-digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-digest.d.ts","sourceRoot":"","sources":["../src/render-digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAQH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAarE;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoB3D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,mFAAmF;AACnF,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8DAA8D;IAC9D,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,8EAA8E;IAC9E,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,qBAAqB,CAwB3F"}
@@ -0,0 +1,310 @@
1
+ /**
2
+ * RenderManifest + content-addressed render storage (#1238, epic #1228
3
+ * Phase 2).
4
+ *
5
+ * #1237 gave a pinned render its identities — `inputDigest` over the
6
+ * declared inputs, `contentDigest` over the canonical rendered bytes. This
7
+ * module makes the render durable: the canonical bytes land in a
8
+ * content-addressed store keyed by `contentDigest`, and a `RenderManifest`
9
+ * — modeled on core's `BuildArchiveManifest`
10
+ * (packages/core/src/components/verbs/build-archive.ts) — records what the
11
+ * bytes are, what produced them, and how to find each document inside them.
12
+ *
13
+ * Storage layout, under `~/.chant/helm-renders/` (override with
14
+ * `CHANT_HELM_RENDER_ROOT`):
15
+ *
16
+ * ```
17
+ * sha256-<64 hex>/ one per distinct contentDigest
18
+ * content.yaml the canonical rendered bytes (canonicalizeRender)
19
+ * manifest.json the RenderManifest
20
+ * inputs/<64 hex>.json inputs index: full-render-inputs key -> digests
21
+ * ```
22
+ *
23
+ * The `sha256-<hex>` entries are the new root the issue asks for: the
24
+ * pre-#1238 cache keyed entries by a *truncated, input-derived* hash
25
+ * (16 hex characters, no algorithm prefix), which is a cache key, not an
26
+ * artifact identity. Those legacy entries are left exactly where they are —
27
+ * unpinned renders keep using them — and pinned renders write here instead.
28
+ * No migration: a truncated key cannot be turned back into a digest.
29
+ *
30
+ * Two renders that produce the same bytes share one `sha256-<hex>` entry —
31
+ * the content file and manifest are written once and never rewritten
32
+ * (first writer wins; the store is immutable, like a build archive entry).
33
+ * Dedup falls out of content addressing rather than being a feature.
34
+ *
35
+ * The inputs index preserves cache-hit behavior: before shelling out to
36
+ * helm, `HelmRender` computes the full-inputs key and reads
37
+ * `inputs/<key>.json` to find the bytes a previous identical render stored.
38
+ * The index key deliberately differs from `inputDigest`: the release name
39
+ * and namespace are baked into the rendered bytes (`.Release.Name`,
40
+ * `--namespace`) but are excluded from `inputDigest` because the release
41
+ * ledger uses that digest as a cross-environment join key (see
42
+ * `helmInputDigest` in ./render-digest.ts). A cache must key on everything
43
+ * that changes the bytes, so the index key includes both.
44
+ *
45
+ * Retention: none, deliberately. The build archive this is modeled on has
46
+ * no garbage collection — an archive entry lives until someone deletes it —
47
+ * and the pre-#1238 render cache behaved the same way. This store follows
48
+ * suit: entries accumulate until removed by hand. If the archive ever grows
49
+ * a retention story, this store should adopt the same one.
50
+ */
51
+ import type { HelmCapabilityProfile } from "./config.js";
52
+ import type { ValueOrigin } from "./values-probe.js";
53
+ /**
54
+ * One document's entry in a render's document index: enough identity to ask
55
+ * "give me the ServiceAccount named X in namespace Y" and enough addressing
56
+ * to answer it without parsing the whole stream.
57
+ */
58
+ export interface RenderDocumentEntry {
59
+ /** Kubernetes kind, e.g. `Deployment`. */
60
+ kind: string;
61
+ /** apiVersion as rendered, e.g. `apps/v1`. */
62
+ apiVersion: string;
63
+ /** `metadata.name`. */
64
+ name: string;
65
+ /** `metadata.namespace`, or `null` for cluster-scoped / namespace-less documents. */
66
+ namespace: string | null;
67
+ /** The helm-inserted `# Source:` origin path, when the document carries one. */
68
+ source: string | null;
69
+ /**
70
+ * Byte offset of this document's first byte inside `content.yaml`
71
+ * (pointing just past the `---` separator line, at the `# Source:` header
72
+ * when there is one).
73
+ */
74
+ start: number;
75
+ /** Byte length of the document, up to the next separator (or end of file). */
76
+ length: number;
77
+ /** `sha256:` over exactly those bytes — lets a reader verify a slice without trusting offsets. */
78
+ digest: string;
79
+ }
80
+ /**
81
+ * The durable record of one pinned render — what `manifest.json` holds.
82
+ * Modeled on `BuildArchiveManifest`: versioned, content-addressed, and
83
+ * carrying both identity sides the epic's Decisions require — the
84
+ * input-side join key (`inputDigest`, with `valuesDigest` as its
85
+ * values-only component) for cross-environment questions, and
86
+ * `contentDigest` proving what this cluster's profile actually received.
87
+ */
88
+ export interface RenderManifest {
89
+ /** Manifest schema version, so an incompatible future shape is detected before being misread. */
90
+ version: 1;
91
+ /** Chart name or local chart path, as the render declared it. */
92
+ chart: string;
93
+ /** Pinned chart version, or `null` for a local chart rendered without one. */
94
+ chartVersion: string | null;
95
+ /** Chart repo URL, or `null` for a local chart. */
96
+ repo: string | null;
97
+ /** Helm release name baked into the bytes (`.Release.Name`). */
98
+ releaseName: string;
99
+ /** Namespace the render targeted (`--namespace`), or `null`. */
100
+ namespace: string | null;
101
+ /**
102
+ * `sha256:` over the canonical JSON of the resolved values alone — the
103
+ * input-side join key the epic's ledger queries use together with
104
+ * `(chart, chartVersion)`.
105
+ */
106
+ valuesDigest: string;
107
+ /**
108
+ * `sha256:` over the full declared-input set (chart reference, version,
109
+ * values, capability facts) — `helmInputDigest`, the same digest the
110
+ * release ledger records on deploy (#1243).
111
+ */
112
+ inputDigest: string;
113
+ /** The capability profile the render was pinned against. `cluster` is the profile's declared name — profiles are per cluster. */
114
+ capabilityProfile: {
115
+ cluster: string;
116
+ kubeVersion: string;
117
+ apiVersions: string[];
118
+ };
119
+ /** `sha256:` over the canonical rendered bytes — the artifact identity, and this entry's storage key. */
120
+ contentDigest: string;
121
+ /** Number of documents in the canonical stream (including any the index could not identify). */
122
+ docCount: number;
123
+ /** Index of identifiable documents: kind/namespace/name -> byte span + per-document digest. */
124
+ documents: RenderDocumentEntry[];
125
+ /** ISO-8601 timestamp this manifest was written. Not part of any digest. */
126
+ renderedAt: string;
127
+ /**
128
+ * Version of the helm binary that produced the bytes. Load-bearing: the
129
+ * default kube version is a property of the binary (epic finding 1), so
130
+ * this field is what explains a digest mismatch between two machines.
131
+ */
132
+ helmVersion: string;
133
+ /** chant version that wrote this manifest. */
134
+ chantVersion: string;
135
+ /** Source ref/commit the render was produced from, when the caller supplied one. */
136
+ sourceRef: string | null;
137
+ /**
138
+ * `sha256:` over the canonical JSON of the coalesced values the
139
+ * build-time probe (#1251) observed for every chart instance, keyed by
140
+ * scope path — `coalescedValuesDigest` from `./values-probe.ts`. `null`
141
+ * when the probe did not run for this render (a repo-fetched chart, whose
142
+ * source the probe needs on disk, or a probe failure — never fabricated).
143
+ */
144
+ coalescedValuesDigest: string | null;
145
+ /**
146
+ * Each coalesced value's winning layer (#1252), dot-joined root-coordinate
147
+ * path to `ValueOrigin` — `computeValueSources` from `./values-probe.ts`.
148
+ * `null` under the same conditions as `coalescedValuesDigest`.
149
+ */
150
+ valueSources: Record<string, ValueOrigin> | null;
151
+ }
152
+ /** What `inputs/<key>.json` holds: the digests a full-inputs cache key resolves to. */
153
+ export interface RenderInputsIndexEntry {
154
+ version: 1;
155
+ inputDigest: string;
156
+ contentDigest: string;
157
+ }
158
+ /**
159
+ * Root of the render store. `CHANT_HELM_RENDER_ROOT` overrides the default
160
+ * `~/.chant/helm-renders` — the same directory the legacy input-keyed cache
161
+ * lives in; the two coexist because legacy entries are bare 16-hex names
162
+ * and store entries are `sha256-` prefixed.
163
+ */
164
+ export declare function renderStoreRoot(): string;
165
+ /** The full set of inputs that determine a pinned render's bytes. */
166
+ export interface RenderCacheKeySource {
167
+ /** Chart reference — a local path, or `<repo-url>/<chart>` for repo-fetched charts (same convention `helmInputDigest` uses). */
168
+ chart: string;
169
+ chartVersion?: string;
170
+ /** Release name — baked into the bytes via `.Release.Name`, so a real cache input even though `inputDigest` excludes it. */
171
+ releaseName: string;
172
+ /** Namespace — baked in via `--namespace`, likewise excluded from `inputDigest`. */
173
+ namespace?: string;
174
+ values?: Record<string, unknown>;
175
+ capabilityProfile: HelmCapabilityProfile;
176
+ }
177
+ /**
178
+ * Cache key over *everything* that changes a pinned render's bytes — a
179
+ * strict superset of `helmInputDigest`'s inputs (adds release name,
180
+ * namespace, and the profile's declared name, mirroring the legacy cache
181
+ * key's fields). 64 hex characters, no prefix: this is a lookup key, not an
182
+ * artifact identity.
183
+ */
184
+ export declare function renderCacheKey(source: RenderCacheKeySource): string;
185
+ /**
186
+ * `sha256:` over the canonical JSON of the resolved values alone — the
187
+ * `valuesDigest` half of the ledger's input-side join key
188
+ * `(chart, chartVersion, valuesDigest)`. Absent values digest as `{}`,
189
+ * matching `helmInputDigest`'s treatment.
190
+ */
191
+ export declare function helmValuesDigest(values?: Record<string, unknown>): string;
192
+ /**
193
+ * Build the document index over a canonical stream: for every identifiable
194
+ * document (it parses and carries `kind` + `metadata.name`), its
195
+ * kind/namespace/name identity, byte span, and per-document digest.
196
+ * Returns the index and the total document count — the count includes
197
+ * documents the index could not identify, so `docCount` is always the
198
+ * number of documents the artifact carries.
199
+ */
200
+ export declare function indexRenderDocuments(canonical: string): {
201
+ documents: RenderDocumentEntry[];
202
+ docCount: number;
203
+ };
204
+ export interface PersistHelmRenderInput {
205
+ /** The `helm template` output — raw or already canonical; it is canonicalized before storage either way. */
206
+ rendered: string;
207
+ /** Release name the render was produced under (`HelmRenderProps.name`). */
208
+ releaseName: string;
209
+ /** Chart name or local chart path, as declared. */
210
+ chart: string;
211
+ /** Chart repo URL for repo-fetched charts. */
212
+ repo?: string;
213
+ chartVersion?: string;
214
+ namespace?: string;
215
+ values?: Record<string, unknown>;
216
+ /**
217
+ * The capability profile the render was pinned against. Absent means the
218
+ * render was unpinned — persistence is refused, because an unpinned
219
+ * render's bytes are a function of the local helm binary's defaults and
220
+ * have no identity worth storing.
221
+ */
222
+ capabilityProfile?: HelmCapabilityProfile;
223
+ /** Version of the helm binary that produced the bytes. Recorded as `"unknown"` when not supplied. */
224
+ helmVersion?: string;
225
+ /** Source ref/commit, when the caller has one. Never fabricated. */
226
+ sourceRef?: string;
227
+ /**
228
+ * The build-time coalesced-values probe's digest (#1251), when the caller
229
+ * ran one for this render. Absent (not merely `undefined`-passed) records
230
+ * `null` in the manifest — the probe needs the chart source on disk, so a
231
+ * repo-fetched render legitimately has none.
232
+ */
233
+ coalescedValuesDigest?: string;
234
+ /** The probe's value-source attribution (#1252), alongside `coalescedValuesDigest`. */
235
+ valueSources?: Record<string, ValueOrigin>;
236
+ /** Clock override for tests. */
237
+ now?: () => Date;
238
+ /** Store root override; defaults to `renderStoreRoot()`. */
239
+ root?: string;
240
+ }
241
+ export interface PersistedHelmRender {
242
+ /** The manifest now on disk — the existing one when the content was already stored. */
243
+ manifest: RenderManifest;
244
+ /** Directory the render lives in: `<root>/sha256-<hex>`. */
245
+ dir: string;
246
+ /**
247
+ * True when this contentDigest was already in the store — the bytes and
248
+ * manifest were left untouched (only the inputs index was updated).
249
+ */
250
+ deduplicated: boolean;
251
+ }
252
+ /**
253
+ * Persist one pinned render: canonical bytes under their `contentDigest`,
254
+ * the `RenderManifest` beside them, and an inputs-index entry so an
255
+ * identical future render is a cache hit.
256
+ *
257
+ * Content-addressed entries are immutable: when the digest directory
258
+ * already holds a manifest, both files are left as they are and the
259
+ * existing manifest is returned (`deduplicated: true`). The inputs index is
260
+ * still written — a new input combination can legitimately map to bytes the
261
+ * store already holds.
262
+ *
263
+ * Refuses an unpinned render (no capability profile) with the specific
264
+ * reason: no profile means the bytes depend on the local helm binary's
265
+ * defaulted capabilities, so they have no stable content identity to store
266
+ * under.
267
+ */
268
+ export declare function persistHelmRender(input: PersistHelmRenderInput): PersistedHelmRender;
269
+ /** Load the `RenderManifest` stored under a content digest, or `undefined` when the store has no such entry. */
270
+ export declare function loadRenderManifest(contentDigest: string, opts?: {
271
+ root?: string;
272
+ }): RenderManifest | undefined;
273
+ /** Load the canonical rendered bytes stored under a content digest, or `undefined` when absent. */
274
+ export declare function loadRenderContent(contentDigest: string, opts?: {
275
+ root?: string;
276
+ }): string | undefined;
277
+ /** Resolve a full-inputs cache key through the inputs index, or `undefined` on a miss. */
278
+ export declare function findRenderByCacheKey(cacheKey: string, opts?: {
279
+ root?: string;
280
+ }): RenderInputsIndexEntry | undefined;
281
+ /**
282
+ * Every manifest in the store, sorted by `renderedAt` then `contentDigest`
283
+ * for a stable listing. Entries whose manifest is missing or unreadable are
284
+ * skipped — a listing never fails on one corrupt entry. This is the query
285
+ * surface the diff issues (#1249/#1250) resolve digests against.
286
+ */
287
+ export declare function listRenderManifests(opts?: {
288
+ root?: string;
289
+ }): RenderManifest[];
290
+ /** How a caller names one document inside a stored render. */
291
+ export interface RenderDocumentRef {
292
+ kind: string;
293
+ name: string;
294
+ /** Omit (or pass `null`) to match a cluster-scoped / namespace-less document. */
295
+ namespace?: string | null;
296
+ }
297
+ /**
298
+ * Resolve one document by kind/namespace/name to its exact bytes inside a
299
+ * stored render, via the manifest's document index. The slice is verified
300
+ * against the entry's per-document digest before being returned — corrupt
301
+ * content is an error, never silently wrong bytes. `undefined` means the
302
+ * store has no such render or the index has no such document.
303
+ */
304
+ export declare function readRenderDocument(contentDigest: string, ref: RenderDocumentRef, opts?: {
305
+ root?: string;
306
+ }): {
307
+ entry: RenderDocumentEntry;
308
+ text: string;
309
+ } | undefined;
310
+ //# sourceMappingURL=render-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-store.d.ts","sourceRoot":"","sources":["../src/render-store.ts"],"names":[],"mappings":"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"}