mirror of
https://github.com/samvallad33/vestige.git
synced 2026-06-08 20:25:16 +02:00
Some checks failed
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (ubuntu-latest) (push) Has been cancelled
Test Suite / Unit Tests (push) Has been cancelled
Test Suite / MCP E2E Tests (push) Has been cancelled
Test Suite / Dashboard Build (push) Has been cancelled
Test Suite / Code Coverage (push) Has been cancelled
CI / Release Build (aarch64-apple-darwin) (push) Has been cancelled
CI / Release Build (x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / Release Build (x86_64-apple-darwin) (push) Has been cancelled
Test Suite / User Journey Tests (push) Has been cancelled
Concrete search, irreversible purge, first-class contradictions tool, vestige update CLI, dense dream persistence fix, embedding-model upgrade repair, and a /dashboard/waitlist Pro early-access preview. 25 MCP tools. SQLite migration v13. Backwards compatible: 'delete' remains as a 'purge' alias. Closes #50, #51.
118 lines
3.5 KiB
Bash
Executable file
118 lines
3.5 KiB
Bash
Executable file
#!/bin/bash
|
|
# synthesis-stop-validator.sh — optional Stop hook
|
|
#
|
|
# Blocks a narrow failure mode: a response that cites multiple memories but
|
|
# stops at summary instead of composing them into a decision. This public-safe
|
|
# version contains no private examples or local-user paths.
|
|
|
|
set -euo pipefail
|
|
|
|
INPUT="$(cat)"
|
|
TRANSCRIPT_PATH="$(printf '%s' "$INPUT" | /usr/bin/python3 -c 'import sys,json;d=json.load(sys.stdin);print(d.get("transcript_path",""))' 2>/dev/null || printf '')"
|
|
|
|
if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
export TRANSCRIPT_PATH
|
|
PYFILE=$(mktemp -t vestige-stop-validator.XXXXXX)
|
|
trap 'rm -f "$PYFILE"' EXIT
|
|
cat > "$PYFILE" <<'PYEOF'
|
|
import json, os, re, sys
|
|
|
|
transcript = os.environ.get("TRANSCRIPT_PATH", "")
|
|
last_user = ""
|
|
last_assistant = ""
|
|
|
|
try:
|
|
with open(transcript) as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
try:
|
|
obj = json.loads(line)
|
|
except Exception:
|
|
continue
|
|
role = obj.get("role") or obj.get("type", "")
|
|
content = obj.get("message", {}).get("content", obj.get("content", ""))
|
|
text = ""
|
|
if isinstance(content, list):
|
|
for block in content:
|
|
if isinstance(block, dict) and block.get("type") == "text":
|
|
text += block.get("text", "") + "\n"
|
|
elif isinstance(content, str):
|
|
text = content
|
|
if role == "user":
|
|
last_user = text
|
|
elif role == "assistant":
|
|
last_assistant = text
|
|
except Exception:
|
|
sys.exit(0)
|
|
|
|
decision_re = re.compile(
|
|
r"(submit|submission|final|ship|launch|deploy|commit|decide|decision|"
|
|
r"recommend|should i|what should|purchase|buy|invest|architect|architecture|"
|
|
r"strategy|prep|prioriti|compose|tradeoff|trade-off|config|which "
|
|
r"(should|model|approach|one)|pick|choose|benchmark|competition|perform)",
|
|
re.IGNORECASE,
|
|
)
|
|
if not decision_re.search(last_user):
|
|
sys.exit(0)
|
|
|
|
memory_re = re.compile(
|
|
r"(memory|vestige|recall|retriev|saved memor|stored memor|prior memor|"
|
|
r"fsrs|trust score|deep_reference|smart_ingest)",
|
|
re.IGNORECASE,
|
|
)
|
|
if not memory_re.search(last_assistant):
|
|
sys.exit(0)
|
|
|
|
summary_patterns = [
|
|
r"memory\s+[a-f0-9]{4,}",
|
|
r"saved memory",
|
|
r"according to memory",
|
|
r"the memory (says|states|notes|indicates)",
|
|
r"per memory",
|
|
r"memories? (say|says|state|note|indicate)",
|
|
]
|
|
summary_hits = 0
|
|
for pat in summary_patterns:
|
|
summary_hits += len(re.findall(pat, last_assistant, re.IGNORECASE))
|
|
|
|
composition_re = re.compile(
|
|
r"(compos|combin|together|concrete action|recommend(ation)? [:\-]|"
|
|
r"never[- ]composed|the synthesis is|therefore|so the action is)",
|
|
re.IGNORECASE,
|
|
)
|
|
composition_hits = len(composition_re.findall(last_assistant))
|
|
|
|
if summary_hits >= 3 and composition_hits == 0:
|
|
print("BLOCK_SUMMARY")
|
|
sys.exit(0)
|
|
|
|
print("PASS")
|
|
PYEOF
|
|
|
|
RESULT="$(/usr/bin/python3 "$PYFILE")"
|
|
|
|
case "$RESULT" in
|
|
BLOCK_SUMMARY)
|
|
cat >&2 <<'BLOCKMSG'
|
|
[STOP BLOCKED — VESTIGE SYNTHESIS VALIDATOR]
|
|
|
|
The response cites multiple memories but does not compose them into a decision.
|
|
Rewrite it so the retrieved evidence becomes:
|
|
|
|
1. Evidence: the memory facts that matter.
|
|
2. Implication: what those facts change.
|
|
3. Action: the concrete recommendation.
|
|
|
|
Do not stop at "Memory A says X, Memory B says Y." Compose the evidence.
|
|
BLOCKMSG
|
|
exit 2
|
|
;;
|
|
*)
|
|
exit 0
|
|
;;
|
|
esac
|