[BUG] Dynamic artifact cache omits selected source and linker identity #24

Open
opened 2026-09-12 14:58:13 +02:00 by erikinkinen · 0 comments
Owner

Summary

The dynamic executable cache key omits the contents of explicitly selected
external source and linker files. Changing either file, or selecting another
file with the same basename, leaves the key unchanged when component-owned
inputs and build configuration stay fixed. A cache hit can therefore select an
artifact whose primary compiler inputs no longer match the requested build.

Reproduction

Use Integration b518b6ad1d2f3e7a36a5d796eaff3103c051bb84. Source its unchanged
scripts/lib/service-build.sh in an isolated fixture with a component tree, an
empty-dependency service record and valid empty shared-object registry. Select
TARGET=x86_64-unknown-none, PROFILE=release, and explicit source/linker files
outside the component tree.

Call the original gateway using the existing argument order:

dynamic_artifact_cache_key service fixture-service "$component_dir" \
  runtime fixture_entry "$external_source" "$external_linker"

Keep component files unchanged and repeat after changing only the external source
bytes, changing only the external linker bytes, or selecting alternate external
files named main.rs and linker.ld. Repeat both with freshly prepared cache
context and with the original unprepared path. A feature-only change is a control. Also select distinct same-basename sources
and linkers already present in one unchanged component tree, and a component-local
source symlink resolving to an external file whose bytes then change.

Expected and actual behavior

Expected: changes to explicitly selected primary compiler inputs invalidate the
cache identity; missing selected inputs fail before a cache can be reused.

Actual: in 28 local observations, each mode returned the same key after source or
linker content changes and after same-basename alternative selections. Missing
selected files also returned the prior key. Internal same-basename alternatives also alias despite selecting different
component-owned entries. An apparently internal source symlink continues to alias
when its external target changes. Every invocation exited zero with empty stderr. Changing the declared feature string did change the key, showing
that the real fingerprint gateway was exercised rather than a constant stub.

Environment and identity

  • Component: Integration
    b518b6ad1d2f3e7a36a5d796eaff3103c051bb84; 50 selected original script blobs
    used without modifications, with an explicitly authored host catalog fixture.
  • Build/runtime configuration: service cache key, release profile,
    x86_64-unknown-none, fixed entry and runtime feature selection; no image.
  • Host/tools: x86_64 Linux, Python 3.14.7, Bash, selected Rust 1.93.0 version
    queries and local LLVM tools. No compilation or VM execution was performed.
  • Inputs/authority: explicit component, external source/linker and registry paths;
    no implicit external parent-tree discovery and no network or publication access.
  • Last known unaffected revision: not established by this bounded investigation.

Evidence and prior checks

Original Git blob hashes, each source/linker input snapshot, unchanged component
hashes, all keys and command status/output receipts were retained separately.
Both prepared and unprepared cache routes reproduce the omission. A declared
feature change invalidates the key in both routes. Each command had a 30-second
hard deadline, 10-second output-stall deadline, 1 MiB output budget and owned
subprocess-group cleanup.

The proposed correction must bind selected bytes and selection coordinates,
reject missing inputs before lookup, and distinguish resolved input ownership.
Cache bypass for external sources/linkers without complete declared input
coverage must preserve their existing compilation support. These observations concern primary selected files;
they do not establish complete external module or linker-include dependency
closure, artifact restoration behavior, guest execution or self-hosting.

Published correction: signed Integration 381bccd87c5632e9d1af8aa9d0aca295cbc00e1f in WIP PR #12. The final 32 warning-denied cache tests and existing shell fixture pass; every original fixture assertion is preserved. CI syntax and all 113 Markdown files pass. Original failing replays remain retained. Current-head CI, complete dependency closure and fresh image/guest acceptance remain open.

Tracking

Related compiler-coordinate reproducibility work:
#22.
This cache omission has separate original-source evidence and requires a
separately reviewed correction. No cache threshold, retry or full-image rebuild
is part of this reproduction.

## Summary The dynamic executable cache key omits the contents of explicitly selected external source and linker files. Changing either file, or selecting another file with the same basename, leaves the key unchanged when component-owned inputs and build configuration stay fixed. A cache hit can therefore select an artifact whose primary compiler inputs no longer match the requested build. ## Reproduction Use Integration `b518b6ad1d2f3e7a36a5d796eaff3103c051bb84`. Source its unchanged `scripts/lib/service-build.sh` in an isolated fixture with a component tree, an empty-dependency service record and valid empty shared-object registry. Select `TARGET=x86_64-unknown-none`, `PROFILE=release`, and explicit source/linker files outside the component tree. Call the original gateway using the existing argument order: ```sh dynamic_artifact_cache_key service fixture-service "$component_dir" \ runtime fixture_entry "$external_source" "$external_linker" ``` Keep component files unchanged and repeat after changing only the external source bytes, changing only the external linker bytes, or selecting alternate external files named `main.rs` and `linker.ld`. Repeat both with freshly prepared cache context and with the original unprepared path. A feature-only change is a control. Also select distinct same-basename sources and linkers already present in one unchanged component tree, and a component-local source symlink resolving to an external file whose bytes then change. ## Expected and actual behavior Expected: changes to explicitly selected primary compiler inputs invalidate the cache identity; missing selected inputs fail before a cache can be reused. Actual: in 28 local observations, each mode returned the same key after source or linker content changes and after same-basename alternative selections. Missing selected files also returned the prior key. Internal same-basename alternatives also alias despite selecting different component-owned entries. An apparently internal source symlink continues to alias when its external target changes. Every invocation exited zero with empty stderr. Changing the declared feature string did change the key, showing that the real fingerprint gateway was exercised rather than a constant stub. ## Environment and identity - Component: Integration `b518b6ad1d2f3e7a36a5d796eaff3103c051bb84`; 50 selected original script blobs used without modifications, with an explicitly authored host catalog fixture. - Build/runtime configuration: service cache key, release profile, `x86_64-unknown-none`, fixed entry and runtime feature selection; no image. - Host/tools: x86_64 Linux, Python 3.14.7, Bash, selected Rust 1.93.0 version queries and local LLVM tools. No compilation or VM execution was performed. - Inputs/authority: explicit component, external source/linker and registry paths; no implicit external parent-tree discovery and no network or publication access. - Last known unaffected revision: not established by this bounded investigation. ## Evidence and prior checks Original Git blob hashes, each source/linker input snapshot, unchanged component hashes, all keys and command status/output receipts were retained separately. Both prepared and unprepared cache routes reproduce the omission. A declared feature change invalidates the key in both routes. Each command had a 30-second hard deadline, 10-second output-stall deadline, 1 MiB output budget and owned subprocess-group cleanup. The proposed correction must bind selected bytes and selection coordinates, reject missing inputs before lookup, and distinguish resolved input ownership. Cache bypass for external sources/linkers without complete declared input coverage must preserve their existing compilation support. These observations concern primary selected files; they do not establish complete external module or linker-include dependency closure, artifact restoration behavior, guest execution or self-hosting. Published correction: signed Integration `381bccd87c5632e9d1af8aa9d0aca295cbc00e1f` in [WIP PR #12](https://git.erikinkinen.fi/erix/integration/pulls/12). The final 32 warning-denied cache tests and existing shell fixture pass; every original fixture assertion is preserved. CI syntax and all 113 Markdown files pass. Original failing replays remain retained. Current-head CI, complete dependency closure and fresh image/guest acceptance remain open. ## Tracking Related compiler-coordinate reproducibility work: https://git.erikinkinen.fi/erix/integration/issues/22. This cache omission has separate original-source evidence and requires a separately reviewed correction. No cache threshold, retry or full-image rebuild is part of this reproduction.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
erix/integration#24
No description provided.