154 lines
6.4 KiB
Bash
154 lines
6.4 KiB
Bash
|
|
#!/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],
|
||
|
|
}'
|