Skip to content

The adopted-source fingerprint does not cover @@ includes — a change to an included-only snippet is invisible to staleness detection #2948

Closed

Description

@rbuergi

Split out of #2813 rather than folded into it, because it is a pre-existing gap with a real cost to close, and burying it in the fix would have made the fix's coverage look larger than it is.

What is not covered

NodeTypeSourceFingerprint.Compute (added in #2947) hashes the compile input as
NodeCompileShaping.CollectCompileSources yields it: the deduplicated, non-executable, non-blank
Code nodes a source/test query matched, reduced to (node path, SHA-256 of the code text).

An @@Path/To/Snippet include pulls a Code node that no source query matches. It reaches the
emitted assembly — NodeSetCompiler.ResolveInputs resolves includes after the fold — but it is
absent from the fold, so:

  • editing an included-only snippet does not move AdoptedSourceFingerprint / CurrentSourceFingerprint, and
  • a prebuilt assembly built before that edit still adopts as AdoptedVerified.

BakeEquivalenceTest already pins this shape explicitly: Widget/Snippets/Greeting is asserted
absent from sourceVersions while Greeting is asserted present in the emitted surface.

Why it is not a regression

It is the same set NodeTypeDefinition.CompiledSources records, so IsDirty has always had
this hole too — an included-only edit never dirtied the type and never triggered a recompile. #2947
does not widen the gap; it just makes it worth naming, because the fingerprint now carries a
verified claim where before there was only an unverified one.

What closing it would take

Both sides must resolve includes before hashing:

  • the bake already does (NodeSetCompiler.ResolveInputs → NodeCompileShaping.ResolveCodeIncludes
    against the tree's NodeSet, a dictionary lookup);
  • the live side does not. InstallSourcesWatcher holds only the query-matched nodes, and
    resolving includes there means a mesh read per include, on a path that runs at every hub
    activation and every source edit. That is a real cost and a real reactive-composition change
    (the watcher's Update lambda is pure and synchronous today), which is why it is not smuggled
    into a data-loss fix.

An alternative worth weighing first: fold the include-resolved text in only where it is already
computed — i.e. have the compile stamp the resolved set — so the live half never has to do the
mesh reads.

Acceptance

A test in the shape of AdoptedBuildSourceStampTest: a type whose only change is to an
included-only snippet, whose bundle was baked before that change, must be refused, not adopted
as verified.

Related: #2813 (the fingerprint), #2947 (the PR that made it reachable), #2820 (the execute-time
interlock that consumes BuildProvenance).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions