@intentius/chant-lexicon-helm 0.46.0 → 0.49.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 (118) 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 +18 -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 +1 -1
  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/pinnability/actions.d.ts +76 -0
  34. package/dist/pinnability/actions.d.ts.map +1 -0
  35. package/dist/pinnability/classify.d.ts +129 -0
  36. package/dist/pinnability/classify.d.ts.map +1 -0
  37. package/dist/pinnability/conditions.d.ts +109 -0
  38. package/dist/pinnability/conditions.d.ts.map +1 -0
  39. package/dist/pinnability/index.d.ts +17 -0
  40. package/dist/pinnability/index.d.ts.map +1 -0
  41. package/dist/pinnability/localize.d.ts +124 -0
  42. package/dist/pinnability/localize.d.ts.map +1 -0
  43. package/dist/pinnability/render-stream.d.ts +27 -0
  44. package/dist/pinnability/render-stream.d.ts.map +1 -0
  45. package/dist/pinnability/values.d.ts +69 -0
  46. package/dist/pinnability/values.d.ts.map +1 -0
  47. package/dist/plugin.d.ts.map +1 -1
  48. package/dist/release-observe.d.ts +109 -0
  49. package/dist/release-observe.d.ts.map +1 -0
  50. package/dist/render-diff.d.ts +192 -0
  51. package/dist/render-diff.d.ts.map +1 -0
  52. package/dist/render-digest.d.ts +135 -0
  53. package/dist/render-digest.d.ts.map +1 -0
  54. package/dist/render-store.d.ts +310 -0
  55. package/dist/render-store.d.ts.map +1 -0
  56. package/dist/render-wrapper.d.ts +140 -0
  57. package/dist/render-wrapper.d.ts.map +1 -0
  58. package/dist/render.d.ts +81 -0
  59. package/dist/render.d.ts.map +1 -1
  60. package/dist/rules/whm503.ts +101 -0
  61. package/dist/rules/whm504.ts +52 -0
  62. package/dist/skills/chant-helm.md +7 -0
  63. package/dist/values-probe.d.ts +177 -0
  64. package/dist/values-probe.d.ts.map +1 -0
  65. package/dist/wrapper-chart.d.ts +61 -0
  66. package/dist/wrapper-chart.d.ts.map +1 -0
  67. package/package.json +10 -4
  68. package/src/archive-render.test.ts +201 -0
  69. package/src/archive-render.ts +119 -0
  70. package/src/commands.test.ts +487 -0
  71. package/src/commands.ts +445 -0
  72. package/src/config.test.ts +130 -0
  73. package/src/config.ts +220 -0
  74. package/src/deep-observe-hooks.ts +20 -0
  75. package/src/deep-observe.test.ts +165 -0
  76. package/src/deep-observe.ts +121 -0
  77. package/src/describe-resources.test.ts +255 -0
  78. package/src/describe-resources.ts +198 -0
  79. package/src/index.ts +98 -2
  80. package/src/lifecycle-integration.test.ts +289 -0
  81. package/src/lint/audit-catalog.ts +2 -0
  82. package/src/lint/post-synth/index.ts +4 -0
  83. package/src/lint/post-synth/whm503.test.ts +134 -0
  84. package/src/lint/post-synth/whm503.ts +101 -0
  85. package/src/lint/post-synth/whm504.test.ts +105 -0
  86. package/src/lint/post-synth/whm504.ts +52 -0
  87. package/src/op/activities/cluster-probe.test.ts +66 -0
  88. package/src/op/activities/cluster-probe.ts +148 -0
  89. package/src/op/activities/helm.test.ts +824 -0
  90. package/src/op/activities/helm.ts +628 -5
  91. package/src/op/activities/index.ts +17 -2
  92. package/src/pinnability/actions.ts +263 -0
  93. package/src/pinnability/classify.ts +579 -0
  94. package/src/pinnability/conditions.ts +0 -0
  95. package/src/pinnability/index.ts +77 -0
  96. package/src/pinnability/localize.test.ts +234 -0
  97. package/src/pinnability/localize.ts +644 -0
  98. package/src/pinnability/pinnability.test.ts +560 -0
  99. package/src/pinnability/render-stream.ts +59 -0
  100. package/src/pinnability/values.ts +205 -0
  101. package/src/plugin.test.ts +3 -1
  102. package/src/plugin.ts +47 -0
  103. package/src/release-observe.ts +392 -0
  104. package/src/render-diff.test.ts +366 -0
  105. package/src/render-diff.ts +407 -0
  106. package/src/render-digest.test.ts +186 -0
  107. package/src/render-digest.ts +207 -0
  108. package/src/render-store.test.ts +412 -0
  109. package/src/render-store.ts +621 -0
  110. package/src/render-wrapper.test.ts +259 -0
  111. package/src/render-wrapper.ts +274 -0
  112. package/src/render.test.ts +383 -4
  113. package/src/render.ts +319 -8
  114. package/src/skills/chant-helm.md +7 -0
  115. package/src/values-probe.test.ts +400 -0
  116. package/src/values-probe.ts +627 -0
  117. package/src/wrapper-chart.test.ts +110 -0
  118. package/src/wrapper-chart.ts +124 -0
@@ -0,0 +1,44 @@
1
+ /** What the probe read off the live cluster. */
2
+ export interface LiveClusterCapabilities {
3
+ /** The server's full version string (`serverVersion.gitVersion`), e.g. `v1.33.6+k3s1`. */
4
+ kubeVersion: string;
5
+ /** The server's `major.minor`, e.g. `1.33`, parsed from `serverVersion.major`/`minor` (or `gitVersion` when those are absent). */
6
+ majorMinor: string;
7
+ /** Every API version the cluster serves, one `group/version` (or `v1`) per entry, from `kubectl api-versions`. */
8
+ apiVersions: string[];
9
+ }
10
+ /**
11
+ * Thrown when the cluster's capabilities cannot be read at all — kubectl
12
+ * missing, cluster unreachable, or unparseable output. A deploy that
13
+ * declared a profile cannot verify its guarantee through this error, so the
14
+ * caller must refuse to proceed rather than deploy blind.
15
+ */
16
+ export declare class ClusterProbeError extends Error {
17
+ constructor(message: string);
18
+ }
19
+ /** `major.minor` from a declared or live version string (`1.33`, `1.33.6`, `v1.33.6+k3s1`). Undefined when the string has no parseable major.minor. */
20
+ export declare function majorMinorOf(version: string): string | undefined;
21
+ /**
22
+ * Read the target cluster's capabilities. Uses whatever kubeconfig/context
23
+ * the process environment provides — the same ambient target `helm upgrade`
24
+ * itself will act on, so the probe and the deploy see one cluster.
25
+ */
26
+ export declare function probeClusterCapabilities(signal?: AbortSignal): Promise<LiveClusterCapabilities>;
27
+ /** The declared facts a profile asserts about a cluster — the activity-side profile shape. */
28
+ export interface DeclaredCapabilityProfile {
29
+ name?: string;
30
+ kubeVersion?: string;
31
+ apiVersions?: string[];
32
+ }
33
+ /**
34
+ * Every way `live` diverges from what `profile` declares, one message per
35
+ * divergence, each naming the declared and the live value. Empty when the
36
+ * cluster matches the profile.
37
+ *
38
+ * kubeVersion compares on major.minor (see module doc). apiVersions is a
39
+ * subset check: everything the profile declares must be served; extra API
40
+ * versions on the cluster are not a divergence, since a render only ever
41
+ * probed the declared set.
42
+ */
43
+ export declare function compareCapabilityProfile(profile: DeclaredCapabilityProfile, live: LiveClusterCapabilities): string[];
44
+ //# sourceMappingURL=cluster-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-probe.d.ts","sourceRoot":"","sources":["../../../src/op/activities/cluster-probe.ts"],"names":[],"mappings":"AAyBA,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;IACpB,kIAAkI;IAClI,UAAU,EAAE,MAAM,CAAC;IACnB,kHAAkH;IAClH,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED,uJAAuJ;AACvJ,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGhE;AA6BD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAqBrG;AAED,8FAA8F;AAC9F,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,yBAAyB,EAClC,IAAI,EAAE,uBAAuB,GAC5B,MAAM,EAAE,CAkBV"}
@@ -1,18 +1,192 @@
1
+ import { type AutoReleaseResult } from "@intentius/chant/components/auto-release";
2
+ /**
3
+ * The cluster capability profile a deploy is declared against (epic #1228).
4
+ * Declared, never sniffed — the epic's finding 1 shows the default kube
5
+ * version is a property of the helm binary, so an undeclared profile cannot
6
+ * be part of a stable identity. When declared it joins the input digest.
7
+ */
8
+ export interface HelmCapabilityProfile {
9
+ /** The profile's declared name (its `helm.capabilityProfiles` key), used in assertion messages. Not part of the digest — only the declared facts are. */
10
+ name?: string;
11
+ /** Kubernetes version the render targets (`--kube-version`). */
12
+ kubeVersion?: string;
13
+ /** Extra API versions the render assumes (`--api-versions`). Order-insensitive for the digest. */
14
+ apiVersions?: string[];
15
+ }
1
16
  export interface HelmInstallArgs {
2
17
  /** Helm release name. */
3
18
  name: string;
4
- /** Chart reference (local path or `repo/chart`). */
5
- chart: string;
19
+ /**
20
+ * Chart reference (local path or `repo/chart`). Required for an unpinned
21
+ * deploy; refused alongside `contentDigest` — a pinned deploy's bytes come
22
+ * from the render store, never from a deploy-time render.
23
+ */
24
+ chart?: string;
25
+ /**
26
+ * `sha256:` content digest of a stored pinned render (#1242). When set,
27
+ * the deploy takes the pinned path: the recorded render is loaded from the
28
+ * render store, its digest verified, and those exact bytes installed as a
29
+ * structure-preserving wrapper chart — no deploy-time render. The chart /
30
+ * values / set / chartVersion render inputs are refused in this mode.
31
+ */
32
+ contentDigest?: string;
33
+ /** Render store root override for the pinned path (tests, non-default stores). Defaults to `CHANT_HELM_RENDER_ROOT` / `~/.chant/helm-renders`. */
34
+ renderStoreRoot?: string;
35
+ /** Chart version to pin (`--version`). Part of the input digest. */
36
+ chartVersion?: string;
6
37
  /** Path to a values file. */
7
38
  values?: string;
8
- /** Kubernetes namespace. */
39
+ /** Kubernetes namespace. Defaults to the stored render's namespace on the pinned path. */
9
40
  namespace?: string;
10
41
  /** Additional --set arguments. */
11
42
  set?: Record<string, string>;
43
+ /** Capability profile the deploy is declared against, if any. Part of the input digest when declared, and asserted against the live target cluster before any helm mutation (#1244). */
44
+ capabilityProfile?: HelmCapabilityProfile;
45
+ /**
46
+ * Deliberate escape hatch for the capability-profile assertion (#1244).
47
+ * When the live cluster diverges from the declared profile — or cannot be
48
+ * probed at all — the deploy normally refuses before any helm mutation.
49
+ * Set `true` to deploy anyway; the bypassed divergences are warned about
50
+ * and recorded in the release record (`profileOverride`), so the ledger
51
+ * shows the release knowingly skewed from its declared profile. Has no
52
+ * effect when the cluster matches, and none when no profile is declared.
53
+ */
54
+ overrideProfileAssertion?: boolean;
55
+ /** Component name for the release record. Defaults to the release `name` — a chart's release is its deploy unit. */
56
+ component?: string;
57
+ /** Environment for the release record. Defaults to `"local"`, the same default `chant run --components` applies. */
58
+ env?: string;
59
+ /** Run id for the release record. Defaults to `$GITHUB_RUN_ID`/`$CI_PIPELINE_ID`, then a locally generated id — the same fallback chain `chant components release` uses. */
60
+ runId?: string;
61
+ /** Set `false` to skip release-record emission, mirroring `--no-release-record`. Default: emission is ON. */
62
+ recordRelease?: boolean;
63
+ }
64
+ /** What `helmInstall` returns: the input digest and the release-record outcome, so a workflow can carry both. */
65
+ export interface HelmInstallResult {
66
+ /**
67
+ * `sha256:` digest over the deploy's *inputs* — chart, chart version,
68
+ * resolved values, capability profile if declared (#1243). This is the
69
+ * input-side join key: two environments deploying the same chart at the
70
+ * same version with the same values share it even when their clusters
71
+ * legitimately differ. It is deliberately not a rendered-output digest —
72
+ * that is the pinned-render work of later #1228 phases. Absent only when
73
+ * the digest could not be computed (see `release.reason`).
74
+ */
75
+ inputDigest?: string;
76
+ /** Outcome of the ledger append — `recorded: true` carries the `ReleaseRecord` written. */
77
+ release: AutoReleaseResult;
78
+ /**
79
+ * Outcome of the deploy-time capability-profile assertion (#1244). Present
80
+ * exactly when the deploy declared a profile with assertable facts (on the
81
+ * pinned path the stored render's profile always is one). A mismatch
82
+ * without the override never reaches a result — the activity throws before
83
+ * any helm mutation — so a present outcome is either a verified match or a
84
+ * deliberate, recorded override.
85
+ */
86
+ profileAssertion?: HelmProfileAssertionOutcome;
87
+ /** Helm release name the deploy targeted (`args.name`). */
88
+ releaseName: string;
89
+ /** Namespace the deploy targeted, or `null` when helm's default applied. */
90
+ namespace: string | null;
91
+ /**
92
+ * True when this deploy took the pinned path (#1242): recorded bytes
93
+ * loaded from the render store, digest-verified, installed as a wrapper
94
+ * chart with no deploy-time render.
95
+ */
96
+ pinned: boolean;
97
+ /**
98
+ * `sha256:` content digest of the installed render — the artifact identity
99
+ * (the epic's `renderDigest`, named for the #1237 split). Pinned path only:
100
+ * an unpinned deploy has no rendered-output identity to report.
101
+ */
102
+ contentDigest?: string;
103
+ /**
104
+ * Release revision after the deploy, from `helm get metadata -o json`.
105
+ * Pinned path only, and absent when the metadata read failed after a
106
+ * successful install (best-effort, like the ledger append).
107
+ */
108
+ revision?: number;
109
+ /** Chart version installed — `helm get metadata`'s `version`, falling back to the stored render's. Pinned path only. */
110
+ chartVersion?: string | null;
111
+ /** Number of CRD documents shipped in the wrapper's `crds/` (uninstall-safe; epic finding 4). Pinned path only. */
112
+ crdsApplied?: number;
113
+ /** Number of non-CRD documents installed through the wrapper's templates (hook documents included). Pinned path only. */
114
+ docsApplied?: number;
115
+ /** Number of hook documents among `docsApplied` — helm registers and runs them from their recorded annotations (epic finding 5). Pinned path only. */
116
+ hooksRun?: number;
12
117
  }
118
+ /** Thrown by the pinned path (#1242) when `contentDigest` resolves to nothing in the render store. */
119
+ export declare class PinnedRenderNotFoundError extends Error {
120
+ constructor(contentDigest: string, root: string);
121
+ }
122
+ /** Thrown by the pinned path (#1242) when the stored bytes no longer hash to their digest — store corruption, caught before any mutation. */
123
+ export declare class PinnedRenderIntegrityError extends Error {
124
+ constructor(contentDigest: string, actual: string);
125
+ }
126
+ /** Thrown by the pinned path (#1242) when the call mixes pinned and unpinned inputs, or targets a release name the bytes were not rendered for. */
127
+ export declare class PinnedInstallInputError extends Error {
128
+ constructor(message: string);
129
+ }
130
+ /**
131
+ * Thrown by the pinned path (#1242) when the deploy's declared capability
132
+ * profile disagrees with the profile recorded in the stored render's
133
+ * manifest. Distinct from `CapabilityProfileMismatchError` (#1244, declared
134
+ * vs *live cluster*): this is declared vs *recorded*, checked first and
135
+ * entirely offline.
136
+ */
137
+ export declare class PinnedProfileMismatchError extends Error {
138
+ constructor(release: string, contentDigest: string, divergences: string[]);
139
+ }
140
+ /** How the deploy-time profile assertion (#1244) concluded, when a profile was declared. */
141
+ export type HelmProfileAssertionOutcome = {
142
+ matched: true;
143
+ } | {
144
+ matched: false;
145
+ divergences: string[];
146
+ overridden: true;
147
+ };
148
+ /**
149
+ * Thrown before any helm mutation when the target cluster does not match the
150
+ * deploy's declared capability profile (#1244). The message names every
151
+ * divergence — declared vs live — so the refusal is specific, never a shrug.
152
+ */
153
+ export declare class CapabilityProfileMismatchError extends Error {
154
+ readonly divergences: string[];
155
+ constructor(release: string, profileName: string | undefined, divergences: string[]);
156
+ }
157
+ /**
158
+ * The input-side identity of a helm deploy (#1243): a `sha256:` digest over
159
+ * the canonical JSON of `{ chart, chartVersion, values, capabilityProfile? }`.
160
+ * Canonical JSON (core's `canonicalJson`, RFC 8785 shape) sorts object keys,
161
+ * so the digest is stable across value key order; `apiVersions` is sorted
162
+ * for the same reason. The digest changes when any actual input changes —
163
+ * the chart, its version, a value, the declared profile.
164
+ *
165
+ * Delegates to `helmInputDigest` (#1237) — the same helper `HelmRender`
166
+ * records as a pinned render's `inputDigest` — so a deploy and a render of
167
+ * the same inputs share their identity by construction.
168
+ */
169
+ export declare function helmInstallInputDigest(args: HelmInstallArgs): string;
13
170
  /**
14
- * Run `helm upgrade --install <name> <chart>`.
171
+ * Deploy a helm release and append a `ReleaseRecord` (#1243).
172
+ *
173
+ * Two paths, selected by `contentDigest`:
174
+ *
175
+ * - **Unpinned** (no `contentDigest`): `helm upgrade --install <name>
176
+ * <chart>`, exactly as before #1242 — helm renders at deploy time. The
177
+ * ledger record is keyed by the input digest.
178
+ * - **Pinned** (`contentDigest` set, #1242): the recorded render is loaded
179
+ * from the render store, its digest verified, and those exact bytes
180
+ * installed as a structure-preserving wrapper chart — no deploy-time
181
+ * render. The ledger record is keyed by the content digest and carries
182
+ * the stored render's input digest alongside it.
183
+ *
184
+ * A ledger-append failure after a successful deploy warns and never throws:
185
+ * the deploy already happened, so a ledger-write hiccup must not turn a
186
+ * finished deploy into a failed activity — the record is observability, not
187
+ * part of the deploy itself.
188
+ *
15
189
  * Uses longInfra profile — 20m timeout, heartbeat every 15s.
16
190
  */
17
- export declare function helmInstall(args: HelmInstallArgs, signal?: AbortSignal): Promise<void>;
191
+ export declare function helmInstall(args: HelmInstallArgs, signal?: AbortSignal): Promise<HelmInstallResult>;
18
192
  //# sourceMappingURL=helm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helm.d.ts","sourceRoot":"","sources":["../../../src/op/activities/helm.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB5F"}
1
+ {"version":3,"file":"helm.d.ts","sourceRoot":"","sources":["../../../src/op/activities/helm.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,8 @@
6
6
  * The `helmInstall` step builder stays in core (@intentius/chant/op), re-exported
7
7
  * from the temporal Op-authoring barrel like the other core builders.
8
8
  */
9
- export { helmInstall } from "./helm.js";
10
- export type { HelmInstallArgs } from "./helm.js";
9
+ export { helmInstall, helmInstallInputDigest, CapabilityProfileMismatchError, PinnedRenderNotFoundError, PinnedRenderIntegrityError, PinnedInstallInputError, PinnedProfileMismatchError, } from "./helm.js";
10
+ export type { HelmInstallArgs, HelmInstallResult, HelmCapabilityProfile, HelmProfileAssertionOutcome, } from "./helm.js";
11
+ export { probeClusterCapabilities, compareCapabilityProfile, ClusterProbeError } from "./cluster-probe.js";
12
+ export type { LiveClusterCapabilities, DeclaredCapabilityProfile } from "./cluster-probe.js";
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/op/activities/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,8BAA8B,EAC9B,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,QAAQ,CAAC;AAChB,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxG,YAAY,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Go template action extraction and control-flow scoping (#1234, epic #1228).
3
+ *
4
+ * The pinnability gate inspects template ACTIONS (`{{ ... }}`), never raw
5
+ * text. That distinction is finding 9: cert-manager carries 52 textual
6
+ * "lookup" occurrences, all comment prose, and a real template-action count
7
+ * of 0 — a text-matching gate refuses a chart that is perfectly pinnable.
8
+ *
9
+ * Beyond extraction, this module reconstructs the control-flow structure of a
10
+ * template file — which `if` / `with` / `range` blocks enclose each action —
11
+ * so the classifier can ask whether a construct is REACHABLE under the
12
+ * supplied values, not merely present. Reachability is what separates
13
+ * "unpinnable" from "pinnable with a recorded conditional hazard": bundled
14
+ * grafana's control-flow `lookup` sits behind `persistence.enabled`, off by
15
+ * default, so a default-values render never consults the cluster.
16
+ */
17
+ export type ActionKind = "if" | "elseif" | "else" | "with" | "range" | "define" | "block" | "end" | "other";
18
+ export interface TemplateAction {
19
+ /** Path of the file the action was found in (as given by the caller). */
20
+ file: string;
21
+ /** 1-based line the action starts on. */
22
+ line: number;
23
+ /** The action body between `{{` and `}}`, trim markers stripped. */
24
+ body: string;
25
+ /** Structural role of the action, from its leading keyword. */
26
+ kind: ActionKind;
27
+ }
28
+ /**
29
+ * One enclosing control-flow frame for an action. `conditions` are the
30
+ * expressions that must hold for the frame's branch to run; `negatedConditions`
31
+ * are prior branch conditions that must NOT hold (an `else` / `else if`
32
+ * branch runs only when every earlier branch condition was false).
33
+ */
34
+ export interface ScopeFrame {
35
+ kind: "if" | "with" | "range" | "define" | "block" | "dependency-condition";
36
+ conditions: string[];
37
+ negatedConditions: string[];
38
+ /**
39
+ * When a `with` block pins the dot to a `.Values` subtree, the path of that
40
+ * subtree — so bare `.enabled` inside `with .Values.persistence` resolves
41
+ * to `persistence.enabled`. `undefined` means the dot is unresolvable
42
+ * (a `range` element, a non-values `with`, a `define` invoked from an
43
+ * unknown context).
44
+ */
45
+ dotValuesPath?: string[];
46
+ /** Dot is rebound to something we cannot resolve (range element etc.). */
47
+ dotUnresolvable?: boolean;
48
+ }
49
+ export interface ScopedAction {
50
+ action: TemplateAction;
51
+ /** Enclosing frames, outermost first. Empty for top-level actions. */
52
+ frames: ScopeFrame[];
53
+ }
54
+ /**
55
+ * Extract template actions from a source file, skipping comment actions
56
+ * (`{{/* ... *\/}}`). Text outside actions — including YAML `#` comments,
57
+ * where finding 9's 52 false positives lived — is never inspected by any
58
+ * scan built on this.
59
+ */
60
+ export declare function extractActions(source: string, file: string): TemplateAction[];
61
+ /**
62
+ * The pipeline of an action, structural keyword and variable assignment
63
+ * stripped: `if X` → `X`, `range $i, $v := X` → `X`, `$pw := X` → `X`.
64
+ * This is what condition evaluation and call-reachability parse.
65
+ */
66
+ export declare function actionPipeline(action: TemplateAction): string;
67
+ /**
68
+ * Walk a file's actions and attach the enclosing control-flow frames to each.
69
+ * `else` / `else if` branches carry the prior branch conditions as
70
+ * `negatedConditions`. Structure that cannot be tracked (an unbalanced
71
+ * `end`, template text split across files) degrades to fewer frames — which
72
+ * only ever makes the classifier MORE conservative, never less: a missing
73
+ * frame means a gate we cannot prove closed.
74
+ */
75
+ export declare function scopeActions(actions: TemplateAction[]): ScopedAction[];
76
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/pinnability/actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,UAAU,GAClB,IAAI,GACJ,QAAQ,GACR,MAAM,GACN,MAAM,GACN,OAAO,GACP,QAAQ,GACR,OAAO,GACP,KAAK,GACL,OAAO,CAAC;AAEZ,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,sBAAsB,CAAC;IAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,cAAc,CAAC;IACvB,sEAAsE;IACtE,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAaD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAqC7E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAO7D;AAeD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,CAwGtE"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * The pinnability gate (#1234, epic #1228 Phase 1).
3
+ *
4
+ * A render is pinnable exactly when every input to it is closed. `helm
5
+ * template` has three inputs beyond (chart, values) that are silently
6
+ * defaulted or silently empty:
7
+ *
8
+ * - cluster capabilities — closable via --kube-version / --api-versions
9
+ * - generated values — closable by supplying the value as an input
10
+ * - cluster state (lookup) — not closable offline
11
+ *
12
+ * The gate is therefore not "is this chart deterministic" but "are all of
13
+ * this render's inputs closed" — a property of `(chart, values)`, not of the
14
+ * chart alone. Concretely:
15
+ *
16
+ * - A control-flow `lookup` that is REACHABLE under the supplied values is
17
+ * a hard refusal: it changes which documents exist, and no value
18
+ * substitution recovers that.
19
+ * - A control-flow `lookup` the supplied values leave gated OFF is a
20
+ * recorded conditional hazard, not a refusal — bundled grafana's
21
+ * `lookup` behind `persistence.enabled: false` never runs, so the
22
+ * render is pinnable; flipping that value re-classifies the pair.
23
+ * - Value-position `lookup` is a declared-input requirement (epic
24
+ * Decisions): it changes a field, not the document set.
25
+ * - `.Capabilities.*` references require an explicit capability profile —
26
+ * the default is a property of the helm BINARY (3.16.2 says v1.31.0,
27
+ * 4.1.1 says v1.35.0), so an unpinned render's digest depends on who
28
+ * rendered it. 11 of the 13 survey charts hit this; it is the normal
29
+ * case, not an error.
30
+ * - Generated values (`randAlphaNum` and friends) are detected statically
31
+ * and named; the double-render localizer (#1236) confirms them
32
+ * dynamically. They classify as closable when a `.Values` path in the
33
+ * same action can supply them.
34
+ *
35
+ * A chart that fails is refused with the specific construct and location,
36
+ * and keeps working unpinned. Adoption is incremental.
37
+ */
38
+ import { type GatePath } from "./conditions.js";
39
+ export type PinnabilityVerdict = "deterministic" | "pinnable" | "unpinnable";
40
+ /** One `.Capabilities.*` reference; any of these makes a profile required. */
41
+ export interface CapabilityRequirement {
42
+ file: string;
43
+ line: number;
44
+ capability: "KubeVersion" | "APIVersions";
45
+ }
46
+ /** An input that must be (or has been) closed for the render to pin. */
47
+ export interface ClosedInput {
48
+ kind: "generated-value" | "value-position-lookup" | "supplied-values";
49
+ file?: string;
50
+ line?: number;
51
+ /** Template function for generated values (randAlphaNum, genCA, ...). */
52
+ fn?: string;
53
+ /** Root-scoped `.Values` path that can supply the input, when one exists. */
54
+ valuesPath?: string;
55
+ /** Can this input be closed by supplying a value at all? */
56
+ suppliable?: boolean;
57
+ detail: string;
58
+ }
59
+ /**
60
+ * A control-flow `lookup` the supplied values leave unreachable. Recorded —
61
+ * not refused — so that flipping the gating value later re-classifies the
62
+ * `(chart, values)` pair instead of silently changing which documents exist.
63
+ */
64
+ export interface ConditionalHazard {
65
+ /** Instance scope in root coordinates ("" = the top-level chart, "grafana" = that subchart). */
66
+ chart: string;
67
+ file: string;
68
+ line: number;
69
+ /** The values path(s) currently gating the construct off, with their values. */
70
+ gates: GatePath[];
71
+ detail: string;
72
+ }
73
+ /** A control-flow `lookup` site, aggregated across chart instances. */
74
+ export interface ControlFlowLookup {
75
+ file: string;
76
+ line: number;
77
+ action: string;
78
+ status: "refused" | "hazard";
79
+ /** Instance scopes the site was assessed in ("" = root). */
80
+ charts: string[];
81
+ }
82
+ export interface ValuePositionLookup {
83
+ file: string;
84
+ line: number;
85
+ action: string;
86
+ }
87
+ /** Evidence from an actual double render (#1236 owns producing this). */
88
+ export interface RenderEvidence {
89
+ stable: boolean;
90
+ unstableLines: number;
91
+ }
92
+ export interface PinnabilityReport {
93
+ verdict: PinnabilityVerdict;
94
+ /** `.Capabilities.*` references, one entry per occurrence. Empty = no profile needed. */
95
+ requiresProfile: CapabilityRequirement[];
96
+ closedInputs: ClosedInput[];
97
+ hazards: ConditionalHazard[];
98
+ /** Human-readable summary; refusal reasons first, specific per construct. */
99
+ reasons: string[];
100
+ /** Raw lookup findings, for surfaces that need counts or locations. */
101
+ lookups: {
102
+ controlFlow: ControlFlowLookup[];
103
+ valuePosition: ValuePositionLookup[];
104
+ };
105
+ /** Non-fatal scan caveats (an unvendored dependency, etc.). */
106
+ warnings: string[];
107
+ }
108
+ export interface ClassifyChartOptions {
109
+ /** Values overrides, as `helm template --values` would merge them. */
110
+ values?: unknown;
111
+ /** Values files to load and merge (in order) over the chart defaults. */
112
+ valuesFiles?: string[];
113
+ /** Double-render evidence, when the caller has rendered. */
114
+ renderEvidence?: RenderEvidence;
115
+ }
116
+ /**
117
+ * Template files of ONE chart directory — `templates/` at any depth below
118
+ * it, excluding `charts/` (subcharts are their own instances) and NOTES.txt
119
+ * (rendered for the console, not the cluster).
120
+ */
121
+ export declare function collectOwnTemplateFiles(chartDir: string): string[];
122
+ /**
123
+ * Classify a chart directory against the values a render would be given.
124
+ * Subchart-recursive: dependencies vendored under `charts/` are scanned with
125
+ * their own effective values (aliases get their own scope, `condition:`-
126
+ * disabled dependencies gate their contents — findings 11 and 12).
127
+ */
128
+ export declare function classifyChart(chartDir: string, options?: ClassifyChartOptions): PinnabilityReport;
129
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/pinnability/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAYH,OAAO,EAML,KAAK,QAAQ,EAEd,MAAM,cAAc,CAAC;AAStB,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG,UAAU,GAAG,YAAY,CAAC;AAE7E,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,GAAG,aAAa,CAAC;CAC3C;AAED,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,iBAAiB,GAAG,uBAAuB,GAAG,iBAAiB,CAAC;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,gGAAgG;IAChG,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,4DAA4D;IAC5D,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,yFAAyF;IACzF,eAAe,EAAE,qBAAqB,EAAE,CAAC;IACzC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,uEAAuE;IACvE,OAAO,EAAE;QACP,WAAW,EAAE,iBAAiB,EAAE,CAAC;QACjC,aAAa,EAAE,mBAAmB,EAAE,CAAC;KACtC,CAAC;IACF,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AA2DD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBlE;AA8FD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,oBAAyB,GACjC,iBAAiB,CAqPnB"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Tri-state evaluation of template pipeline conditions against supplied
3
+ * values (#1234, epic #1228).
4
+ *
5
+ * The classifier must decide whether a control-flow construct is REACHABLE
6
+ * under the values the render was given. That needs no template engine —
7
+ * only enough of Go template expression semantics to evaluate the gates
8
+ * charts actually write: `and` / `or` / `not` / `eq` / `ne` / `empty`,
9
+ * parenthesised sub-expressions, literals, and `.Values` paths.
10
+ *
11
+ * Everything else evaluates to UNKNOWN, and unknown always degrades toward
12
+ * refusal, never toward pinning: a gate we cannot prove closed is treated as
13
+ * open. The only way a control-flow `lookup` avoids refusal is a gate that
14
+ * DEFINITIVELY evaluates false against the supplied values.
15
+ *
16
+ * Values fidelity caveat: the evaluator sees chant's approximation of helm's
17
+ * value coalescing (parent-overrides-child, alias scoping, globals — see
18
+ * values.ts). The build-time values probe (#1251) replaces that
19
+ * approximation with helm's own coalescing; until then, exotic mechanisms
20
+ * (`import-values`, `tpl`-computed values) resolve as unknown or absent,
21
+ * both of which are safe directions for a gate.
22
+ */
23
+ export declare const UNKNOWN: unique symbol;
24
+ export type Tri = boolean | typeof UNKNOWN;
25
+ /** Go template truthiness: false, zero, "", nil, empty collection are false. */
26
+ export declare function truthy(v: unknown): boolean;
27
+ /** The evaluation context: effective values plus dot binding. */
28
+ export interface EvalContext {
29
+ /** Effective values for the chart instance being evaluated. */
30
+ values: unknown;
31
+ /**
32
+ * Root-scope prefix of this instance ("grafana" for the grafana subchart of
33
+ * an umbrella), used to report gate paths in the PARENT's coordinates.
34
+ */
35
+ scope: readonly string[];
36
+ /**
37
+ * When the dot is pinned to a `.Values` subtree by an enclosing `with`,
38
+ * that subtree's path; `null` when the dot is the root context;
39
+ * `undefined` when unresolvable.
40
+ */
41
+ dotValuesPath: string[] | null | undefined;
42
+ }
43
+ /** A definitively-false conjunct and the values path responsible for it. */
44
+ export interface GatePath {
45
+ /** Values path in the ROOT chart's coordinates, e.g. "grafana.persistence.enabled". */
46
+ path: string;
47
+ /** The value the path currently holds (rendered for the hazard record). */
48
+ value: unknown;
49
+ }
50
+ export interface EvalResult {
51
+ value: Tri;
52
+ /** When `value` is false: the values path(s) that made it false. */
53
+ gates: GatePath[];
54
+ }
55
+ type Token = {
56
+ t: "lparen";
57
+ } | {
58
+ t: "rparen";
59
+ } | {
60
+ t: "pipe";
61
+ } | {
62
+ t: "str";
63
+ v: string;
64
+ } | {
65
+ t: "num";
66
+ v: number;
67
+ } | {
68
+ t: "word";
69
+ v: string;
70
+ };
71
+ export declare function tokenize(expr: string): Token[] | undefined;
72
+ export type ExprNode = {
73
+ type: "call";
74
+ op: string;
75
+ args: ExprNode[];
76
+ } | {
77
+ type: "atom";
78
+ token: Token;
79
+ } | {
80
+ type: "pipeline";
81
+ stages: ExprNode[];
82
+ };
83
+ /**
84
+ * Parse a pipeline expression into an AST. Returns undefined on anything the
85
+ * small grammar does not cover — which the evaluator then treats as UNKNOWN.
86
+ */
87
+ export declare function parseExpr(expr: string): ExprNode | undefined;
88
+ /**
89
+ * Evaluate a condition expression to a tri-state truth value. When the
90
+ * result is definitively false, `gates` names the values path(s)
91
+ * responsible — the record a conditional hazard carries so that flipping
92
+ * the value later re-classifies the chart.
93
+ */
94
+ export declare function evaluateCondition(expr: string, ctx: EvalContext): EvalResult;
95
+ /**
96
+ * Is a call to `fn` inside `expr` actually evaluated, given short-circuit
97
+ * `and` / `or`? Returns the gates that make it unreachable, or "reachable"
98
+ * when no definitive gate precedes the call.
99
+ *
100
+ * `and A (lookup ...)` with A false never calls lookup (Go templates
101
+ * short-circuit since 1.18, which every supported helm builds against);
102
+ * `or A (lookup ...)` with A true likewise skips it.
103
+ */
104
+ export declare function callReachability(expr: string, fnRe: RegExp, ctx: EvalContext): {
105
+ reachable: Tri;
106
+ gates: GatePath[];
107
+ };
108
+ export {};
109
+ //# sourceMappingURL=conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../../src/pinnability/conditions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,OAAO,eAAoB,CAAC;AACzC,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,OAAO,OAAO,CAAC;AAE3C,gFAAgF;AAChF,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAM1C;AAED,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;;OAIG;IACH,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CAC5C;AAED,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,GAAG,CAAC;IACX,oEAAoE;IACpE,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAID,KAAK,KAAK,GACN;IAAE,CAAC,EAAE,QAAQ,CAAA;CAAE,GACf;IAAE,CAAC,EAAE,QAAQ,CAAA;CAAE,GACf;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GACb;IAAE,CAAC,EAAE,KAAK,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACvB;IAAE,CAAC,EAAE,KAAK,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACvB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7B,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,SAAS,CAiC1D;AAID,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,EAAE,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAO5D;AAuMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,UAAU,CAW5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,WAAW,GACf;IAAE,SAAS,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,CA8CvC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Pinnability gate for helm renders (#1234, epic #1228 Phase 1).
3
+ *
4
+ * `classifyChart` is the entry point the pinned-render pipeline
5
+ * (#1235–#1240) calls before anything is pinned; the survey harness
6
+ * (lexicons/helm/test/survey) asserts its verdicts over a corpus of real
7
+ * upstream charts. This module deliberately imports nothing from the
8
+ * lexicon's generated artifacts, so it loads on a fresh clone and in the
9
+ * survey CI job without a generation step.
10
+ */
11
+ export { classifyChart, type PinnabilityVerdict, type PinnabilityReport, type ClassifyChartOptions, type CapabilityRequirement, type ClosedInput, type ConditionalHazard, type ControlFlowLookup, type ValuePositionLookup, type RenderEvidence, collectOwnTemplateFiles, } from "./classify.js";
12
+ export { actionPipeline, extractActions, scopeActions, type TemplateAction, type ActionKind, type ScopedAction, type ScopeFrame, } from "./actions.js";
13
+ export { UNKNOWN, truthy, evaluateCondition, callReachability, parseExpr, type Tri, type EvalContext, type EvalResult, type GatePath, } from "./conditions.js";
14
+ export { buildChartInstances, mergeValues, valueAtPath, readChartMeta, type ChartInstance, type ChartDependency, type ChartMeta, } from "./values.js";
15
+ export { splitDocuments, sourcePath, isCrdSource, routeBySource, countDifferingLines, type RoutedDocuments, } from "./render-stream.js";
16
+ export { localizeOpenInputs, diffRenderPair, type RenderFn, type PinStyle, type CandidatePin, type LocalizedOccurrence, type LocalizedInput, type LocalizationReport, type LocalizeOptions, } from "./localize.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pinnability/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,EACd,cAAc,EACd,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,OAAO,EACP,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,KAAK,GAAG,EACR,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,cAAc,EACd,UAAU,EACV,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC"}