feat: resolve tagless images through the governing chart's appVersion - #43
Merged
Merged
Conversation
Reading a scalar's exact source text, rather than the value YAML parsed it into, is about to have a second reader: chart metadata needs `appVersion` read under the same rules a tag is read under. Move the primitive into its own module so both readers agree on what "usable" means instead of one importing an internal of the other. Pure move. The extract-image-references test suite is untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A values file means little on its own. Its tags may be absent, in which case Helm renders `.Chart.AppVersion` in their place, and whether the file is worth reading at all depends on the chart it sits under. The nearest ancestor holding `Chart.yaml` wins, so a subchart's values file resolves against the subchart's own metadata rather than its parent's, which is what Helm would actually deploy. Everything under the chart's `templates/` directory is out of scope, Go template source being nothing this package can check. With no chart above it, a file is in scope only when its own name says it is a values file. Paths are split on `/` rather than handed to `node:path`. Callers pass a URI path, forward-slash separated on every platform, and this package stays free of platform path semantics. `ResolvedTag` distinguishes the two provenances because they differ in what they can offer a message: a tag written in the file has a range to underline, a tag taken from chart metadata has a file to point at. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ppVersion
Which YAML files this extension marks up is now the Helm package's answer,
not a filename pattern here: anything beneath a chart directory is in scope,
that chart's `templates/` directory never is, and a tagless reference is
checked against the governing chart's `appVersion`, which is what Helm would
render in its place.
A tagless reference nothing can resolve is dropped before the registry is
asked, so it renders no mark, no hover, and no diagnostic. That makes the
`'no-tag'` reason dead, and with it the `UncheckedReason` and
`ReferenceVerdict` wrappers: every surface now takes `ImageVerdict` and
`UnverifiableReason` from the registry package directly. Callers migrated and
the old names deleted in one wave rather than aliased.
A tag the file never wrote needs saying so. Its `tag-not-found` diagnostic
attaches to the repository value, there being nothing else to underline, and
both the diagnostic and the hover name the chart it came from through one
shared sentence, so the two surfaces cannot word it differently.
A `Chart.{yaml,yml}` watcher re-checks the open documents each chart governs.
A version bump otherwise leaves a stale checkmark standing at exactly the
moment correctness matters most.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Accepting `Chart.yml` alongside `Chart.yaml` resolved an `appVersion` out of a file Helm's own loader ignores, contradicting the reason chart context exists: to answer with what Helm would actually deploy. Dropping it also halves the filesystem probes per ancestor directory, and leaves a single exported constant a watcher can be built from rather than a list another workspace has to spell out again. A chart's own `Chart.yaml` also came back in scope as a values file, since the exclusion test only looked for a `templates` segment. It declares a chart rather than supplying values to one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The watcher glob spelled out the chart metadata names a second time, in a different workspace from the resolver that reads them. A future third spelling would have left the watcher silently under-covering, which shows up as nothing happening. It is derived from the resolver's constant now. The `onDidCreate` registration could match nothing. A document checked without a chart records no metadata path, so a chart appearing above it never re-checks it. Catching that means re-resolving every open document on every write, which no ticket has asked for, so the dead registration goes and the limitation is written down on the handler instead. `chartProvenanceSentence` moves out of the module that produces checks and into its own, beside `source-range`, the established home for a helper the diagnostic and hover surfaces share. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two Chart.yaml saves in quick succession could let the slower registry answer publish last, leaving a result for an appVersion already replaced. Only the latest check started for a document now publishes. The watcher test now bumps appVersion before the change event, so it proves the re-check uses the new version, and the ImageReference docstring no longer defers appVersion resolution to a later ticket. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tagless image references start getting answers. An
image:block with arepositoryand notagis now checked against theappVersionof the chart that governs the file, matching what Helm itself would render, where before it produced a muted question mark and nothing else. File scope widens with it: any YAML file beneath a chart directory is checked, so environment overlays likeproduction.yamlget the same scrutiny asvalues.yaml, and anything under that chart'stemplates/is skipped because Go template source renders to nothing checkable.The governing chart is the one in the nearest ancestor directory holding
Chart.yaml. That single rule is what makes a subchart's values file resolve against the subchart's ownappVersionrather than its parent's, which is the version actually deployed. One walk up the tree answers scope, the templates exclusion, and tag resolution together, rather than three rules that could disagree.A tag the file never wrote needs different handling on every surface, so the resolved tag is a discriminated union. A
filetag carries a range to underline. Achart-metadatatag carries the metadata path instead, so its diagnostic attaches to the repository value and its message names the chart. Surfaces cannot forget the distinction, because there is no range on that arm to reach for. Saving aChart.yamlre-checks the open files that chart governs, since a version bump is exactly when a stale checkmark costs the most.Chart context lives in the Helm package with the filesystem read injected, per the decision recorded in #17: which chart governs which values file is Helm knowledge, and leaving it in an editor extension guarantees a future CLI reimplements it. The module holds no platform path semantics and splits URI paths itself.
no-tagis gone. The ticket requires silence when there is no chart metadata or noappVersion, so those references are dropped before any registry is asked, which made the reason dead. ItsReferenceVerdictandUncheckedReasonaliases went with it in the same wave rather than surviving as shims, and the five consumers now useImageVerdictandUnverifiableReasonfrom the registry package directly.Reviewer notes
appVersiongoes through the same path as tags for the same reason: YAML coercesappVersion: 1.10to the float1.1, and a chart whoseappVersionis templated is no more usable than one with none.Chart.ymlwas accepted alongsideChart.yamland should not have been, since Helm's own loader recognises onlyChart.yaml, so accepting it would resolve anappVersionout of a file Helm ignores. Dropping it also halves the filesystem probes per directory level and lets the watcher glob be derived from the resolver's constant instead of spelled out again in another workspace.Chart.yamlcame back in scope as a values file, because the exclusion only tested for atemplatessegment. Harmless in practice, sincedependencies[].repositoryentries carry no corroborating sibling key, but it is fixed rather than left to chance.onDidCreateregistration was deleted because it could match nothing. A document checked without a chart records no metadata path, so aChart.yamlappearing above it would never re-check it. Catching that means re-resolving every open document on every write, which no ticket has asked for, and the limitation is documented on the handler.Known gaps
vscode.Uri.filepins the reader's scheme tofile, so a virtual workspace resolves no charts and falls back to the values-file naming rule. Noted in the reader's own docstring.Closes #24
🤖 Generated with Claude Code