2 Commits

Author SHA1 Message Date
560154c727 docs(kyberforge): note repro caveat for ADR-0017 verification command
Running ADR-0017's cited live behavioral test literally from this
repo's root gives a contaminated signal: this repo's own project-level
.claude/settings.json enables all 6 holocron plugins, so Claude Code
loads all of them rather than isolating kyberforge's discoverability.
Documents the neutral-cwd + absolute --plugin-dir reproduction needed
to isolate the signal.
2026-08-13 20:51:34 +00:00
2c731eb476 test(kyberforge): cover sync-marketplace-mirror.sh drift-guard
Its sibling sync-plugin-content.sh has thorough coverage
(tests/test-sync-plugin-content.sh) but this drift guard -- wired into
pre-commit as check-marketplace-mirror-sync, keeping
.claude-plugin/marketplace.json and .github/plugin/marketplace.json in
sync -- had none. A silent regression here would let the two
marketplace manifests drift without any test catching it.

Covers: missing-source no-op in both real-sync and --check modes,
drift detection when the mirror is missing or stale, real sync
producing a byte-identical mirror, --check clean immediately after
sync, drift from an edited source cleared by re-sync, an
already-in-sync mirror reporting no drift, usage-error rejection of
unrecognized/extra arguments, and idempotency of repeated syncs.
2026-08-13 20:45:10 +00:00
2 changed files with 193 additions and 0 deletions

View File

@@ -162,4 +162,13 @@ reinjection existing beyond working around this specific upstream gap.
upstream) would let `sync-plugin-content.sh` and its drift gate be deleted outright — nothing in upstream) would let `sync-plugin-content.sh` and its drift gate be deleted outright — nothing in
this ADR's decision depends on the flat mirror existing beyond satisfying the current installer's this ADR's decision depends on the flat mirror existing beyond satisfying the current installer's
convention-scan contract. convention-scan contract.
- **Reproduction note (2026-08-13):** the live behavioral test cited in "Decision" above
(`claude --plugin-dir plugins/kyberforge -p "list your skills and agents"`) is only a clean
kyberforge-only signal when run from a working directory outside this repo. Run literally as
written, from this repo's root, this repo's own project-level `.claude/settings.json` sets
`enabledPlugins` to true for all 6 holocron plugins (kyberforge, git, gitea, core, lint, bin), so
Claude Code loads all 6 plugins' skills/agents, not just kyberforge's — conflating kyberforge's
discoverability with the other 5 plugins' already-enabled content. To isolate the signal, run
from a neutral cwd outside `/root/ai-development` with an absolute `--plugin-dir` path, e.g.
`cd /some/neutral/dir && claude --plugin-dir /root/ai-development/plugins/kyberforge -p "list your skills and agents"`.
- Reference: issue #90 (https://git.dev.rkdr.net/Defame1297/holocron/issues/90). - Reference: issue #90 (https://git.dev.rkdr.net/Defame1297/holocron/issues/90).

View File

@@ -0,0 +1,184 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SCRIPT="$REPO_ROOT/scripts/sync-marketplace-mirror.sh"
PASS=0
FAIL=0
pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
# Minimal fixture: a bare directory with no .git of its own. Since
# scripts/sync-marketplace-mirror.sh resolves REPO_ROOT via
# `git rev-parse --show-toplevel 2>/dev/null || pwd`, and mktemp -d creates
# directories outside any git worktree, cd'ing into the fixture before
# invoking the script makes REPO_ROOT resolve to the fixture itself -- so
# every test runs against an isolated .claude-plugin/ + .github/plugin/ pair
# instead of this repo's real marketplace.json files.
make_fixture() {
mktemp -d
}
SRC_REL=".claude-plugin/marketplace.json"
DST_REL=".github/plugin/marketplace.json"
CONTENT_A='{"plugins":[{"name":"demo","version":"1.0.0"}]}'
CONTENT_B='{"plugins":[{"name":"demo","version":"2.0.0"}]}'
write_src() {
local dir="$1" content="$2"
mkdir -p "$dir/.claude-plugin"
printf '%s' "$content" > "$dir/$SRC_REL"
}
write_dst() {
local dir="$1" content="$2"
mkdir -p "$dir/.github/plugin"
printf '%s' "$content" > "$dir/$DST_REL"
}
run_script() {
local dir="$1"
shift
(cd "$dir" && bash "$SCRIPT" "$@")
}
CLEANUP_DIRS=()
trap 'rm -rf "${CLEANUP_DIRS[@]}"' EXIT
track() { CLEANUP_DIRS+=("$1"); }
# --- 1. No .claude-plugin/marketplace.json at all: real-sync mode is a no-op, exit 0 ---
echo ""
echo "--- missing source: real sync exits 0 and creates nothing ---"
FIXTURE1="$(make_fixture)"; track "$FIXTURE1"
if run_script "$FIXTURE1" > /dev/null 2>&1 && [[ ! -e "$FIXTURE1/$DST_REL" ]]; then
pass "missing source exits 0 in real-sync mode without creating a mirror"
else
fail "missing source should exit 0 and create nothing in real-sync mode"
fi
# --- 2. No source: --check mode is also a no-op, exit 0 (nothing to drift-check) ---
echo ""
echo "--- missing source: --check exits 0 (nothing to compare) ---"
FIXTURE2="$(make_fixture)"; track "$FIXTURE2"
if run_script "$FIXTURE2" --check > /dev/null 2>&1; then
pass "missing source exits 0 in --check mode"
else
fail "missing source should exit 0 in --check mode, not report drift"
fi
# --- 3. Source exists, mirror missing entirely: --check reports drift (exit 1) ---
echo ""
echo "--- --check reports drift when the mirror file does not exist yet ---"
FIXTURE3="$(make_fixture)"; track "$FIXTURE3"
write_src "$FIXTURE3" "$CONTENT_A"
if run_script "$FIXTURE3" --check > /dev/null 2>&1; then
fail "exited 0 with no mirror file present -- expected drift (exit 1)"
else
pass "missing mirror file is reported as drift"
fi
# --- 4. Real sync creates the mirror (and its parent dir) byte-identical to the source ---
echo ""
echo "--- real sync creates .github/plugin/marketplace.json byte-identical to source ---"
FIXTURE4="$(make_fixture)"; track "$FIXTURE4"
write_src "$FIXTURE4" "$CONTENT_A"
if run_script "$FIXTURE4" > /dev/null 2>&1 \
&& [[ -f "$FIXTURE4/$DST_REL" ]] \
&& diff -q "$FIXTURE4/$SRC_REL" "$FIXTURE4/$DST_REL" > /dev/null 2>&1; then
pass "real sync creates the mirror file identical to the source"
else
fail "real sync did not create a byte-identical mirror file"
fi
# --- 5. --check is clean immediately after a real sync ---
echo ""
echo "--- --check is clean right after syncing ---"
if run_script "$FIXTURE4" --check > /dev/null 2>&1; then
pass "no drift reported immediately after syncing"
else
fail "drift reported right after syncing -- sync and check disagree"
fi
# --- 6. Editing the source after a sync introduces drift; re-sync clears it ---
echo ""
echo "--- source edited after sync is detected as drift, cleared by re-sync ---"
write_src "$FIXTURE4" "$CONTENT_B"
if run_script "$FIXTURE4" --check > /dev/null 2>&1; then
fail "no drift reported after editing the source -- expected drift"
else
pass "editing the source after a sync is detected as drift"
run_script "$FIXTURE4" > /dev/null 2>&1
if run_script "$FIXTURE4" --check > /dev/null 2>&1; then
pass "re-sync clears the drift"
else
fail "re-sync did not clear the drift"
fi
fi
# --- 7. A mirror that was hand-seeded already identical to the source: --check is clean ---
echo ""
echo "--- --check is clean when the mirror already matches, without ever syncing ---"
FIXTURE7="$(make_fixture)"; track "$FIXTURE7"
write_src "$FIXTURE7" "$CONTENT_A"
write_dst "$FIXTURE7" "$CONTENT_A"
if run_script "$FIXTURE7" --check > /dev/null 2>&1; then
pass "an already-in-sync mirror reports no drift"
else
fail "an already-in-sync mirror should report no drift"
fi
# --- 8. A stale, pre-existing mirror that differs from source: --check flags it, sync fixes it ---
echo ""
echo "--- a stale pre-existing mirror is flagged by --check and overwritten by sync ---"
FIXTURE8="$(make_fixture)"; track "$FIXTURE8"
write_src "$FIXTURE8" "$CONTENT_A"
write_dst "$FIXTURE8" "$CONTENT_B"
if run_script "$FIXTURE8" --check > /dev/null 2>&1; then
fail "a stale mirror was not flagged as drift"
else
pass "a stale pre-existing mirror is flagged as drift"
fi
run_script "$FIXTURE8" > /dev/null 2>&1
if diff -q "$FIXTURE8/$SRC_REL" "$FIXTURE8/$DST_REL" > /dev/null 2>&1; then
pass "real sync overwrites the stale mirror to match the source"
else
fail "real sync did not overwrite the stale mirror"
fi
# --- 9. An unknown/extra positional argument is rejected with a usage error ---
echo ""
echo "--- an unrecognized argument is rejected (usage, exit 1) ---"
FIXTURE9="$(make_fixture)"; track "$FIXTURE9"
write_src "$FIXTURE9" "$CONTENT_A"
if run_script "$FIXTURE9" --bogus > /dev/null 2>&1; then
fail "exited 0 with an unrecognized argument -- expected a usage error"
else
pass "an unrecognized argument is rejected"
fi
# --- 10. --check followed by a stray extra argument is also rejected ---
echo ""
echo "--- --check plus a trailing extra argument is rejected (usage, exit 1) ---"
if run_script "$FIXTURE9" --check extra > /dev/null 2>&1; then
fail "exited 0 with --check plus a trailing argument -- expected a usage error"
else
pass "--check plus a trailing extra argument is rejected"
fi
# --- 11. Real sync is idempotent: running it twice in a row leaves the mirror unchanged ---
echo ""
echo "--- running real sync twice in a row is idempotent ---"
FIXTURE11="$(make_fixture)"; track "$FIXTURE11"
write_src "$FIXTURE11" "$CONTENT_A"
run_script "$FIXTURE11" > /dev/null 2>&1
run_script "$FIXTURE11" > /dev/null 2>&1
if run_script "$FIXTURE11" --check > /dev/null 2>&1; then
pass "running sync twice in a row is idempotent"
else
fail "a second sync run introduced unexpected drift"
fi
echo ""
echo "Results: $PASS passed, $FAIL failed"
[[ $FAIL -eq 0 ]]