2026-07-21 11:46:35 +01:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
#
|
2026-07-21 12:07:51 +01:00
|
|
|
# adr-076 domain-activation invariants — behavioural test for the two-path domain
|
2026-07-21 11:46:35 +01:00
|
|
|
# activation gate in install/ontoref-global (_dispatch_domain).
|
|
|
|
|
#
|
|
|
|
|
# Asserts, against the SOURCE wrapper (not the installed copy):
|
|
|
|
|
# T1 bond path — a bond-only consumer (carrier, NO manifest) activates.
|
|
|
|
|
# T2 refusal — a bare project (no manifest, no carrier) is refused.
|
|
|
|
|
# T3 additive Hard — a repo_kind-matching project activates IDENTICALLY with
|
|
|
|
|
# and without a carrier present (constraint
|
|
|
|
|
# `bond-path-is-purely-additive`: the carrier never alters
|
|
|
|
|
# an outcome the repo_kind path already granted).
|
|
|
|
|
# T4 bond rescues — a manifest whose repo_kind does NOT match is refused
|
|
|
|
|
# without a carrier, and activates WITH one.
|
|
|
|
|
#
|
|
|
|
|
# "Activated" = the dispatch passed the gate and proceeded to run the domain's
|
|
|
|
|
# commands.nu; the gate's refusal line is absent. The command itself may then
|
|
|
|
|
# fail on its own logic (the fixtures are not real rustelo sites) — that failure
|
|
|
|
|
# is BEYOND the gate and is exactly what proves the gate let it through.
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
|
|
|
|
|
|
WRAPPER="install/ontoref-global"
|
|
|
|
|
DOMAIN="rustelo" # a real installed domain with repo_kinds.txt = RusteloApp
|
|
|
|
|
REFUSAL="not available for this project"
|
|
|
|
|
|
|
|
|
|
# ── locate a data dir (ONTOREF_ROOT) so domains/ + dispatcher resolve ─────────
|
|
|
|
|
DD=""
|
|
|
|
|
for candidate in "$HOME/Library/Application Support/ontoref" "$HOME/.local/share/ontoref"; do
|
|
|
|
|
if [[ -d "$candidate/domains/$DOMAIN" ]]; then DD="$candidate"; break; fi
|
|
|
|
|
done
|
|
|
|
|
if [[ -z "$DD" ]]; then
|
|
|
|
|
echo "bond-dispatch-test: no installed data dir with domains/$DOMAIN — run 'just install-daemon' first" >&2
|
|
|
|
|
exit 3
|
|
|
|
|
fi
|
|
|
|
|
|
2026-07-21 12:07:51 +01:00
|
|
|
echo "== adr-076 domain-activation invariants =="
|
2026-07-21 11:46:35 +01:00
|
|
|
echo " wrapper=$WRAPPER data_dir=$DD domain=$DOMAIN"
|
|
|
|
|
echo
|
|
|
|
|
|
|
|
|
|
TMP="$(mktemp -d)"
|
|
|
|
|
trap 'rm -rf "$TMP"' EXIT
|
|
|
|
|
|
|
|
|
|
PASS=0
|
|
|
|
|
FAIL=0
|
|
|
|
|
|
|
|
|
|
# Run the source wrapper against a project root; echo combined output.
|
|
|
|
|
run_dispatch() {
|
|
|
|
|
local root="$1"
|
|
|
|
|
ONTOREF_ROOT="$DD" ONTOREF_PROJECT_ROOT="$root" bash "$WRAPPER" "$DOMAIN" routes 2>&1 || true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# assert_activated <label> <project_root>
|
|
|
|
|
assert_activated() {
|
|
|
|
|
local label="$1" root="$2" out
|
|
|
|
|
out="$(run_dispatch "$root")"
|
|
|
|
|
if echo "$out" | grep -qF "$REFUSAL"; then
|
|
|
|
|
echo " FAIL $label — gate REFUSED (expected activation)"; FAIL=$((FAIL + 1))
|
|
|
|
|
else
|
|
|
|
|
echo " pass $label — gate passed"; PASS=$((PASS + 1))
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# assert_refused <label> <project_root>
|
|
|
|
|
assert_refused() {
|
|
|
|
|
local label="$1" root="$2" out
|
|
|
|
|
out="$(run_dispatch "$root")"
|
|
|
|
|
if echo "$out" | grep -qF "$REFUSAL"; then
|
|
|
|
|
echo " pass $label — gate refused"; PASS=$((PASS + 1))
|
|
|
|
|
else
|
|
|
|
|
echo " FAIL $label — gate ACTIVATED (expected refusal)"; FAIL=$((FAIL + 1))
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ── fixtures ──────────────────────────────────────────────────────────────────
|
|
|
|
|
make_carrier() {
|
|
|
|
|
local root="$1"
|
|
|
|
|
mkdir -p "$root/.domains-ontoref/$DOMAIN"
|
|
|
|
|
cat > "$root/.domains-ontoref/$DOMAIN/bonds.ncl" <<EOF
|
|
|
|
|
let s = import "bond.ncl" in
|
|
|
|
|
{
|
|
|
|
|
domain = "$DOMAIN",
|
|
|
|
|
bonds = [
|
|
|
|
|
{ id = "test-to-$DOMAIN", from = "test", to = "$DOMAIN", axis = 'Dependency, state = 'Linked, dep_kind = 'Conformist, mutual = false, plane = "$DOMAIN" },
|
|
|
|
|
],
|
|
|
|
|
} | s.BondSet
|
|
|
|
|
EOF
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
make_manifest() {
|
|
|
|
|
local root="$1" kind="$2"
|
|
|
|
|
mkdir -p "$root/.ontoref/ontology"
|
|
|
|
|
printf 'let m = import "manifest" in\n{ project = "t", repo_kind = %s }\n' "'$kind" \
|
|
|
|
|
> "$root/.ontoref/ontology/manifest.ncl"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# T1 — bond-only consumer (carrier, no manifest)
|
|
|
|
|
BOND_ONLY="$TMP/bond-only"; mkdir -p "$BOND_ONLY"; make_carrier "$BOND_ONLY"
|
|
|
|
|
assert_activated "T1 bond-only (carrier, no manifest)" "$BOND_ONLY"
|
|
|
|
|
|
|
|
|
|
# T2 — bare project (no manifest, no carrier)
|
|
|
|
|
BARE="$TMP/bare"; mkdir -p "$BARE"
|
|
|
|
|
assert_refused "T2 bare (no manifest, no carrier)" "$BARE"
|
|
|
|
|
|
|
|
|
|
# T3 — additive Hard: repo_kind match, with vs without carrier → both activate
|
|
|
|
|
MANAGED="$TMP/managed"; make_manifest "$MANAGED" "RusteloApp"
|
|
|
|
|
assert_activated "T3a managed repo_kind, no carrier" "$MANAGED"
|
|
|
|
|
make_carrier "$MANAGED"
|
|
|
|
|
assert_activated "T3b managed repo_kind, WITH carrier (additive)" "$MANAGED"
|
|
|
|
|
|
|
|
|
|
# T4 — bond rescues a non-matching repo_kind
|
|
|
|
|
WRONG="$TMP/wrong-kind"; make_manifest "$WRONG" "SomeOtherKind"
|
|
|
|
|
assert_refused "T4a wrong repo_kind, no carrier" "$WRONG"
|
|
|
|
|
make_carrier "$WRONG"
|
|
|
|
|
assert_activated "T4b wrong repo_kind, WITH carrier (bond rescues)" "$WRONG"
|
|
|
|
|
|
|
|
|
|
echo
|
|
|
|
|
echo "== summary: $PASS passed, $FAIL failed =="
|
|
|
|
|
[[ "$FAIL" -eq 0 ]] || exit 1
|