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.
126 lines
3.6 KiB
Bash
Executable File
126 lines
3.6 KiB
Bash
Executable File
#!/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 <contract.yaml>" >&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" |