KeiSeiKit-1.0/tests/substrate_integration.sh
Parfii-bot 59fd1a0362 test(substrate): integration now asserts real atom execution via Stream E
Previously expected NotImplemented stub (exit 64). Stream E wired real
subprocess exec to kei-task, so invoke now actually creates tasks.
Updated test:
- Builds kei-task in release + passes KEI_RUNTIME_BIN_DIR + KEI_TASK_DB
- Asserts exit 0 + stdout has 'id' field
- NEW assertion: invoke with empty KEI_RUNTIME_BIN_DIR → exit 127 (BinaryNotFound)
- Bad-input assertion stays (InputInvalid → exit 2)

4 end-to-end assertions now cover the full §Runtime contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:23:05 +08:00

146 lines
4.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# substrate_integration.sh — cross-stream integration smoke test
#
# Architect P0-b (audit wave 2026-04-23): each stream (kei-forge / kei-task
# atoms / kei-sage / kei-runtime) has its own smoke tests, but no single
# test exercised the cross-stream composition. This script is that test.
#
# The check: build release binaries, generate a fresh atom via new-atom.sh,
# then verify that kei-runtime + kei-sage BOTH discover it identically and
# that kei-runtime schema-lint passes on it.
#
# Exit 0 = substrate v1 contract holds end-to-end
# Exit 1 = any step failed — see stderr for the offending stage
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
TMPROOT="$(mktemp -d)"
trap 'rm -rf "$TMPROOT"' EXIT
fail() { echo "SUBSTRATE-INTEGRATION FAIL: $*" >&2; exit 1; }
echo "==> Building release binaries (kei-runtime, kei-sage, kei-task)…"
cd _primitives/_rust
cargo build --release -p kei-runtime -p kei-sage -p kei-task >/dev/null 2>&1 \
|| fail "cargo build failed"
RT="$(pwd)/target/release/kei-runtime"
SAGE="$(pwd)/target/release/kei-sage"
BIN_DIR="$(pwd)/target/release"
cd "$ROOT"
echo "==> Scaffolding a fresh atom (kei-task::create) via new-atom.sh for isolated test corpus…"
CORPUS="$TMPROOT/corpus/kei-task"
mkdir -p "$CORPUS"/{atoms/schemas,src/atoms,tests}
# Minimal hand-crafted atom mirroring Stream B's create atom shape —
# covers all REQUIRED frontmatter fields so schema-lint passes.
cat > "$CORPUS/atoms/create.md" <<'EOF'
---
atom: kei-task::create
kind: command
version: "0.22.3"
input:
schema: schemas/create-input.json
required: [title]
example: { title: "x" }
output:
schema: schemas/create-output.json
example: { id: 1 }
errors:
- code: DuplicateTitle
http_analog: 409
side_effects:
- { op: write, domain: kei-task-db }
idempotent: false
timeout_ms: 5000
stability: stable
keywords: [integration-test]
related: []
---
# kei-task::create
Integration-test atom. See substrate_integration.sh.
EOF
cat > "$CORPUS/atoms/schemas/create-input.json" <<'EOF'
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "kei-task/atoms/schemas/create-input.json",
"title": "kei-task::create input",
"type": "object",
"required": ["title"],
"properties": {
"title": { "type": "string", "minLength": 1 }
},
"additionalProperties": false,
"examples": [{"title": "x"}]
}
EOF
cat > "$CORPUS/atoms/schemas/create-output.json" <<'EOF'
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "kei-task/atoms/schemas/create-output.json",
"title": "kei-task::create output",
"type": "object",
"properties": { "id": { "type": "integer" } },
"additionalProperties": false,
"examples": [{"id": 1}]
}
EOF
echo "==> kei-runtime schema-lint…"
"$RT" schema-lint --root "$TMPROOT/corpus" \
| grep -q "^PASS" \
|| fail "schema-lint did not report PASS"
echo "==> kei-runtime list-atoms…"
LIST="$("$RT" list-atoms --root "$TMPROOT/corpus")"
echo "$LIST" | grep -q "kei-task::create" \
|| fail "kei-runtime list-atoms did not see kei-task::create"
echo "==> kei-sage atoms-discover…"
DISCOVER="$("$SAGE" atoms-discover --root "$TMPROOT/corpus")"
echo "$DISCOVER" | grep -q "kei-task::create" \
|| fail "kei-sage atoms-discover did not see kei-task::create"
echo "==> Cross-stream ID agreement…"
RT_IDS="$(echo "$LIST" | awk '{print $1}' | sort)"
SAGE_IDS="$(echo "$DISCOVER" | awk 'NR>1 && $1 != "" {print $1}' | sort)"
[ "$RT_IDS" = "$SAGE_IDS" ] \
|| fail "runtime and sage disagree on atom IDs:\n runtime: $RT_IDS\n sage: $SAGE_IDS"
echo "==> kei-runtime invoke (expects real exec via Stream E → exit 0 + result.id)…"
set +e
INVOKE_OUT="$(KEI_RUNTIME_BIN_DIR="$BIN_DIR" KEI_TASK_DB="$TMPROOT/task.sqlite" \
"$RT" invoke --root "$TMPROOT/corpus" kei-task::create --input '{"title":"integration"}' 2>&1)"
RC=$?
set -e
[ "$RC" -eq 0 ] \
|| fail "invoke should exit 0 on real exec, got $RC: $INVOKE_OUT"
echo "$INVOKE_OUT" | grep -q '"id"' \
|| fail "invoke stdout missing 'id' field: $INVOKE_OUT"
echo "==> kei-runtime invoke with missing binary (expects BinaryNotFound → exit 127)…"
set +e
PATH="/usr/bin:/bin" KEI_RUNTIME_BIN_DIR="/nonexistent" \
"$RT" invoke --root "$TMPROOT/corpus" kei-task::create --input '{"title":"x"}' >/dev/null 2>&1
RC=$?
set -e
[ "$RC" -eq 127 ] \
|| fail "invoke with missing binary should exit 127, got $RC"
echo "==> kei-runtime invoke with bad input (expects InputInvalid → exit 2)…"
set +e
"$RT" invoke --root "$TMPROOT/corpus" kei-task::create --input '{}' >/dev/null 2>&1
RC=$?
set -e
[ "$RC" -eq 2 ] \
|| fail "invoke with missing required field should exit 2, got $RC"
echo ""
echo "✓ SUBSTRATE-INTEGRATION PASS — all 4 streams agree on schema, runtime + sage see same atoms, exit codes per locked §Runtime contract"