ACDL — Agentic Cloud Delivery Platform · Audit Timeline
-, "body": ""} to stdout
- and exit 1.
-"""
-import argparse
-import base64
-import json
-import os
-import sys
-import urllib.error
-import urllib.parse
-import urllib.request
-
-
-def _request(method: str, url: str, token: str, body: dict = None):
- """Perform an HTTP request with the Gitea auth header. Returns
- (status_code, response_body_text). Raises URLError on network failure."""
- data = None
- headers = {"Authorization": f"token {token}",
- "Accept": "application/json"}
- if body is not None:
- data = json.dumps(body).encode("utf-8")
- headers["Content-Type"] = "application/json"
- req = urllib.request.Request(url, data=data, method=method, headers=headers)
- try:
- with urllib.request.urlopen(req) as resp:
- return resp.getcode(), resp.read().decode("utf-8", "replace")
- except urllib.error.HTTPError as exc:
- # HTTPError carries the response body
- try:
- body_text = exc.read().decode("utf-8", "replace")
- except Exception:
- body_text = ""
- return exc.code, body_text
- except urllib.error.URLError as exc:
- # Network-level failure (connection refused, DNS, timeout). Return
- # a synthetic 0 status + the reason so callers can report cleanly
- # without a stack trace.
- return 0, f"URLError: {exc.reason}"
-
-
-def get_existing_sha(host: str, owner: str, repo: str, path: str,
- branch: str, token: str):
- """Return (sha-or-None, error_status_or_None). On 200 returns the sha.
- On 404 returns (None, None). Other codes return (None, (status, body))."""
- qs = urllib.parse.urlencode({"ref": branch})
- url = f"{host}/api/v1/repos/{owner}/{repo}/contents/{path}?{qs}"
- status, body = _request("GET", url, token)
- if status == 200:
- try:
- data = json.loads(body)
- return data.get("sha"), None
- except (ValueError, TypeError):
- return None, (status, body)
- if status == 404:
- return None, None
- return None, (status, body)
-
-
-def upload(host: str, owner: str, repo: str, path: str, branch: str,
- message: str, content_b64: str, sha, token: str):
- """PUT (update) or POST (create) the file. Returns (new_sha, None) on
- success or (None, (status, body)) on HTTP error."""
- url = f"{host}/api/v1/repos/{owner}/{repo}/contents/{path}"
- if sha:
- body = {"content": content_b64, "message": message,
- "branch": branch, "sha": sha}
- status, resp = _request("PUT", url, token, body)
- else:
- body = {"content": content_b64, "message": message, "branch": branch}
- status, resp = _request("POST", url, token, body)
- if status in (200, 201):
- try:
- data = json.loads(resp)
- # The file-contents API returns the new content object either at
- # top-level `content` (POST create) or `content` (PUT update).
- new_sha = None
- if isinstance(data, dict):
- content_obj = data.get("content") or data
- if isinstance(content_obj, dict):
- new_sha = content_obj.get("sha")
- return new_sha, None
- except (ValueError, TypeError):
- return None, None
- return None, (status, resp)
-
-
-def main() -> int:
- parser = argparse.ArgumentParser(
- description="Upload a local audit.json to the acdl-evidence Gitea "
- "repo via the file-contents API (D-028/D-029).")
- parser.add_argument("--audit", required=True,
- help="Local audit.json file to upload")
- parser.add_argument("--owner", default="continuous-intelligence",
- help="Gitea org (default: continuous-intelligence)")
- parser.add_argument("--repo", default="acdl-evidence",
- help="Gitea repo (default: acdl-evidence)")
- parser.add_argument("--branch", default="main",
- help="Target branch (default: main)")
- parser.add_argument("--path", default="audit.json",
- help="Remote path in the repo (default: audit.json)")
- parser.add_argument("--token-env", default="ACDL_GITEA_TOKEN",
- help="Env var name holding the Gitea token "
- "(default: ACDL_GITEA_TOKEN)")
- parser.add_argument("--host", default="https://git.cloudinit.dev",
- help="Gitea host URL (default: https://git.cloudinit.dev)")
- parser.add_argument("--message", default="chore(evidence): update audit.json",
- help="Commit message (default: chore(evidence): "
- "update audit.json)")
- args = parser.parse_args()
-
- token = os.environ.get(args.token_env)
- if not token:
- print(f"finalize_evidence: required env var {args.token_env} is not "
- f"set", file=sys.stderr)
- return 1
-
- # Read + base64-encode the local audit file. Missing/unreadable file is
- # a clean exit 1 (no stack trace).
- try:
- with open(args.audit, "rb") as fh:
- raw = fh.read()
- except OSError as exc:
- print(f"finalize_evidence: cannot read {args.audit}: {exc}",
- file=sys.stderr)
- return 1
- content_b64 = base64.b64encode(raw).decode("ascii")
-
- # Discover existing sha (update vs create).
- sha, err = get_existing_sha(args.host, args.owner, args.repo,
- args.path, args.branch, token)
- if err is not None:
- status, body = err
- print(json.dumps({"uploaded": False, "status": status, "body": body}))
- return 1
-
- # Upload (PUT if sha, POST otherwise).
- new_sha, err = upload(args.host, args.owner, args.repo, args.path,
- args.branch, args.message, content_b64, sha, token)
- if err is not None:
- status, body = err
- print(json.dumps({"uploaded": False, "status": status, "body": body}))
- return 1
-
- print(json.dumps({"uploaded": True, "path": args.path,
- "sha": new_sha}))
- return 0
-
-
-if __name__ == "__main__":
- sys.exit(main())
\ No newline at end of file
diff --git a/demo/scripts/gitea_setup.sh b/demo/scripts/gitea_setup.sh
deleted file mode 100755
index adcff18..0000000
--- a/demo/scripts/gitea_setup.sh
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/env bash
-# Phase 01 Gitea scaffolding. Idempotent.
-#
-# Creates the two new repos under the continuous-intelligence org, pushes a
-# placeholder index.html to acdl-evidence, and creates qa + prod branches on
-# acdl-contracts. Running against existing repos / branches / files is a
-# no-op (409 or 422 is treated as success).
-#
-# Usage: ACDL_GITEA_TOKEN= scripts/gitea_setup.sh
-# Exit codes: 0 = success (created or already existed); 1 = unrecoverable error.
-
-set -euo pipefail
-
-GITEA_HOST="${GITEA_HOST:-https://git.cloudinit.dev}"
-ORG="continuous-intelligence"
-TOKEN="${ACDL_GITEA_TOKEN:?ACDL_GITEA_TOKEN is required}"
-API="${GITEA_HOST}/api/v1"
-
-AUTH=(-H "Authorization: token ${TOKEN}" -H "Content-Type: application/json")
-
-log() { printf '[setup] %s\n' "$*"; }
-warn() { printf '[setup][WARN] %s\n' "$*" >&2; }
-err() { printf '[setup][ERROR] %s\n' "$*" >&2; }
-
-# --- helpers ----------------------------------------------------------------
-
-# http_status_code URL
-http_get_status() {
- local url="$1"
- curl -sS -o /dev/null -w "%{http_code}" "${AUTH[@]}" "$url"
-}
-
-# repo_exists NAME -> 0 if exists, 1 otherwise
-repo_exists() {
- local name="$1"
- local status
- status=$(http_get_status "${API}/repos/${ORG}/${name}")
- [ "$status" = "200" ]
-}
-
-# create_repo NAME DESCRIPTION
-create_repo() {
- local name="$1"
- local description="$2"
- local body
- body=$(python3 -c "
-import json, sys
-print(json.dumps({
- 'name': '${name}',
- 'description': ${description@Q},
- 'private': True,
- 'default_branch': 'main',
- 'auto_init': True,
- 'gitignores': 'Python',
- 'license': '',
- 'readme': 'Default'
-}))
-")
- log "Creating repo ${ORG}/${name} (default_branch=main, auto_init=true)"
- local status body_out
- status=$(curl -sS -o /tmp/setup_repo_create.json -w "%{http_code}" \
- "${AUTH[@]}" -X POST -d "$body" \
- "${API}/orgs/${ORG}/repos")
- case "$status" in
- 201) log " created (HTTP 201)" ;;
- 409) log " already exists (HTTP 409); skipping" ;;
- *)
- err "create_repo ${name} failed: HTTP ${status}"
- cat /tmp/setup_repo_create.json >&2 || true
- return 1
- ;;
- esac
-}
-
-# set_repo_visibility REPO VISIBILITY (public|private)
-set_repo_visibility() {
- local repo="$1"
- local visibility="$2"
- local body
- body=$(python3 -c "
-import json
-is_private = ('${visibility}' == 'private')
-print(json.dumps({'private': is_private, 'visibility': '${visibility}'}))
-")
- log "Setting ${repo} visibility to ${visibility}"
- local status
- status=$(curl -sS -o /tmp/setup_vis.json -w "%{http_code}" \
- "${AUTH[@]}" -X PATCH -d "$body" \
- "${API}/repos/${ORG}/${repo}")
- case "$status" in
- 200) log " ok (HTTP 200)" ;;
- *) warn "set_repo_visibility ${repo} -> ${visibility} returned HTTP ${status} (continuing)"; cat /tmp/setup_vis.json >&2 || true ;;
- esac
-}
-
-# file_exists REPO PATH -> 0 if the file already exists on the default branch
-file_exists_on_default() {
- local repo="$1"
- local path="$2"
- local status
- status=$(http_get_status "${API}/repos/${ORG}/${repo}/contents/${path}?ref=main")
- [ "$status" = "200" ]
-}
-
-# create_placeholder_index REPO
-create_placeholder_index() {
- local repo="$1"
- local path="index.html"
- local placeholder
- placeholder='
-
-
-
- ACDL Evidence
-
-
-
- ACDL Evidence Stream
- Evidence timeline will appear here in Phase 05.
- Placeholder served via Gitea raw file URL (D-012; Gitea has no native Pages).
-
-'
-
- if file_exists_on_default "$repo" "$path"; then
- log "index.html already exists on ${repo} main; skipping"
- return 0
- fi
-
- local body
- body=$(python3 -c "
-import json, base64
-content = '''${placeholder}'''
-print(json.dumps({
- 'content': base64.b64encode(content.encode('utf-8')).decode('ascii'),
- 'message': 'Initial placeholder index.html (Phase 01, D-016)',
- 'branch': 'main'
-}))
-")
- log "Pushing placeholder index.html to ${repo} main"
- local status
- status=$(curl -sS -o /tmp/setup_index_push.json -w "%{http_code}" \
- "${AUTH[@]}" -X POST -d "$body" \
- "${API}/repos/${ORG}/${repo}/contents/${path}")
- case "$status" in
- 201) log " pushed (HTTP 201)" ;;
- 409|422) log " already exists or conflict (HTTP ${status}); skipping" ;;
- *)
- err "create_placeholder_index on ${repo} failed: HTTP ${status}"
- cat /tmp/setup_index_push.json >&2 || true
- return 1
- ;;
- esac
-}
-
-# branch_exists REPO BRANCH -> 0 if exists
-branch_exists() {
- local repo="$1"
- local branch="$2"
- local status
- status=$(http_get_status "${API}/repos/${ORG}/${repo}/branches/${branch}")
- [ "$status" = "200" ]
-}
-
-# create_branch REPO BRANCH FROM_REF
-create_branch() {
- local repo="$1"
- local branch="$2"
- local from_ref="$3"
- if branch_exists "$repo" "$branch"; then
- log "Branch ${branch} already exists on ${repo}; skipping"
- return 0
- fi
- local body
- body=$(python3 -c "
-import json
-print(json.dumps({'new_branch_name': '${branch}', 'old_branch_name': '${from_ref}'}))
-")
- log "Creating branch ${branch} on ${repo} from ${from_ref}"
- local status
- status=$(curl -sS -o /tmp/setup_branch.json -w "%{http_code}" \
- "${AUTH[@]}" -X POST -d "$body" \
- "${API}/repos/${ORG}/${repo}/branches")
- case "$status" in
- 201) log " created (HTTP 201)" ;;
- 409) log " already exists (HTTP 409); skipping" ;;
- *)
- err "create_branch ${branch} on ${repo} failed: HTTP ${status}"
- cat /tmp/setup_branch.json >&2 || true
- return 1
- ;;
- esac
-}
-
-# --- main -------------------------------------------------------------------
-
-log "Host: ${GITEA_HOST}"
-log "Org: ${ORG}"
-log "Token: "
-
-# Step 1: create acdl-contracts
-if ! repo_exists acdl-contracts; then
- create_repo acdl-contracts "ACDL developer + agentic entry surface (contract.yaml + issue trigger)" || exit 1
-else
- log "acdl-contracts already exists; skipping create"
-fi
-
-# Step 2: create acdl-evidence
-if ! repo_exists acdl-evidence; then
- create_repo acdl-evidence "ACDL hash-chained audit timeline served as a static site via raw file URLs" || exit 1
-else
- log "acdl-evidence already exists; skipping create"
-fi
-
-# Step 2b: make acdl-evidence public so the Phase 05 UI (index.html) can
-# fetch audit.json from a browser without exposing the API token (D-012
-# raw-URL approach). acdl-contracts stays private.
-set_repo_visibility acdl-evidence public
-
-# Step 3: push placeholder index.html to acdl-evidence
-create_placeholder_index acdl-evidence || exit 1
-
-# Step 4: create qa + prod branches on acdl-contracts (visible stand-in for
-# the unsupported Gitea environments API; per D-013).
-create_branch acdl-contracts qa main || exit 1
-create_branch acdl-contracts prod main || exit 1
-
-log "Done. Run scripts/verify_phase01.sh to confirm success criteria."
-exit 0
\ No newline at end of file
diff --git a/demo/scripts/l3b_agent_stub.py b/demo/scripts/l3b_agent_stub.py
deleted file mode 100755
index bf1c93f..0000000
--- a/demo/scripts/l3b_agent_stub.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python3
-"""l3b_agent_stub.py — D-008 / D-026 / D-021
-
-Parses a GitHub/Gitea Issue body by keywords and emits a contract.yaml that
-selects an L2 stack. This is the agentic (L3B) entry surface: deterministic
-keyword matching, no external AI APIs.
-
-D-008 keyword map (priority order — first match wins):
- gas, price, ingest, data-lake -> l2-commodity-price-feed
- invoice, billing -> l2-invoice-service
- analytics, historical, query -> l2-energy-analytics-api
- regulatory, compliance, reporting, trading
- -> l2-regulatory-reporting
- (no match) -> l2-invoice-service (fallback)
-
-Output contract.yaml (D-021 schema):
- stack:
- inputs:
- environment: dev
- owner: citizen-developer
- source: l3b-agent-stub
- public-ingress: false
-
-Input:
- argv[1] = issue body text (or stdin if argv[1] absent/empty)
- -o = write the contract to a file (default: stdout)
-Exit:
- 0 on success, 1 on empty input
-"""
-import sys
-
-
-# Ordered keyword groups -> L2 stack mapping (D-008). First match wins.
-KEYWORD_MAP = [
- (("gas", "price", "ingest", "data-lake"), "l2-commodity-price-feed"),
- (("invoice", "billing"), "l2-invoice-service"),
- (("analytics", "historical", "query"), "l2-energy-analytics-api"),
- (("regulatory", "compliance", "reporting", "trading"), "l2-regulatory-reporting"),
-]
-
-FALLBACK_STACK = "l2-invoice-service"
-
-
-def map_issue_to_stack(text: str) -> str:
- lowered = text.lower()
- for keywords, stack in KEYWORD_MAP:
- for kw in keywords:
- if kw in lowered:
- return stack
- return FALLBACK_STACK
-
-
-def render_contract(stack: str) -> str:
- # Fixed-schema YAML (D-021). Emitted as text (no yaml dependency needed).
- return (
- f"stack: {stack}\n"
- "inputs:\n"
- " environment: dev\n"
- " owner: citizen-developer\n"
- " source: l3b-agent-stub\n"
- "public-ingress: false\n"
- )
-
-
-def read_issue_body(args: list) -> str:
- """Read issue body from args[0] (already-stripped argv, no script name)
- or stdin. Empty -> error."""
- if len(args) >= 1 and args[0].strip():
- return args[0]
- # Fall back to stdin if argv body is absent or empty.
- if not sys.stdin.isatty():
- data = sys.stdin.read()
- if data.strip():
- return data
- return ""
-
-
-def parse_output_flag(argv: list):
- """Extract -o from argv (returns (rest, output_path))."""
- output_path = None
- rest = []
- i = 1
- while i < len(argv):
- arg = argv[i]
- if arg == "-o":
- if i + 1 < len(argv):
- output_path = argv[i + 1]
- i += 2
- continue
- else:
- print("l3b_agent_stub: -o requires a path argument", file=sys.stderr)
- sys.exit(1)
- rest.append(arg)
- i += 1
- return rest, output_path
-
-
-def main() -> int:
- rest, output_path = parse_output_flag(sys.argv)
- body = read_issue_body(rest)
- if not body.strip():
- print("l3b_agent_stub: empty issue body (no argv[1] and no stdin)", file=sys.stderr)
- return 1
-
- stack = map_issue_to_stack(body)
- contract = render_contract(stack)
-
- if output_path:
- with open(output_path, "w", encoding="utf-8") as fh:
- fh.write(contract)
- else:
- sys.stdout.write(contract)
-
- return 0
-
-
-if __name__ == "__main__":
- sys.exit(main())
\ No newline at end of file
diff --git a/demo/scripts/mock_executor.sh b/demo/scripts/mock_executor.sh
deleted file mode 100755
index df02770..0000000
--- a/demo/scripts/mock_executor.sh
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env bash
-# mock_executor.sh — REQ-06 / D-022
-#
-# Reads a contract.yaml, resolves the L2 composition, invokes each L1's
-# mock_apply.sh in order, and writes state.json to the current working
-# directory.
-#
-# Input: argv[1] = path to a contract.yaml file.
-# Output:
-# - stdout: per-L1 progress (echoed from each mock_apply.sh)
-# - state.json in cwd: {"l2": "...", "l1s": [...], "contract": {...}}
-# Exit:
-# 0 if all L1s exit 0; 1 if any L1 exited non-zero (state.json is still
-# written with the recorded exit codes).
-set -euo pipefail
-
-if [[ $# -lt 1 ]]; then
- echo "usage: mock_executor.sh " >&2
- exit 1
-fi
-
-CONTRACT_PATH="$1"
-
-if [[ ! -f "$CONTRACT_PATH" ]]; then
- echo "contract not found: $CONTRACT_PATH" >&2
- exit 1
-fi
-
-# --- Parse the contract (stack + full contract dict) via python3 + yaml. ---
-# Emit stack on line 1 and the full contract JSON on line 2, then read both
-# lines into separate bash variables (so the JSON's internal spaces survive).
-CONTRACT_PARSED=$(python3 - "$CONTRACT_PATH" <<'PY'
-import sys, json, yaml
-path = sys.argv[1]
-with open(path, "r", encoding="utf-8") as fh:
- contract = yaml.safe_load(fh)
-if not isinstance(contract, dict):
- sys.stderr.write("contract is not a mapping\n")
- sys.exit(2)
-stack = contract.get("stack", "")
-# Use a compact JSON (no spaces) so the single-line contract survives bash
-# variable capture cleanly.
-print(stack)
-print(json.dumps(contract, sort_keys=True, separators=(",", ":")))
-PY
-)
-
-STACK=$(printf '%s\n' "$CONTRACT_PARSED" | sed -n '1p')
-CONTRACT_JSON=$(printf '%s\n' "$CONTRACT_PARSED" | sed -n '2p')
-
-if [[ -z "$STACK" ]]; then
- echo "contract missing 'stack' key" >&2
- exit 1
-fi
-
-# --- Resolve the L2 manifest. ---
-L2_MANIFEST="modules/l2/${STACK}/manifest.yaml"
-if [[ ! -f "$L2_MANIFEST" ]]; then
- echo "L2_NOT_FOUND: ${STACK}" >&2
- exit 1
-fi
-
-# --- Read the L2's l1s: list (ordered names) via python. ---
-L1_NAMES_JSON=$(python3 - "$L2_MANIFEST" <<'PY'
-import sys, json, yaml
-path = sys.argv[1]
-with open(path, "r", encoding="utf-8") as fh:
- manifest = yaml.safe_load(fh)
-l1s = manifest.get("l1s", []) if isinstance(manifest, dict) else []
-names = [entry.get("name", "") for entry in l1s if isinstance(entry, dict)]
-print(json.dumps(names))
-PY
-)
-
-# --- Invoke each L1's mock_apply.sh in order, recording exit codes. ---
-# Build the l1s results array in JSON via python, appending as we go.
-RESULTS_JSON="[]"
-
-ALL_OK=0
-while IFS= read -r L1_NAME; do
- L1_SCRIPT="modules/l1/${L1_NAME}/mock_apply.sh"
- if [[ ! -f "$L1_SCRIPT" ]]; then
- echo "L1_NOT_FOUND: ${L1_NAME}" >&2
- exit 1
- fi
-
- # Capture stdout + exit code. stderr passes through.
- L1_OUT=$(bash "$L1_SCRIPT")
- L1_RC=$?
-
- # Echo the L1's stdout so the pipeline sees the progress lines.
- printf '%s\n' "$L1_OUT"
-
- # Record {"name": ..., "applied": true, "exit_code": ...}.
- RESULTS_JSON=$(python3 - "$RESULTS_JSON" "$L1_NAME" "$L1_RC" <<'PY'
-import sys, json
-results = json.loads(sys.argv[1])
-name = sys.argv[2]
-rc = int(sys.argv[3])
-results.append({"name": name, "applied": True, "exit_code": rc})
-print(json.dumps(results))
-PY
-)
-
- if [[ $L1_RC -ne 0 ]]; then
- ALL_OK=1
- fi
-done < <(python3 -c "import sys, json; print('\n'.join(json.loads(sys.argv[1])))" "$L1_NAMES_JSON")
-
-# --- Write state.json to the current working directory (D-022). ---
-python3 - "$RESULTS_JSON" "$STACK" "$CONTRACT_JSON" <<'PY'
-import sys, json
-results = json.loads(sys.argv[1])
-stack = sys.argv[2]
-contract = json.loads(sys.argv[3])
-state = {
- "l2": stack,
- "l1s": results,
- "contract": contract,
-}
-with open("state.json", "w", encoding="utf-8") as fh:
- json.dump(state, fh, indent=2)
- fh.write("\n")
-PY
-
-exit "$ALL_OK"
\ No newline at end of file
diff --git a/demo/scripts/policy_checker.py b/demo/scripts/policy_checker.py
deleted file mode 100755
index 59fe163..0000000
--- a/demo/scripts/policy_checker.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python3
-"""policy_checker.py — REQ-07 / D-025
-
-Reads a contract.yaml and enforces the single Phase-03 policy rule:
-`public-ingress: true` is forbidden.
-
-Input: argv[1] = path to a contract.yaml file.
-Output: stdout "POLICY_PASS" or "POLICY_VIOLATION:PUBLIC_INGRESS"
-Exit: 0 on pass, 1 on violation.
-
-Idempotent, no side effects (no file writes). Treats an absent or falsy
-`public-ingress` key as a pass.
-"""
-import sys
-import yaml
-
-
-def main() -> int:
- if len(sys.argv) < 2:
- print("usage: policy_checker.py ", file=sys.stderr)
- return 2
-
- contract_path = sys.argv[1]
-
- try:
- with open(contract_path, "r", encoding="utf-8") as fh:
- contract = yaml.safe_load(fh)
- except FileNotFoundError:
- print(f"contract not found: {contract_path}", file=sys.stderr)
- return 2
- except yaml.YAMLError as exc:
- print(f"invalid yaml: {exc}", file=sys.stderr)
- return 2
-
- # Treat missing/non-mapping as no policy violation.
- if not isinstance(contract, dict):
- print("POLICY_PASS")
- return 0
-
- public_ingress = contract.get("public-ingress", False)
-
- if public_ingress is True:
- print("POLICY_VIOLATION:PUBLIC_INGRESS")
- return 1
-
- print("POLICY_PASS")
- return 0
-
-
-if __name__ == "__main__":
- sys.exit(main())
\ No newline at end of file
diff --git a/demo/scripts/run_demo.sh b/demo/scripts/run_demo.sh
deleted file mode 100755
index 4c19739..0000000
--- a/demo/scripts/run_demo.sh
+++ /dev/null
@@ -1,258 +0,0 @@
-#!/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:
-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:
-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//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
\ No newline at end of file
diff --git a/demo/scripts/verify_phase01.sh b/demo/scripts/verify_phase01.sh
deleted file mode 100755
index 425b464..0000000
--- a/demo/scripts/verify_phase01.sh
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env bash
-# Phase 01 verification script.
-# Confirms the three-repo scaffold exists under the continuous-intelligence
-# Gitea org and that the Phase 01 visible artifacts (placeholder index.html on
-# acdl-evidence; qa + prod branches on acdl-contracts) are present.
-#
-# Usage: ACDL_GITEA_TOKEN= scripts/verify_phase01.sh
-# Exit codes: 0 = all checks passed; 1 = one or more checks failed.
-
-set -euo pipefail
-
-GITEA_HOST="${GITEA_HOST:-https://git.cloudinit.dev}"
-ORG="continuous-intelligence"
-TOKEN="${ACDL_GITEA_TOKEN:-}"
-
-fail_count=0
-note() { printf ' [%s] %s\n' "$1" "$2"; }
-pass() { note "PASS" "$1"; }
-fail() { note "FAIL" "$1"; fail_count=$((fail_count + 1)); }
-warn() { printf ' [WARN] %s\n' "$1" >&2; }
-
-echo "== Phase 01 verification =="
-echo "Host: $GITEA_HOST"
-echo "Org: $ORG"
-if [ -n "$TOKEN" ]; then
- echo "Token: "
-else
- echo "Token: "
-fi
-echo
-
-# --- Check 1: acdl-contracts repo exists ---
-echo "-- Check 1: acdl-contracts repo exists --"
-status=$(curl -sS -o /tmp/p01_contracts.json -w "%{http_code}" \
- -H "Authorization: token ${TOKEN}" \
- "${GITEA_HOST}/api/v1/repos/${ORG}/acdl-contracts")
-if [ "$status" = "200" ]; then
- default_branch=$(python3 -c "import json; print(json.load(open('/tmp/p01_contracts.json')).get('default_branch','?'))")
- pass "acdl-contracts exists (default_branch=${default_branch})"
-else
- fail "acdl-contracts GET returned HTTP ${status}"
-fi
-
-# --- Check 2: acdl-evidence repo exists ---
-echo "-- Check 2: acdl-evidence repo exists --"
-status=$(curl -sS -o /tmp/p01_evidence.json -w "%{http_code}" \
- -H "Authorization: token ${TOKEN}" \
- "${GITEA_HOST}/api/v1/repos/${ORG}/acdl-evidence")
-if [ "$status" = "200" ]; then
- default_branch=$(python3 -c "import json; print(json.load(open('/tmp/p01_evidence.json')).get('default_branch','?'))")
- pass "acdl-evidence exists (default_branch=${default_branch})"
-else
- fail "acdl-evidence GET returned HTTP ${status}"
-fi
-
-# --- Check 3: acdl-evidence raw index.html returns 200 (Pages substitute per D-012/D-016) ---
-# acdl-evidence is public per gitea_setup.sh step 2b, so the raw URL should
-# work without auth. We also try with the auth header as a fallback so the
-# check does not spuriously fail if the repo visibility was reset.
-echo "-- Check 3: acdl-evidence raw index.html returns 200 --"
-index_url="${GITEA_HOST}/${ORG}/acdl-evidence/raw/branch/main/index.html"
-status=$(curl -sS -o /tmp/p01_index.html -w "%{http_code}" "${index_url}")
-if [ "$status" != "200" ] && [ -n "$TOKEN" ]; then
- warn "raw URL returned ${status} unauth; retrying with Authorization header"
- status=$(curl -sS -o /tmp/p01_index.html -w "%{http_code}" \
- -H "Authorization: token ${TOKEN}" "${index_url}")
-fi
-if [ "$status" = "200" ]; then
- body_size=$(wc -c < /tmp/p01_index.html)
- if grep -q "ACDL Evidence" /tmp/p01_index.html; then
- pass "raw index.html returns 200 with placeholder body (${body_size} bytes)"
- else
- fail "raw index.html returns 200 but body does not contain 'ACDL Evidence' marker"
- fi
-else
- fail "GET ${index_url} returned HTTP ${status}"
-fi
-
-# --- Check 4: qa + prod branches exist on acdl-contracts ---
-echo "-- Check 4: qa + prod branches exist on acdl-contracts --"
-status=$(curl -sS -o /tmp/p01_branches.json -w "%{http_code}" \
- -H "Authorization: token ${TOKEN}" \
- "${GITEA_HOST}/api/v1/repos/${ORG}/acdl-contracts/branches?limit=50")
-if [ "$status" != "200" ]; then
- fail "list branches on acdl-contracts returned HTTP ${status}"
-else
- for want in qa prod; do
- if python3 -c "
-import json, sys
-branches = json.load(open('/tmp/p01_branches.json'))
-names = [b.get('name', '') for b in branches]
-sys.exit(0 if '${want}' in names else 1)
-"; then
- pass "branch '${want}' exists on acdl-contracts"
- else
- fail "branch '${want}' missing on acdl-contracts"
- fi
- done
-fi
-
-echo
-echo "== Summary =="
-if [ "$fail_count" -eq 0 ]; then
- echo "Phase 01 verification PASSED (all checks ok)"
- exit 0
-else
- echo "Phase 01 verification FAILED (${fail_count} check(s) failed)"
- exit 1
-fi
\ No newline at end of file
diff --git a/demo/scripts/verify_phase02.sh b/demo/scripts/verify_phase02.sh
deleted file mode 100755
index ef4b6ac..0000000
--- a/demo/scripts/verify_phase02.sh
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env bash
-# Phase 02 verification script.
-# Confirms the 8 L1 module folders exist under modules/l1/ with the exact
-# names from REQ-02, each containing a valid manifest.yaml (D-017 schema)
-# and a uniform mock_apply.sh (D-007 + D-018) that exits 0 with the
-# expected echo markers.
-#
-# Usage: scripts/verify_phase02.sh
-# Exit codes: 0 = all checks passed; 1 = one or more checks failed.
-
-set -euo pipefail
-
-ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-L1_DIR="${ROOT}/modules/l1"
-
-# Expected L1 names per REQ-02 / D-019.
-EXPECTED_L1S=(
- l1-eks-fargate
- l1-iam-role
- l1-lambda
- l1-api-gateway
- l1-eventbridge
- l1-sqs
- l1-s3
- l1-cloudwatch
-)
-
-fail_count=0
-pass() { printf ' [PASS] %s\n' "$1"; }
-fail() { printf ' [FAIL] %s\n' "$1"; fail_count=$((fail_count + 1)); }
-
-echo "== Phase 02 verification =="
-echo "L1 dir: ${L1_DIR}"
-echo
-
-# --- Check 1: exactly 8 L1 folders with the expected names ---
-echo "-- Check 1: 8 L1 folders with expected names --"
-if [ ! -d "$L1_DIR" ]; then
- fail "modules/l1/ does not exist"
- echo
- echo "== Summary =="
- echo "Phase 02 verification FAILED (${fail_count} check(s) failed)"
- exit 1
-fi
-
-actual_folders=$(ls "$L1_DIR" | sort | tr '\n' ' ')
-expected_folders=$(printf '%s\n' "${EXPECTED_L1S[@]}" | sort | tr '\n' ' ')
-if [ "$actual_folders" = "$expected_folders" ]; then
- pass "exactly 8 L1 folders present and named correctly"
-else
- fail "L1 folder list mismatch"
- echo " expected: $expected_folders"
- echo " actual: $actual_folders"
-fi
-
-# --- Per-L1 checks ---
-for l1 in "${EXPECTED_L1S[@]}"; do
- echo "-- L1: ${l1} --"
- dir="${L1_DIR}/${l1}"
-
- # Check 2a: folder exists
- if [ ! -d "$dir" ]; then
- fail "${l1}: folder missing"
- continue
- fi
- pass "${l1}: folder exists"
-
- # Check 2b: manifest.yaml exists + parses + name matches folder + kind=l1
- manifest="${dir}/manifest.yaml"
- if [ ! -f "$manifest" ]; then
- fail "${l1}: manifest.yaml missing"
- else
- manifest_ok=$(python3 -c "
-import yaml, sys
-try:
- d = yaml.safe_load(open('${manifest}'))
- name = d.get('name') == '${l1}'
- kind = d.get('kind') == 'l1'
- has_inputs = isinstance(d.get('inputs'), dict)
- sys.exit(0 if (name and kind and has_inputs) else 1)
-except Exception as e:
- print(f' parse error: {e}', file=sys.stderr)
- sys.exit(2)
-" 2>/dev/null; echo $?)
- if [ "$manifest_ok" = "0" ]; then
- pass "${l1}: manifest.yaml valid (name=${l1}, kind=l1, inputs present)"
- else
- fail "${l1}: manifest.yaml invalid (name/kind/inputs check failed; rc=${manifest_ok})"
- fi
- fi
-
- # Check 2c: mock_apply.sh exists + executable + bash -n clean
- apply="${dir}/mock_apply.sh"
- if [ ! -f "$apply" ]; then
- fail "${l1}: mock_apply.sh missing"
- continue
- fi
- if [ ! -x "$apply" ]; then
- fail "${l1}: mock_apply.sh not executable"
- else
- pass "${l1}: mock_apply.sh is executable"
- fi
- if ! bash -n "$apply" 2>/dev/null; then
- fail "${l1}: mock_apply.sh bash -n failed"
- else
- pass "${l1}: mock_apply.sh bash -n clean"
- fi
-
- # Check 2d: end-to-end run: exit 0 + expected markers, completes in <2s
- start=$(date +%s)
- output=$("$apply" 2>&1)
- rc=$?
- elapsed=$(( $(date +%s) - start ))
- if [ "$rc" -ne 0 ]; then
- fail "${l1}: mock_apply.sh exited ${rc}"
- elif ! echo "$output" | grep -qF "[L1: ${l1}] applying..."; then
- fail "${l1}: missing '[L1: ${l1}] applying...' marker"
- elif ! echo "$output" | grep -qF "[L1: ${l1}] OK"; then
- fail "${l1}: missing '[L1: ${l1}] OK' marker"
- elif [ "$elapsed" -lt 1 ] || [ "$elapsed" -gt 2 ]; then
- fail "${l1}: run took ${elapsed}s (expected ~1s; 1<=t<=2 ok)"
- else
- pass "${l1}: mock_apply.sh runs, exits 0, markers correct (${elapsed}s)"
- fi
-done
-
-echo
-echo "== Summary =="
-if [ "$fail_count" -eq 0 ]; then
- echo "Phase 02 verification PASSED (8 L1 modules, all checks ok)"
- exit 0
-else
- echo "Phase 02 verification FAILED (${fail_count} check(s) failed)"
- exit 1
-fi
\ No newline at end of file
diff --git a/demo/scripts/verify_phase03.sh b/demo/scripts/verify_phase03.sh
deleted file mode 100755
index 83cccf0..0000000
--- a/demo/scripts/verify_phase03.sh
+++ /dev/null
@@ -1,240 +0,0 @@
-#!/usr/bin/env bash
-# Phase 03 verification script.
-# Confirms the 4 L2 modules and the 5 core scripts conform to their contracts.
-#
-# Usage: scripts/verify_phase03.sh
-# Exit codes: 0 = all checks passed; 1 = one or more checks failed.
-
-set -uo pipefail
-
-ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-cd "$ROOT"
-
-fail_count=0
-pass() { printf ' [PASS] %s\n' "$1"; }
-fail() { printf ' [FAIL] %s\n' "$1"; fail_count=$((fail_count + 1)); }
-
-# Expected L2 names per REQ-04.
-EXPECTED_L2S=(
- l2-invoice-service
- l2-commodity-price-feed
- l2-energy-analytics-api
- l2-regulatory-reporting
-)
-
-echo "== Phase 03 verification =="
-echo "Root: ${ROOT}"
-echo
-
-# --- Check 1: exactly 4 L2 folders with the expected names ---
-echo "-- Check 1: 4 L2 folders with expected names --"
-actual=$(ls modules/l2/ 2>/dev/null | sort | tr '\n' ' ')
-expected=$(printf '%s\n' "${EXPECTED_L2S[@]}" | sort | tr '\n' ' ')
-if [ "$actual" = "$expected" ]; then
- pass "exactly 4 L2 folders present and named correctly"
-else
- fail "L2 folder list mismatch"
- echo " expected: $expected"
- echo " actual: $actual"
-fi
-
-# --- Check 2: each L2 manifest.yaml validates + references 5 existing L1s ---
-echo "-- Check 2: L2 manifests reference 5 existing L1s --"
-l2_validate=$(python3 << 'PYEOF' || true
-import yaml, glob, os, sys
-ok = True
-l1s = set(os.listdir('modules/l1'))
-for f in sorted(glob.glob('modules/l2/*/manifest.yaml')):
- d = yaml.safe_load(open(f))
- folder = os.path.basename(os.path.dirname(f))
- problems = []
- if d.get('name') != folder: problems.append(f"name != {folder}")
- if d.get('kind') != 'l2': problems.append("kind != l2")
- refs = [x.get('name') for x in d.get('l1s', [])]
- if len(refs) != 5: problems.append(f"expected 5 l1s, got {len(refs)}")
- unknown = [r for r in refs if r not in l1s]
- if unknown: problems.append(f"unknown L1 refs: {unknown}")
- # each l1 entry must have an inputs: map
- for x in d.get('l1s', []):
- if not isinstance(x.get('inputs'), dict): problems.append(f"l1 {x.get('name')} missing inputs map")
- status = 'OK' if not problems else 'FAIL: ' + '; '.join(problems)
- print(f' [{status}] {f}')
- if problems: ok = False
-sys.exit(0 if ok else 1)
-PYEOF
-)
-echo "$l2_validate"
-if [ "$l2_validate" = "" ] || echo "$l2_validate" | grep -q FAIL; then
- if ! echo "$l2_validate" | grep -q PASS; then
- fail "one or more L2 manifests invalid (see above)"
- fi
-else
- pass "all 4 L2 manifests valid"
-fi
-# Re-run for the explicit pass/fail count
-python3 << 'PYEOF' > /tmp/l2_check.txt 2>&1 || true
-import yaml, glob, os, sys
-ok = True
-l1s = set(os.listdir('modules/l1'))
-for f in sorted(glob.glob('modules/l2/*/manifest.yaml')):
- d = yaml.safe_load(open(f))
- folder = os.path.basename(os.path.dirname(f))
- if d.get('name') != folder: ok = False
- if d.get('kind') != 'l2': ok = False
- refs = [x.get('name') for x in d.get('l1s', [])]
- if len(refs) != 5: ok = False
- if any(r not in l1s for r in refs): ok = False
- for x in d.get('l1s', []):
- if not isinstance(x.get('inputs'), dict): ok = False
-sys.exit(0 if ok else 1)
-PYEOF
-if [ $? -eq 0 ]; then pass "all 4 L2 manifests pass structural + reference checks"; else fail "L2 manifest structural check"; fi
-
-# --- Check 3: typecheck (bash -n + py_compile + yaml load) ---
-echo "-- Check 3: typecheck --"
-if bash -n scripts/mock_executor.sh; then pass "bash -n mock_executor.sh"; else fail "bash -n mock_executor.sh"; fi
-if python3 -m py_compile scripts/policy_checker.py scripts/confidence_signal.py scripts/evidence_writer.py scripts/l3b_agent_stub.py 2>/dev/null; then
- pass "py_compile all 4 python scripts"
-else
- fail "py_compile"
-fi
-if python3 -c "import yaml, glob; [yaml.safe_load(open(f)) for f in glob.glob('modules/l2/*/manifest.yaml')]" 2>/dev/null; then
- pass "yaml load all L2 manifests"
-else
- fail "yaml load L2 manifests"
-fi
-
-# --- Check 4: policy_checker (D-025) ---
-echo "-- Check 4: policy_checker behavior (D-025) --"
-WORK="$(mktemp -d)"
-trap 'rm -rf "$WORK" "$ROOT/tmp_pass_contract.yaml" "$ROOT/tmp_fail_contract.yaml" "$ROOT/state.json" 2>/dev/null || true' EXIT
-printf 'stack: l2-commodity-price-feed\npublic-ingress: false\n' > "$WORK/pass.yaml"
-printf 'stack: l2-regulatory-reporting\npublic-ingress: true\n' > "$WORK/fail.yaml"
-out=$(python3 scripts/policy_checker.py "$WORK/pass.yaml" 2>&1); rc=$?
-if [ "$out" = "POLICY_PASS" ] && [ "$rc" = "0" ]; then
- pass "policy_checker pass contract -> POLICY_PASS exit 0"
-else
- fail "policy_checker pass contract: got '$out' exit=$rc"
-fi
-out=$(python3 scripts/policy_checker.py "$WORK/fail.yaml" 2>&1); rc=$?
-if [ "$out" = "POLICY_VIOLATION:PUBLIC_INGRESS" ] && [ "$rc" = "1" ]; then
- pass "policy_checker fail contract -> POLICY_VIOLATION:PUBLIC_INGRESS exit 1"
-else
- fail "policy_checker fail contract: got '$out' exit=$rc"
-fi
-
-# --- Check 5: confidence_signal (D-024) ---
-echo "-- Check 5: confidence_signal behavior (D-024) --"
-out=$(python3 scripts/confidence_signal.py "$WORK/pass.yaml" 2>&1); rc=$?
-if echo "$out" | grep -q '"score": 0.90' && [ "$rc" = "0" ]; then
- pass "confidence_signal pass -> score 0.90 exit 0"
-else
- fail "confidence_signal pass: got '$out' exit=$rc"
-fi
-out=$(python3 scripts/confidence_signal.py "$WORK/fail.yaml" 2>&1); rc=$?
-if echo "$out" | grep -q '"score": 0.40' && [ "$rc" = "0" ]; then
- pass "confidence_signal fail -> score 0.40 exit 0"
-else
- fail "confidence_signal fail: got '$out' exit=$rc"
-fi
-
-# --- Check 6: evidence_writer hash chain (D-023) ---
-echo "-- Check 6: evidence_writer hash chain (D-023) --"
-rm -f "$WORK/audit.json"
-python3 scripts/evidence_writer.py --stage dev --event "dev start" --audit "$WORK/audit.json" > /dev/null
-python3 scripts/evidence_writer.py --stage qa --event "qa approved" --audit "$WORK/audit.json" > /dev/null
-python3 scripts/evidence_writer.py --stage prod --event "prod approved" --audit "$WORK/audit.json" > /dev/null
-chain_ok=$(python3 << PYEOF
-import json, hashlib, sys
-try:
- events = json.load(open("$WORK/audit.json"))
- assert len(events) == 4, f"expected 4 (genesis + 3), got {len(events)}"
- assert events[0]['prev_hash'] == 'GENESIS', "genesis prev_hash"
- for i in range(1, len(events)):
- assert events[i]['prev_hash'] == events[i-1]['hash'], f"chain break at {i}"
- e = dict(events[i]); h = e.pop('hash'); e['hash'] = ''
- canon = json.dumps(e, sort_keys=True, separators=(',',':'))
- assert hashlib.sha256(canon.encode()).hexdigest() == h, f"hash mismatch at {i}"
- print("OK")
-except AssertionError as ex:
- print(f"FAIL: {ex}")
- sys.exit(1)
-PYEOF
-)
-if [ "$chain_ok" = "OK" ]; then
- pass "evidence_writer: 4 events, GENESIS + 3, chain links + hashes valid"
-else
- fail "evidence_writer chain: $chain_ok"
-fi
-
-# --- Check 7: mock_executor (D-022) ---
-echo "-- Check 7: mock_executor writes state.json (D-022) --"
-rm -f "$ROOT/state.json"
-out=$(bash scripts/mock_executor.sh "$WORK/pass.yaml" 2>&1); rc=$?
-if [ "$rc" != "0" ]; then
- fail "mock_executor exit $rc (expected 0)"
-else
- me_ok=$(python3 << PYEOF
-import json, sys
-try:
- s = json.load(open("$ROOT/state.json"))
- assert s['l2'] == 'l2-commodity-price-feed', f"l2 mismatch: {s.get('l2')}"
- assert 'l1s' in s and len(s['l1s']) == 5, f"expected 5 l1s, got {len(s.get('l1s', []))}"
- assert all(x['applied'] is True and x['exit_code'] == 0 for x in s['l1s']), "l1 not all applied+0"
- assert 'contract' in s, "missing contract field"
- print("OK")
-except Exception as ex:
- print(f"FAIL: {ex}")
- sys.exit(1)
-PYEOF
-)
- if [ "$me_ok" = "OK" ]; then
- pass "mock_executor: state.json with l2 + 5 l1s (all exit 0) + contract"
- else
- fail "mock_executor state.json: $me_ok"
- fi
-fi
-rm -f "$ROOT/state.json"
-
-# --- Check 8: l3b_agent_stub D-008 keyword map ---
-echo "-- Check 8: l3b_agent_stub keyword map (D-008) --"
-act3=$(python3 scripts/l3b_agent_stub.py "We need to ingest natural gas prices from Platts and report on compliance." 2>&1)
-if echo "$act3" | grep -q 'stack: l2-commodity-price-feed'; then
- pass "l3b Act 3 example -> l2-commodity-price-feed"
-else
- fail "l3b Act 3 example: got '$act3'"
-fi
-fallback=$(python3 scripts/l3b_agent_stub.py "please deploy something" 2>&1)
-if echo "$fallback" | grep -q 'stack: l2-invoice-service'; then
- pass "l3b fallback (no keywords) -> l2-invoice-service"
-else
- fail "l3b fallback: got '$fallback'"
-fi
-regulatory=$(python3 scripts/l3b_agent_stub.py "regulatory compliance reporting for trading desk" 2>&1)
-if echo "$regulatory" | grep -q 'stack: l2-regulatory-reporting'; then
- pass "l3b regulatory keywords -> l2-regulatory-reporting"
-else
- fail "l3b regulatory: got '$regulatory'"
-fi
-invoice=$(python3 scripts/l3b_agent_stub.py "monthly invoice and billing reconciliation" 2>&1)
-if echo "$invoice" | grep -q 'stack: l2-invoice-service'; then
- pass "l3b invoice keywords -> l2-invoice-service"
-else
- fail "l3b invoice: got '$invoice'"
-fi
-analytics=$(python3 scripts/l3b_agent_stub.py "historical analytics and query API" 2>&1)
-if echo "$analytics" | grep -q 'stack: l2-energy-analytics-api'; then
- pass "l3b analytics keywords -> l2-energy-analytics-api"
-else
- fail "l3b analytics: got '$analytics'"
-fi
-
-echo
-echo "== Summary =="
-if [ "$fail_count" -eq 0 ]; then
- echo "Phase 03 verification PASSED (4 L2s + 5 core scripts, all checks ok)"
- exit 0
-else
- echo "Phase 03 verification FAILED (${fail_count} check(s) failed)"
- exit 1
-fi
\ No newline at end of file
diff --git a/demo/scripts/verify_phase04.sh b/demo/scripts/verify_phase04.sh
deleted file mode 100755
index be98497..0000000
--- a/demo/scripts/verify_phase04.sh
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/usr/bin/env bash
-# Phase 04 verification script.
-# Confirms the pipeline workflow + issue trigger + finalize_evidence.py
-# conform to the Phase 04 plan and the Gitea Actions topology in
-# ARCHITECTURE.md. Does NOT execute a real Gitea Actions run (act_runner
-# is not registered in this environment); validates structure + syntax
-# + a dry-run of finalize_evidence.py against a dead host.
-#
-# Usage: scripts/verify_phase04.sh
-# Exit codes: 0 = all checks passed; 1 = one or more checks failed.
-
-set -uo pipefail
-
-ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-cd "$ROOT"
-
-fail_count=0
-pass() { printf ' [PASS] %s\n' "$1"; }
-fail() { printf ' [FAIL] %s\n' "$1"; fail_count=$((fail_count + 1)); }
-
-echo "== Phase 04 verification =="
-echo "Root: ${ROOT}"
-echo
-
-# --- Check 1: typecheck ---
-echo "-- Check 1: typecheck --"
-if bash -n scripts/finalize_evidence.py 2>/dev/null || python3 -m py_compile scripts/finalize_evidence.py 2>/dev/null; then
- pass "py_compile finalize_evidence.py"
-else
- fail "py_compile finalize_evidence.py"
-fi
-if python3 -c "import yaml; yaml.safe_load(open('.gitea/workflows/pipeline.yml')); yaml.safe_load(open('contracts-repo/.gitea/workflows/issue-to-contract.yml'))" 2>/dev/null; then
- pass "yaml load both workflows"
-else
- fail "yaml load workflows"
-fi
-
-# --- Check 2: pipeline.yml structure ---
-echo "-- Check 2: pipeline.yml structure (D-027, D-028) --"
-p_struct=$(python3 << 'PYEOF'
-import yaml, sys
-try:
- d = yaml.safe_load(open('.gitea/workflows/pipeline.yml'))
- on = d.get('on', d.get(True)) or {}
- assert 'workflow_dispatch' in on, 'no workflow_dispatch trigger'
- inputs = on['workflow_dispatch']['inputs']
- assert set(inputs.keys()) == {'contract-ref', 'approve_qa', 'approve_prod'}, f'inputs: {set(inputs.keys())}'
- assert inputs['contract-ref']['type'] == 'string', 'contract-ref type'
- assert inputs['approve_qa']['type'] == 'boolean', 'approve_qa type'
- assert inputs['approve_prod']['type'] == 'boolean', 'approve_prod type'
- jobs = d['jobs']
- assert set(jobs.keys()) == {'dev', 'qa-gate', 'prod-gate', 'finalize'}, f'jobs: {set(jobs.keys())}'
- dev_if = jobs['dev'].get('if', '')
- assert 'approve_qa' in dev_if and 'approve_prod' in dev_if, f'dev.if: {dev_if}'
- qa_if = jobs['qa-gate'].get('if', '')
- assert 'approve_qa' in qa_if, f'qa-gate.if: {qa_if}'
- prod_if = jobs['prod-gate'].get('if', '')
- assert 'approve_prod' in prod_if, f'prod-gate.if: {prod_if}'
- fin_needs = jobs['finalize'].get('needs', [])
- assert fin_needs == ['prod-gate'] or fin_needs == 'prod-gate', f'finalize.needs: {fin_needs}'
- # All jobs runs-on ubuntu-latest
- for name, job in jobs.items():
- assert job.get('runs-on') == 'ubuntu-latest', f'{name} runs-on: {job.get("runs-on")}'
- print('OK')
-except AssertionError as ex:
- print(f'FAIL: {ex}')
- sys.exit(1)
-except Exception as ex:
- print(f'FAIL: {ex}')
- sys.exit(1)
-PYEOF
-)
-if [ "$p_struct" = "OK" ]; then
- pass "pipeline.yml: 3 inputs + 4 jobs + correct if: conditions + finalize.needs=prod-gate"
-else
- fail "pipeline.yml structure: $p_struct"
-fi
-
-# --- Check 3: pipeline.yml references core scripts ---
-echo "-- Check 3: pipeline.yml references core scripts (D-029) --"
-text=$(cat .gitea/workflows/pipeline.yml)
-missing=""
-for ref in policy_checker.py confidence_signal.py mock_executor.sh evidence_writer.py finalize_evidence.py; do
- if ! echo "$text" | grep -qF "$ref"; then
- missing="$missing $ref"
- fi
-done
-if [ -z "$missing" ]; then
- pass "pipeline.yml references all 5 core scripts"
-else
- fail "pipeline.yml missing references:$missing"
-fi
-# Branch-pin documentation
-if echo "$text" | grep -q 'milestone/v1.0-initial'; then
- pass "pipeline.yml documents branch-pin to milestone/v1.0-initial"
-else
- fail "pipeline.yml missing branch-pin reference"
-fi
-
-# --- Check 4: issue-to-contract.yml structure ---
-echo "-- Check 4: issue-to-contract.yml structure (D-030) --"
-i_struct=$(python3 << 'PYEOF'
-import yaml, sys
-try:
- d = yaml.safe_load(open('contracts-repo/.gitea/workflows/issue-to-contract.yml'))
- on = d.get('on', d.get(True)) or {}
- assert 'issues' in on, 'no issues trigger'
- assert on['issues']['types'] == ['opened'], f'types: {on["issues"]["types"]}'
- assert 'parse-and-trigger' in d['jobs'], 'no parse-and-trigger job'
- assert d['jobs']['parse-and-trigger'].get('runs-on') == 'ubuntu-latest', 'runs-on'
- print('OK')
-except AssertionError as ex:
- print(f'FAIL: {ex}')
- sys.exit(1)
-PYEOF
-)
-if [ "$i_struct" = "OK" ]; then
- pass "issue-to-contract.yml: issues[opened] + parse-and-trigger job"
-else
- fail "issue-to-contract.yml structure: $i_struct"
-fi
-
-# --- Check 5: issue-to-contract.yml references + dispatch endpoint ---
-echo "-- Check 5: issue-to-contract.yml references + dispatch (D-014, D-030) --"
-text=$(cat contracts-repo/.gitea/workflows/issue-to-contract.yml)
-missing=""
-for ref in l3b_agent_stub.py 'actions/workflows/pipeline.yml/dispatches' 'contract-ref' 'gitea.event.issue.number' 'GITEA_TOKEN' 'new_branch'; do
- if ! echo "$text" | grep -qF "$ref"; then
- missing="$missing $ref"
- fi
-done
-if [ -z "$missing" ]; then
- pass "issue-to-contract.yml: l3b_agent_stub + dispatch + contract-ref + issue number + token + new_branch"
-else
- fail "issue-to-contract.yml missing references:$missing"
-fi
-
-# --- Check 6: finalize_evidence.py --help + clean failure ---
-echo "-- Check 6: finalize_evidence.py CLI + clean failure modes ---"
-out=$(python3 scripts/finalize_evidence.py --help 2>&1); rc=$?
-if [ "$rc" = "0" ] && echo "$out" | grep -qi 'usage\|--audit\|--owner'; then
- pass "finalize_evidence.py --help exits 0 with usage"
-else
- fail "finalize_evidence.py --help: rc=$rc"
-fi
-
-# Missing audit file (with a fake token so it gets past the env check) → exit 1, no stack trace
-out=$(ACDL_GITEA_TOKEN=fake python3 scripts/finalize_evidence.py --audit /tmp/definitely_nonexistent_audit.json 2>&1); rc=$?
-if [ "$rc" = "1" ] && ! echo "$out" | grep -q 'Traceback'; then
- pass "finalize_evidence.py missing file → exit 1, no stack trace"
-else
- fail "finalize_evidence.py missing file: rc=$rc, out='$out'"
-fi
-
-# Missing token env (audit file present) → exit 1, no stack trace
-printf '[]\n' > /tmp/empty_audit.json
-out=$(env -u ACDL_GITEA_TOKEN python3 scripts/finalize_evidence.py --audit /tmp/empty_audit.json 2>&1); rc=$?
-if [ "$rc" = "1" ] && ! echo "$out" | grep -q 'Traceback'; then
- pass "finalize_evidence.py missing token env → exit 1, no stack trace"
-else
- fail "finalize_evidence.py missing token: rc=$rc, out='$out'"
-fi
-
-# --- Check 7: finalize_evidence.py dry-run against a dead host (clean failure) ---
-echo "-- Check 7: finalize_evidence.py dry-run against dead host ---"
-# Use a real audit.json but point at a host that will refuse the connection.
-printf '[{"seq":0,"ts":"2026-07-21T00:00:00Z","stage":"genesis","event":"init","prev_hash":"GENESIS","hash":"x"}]\n' > /tmp/real_audit.json
-out=$(ACDL_GITEA_TOKEN=fake GITEA_HOST=http://127.0.0.1:0 python3 scripts/finalize_evidence.py --audit /tmp/real_audit.json --host http://127.0.0.1:0 2>&1); rc=$?
-if [ "$rc" = "1" ] && ! echo "$out" | grep -q 'Traceback'; then
- pass "finalize_evidence.py dead host → exit 1, no stack trace (clean API failure)"
-else
- fail "finalize_evidence.py dead host: rc=$rc, out='$out'"
-fi
-
-# Cleanup
-rm -f /tmp/empty_audit.json /tmp/real_audit.json
-
-echo
-echo "== Summary =="
-if [ "$fail_count" -eq 0 ]; then
- echo "Phase 04 verification PASSED (pipeline + issue trigger + finalize helper, all checks ok)"
- exit 0
-else
- echo "Phase 04 verification FAILED (${fail_count} check(s) failed)"
- exit 1
-fi
\ No newline at end of file
diff --git a/demo/scripts/verify_phase05.sh b/demo/scripts/verify_phase05.sh
deleted file mode 100755
index 97d28c7..0000000
--- a/demo/scripts/verify_phase05.sh
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/usr/bin/env bash
-# Phase 05 verification script.
-# Validates the evidence UI + the 4-act demo dry-run.
-#
-# Usage: scripts/verify_phase05.sh
-# Exit codes: 0 = all checks passed; 1 = one or more checks failed.
-
-set -uo pipefail
-
-ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-cd "$ROOT"
-
-fail_count=0
-pass() { printf ' [PASS] %s\n' "$1"; }
-fail() { printf ' [FAIL] %s\n' "$1"; fail_count=$((fail_count + 1)); }
-
-GITEA_HOST="${GITEA_HOST:-https://git.cloudinit.dev}"
-ORG="continuous-intelligence"
-EVIDENCE_REPO="acdl-evidence"
-
-echo "== Phase 05 verification =="
-echo "Root: ${ROOT}"
-echo
-
-# --- Check 1: evidence-ui/index.html structure ---
-echo "-- Check 1: evidence-ui/index.html structure (D-032, REQ-14) --"
-UI="evidence-ui/index.html"
-if [ ! -f "$UI" ]; then
- fail "$UI missing"
-else
- pass "$UI exists"
- size=$(wc -c < "$UI")
- if [ "$size" -ge 1000 ] && [ "$size" -le 30000 ]; then
- pass "$UI size ${size} bytes (within 1-30 KB range)"
- else
- fail "$UI size ${size} bytes (expected 1-30 KB)"
- fi
- ui_check=$(python3 << 'PYEOF'
-import re, sys
-content = open('evidence-ui/index.html').read()
-problems = []
-if '' not in content: problems.append('missing inline