Skip to content

fix(watch): preserve shorthand requirements when resolving watched sources #18

Closed as not planned

Description

@showxu

Summary

When a source is already watched, add <source>@branch:other matches its watch record and installs the watched baseline, silently ignoring the typed branch requirement. The equivalent --branch other flag is rejected. The same user intent therefore has different behavior depending on syntax.

Code evidence at 5d4987b:

  • Sources/Core/RuntimeService.swift:235 routes ordinary adds through resolveSourceOrWatch.
  • Sources/Core/WatchLedger.swift:737 parses the input but compares only source identity when matching a watch.
  • Sources/Core/RuntimeService.swift:782 selects the watch before normal source resolution; :786 checks only the separate requirement argument used by flags.
  • Sources/Core/RuntimeService.swift:797 chooses the watch baseline/reviewed commit, and :815 reconstructs source data from the watch rather than the input selectors.

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-watch-routing"
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/skills/demo" demo watched-main
isolated git init -q -b main "$repro_root/source"
isolated git -C "$repro_root/source" add .
isolated git -C "$repro_root/source" commit -qm main
isolated git -C "$repro_root/source" checkout -qb other
write_skill "$repro_root/source/skills/demo" demo requested-other
isolated git -C "$repro_root/source" add .
isolated git -C "$repro_root/source" commit -qm other
isolated git -C "$repro_root/source" checkout -q main
skill add "$repro_root/source" --branch main --watch-only --skill demo --agent codex
skill add "$repro_root/source@branch:other" --skill demo --agent codex --mode copy
printf 'installed content: '
tail -1 .agents/skills/demo/SKILL.md
set +e
skill add "$repro_root/source" --branch other --skill demo --agent codex --mode copy
printf 'flag form exit: %s\n' "$?"

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

watched source path skills/demo
installed demo for codex at <temp>/project/.agents/skills/demo
installed content: watched-main
Error: Invalid source: source requirement flags cannot be used with a watch source
flag form exit: 1

Expected Behavior

Parse and validate requirement intent before choosing the watch/source route. A requirement supplied in typed shorthand must not be silently discarded.

Maintainer decision: either treat an explicit source requirement as ordinary source resolution, or reject it consistently while the input resolves to a watch. Keep watch-ID-based installation and its reviewed-commit rules explicit.

Completion checks:

  • Flag and shorthand forms for branch/revision/version requirements have equivalent results or errors.
  • The two-branch fixture never reports success while ignoring other.
  • Existing watch-ID installs continue to use their accepted baseline/reviewed commit.
  • Cover both a local Git path and hosted-source parsing; run swift test.

Actual Behavior

The shorthand add exits successfully and installs watched-main, even though the requested branch contains requested-other. The flag form exits 1. The executed fixture uses one source identity, so no identity collision is involved.

Related: #10 concerns scope, and #9 concerns inspection writes. This report concerns add routing and requirement validation within one project. 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.

Activity

  1. showxu commented on Oct 18, 2026

    @showxu
    ContributorAuthor

    Superseded by the design adopted in #29 (Watch). Watch is now a subscription that reports upstream changes; it no longer routes or gates installs, so shorthand requirements are resolved only by add and update.

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