The curator Python backend (package, tests, systemd units, config templates, scripts) now lives under scenarios/curator/backend and is the single source of truth; the live checkout at the workspace path is a runtime copy. Exported from the app repo's tracked tree via git archive (no history, .pi/venv/caches excluded). 149 unit tests pass from the new location. profile.toml backend is now repo-relative (scenarios/curator/backend); verify-generated.sh resolves a relative backend against REPO_ROOT. verify-no-secrets ASSIGN heuristic now requires value entropy so vendored kwargs like token=extraction_token no longer false-positive. README documents the backend/ layout and the operator-owned app rollout step.
66 lines
2.5 KiB
Bash
Executable File
66 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ---------------------------------------------------------------------------
|
|
# Check that generated regions in tracked files are current.
|
|
#
|
|
# The tool list inside a scenario's system prompt is generated from the backend's
|
|
# contracts module. It has to be generated rather than referenced because pi does
|
|
# not put the tool list in the prompt when --system-prompt is used: the
|
|
# customPrompt branch returns before `toolsList` is assembled, so `promptSnippet`
|
|
# and `promptGuidelines` never reach the model.
|
|
#
|
|
# That makes the prompt a copy of the tool definitions, and a copy drifts. The
|
|
# failure is quiet and bad: the model is told about a tool that no longer exists,
|
|
# or not told about one that does, and answers from memory instead of asking.
|
|
#
|
|
# Run by the pre-commit hook. The backend path comes from profile.toml, so this
|
|
# checks against the code that will actually serve the tools.
|
|
# ---------------------------------------------------------------------------
|
|
# shellcheck source=lib/common.sh
|
|
. "$(dirname "${BASH_SOURCE[0]}")/lib/common.sh"
|
|
|
|
FIX=0
|
|
[ "${1:-}" = "--fix" ] && FIX=1
|
|
|
|
STALE=0
|
|
CHECKED=0
|
|
|
|
while IFS= read -r profile; do
|
|
name="$(basename "$(dirname "$profile")")"
|
|
backend="$(toml_get "$profile" scenario backend)"
|
|
[ -n "$backend" ] || continue
|
|
case "$backend" in /*) ;; *) backend="$REPO_ROOT/$backend" ;; esac
|
|
[ -d "$backend" ] || { warn "$name: backend not found: $backend"; continue; }
|
|
|
|
while IFS= read -r prompt; do
|
|
[ -f "$prompt" ] || continue
|
|
grep -q 'BEGIN GENERATED TOOL LIST' "$prompt" || continue
|
|
CHECKED=$((CHECKED + 1))
|
|
rel="${prompt#"$REPO_ROOT"/}"
|
|
if PYTHONPATH="$backend" python3 - "$prompt" "$FIX" <<'PY'
|
|
import pathlib, sys
|
|
from curator import contracts
|
|
path, fix = pathlib.Path(sys.argv[1]), sys.argv[2] == "1"
|
|
text = path.read_text(encoding="utf-8")
|
|
current = contracts.splice_tool_prose(text)
|
|
if current == text:
|
|
sys.exit(0)
|
|
if fix:
|
|
path.write_text(current, encoding="utf-8")
|
|
sys.exit(0)
|
|
sys.exit(1)
|
|
PY
|
|
then
|
|
if [ "$FIX" -eq 1 ]; then ok "$rel"; else ok "$rel"; fi
|
|
else
|
|
STALE=$((STALE + 1))
|
|
warn "stale generated region: $rel"
|
|
fi
|
|
done < <(find "$(dirname "$profile")/workspace" -name '*.md' -type f 2>/dev/null | sort)
|
|
done < <(find "$REPO_ROOT/scenarios" -mindepth 2 -maxdepth 2 -name profile.toml | sort)
|
|
|
|
if [ "$STALE" -gt 0 ]; then
|
|
die "$STALE generated region(s) out of date. Regenerate with:
|
|
scripts/verify-generated.sh --fix"
|
|
fi
|
|
ok "verify-generated: $CHECKED file(s) checked, all current"
|