Skip to content

Describe generated components by logical path, not write location (v0.1.16) - #59

Merged
Volv-G merged 1 commit into
masterfrom
piforge/tangle-pipeline-crud/tangle-cli-logical-provenance-ou-659cb96
Sep 18, 2026
Merged

Volv-G merged 1 commit into
masterfrom
piforge/tangle-pipeline-crud/tangle-cli-logical-provenance-ou-659cb96

Conversation

@Volv-G

@Volv-G Volv-G commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

(AI-assisted)

A generated component carries annotations describing where it came from: component_yaml_path,
python_original_code_path, and the git_* set. These were derived from wherever the YAML happened to be
written, which turns an incidental choice by the caller into part of the component's identity.

Git provenance could disappear

Repository details were read from the common ancestor of the source file and the output path. That ancestor
is only inside the checkout when the output is. Generate to a directory outside the repository and the
lookup runs somewhere that is not a repository at all, so every git_* annotation is dropped and the
component records no origin whatsoever.

This needs no unusual setup to hit -- the output folder is configurable, so pointing it outside the checkout
is enough.

Bytes depended on where the file was written

Because the physical path reached the annotations, generating identical source to two different locations
produced different content, and therefore a different digest. Anything treating the digest as an identity
for the same source saw two unequal results.

What changed

Repository details are now read from the source file's own directory. The source is what the provenance is
about, and its directory is inside the checkout whenever the source is -- including when the file is reached
through a symlink from outside.

A component can also now keep its identity when written somewhere incidental. The optional
logical_output_path says where the component is to be understood to live; the bytes still go where the
caller asked. Callers that stage output in a scratch location can describe the component truthfully without
publishing a path that is meaningless to anyone else.

Compatibility

The parameter is opt-in. When it is not supplied the emitted bytes are unchanged, and two tests exist purely
to pin that: omitting it, and passing it equal to the physical path, must both be indistinguishable from the
previous behaviour.

It is also forwarded only when actually set. Several hops here are overridable, and passing a new keyword
unconditionally would break an override written against the previous signature even though that caller never
asked for the feature. A test exercises a subclass carrying the exact prior signature.

The annotation path is deliberately kept unresolved. Legacy path annotation records the name it was given, so
resolving would rewrite it whenever the output is a symlink; only the common-ancestor computation resolves.

The container image is still read back from the physical output. logical_output_path is provenance only --
reading content from a location that was never written would make a non-existent path behavioural. A caller
writing to a fresh output supplies the image, as before.

Verification

Tests drive the real generator end to end against a genuine repository, because the behaviour under test
is the path derivation; a stub cannot demonstrate it. They assert against real annotation keys and cover:
provenance surviving an output outside the checkout, the logical path being recorded instead of the physical
one, two writes to different locations producing identical bytes, no host or staging path appearing in any
annotation, a symlinked output keeping its lexical name, a symlinked source keeping its repository, and the
two compatibility cases above.

Each was confirmed to fail when the corresponding fix is reverted.

….1.16)

Component provenance annotations were derived from wherever the YAML happened
to be written. Two defects followed.

Git provenance could vanish entirely. Repository details were read from the
common ancestor of the source file and the output path; when a caller wrote
outside the checkout that ancestor is not in the repository, so every git_*
annotation was silently dropped. This is reachable today by configuring an
output folder outside the checkout.

Bytes were unstable. Because the physical path reached the annotations, the
same source generated to two locations produced different content, and so a
different digest.

Repository details are now read from the source file's own directory, which is
inside the checkout whenever the source is. A generated component also keeps
its identity when written somewhere incidental: the optional
logical_output_path records where the component is to be understood to live,
while the bytes are written where the caller asked.

The parameter is opt-in and forwarded only when set, so existing callers --
including overrides written against the previous signatures -- are unaffected,
and the annotation path is kept unresolved so symlinked outputs still record
the name they were given.

Assisted-By: devx/6257e672-aaa7-443c-a4e1-a0150a485d9d
@Volv-G
Volv-G requested a review from Ark-kun as a code owner September 18, 2026 00:16
@Volv-G
Volv-G merged commit f5253e1 into master Sep 18, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant