#!/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], }'