e044a2de0d
---ci--- project: acdl phase: 6 milestone: v1.1 status: plan-as-execute persona: lead-developer tasks: [T-6.1, T-6.2, T-6.3, T-6.4] ---/ci--- Archive the v1.0 demo under demo/ (D-037) and reorient the repo to the real platform. Wave 1 of the Phase 06 plan. - T-6.1: git mv modules/, scripts/, evidence-ui/, contracts/, contracts-repo/, .gitea/ -> demo/; mv ACDL_DEMO.md + runner-data/ -> demo/ - T-6.2: scaffold new v1.1 top-level dirs (platform/, schemas/, adapters/, terraform/, modules-ir/) with .gitkeep - T-6.3: create top-level scripts/verify_phase06.sh (v1.1 verify scripts live at top-level, NOT demo/scripts/ which holds the v1.0 demo verify scripts) - T-6.4: rewrite README.md to reflect the real platform (vision + architecture links, new layout, status v1.1 active); add runner-data/ to .gitignore All moves via git mv (history preserved). Repo root now contains only README.md, demo/, docs/, .ciagent/, and the new empty v1.1 dirs.
258 lines
9.4 KiB
Bash
Executable File
258 lines
9.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/run_demo.sh — Phase 05 dry-run simulation of the 4 demo acts (T-5.2).
|
|
#
|
|
# Simulates the full 4-act demo locally (no act_runner) by calling the core
|
|
# scripts in sequence and writing hash-chained evidence events to audit.json,
|
|
# then optionally uploads audit.json + evidence-ui/index.html to acdl-evidence
|
|
# main via finalize_evidence.py (D-031, D-033).
|
|
#
|
|
# Usage: scripts/run_demo.sh [--no-upload]
|
|
# --no-upload skip the Gitea API calls (useful for testing without a token)
|
|
|
|
set -uo pipefail
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Parse args
|
|
# -----------------------------------------------------------------------------
|
|
UPLOAD=1
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--no-upload)
|
|
UPLOAD=0
|
|
;;
|
|
*)
|
|
echo "run_demo.sh: unknown argument: $arg" >&2
|
|
echo "usage: scripts/run_demo.sh [--no-upload]" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Paths
|
|
# -----------------------------------------------------------------------------
|
|
# Repo root = location of this script's parent dir.
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
|
WORKDIR="/tmp/acdl_demo_run"
|
|
AUDIT="$WORKDIR/audit.json"
|
|
CONTRACTS="$WORKDIR/contracts"
|
|
|
|
# Track failures so we can return non-zero at the end (we do NOT use set -e
|
|
# because policy_checker intentionally exits 1 on Act 4).
|
|
FAIL=0
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Helpers
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# Write one evidence event. Args: <stage> <event-text>
|
|
ev() {
|
|
local stage="$1"
|
|
local text="$2"
|
|
if ! python3 "$SCRIPT_DIR/evidence_writer.py" --stage "$stage" --event "$text" --audit "$AUDIT"; then
|
|
echo "run_demo.sh: evidence_writer failed for stage=$stage text=$text" >&2
|
|
FAIL=1
|
|
fi
|
|
}
|
|
|
|
# Run a contract through the Act 2/3 pipeline (policy -> confidence -> executor).
|
|
# Assumes the contract already passed policy (caller verifies). Writes the
|
|
# standard 4-event sequence. Args: <act-label> <dev-applied-event-text>
|
|
run_passing_pipeline() {
|
|
local dev_event="$1"
|
|
|
|
ev dev "$dev_event"
|
|
ev qa "qa approved"
|
|
ev prod "prod approved"
|
|
ev finalize "finalize: audit.json committed to acdl-evidence"
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Setup working directory
|
|
# -----------------------------------------------------------------------------
|
|
mkdir -p "$CONTRACTS"
|
|
rm -f "$AUDIT"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Initialize audit (genesis)
|
|
# -----------------------------------------------------------------------------
|
|
echo "== run_demo.sh: initializing audit at $AUDIT =="
|
|
ev genesis "audit log initialized"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Act 1 — Friction
|
|
# -----------------------------------------------------------------------------
|
|
echo "== Act 1 — Friction =="
|
|
ev dev "Act 1 Friction: manual 2-week deployment (legacy process)"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Act 2 — Developer Self-Service
|
|
# -----------------------------------------------------------------------------
|
|
echo "== Act 2 — Developer Self-Service =="
|
|
cat > "$CONTRACTS/act2.yaml" <<'YAML'
|
|
stack: l2-commodity-price-feed
|
|
inputs:
|
|
environment: dev
|
|
owner: platform-team
|
|
public-ingress: false
|
|
YAML
|
|
|
|
ACT2_POLICY="$(python3 "$SCRIPT_DIR/policy_checker.py" "$CONTRACTS/act2.yaml")"
|
|
ACT2_POLICY_RC=$?
|
|
echo " policy_checker: $ACT2_POLICY (rc=$ACT2_POLICY_RC)"
|
|
if [ "$ACT2_POLICY" != "POLICY_PASS" ]; then
|
|
echo "run_demo.sh: Act 2 expected POLICY_PASS, got '$ACT2_POLICY'" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
ACT2_CONF="$(python3 "$SCRIPT_DIR/confidence_signal.py" "$CONTRACTS/act2.yaml")"
|
|
echo " confidence_signal: $ACT2_CONF"
|
|
# Expected: {"score": 0.90, "reason": "POLICY_PASS"}
|
|
|
|
# mock_executor.sh resolves modules/l2/<stack>/manifest.yaml relative to its
|
|
# cwd, so it must run from the repo root. It writes state.json to its cwd;
|
|
# clean it up from the repo root afterward so no stray file is left there.
|
|
(
|
|
cd "$REPO_ROOT" && bash "$SCRIPT_DIR/mock_executor.sh" "$CONTRACTS/act2.yaml"
|
|
)
|
|
MOCK_RC=$?
|
|
rm -f "$REPO_ROOT/state.json"
|
|
if [ "$MOCK_RC" -ne 0 ]; then
|
|
echo "run_demo.sh: Act 2 mock_executor failed (rc=$MOCK_RC)" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
run_passing_pipeline "dev applied: l2-commodity-price-feed"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Act 3 — Citizen Developer
|
|
# -----------------------------------------------------------------------------
|
|
echo "== Act 3 — Citizen Developer =="
|
|
ISSUE_BODY="We need to ingest natural gas prices from Platts and report on compliance for the trading desk."
|
|
if ! python3 "$SCRIPT_DIR/l3b_agent_stub.py" "$ISSUE_BODY" -o "$CONTRACTS/act3.yaml"; then
|
|
echo "run_demo.sh: l3b_agent_stub failed for Act 3" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
# Confirm the generated contract's stack (D-008: gas/price matches first).
|
|
ACT3_STACK="$(python3 -c "import yaml,sys; print(yaml.safe_load(open('$CONTRACTS/act3.yaml'))['stack'])" 2>/dev/null || echo "")"
|
|
echo " l3b generated stack: $ACT3_STACK"
|
|
if [ "$ACT3_STACK" != "l2-commodity-price-feed" ]; then
|
|
echo "run_demo.sh: WARNING Act 3 expected stack l2-commodity-price-feed, got '$ACT3_STACK'" >&2
|
|
# Continue anyway per the task spec.
|
|
fi
|
|
|
|
ACT3_POLICY="$(python3 "$SCRIPT_DIR/policy_checker.py" "$CONTRACTS/act3.yaml")"
|
|
ACT3_POLICY_RC=$?
|
|
echo " policy_checker: $ACT3_POLICY (rc=$ACT3_POLICY_RC)"
|
|
if [ "$ACT3_POLICY" != "POLICY_PASS" ]; then
|
|
echo "run_demo.sh: Act 3 expected POLICY_PASS, got '$ACT3_POLICY'" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
ACT3_CONF="$(python3 "$SCRIPT_DIR/confidence_signal.py" "$CONTRACTS/act3.yaml")"
|
|
echo " confidence_signal: $ACT3_CONF"
|
|
|
|
(
|
|
cd "$REPO_ROOT" && bash "$SCRIPT_DIR/mock_executor.sh" "$CONTRACTS/act3.yaml"
|
|
)
|
|
MOCK_RC=$?
|
|
rm -f "$REPO_ROOT/state.json"
|
|
if [ "$MOCK_RC" -ne 0 ]; then
|
|
echo "run_demo.sh: Act 3 mock_executor failed (rc=$MOCK_RC)" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
run_passing_pipeline "dev applied: l2-commodity-price-feed (Act 3 from issue)"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Act 4 — Safety Net
|
|
# -----------------------------------------------------------------------------
|
|
echo "== Act 4 — Safety Net =="
|
|
cat > "$CONTRACTS/act4.yaml" <<'YAML'
|
|
stack: l2-regulatory-reporting
|
|
inputs:
|
|
environment: dev
|
|
owner: platform-team
|
|
public-ingress: true
|
|
YAML
|
|
|
|
# policy_checker exits 1 on violation; capture without failing the script.
|
|
ACT4_POLICY="$(python3 "$SCRIPT_DIR/policy_checker.py" "$CONTRACTS/act4.yaml" 2>&1 || true)"
|
|
echo " policy_checker: $ACT4_POLICY"
|
|
if [ "$ACT4_POLICY" != "POLICY_VIOLATION:PUBLIC_INGRESS" ]; then
|
|
echo "run_demo.sh: Act 4 expected POLICY_VIOLATION:PUBLIC_INGRESS, got '$ACT4_POLICY'" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
ACT4_CONF="$(python3 "$SCRIPT_DIR/confidence_signal.py" "$CONTRACTS/act4.yaml")"
|
|
echo " confidence_signal: $ACT4_CONF"
|
|
# Expected: {"score": 0.40, "reason": "POLICY_VIOLATION:PUBLIC_INGRESS"}
|
|
|
|
# Score < 0.50 -> dev rejects. Do NOT run mock_executor, do NOT write qa/prod/finalize.
|
|
ev dev "dev rejected: POLICY_VIOLATION:PUBLIC_INGRESS (confidence 0.40 < 0.50)"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Summary
|
|
# -----------------------------------------------------------------------------
|
|
echo "== Summary =="
|
|
python3 - "$AUDIT" <<'PY'
|
|
import json, sys
|
|
audit = json.load(open(sys.argv[1]))
|
|
for e in audit:
|
|
print(f"{e['seq']} | {e['stage']} | {e['event']} | {e['hash'][:12]}")
|
|
print(f"total events: {len(audit)}")
|
|
PY
|
|
|
|
EVENT_COUNT="$(python3 -c "import json; print(len(json.load(open('$AUDIT'))))")"
|
|
echo "event count: $EVENT_COUNT"
|
|
|
|
if [ "$EVENT_COUNT" -lt 11 ]; then
|
|
echo "run_demo.sh: expected >= 11 events, got $EVENT_COUNT" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Upload (optional)
|
|
# -----------------------------------------------------------------------------
|
|
if [ "$UPLOAD" -eq 1 ]; then
|
|
echo "== Upload =="
|
|
if [ -z "${ACDL_GITEA_TOKEN:-}" ]; then
|
|
echo "run_demo.sh: ACDL_GITEA_TOKEN not set; skipping upload (use --no-upload to silence)" >&2
|
|
else
|
|
# Upload audit.json to acdl-evidence main.
|
|
if python3 "$SCRIPT_DIR/finalize_evidence.py" --audit "$AUDIT"; then
|
|
echo " audit.json uploaded"
|
|
else
|
|
echo "run_demo.sh: finalize_evidence failed for audit.json" >&2
|
|
FAIL=1
|
|
fi
|
|
# Upload index.html (the --audit flag accepts any local file path; --path
|
|
# sets the remote destination).
|
|
if python3 "$SCRIPT_DIR/finalize_evidence.py" \
|
|
--audit "$REPO_ROOT/evidence-ui/index.html" \
|
|
--path index.html \
|
|
--message "chore(ui): update index.html (demo dry run)"; then
|
|
echo " index.html uploaded"
|
|
else
|
|
echo "run_demo.sh: finalize_evidence failed for index.html" >&2
|
|
FAIL=1
|
|
fi
|
|
echo "Uploaded audit.json + index.html to acdl-evidence main"
|
|
echo " raw URL: https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html"
|
|
fi
|
|
else
|
|
echo "== Upload skipped (--no-upload) =="
|
|
fi
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Exit
|
|
# -----------------------------------------------------------------------------
|
|
if [ "$FAIL" -ne 0 ]; then
|
|
echo "run_demo.sh: one or more steps failed (see warnings above)" >&2
|
|
exit 1
|
|
fi
|
|
echo "run_demo.sh: OK ($EVENT_COUNT events)"
|
|
exit 0 |