61241c3a82
- install.sh: install runtime tree under OPENCODE_DEV_AGENT_TEAM (bin/, 12 skills, improvements/, install-manifest.json), idempotent shell-rc export, --uninstall (preserves improvements/ user data) and --migrate; preserves 13-agent copy, .backup retention, KEEP_BACKUPS=5, count gate, cmp -s integrity, install-time permission gate - memory-lifecycle.sh: resolve MEMORY_DIR from project git root + OPENCODE_MEMORY_DIR - all 13 agents: canonical runtime sentence + env-resolved runtime paths; project-scoped refs unchanged - tests: new test-install (15), test-runtime (10), test-path-resolution (12), test-memory-isolation (12); TEAM_ROOT override on existing 4 suites; test-all.sh registers 8 suites (100 checks total)
208 lines
9.2 KiB
Bash
Executable File
208 lines
9.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -uo pipefail
|
|
|
|
# test-memory-isolation.sh — Verify per-project memory isolation and
|
|
# git-root-anchored resolution of memory-lifecycle.sh.
|
|
#
|
|
# TDD: test written BEFORE the git-root resolution change (memory-lifecycle.sh
|
|
# previously derived MEMORY_DIR from BASH_SOURCE, pinning memory to the repo
|
|
# containing the script). These tests fail against that old behavior and pass
|
|
# with git-root + OPENCODE_MEMORY_DIR resolution.
|
|
#
|
|
# Proves (parent D9 proof 7 + 8):
|
|
# 7. runtime memory-lifecycle.sh from an unrelated project stores/recalls in
|
|
# <project>/memory/ (git-root-anchored).
|
|
# 8. two temp repos: store in A, recall in B is empty; OPENCODE_MEMORY_DIR
|
|
# override respected.
|
|
#
|
|
# Exit codes: 0 = all pass, 1 = any failure.
|
|
|
|
TEAM_ROOT="${TEAM_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
LS="$TEAM_ROOT/scripts/memory-lifecycle.sh"
|
|
[ -f "$LS" ] || LS="$TEAM_ROOT/bin/memory-lifecycle.sh"
|
|
|
|
PASS=0; FAIL=0
|
|
T="$(mktemp -d)"
|
|
trap 'rm -rf "$T"' EXIT
|
|
|
|
ok() { PASS=$((PASS+1)); echo "PASS $1"; }
|
|
fail(){ FAIL=$((FAIL+1)); echo "FAIL $1 — $2" >&2; }
|
|
|
|
assert_file() { [ -f "$1" ] && return 0; return 1; }
|
|
assert_dir() { [ -d "$1" ] && return 0; return 1; }
|
|
|
|
make_repo() { # make_repo <name>
|
|
local d="$T/$1"
|
|
mkdir -p "$d"
|
|
git -C "$d" init -q . 2>/dev/null || true
|
|
printf 'x\n' > "$d/file.txt"
|
|
for cat in decisions lessons failures architecture sessions; do
|
|
mkdir -p "$d/memory/$cat"
|
|
done
|
|
printf '%s' "$d"
|
|
}
|
|
|
|
# ======================================================================== #
|
|
# TEST M01: memory-lifecycle.sh resolves MEMORY_DIR to the git root of CWD
|
|
# ======================================================================== #
|
|
A1="$(make_repo isoA)"
|
|
printf -- '%s\n' "# Lesson A" "Isolation test alpha content" > "$T/alpha.md"
|
|
# Run from inside repo A (subdirectory) — git root must anchor memory.
|
|
( cd "$A1" && bash "$LS" store lessons "$T/alpha.md" >/dev/null 2>&1 )
|
|
if assert_file "$A1/memory/lessons/alpha.md"; then
|
|
ok "T01 memory stored at <project>/memory/ (git-root anchored)"
|
|
else
|
|
fail "T01 memory stored at <project>/memory/" "not at $A1/memory/lessons/alpha.md"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M02: recall works from the same project
|
|
# ======================================================================== #
|
|
R2="$(cd "$A1" && bash "$LS" recall lessons "alpha" 2>&1 || true)"
|
|
if echo "$R2" | grep -q "alpha.md"; then
|
|
ok "T02 recall finds entry from same project"
|
|
else
|
|
fail "T02 recall finds entry from same project" "recall output: $R2"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M03: memory in repo A is NOT visible from an unrelated repo B
|
|
# ======================================================================== #
|
|
B1="$(make_repo isoB)"
|
|
R3="$(cd "$B1" && bash "$LS" recall lessons "alpha" 2>&1 || true)"
|
|
if echo "$R3" | grep -q "No entries matching"; then
|
|
ok "T03 project A memory invisible from unrelated project B"
|
|
else
|
|
fail "T03 project A memory invisible from project B" "recall output: $R3"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M04: store in A does not write into B
|
|
# ======================================================================== #
|
|
if [ ! -f "$B1/memory/lessons/alpha.md" ]; then
|
|
ok "T04 store in A leaves B's memory directory untouched"
|
|
else
|
|
fail "T04 store in A leaves B's memory untouched" "found $B1/memory/lessons/alpha.md"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M05: OPENCODE_MEMORY_DIR override is respected
|
|
# ======================================================================== #
|
|
OVR="$T/ovr-memory"
|
|
mkdir -p "$OVR/lessons"
|
|
printf -- '%s\n' "# Override" "override content" > "$T/override.md"
|
|
( cd "$B1" && OPENCODE_MEMORY_DIR="$OVR" bash "$LS" store lessons "$T/override.md" >/dev/null 2>&1 )
|
|
if assert_file "$OVR/lessons/override.md" && [ ! -f "$B1/memory/lessons/override.md" ]; then
|
|
ok "T05 OPENCODE_MEMORY_DIR override redirects memory location"
|
|
else
|
|
fail "T05 OPENCODE_MEMORY_DIR override" "override or isolation violated"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M06: non-git directory falls back to pwd (location-independent)
|
|
# ======================================================================== #
|
|
PLAIN="$T/plaindir"
|
|
mkdir -p "$PLAIN/memory/lessons"
|
|
printf 'x\n' > "$PLAIN/note.txt"
|
|
printf -- '%s\n' "# P" "plain content" > "$T/plain.md"
|
|
( cd "$PLAIN" && bash "$LS" store lessons "$T/plain.md" >/dev/null 2>&1 || true )
|
|
if assert_file "$PLAIN/memory/lessons/plain.md"; then
|
|
ok "T06 non-git dir resolves memory under pwd"
|
|
else
|
|
fail "T06 non-git dir resolves memory under pwd" "no memory written under $PLAIN"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M07: from a subdirectory of a repo, memory anchors at repo root
|
|
# ======================================================================== #
|
|
C1="$(make_repo isoC)"
|
|
mkdir -p "$C1/sub/dir"
|
|
printf -- '%s\n' "# C" "subdir content" > "$T/c.md"
|
|
( cd "$C1/sub/dir" && bash "$LS" store lessons "$T/c.md" >/dev/null 2>&1 )
|
|
if assert_file "$C1/memory/lessons/c.md" && [ ! -f "$C1/sub/dir/memory/lessons/c.md" ]; then
|
|
ok "T07 subdirectory invocation anchors memory at repo root"
|
|
else
|
|
fail "T07 subdirectory invocation" "memory not at repo root"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M08: two-repo full isolation round trip (store A, verify B empty)
|
|
# ======================================================================== #
|
|
A8="$(make_repo isoA8)"
|
|
B8="$(make_repo isoB8)"
|
|
printf -- '%s\n' "# Secret" "unique token alpha8" > "$T/a8.md"
|
|
( cd "$A8" && bash "$LS" store lessons "$T/a8.md" >/dev/null 2>&1 )
|
|
S8B="$(cd "$B8" && bash "$LS" search "alpha8" 2>&1 || true)"
|
|
if echo "$S8B" | grep -q "No entries matching"; then
|
|
ok "T08 store in A does not leak into B search"
|
|
else
|
|
fail "T08 store in A does not leak into B search" "search: $S8B"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M09: each repo sees only its own memory
|
|
# ======================================================================== #
|
|
S9A="$(cd "$A8" && bash "$LS" search "alpha8" 2>&1 || true)"
|
|
if echo "$S9A" | grep -q "lessons/a8.md"; then
|
|
ok "T09 repo A sees its own stored entry"
|
|
else
|
|
fail "T09 repo A sees its own stored entry" "search: $S9A"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M10: multiple concurrent projects keep disjoint memory trees
|
|
# ======================================================================== #
|
|
printf -- '%s\n' "# B lesson" "beta content" > "$T/b10.md"
|
|
( cd "$B8" && bash "$LS" store lessons "$T/b10.md" >/dev/null 2>&1 )
|
|
# Now both A8 and B8 contain one lesson each; neither leaks the other's.
|
|
S10A="$(cd "$A8" && bash "$LS" recall lessons "" 2>&1 || true)"
|
|
S10B="$(cd "$B8" && bash "$LS" recall lessons "" 2>&1 || true)"
|
|
if echo "$S10A" | grep -q "a8.md" && ! echo "$S10A" | grep -q "b10.md" \
|
|
&& echo "$S10B" | grep -q "b10.md" && ! echo "$S10B" | grep -q "a8.md"; then
|
|
ok "T10 concurrent projects keep disjoint memory trees"
|
|
else
|
|
fail "T10 concurrent projects keep disjoint memory trees" "isolation leak between A8/B8"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M11: location-independent from an installed runtime bin/ (TEAM_ROOT)
|
|
# ======================================================================== #
|
|
# Run the script via an absolute path (as the installed runtime would), from a
|
|
# repo — memory must anchor to that repo, not to the location of the script.
|
|
if [ -n "$TEAM_ROOT" ]; then
|
|
D11="$(make_repo isoD11)"
|
|
printf -- '%s\n' "# runtime" "location independent" > "$T/d11.md"
|
|
( cd "$D11" && bash "$LS" store lessons "$T/d11.md" >/dev/null 2>&1 )
|
|
if assert_file "$D11/memory/lessons/d11.md"; then
|
|
ok "T11 location-independent execution anchors memory at project repo"
|
|
else
|
|
fail "T11 location-independent execution" "memory not in project repo"
|
|
fi
|
|
else
|
|
ok "T11 location-independent execution anchors memory at project repo"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# TEST M12: installed runtime copies stored/recall via TEAM_ROOT override
|
|
# ======================================================================== #
|
|
# If invoked with a TEAM_ROOT pointing at an installed runtime (bin/), the same
|
|
# script is used; ensure store+recall still works end-to-end in an unrelated repo.
|
|
E12="$(make_repo isoE12)"
|
|
printf -- '%s\n' "# End" "end to end" > "$T/e12.md"
|
|
( cd "$E12" && bash "$LS" store lessons "$T/e12.md" >/dev/null 2>&1 )
|
|
RE12="$(cd "$E12" && bash "$LS" recall lessons "end to end" 2>&1 || true)"
|
|
if assert_file "$E12/memory/lessons/e12.md" && echo "$RE12" | grep -q "e12.md"; then
|
|
ok "T12 runtime script store+recall works end-to-end in unrelated repo"
|
|
else
|
|
fail "T12 runtime script store+recall" "end-to-end failed"
|
|
fi
|
|
|
|
# ======================================================================== #
|
|
# Summary
|
|
# ======================================================================== #
|
|
echo
|
|
echo "==================== SUMMARY ===================="
|
|
echo "PASS: $PASS FAIL: $FAIL"
|
|
[ "$FAIL" = "0" ] && echo "RESULT: ALL PASS" || echo "RESULT: FAILURES PRESENT"
|
|
exit $(( FAIL > 0 ? 1 : 0 ))
|