ontoref-code/scripts/agent-session-test.sh

154 lines
6.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
#
# O7 piloto self-host smoke test.
#
# Drives the daemon binary through the three-op piloto sequence
# (propose_adr → update_ontology_node → move_fsm_state) via the CLI
# surface added in O5. Verifies that every op emits a signed witness
# and that the projected state files exist post-execution.
#
# The flags `--task`, `--no-raw-tools`, and `--phase` are accepted but
# treated as advisory metadata: tool-surface restriction belongs to
# the launcher (Claude Code / agent harness), not this script. The
# env var ONTOREF_OPS_ENFORCE=strict is honoured as a metadata switch
# that surfaces in the summary output.
set -euo pipefail
cd "$(dirname "$0")/.."
# ── argument parsing ────────────────────────────────────────────────────────
TASK="(unset)"
PHASE="Progressive"
NO_RAW_TOOLS="0"
while [[ $# -gt 0 ]]; do
case "$1" in
--task) TASK="$2"; shift 2 ;;
--task=*) TASK="${1#*=}"; shift ;;
--phase) PHASE="$2"; shift 2 ;;
--phase=*) PHASE="${1#*=}"; shift ;;
--no-raw-tools) NO_RAW_TOOLS="1"; shift ;;
*) echo "agent-session-test: unknown arg '$1'" >&2; exit 2 ;;
esac
done
ENFORCE="${ONTOREF_OPS_ENFORCE:-advisory}"
echo "== O7 piloto self-host smoke test =="
echo " task=$TASK phase=$PHASE no_raw_tools=$NO_RAW_TOOLS enforce=$ENFORCE"
echo
# ── locate the daemon binary ────────────────────────────────────────────────
BIN=""
for candidate in target/release/ontoref-daemon target/debug/ontoref-daemon \
/Volumes/Devel/ontoref/target/release/ontoref-daemon \
/Volumes/Devel/ontoref/target/debug/ontoref-daemon; do
if [[ -x "$candidate" ]]; then BIN="$candidate"; break; fi
done
if [[ -z "$BIN" ]]; then
echo "build daemon first: just build-daemon (or cargo build --release -p ontoref-daemon)" >&2
exit 3
fi
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
mkdir -p "$TMP/.ontology" "$TMP/adrs" "$TMP/reflection"
SEED_HEX="$(printf '42%.0s' {1..32})"
# ── op 1 — propose_adr ──────────────────────────────────────────────────────
echo "→ op 1/3: propose_adr"
INPUTS_1='{
"id": "adr-099",
"slug": "piloto-self-host",
"title": "Piloto self-host",
"decision": "Adopt the operations layer for ontoref itself.",
"ondaod_evaluation": {
"engaged_tensions": ["ontology-vs-reflection"],
"synthesis_state": "Realized",
"motion_direction": "Static"
}
}'
CONTEXT_1="$(jq -n --arg root "$TMP" --arg seed "$SEED_HEX" \
'{actor_id: "developer", signing_key_seed_hex: $seed, project_root: $root}')"
WITNESS_1="$("$BIN" --invoke-op propose_adr \
--invoke-inputs "$INPUTS_1" --invoke-context "$CONTEXT_1")"
echo "$WITNESS_1" | jq -e '.op_id == "propose_adr"' >/dev/null \
|| { echo "propose_adr witness missing op_id"; exit 4; }
[[ -f "$TMP/adrs/adr-099-piloto-self-host.ncl" ]] \
|| { echo "ADR file not written"; exit 5; }
echo " ✓ witness signed; ADR file written"
# ── op 2 — update_ontology_node ─────────────────────────────────────────────
echo "→ op 2/3: update_ontology_node"
INPUTS_2='{
"node_id": "piloto-self-host",
"name": "Piloto Self-Host",
"description": "Records that ontoref runs itself via the operations layer.",
"pole": "Yang",
"level": "Practice"
}'
CORE_SNAPSHOT='{"nodes": [], "edges": []}'
CONTEXT_2="$(jq -n --arg root "$TMP" --arg seed "$SEED_HEX" --argjson core "$CORE_SNAPSHOT" \
'{actor_id: "developer", signing_key_seed_hex: $seed, project_root: $root, core: $core}')"
WITNESS_2="$("$BIN" --invoke-op update_ontology_node \
--invoke-inputs "$INPUTS_2" --invoke-context "$CONTEXT_2")"
echo "$WITNESS_2" | jq -e '.op_id == "update_ontology_node"' >/dev/null \
|| { echo "update_ontology_node witness missing op_id"; exit 6; }
[[ -f "$TMP/.ontology/core.ncl" ]] \
|| { echo "core.ncl not written"; exit 7; }
echo " ✓ witness signed; core.ncl rewritten"
# ── op 3 — move_fsm_state ───────────────────────────────────────────────────
echo "→ op 3/3: move_fsm_state"
INPUTS_3='{ "dimension": "adoption", "new_state": "b" }'
STATE_SNAPSHOT='{
"dimensions": [
{
"id": "adoption",
"name": "Adoption",
"description": "Piloto FSM dimension.",
"current_state": "a",
"desired_state": "c",
"horizon": "Weeks",
"states": [],
"transitions": [
{ "from": "a", "to": "b", "condition": "ready", "catalyst": "", "blocker": "", "horizon": "Weeks" },
{ "from": "b", "to": "c", "condition": "ready", "catalyst": "", "blocker": "", "horizon": "Weeks" }
],
"coupled_with": []
}
]
}'
CONTEXT_3="$(jq -n --arg root "$TMP" --arg seed "$SEED_HEX" --argjson state "$STATE_SNAPSHOT" \
'{actor_id: "developer", signing_key_seed_hex: $seed, project_root: $root, state: $state}')"
WITNESS_3="$("$BIN" --invoke-op move_fsm_state \
--invoke-inputs "$INPUTS_3" --invoke-context "$CONTEXT_3")"
echo "$WITNESS_3" | jq -e '.op_id == "move_fsm_state"' >/dev/null \
|| { echo "move_fsm_state witness missing op_id"; exit 8; }
[[ -f "$TMP/.ontology/state.ncl" ]] \
|| { echo "state.ncl not written"; exit 9; }
grep -q 'current_state = "b"' "$TMP/.ontology/state.ncl" \
|| { echo "state.ncl missing post-mutation current_state"; exit 10; }
echo " ✓ witness signed; state.ncl shows current_state='b'"
# ── summary ─────────────────────────────────────────────────────────────────
echo
echo "== piloto sequence complete =="
jq -n \
--argjson w1 "$WITNESS_1" \
--argjson w2 "$WITNESS_2" \
--argjson w3 "$WITNESS_3" \
--arg task "$TASK" \
--arg phase "$PHASE" \
--arg enforce "$ENFORCE" \
'{
task: $task,
phase: $phase,
enforce: $enforce,
op_ids: [$w1.op_id, $w2.op_id, $w3.op_id],
witness_shapes: [$w1.witness_shape, $w2.witness_shape, $w3.witness_shape],
state_roots: [$w1.state_root_hex, $w2.state_root_hex, $w3.state_root_hex],
}'