Skip to content

fix(cache): resolve unqualified adds independently of cached HEAD #16

Closed
agents-tools/core
#12

Description

@showxu

Summary

An unqualified Git-source add installs different content with a warm cache than with a cold cache. After add --from 1.0.0 leaves the shared checkout at a tag, a later add without a requirement fetches but keeps that checkout's HEAD.

Code evidence at 5d4987b:

  • Sources/Core/ProcessRunner.swift:78 allocates one checkout per source identity.
  • Sources/Core/ProcessRunner.swift:90 checks out only a nonempty selected ref.
  • Sources/Core/ProcessRunner.swift:195 returns no ref for a missing requirement, leaving an existing checkout where a previous operation placed it.
  • Sources/Core/ProcessRunner.swift:342 sends unqualified Git URLs through this cache path. Unpinned local filesystem paths use the direct path at :335 instead.

Reproduction

Executed at 5d4987b.

Run in Bash after cd "<checkout>" && swift build, replacing <checkout> with the absolute path of the checkout at this revision. Use a fresh reproduction directory. The commands isolate HOME, agent configuration, and XDG_*, and remove their fixture root on exit.

set -eu
checkout="<checkout>"
skill_bin="$checkout/.build/debug/skill"
repro_root="$checkout/.build/issue-repro-mutable-cache"
mkdir -p "$repro_root/home" "$repro_root/tmp" "$repro_root/project"
trap 'rm -rf "$repro_root"' EXIT
isolated() {
  env -i PATH="$PATH" HOME="$repro_root/home" \
    CODEX_HOME="$repro_root/home/.codex" \
    CLAUDE_CONFIG_DIR="$repro_root/home/.claude" \
    XDG_CONFIG_HOME="$repro_root/home/.config" \
    XDG_STATE_HOME="$repro_root/home/.local/state" \
    XDG_CACHE_HOME="$repro_root/home/.cache" TMPDIR="$repro_root/tmp" \
    GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null \
    GIT_AUTHOR_NAME=Fixture [email protected] \
    GIT_COMMITTER_NAME=Fixture [email protected] \
    "$@"
}
skill() { isolated "$skill_bin" "$@"; }
write_skill() {
  mkdir -p "$1"
  printf -- '---\nname: %s\ndescription: Reproduction fixture\n---\n%s\n' "$2" "$3" > "$1/SKILL.md"
}
cd "$repro_root/project"

write_skill "$repro_root/source/demo" demo tagged
isolated git init -q -b main "$repro_root/source"
isolated git -C "$repro_root/source" add .
isolated git -C "$repro_root/source" commit -qm tagged
isolated git -C "$repro_root/source" tag 1.0.0
write_skill "$repro_root/source/demo" demo default-head
isolated git -C "$repro_root/source" add .
isolated git -C "$repro_root/source" commit -qm default-head
remote="file://$repro_root/source"
skill add "$remote" --from 1.0.0 --skill demo --agent codex --mode copy
skill add "$remote" --skill demo --agent codex --mode copy
printf 'warm cache content: '
tail -1 .agents/skills/demo/SKILL.md
mkdir "$repro_root/cold-project"
cd "$repro_root/cold-project"
skill add "$remote" --skill demo --agent codex --mode copy
printf 'cold cache content: '
tail -1 .agents/skills/demo/SKILL.md

Observed output (relevant lines; temporary paths shortened to <temp>):

installed demo for codex at <temp>/project/.agents/skills/demo
installed demo for codex at <temp>/project/.agents/skills/demo
warm cache content: tagged
installed demo for codex at <temp>/cold-project/.agents/skills/demo
cold cache content: default-head

Expected Behavior

For the same upstream state and unqualified source input, installation must not depend on the last requirement resolved in the cache. Resolve the intended default revision explicitly or isolate requirement-specific materialization from the shared object cache.

Maintainer decision: define the no-requirement default-ref policy, including remote default-branch changes. That choice must produce consistent warm/cold-cache results.

Completion checks:

  • After range, exact-tag, branch, and revision adds, an unqualified add behaves like a fresh-cache add.
  • Test the Git URL path with a local file:// remote and a default head newer than the selected tag.
  • Preserve explicit requirements and watch review gating; run swift test.

Actual Behavior

The two unqualified adds use the same file:// source with identical upstream state. The warm-cache add installs tagged; the fresh project installs default-head. No restore or update-preview command is involved.

Related: #7 owns restoring locked revisions, and #9 owns inspection writes. This issue is limited to cached HEAD affecting a new, unqualified add. No duplicate found.

Environment

  • Source revision: 5d4987b (5d4987b9e1f94e8b9f85124299f05d5aa4f45f07).
  • CLI version: 0.2.1; built successfully with swift build.
  • Swift: Apple Swift 6.4 (swiftlang-6.4.0.34.1, clang-2100.3.34.1).
  • OS: macOS 27.0.1 (26A434).
  • Architecture: arm64.
  • Git: 2.42.0. Validation date: 2026-10-17.
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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions