#!/usr/bin/env bash # scripts/verify_phase14.sh - verify Phase 14 (l2-microservice-and-contract-schema). set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT" fail() { echo "FAIL: $*" >&2; exit 1; } echo "=== Phase 14 verification ===" # 1. l2-microservice composition + README [ -f modules-ir/l2/l2-microservice/composition.json ] || fail "composition.json missing" [ -f modules-ir/l2/l2-microservice/README.md ] || fail "README.md missing" python3 -c "import json; d=json.load(open('modules-ir/l2/l2-microservice/composition.json')); assert d['name']=='l2-microservice'; assert d['kind']=='l2'; assert d['depth']==1; assert len(d['children'])==6, f'expected 6 children, got {len(d[\"children\"])}'; print('composition: OK (6 children)')" # 2. Registry has l2-microservice python3 -c "import json; r=json.load(open('modules-ir/registry.json')); assert 'l2-microservice' in r; assert r['l2-microservice']['1.0.0']['deprecated']==False; print('registry: l2-microservice@1.0.0 OK')" # 3. Contract schema extended (inputs allow objects + healthcheck field) python3 - <<'PY' import json s = json.load(open("schemas/contract.schema.json")) ap = s["properties"]["inputs"]["additionalProperties"] assert "object" in ap["type"], "inputs.additionalProperties doesn't allow object" assert "healthcheck" in s["properties"], "no healthcheck field" print("contract schema: OK (inputs allow objects + healthcheck field)") PY # 4. contracts/microservice.yaml exists + validates [ -f contracts/microservice.yaml ] || fail "contracts/microservice.yaml missing" python3 - <<'PY' import yaml, json, jsonschema with open("contracts/microservice.yaml") as fh: c = yaml.safe_load(fh) assert c["stack"] == "l2-microservice", f"stack={c['stack']}" assert c["environment"] == "dev" assert "name" in c["inputs"] assert "image" in c["inputs"] assert "port" in c["inputs"] schema = json.load(open("schemas/contract.schema.json")) jsonschema.validate(c, schema) print("microservice.yaml: OK (validates against contract schema)") PY # 5. Resolver + adapter py_compile python3 -m py_compile acdl_platform/contract_resolver.py adapters/terraform/adapter.py || fail "py_compile failed" echo "py_compile: OK" # 6. v1.1 regression: spike.yaml still resolves + adapts WORK=/tmp/p14_verify rm -rf "$WORK"; mkdir -p "$WORK" python3 acdl_platform/contract_resolver.py contracts/spike.yaml "$WORK/spike_ir.json" 2>/dev/null || fail "v1.1 regression: resolver failed" python3 adapters/terraform/adapter.py "$WORK/spike_ir.json" "$WORK/spike_tf" 2>/dev/null || fail "v1.1 regression: adapter failed" grep -q 'resource "aws_s3_bucket" "s3"' "$WORK/spike_tf/main.tf" || fail "v1.1 regression: no aws_s3_bucket" grep -q 'bucket = "acdl-spike-bucket"' "$WORK/spike_tf/main.tf" || fail "v1.1 regression: no bucket arg" echo "v1.1 regression: OK (spike.yaml -> l1-s3 -> aws_s3_bucket)" # 7. v1.2 resolution: microservice.yaml -> IR with all 6 L1s' resources python3 acdl_platform/contract_resolver.py contracts/microservice.yaml "$WORK/ms_ir.json" 2>/dev/null || fail "v1.2: resolver failed" python3 - <<'PY' import json ir = json.load(open("/tmp/p14_verify/ms_ir.json")) rsc = ir["resources"] print(f"v1.2 IR: {len(rsc)} resources") assert len(rsc) >= 6, f"expected >=6 resources, got {len(rsc)}" types = {r["type"] for r in rsc} expected_types = {"aws:ec2:vpc", "aws:ec2:subnet", "aws:ec2:routetable", "aws:ecs:cluster", "aws:ecr:repository", "aws:iam:role", "aws:elbv2:loadbalancer", "aws:elbv2:targetgroup", "aws:elbv2:listener", "aws:ecs:task_definition", "aws:ecs:service"} assert types == expected_types, f"missing types: {expected_types - types}, extra: {types - expected_types}" # Check child->child refs exist ref_found = False for r in rsc: for v in r.get("inputs", {}).values(): if isinstance(v, str) and v.startswith("ref:"): ref_found = True break assert ref_found, "no child->child refs in IR" print(f" types: {sorted(types)}") print(" child->child refs: present") PY # 8. v1.2 adaptation: IR -> TF python3 adapters/terraform/adapter.py "$WORK/ms_ir.json" "$WORK/ms_tf" 2>/dev/null || fail "v1.2: adapter failed" grep -q 'resource "aws_vpc"' "$WORK/ms_tf/main.tf" || fail "v1.2: no aws_vpc in TF" grep -q 'resource "aws_ecs_cluster"' "$WORK/ms_tf/main.tf" || fail "v1.2: no aws_ecs_cluster in TF" grep -q 'resource "aws_ecs_service"' "$WORK/ms_tf/main.tf" || fail "v1.2: no aws_ecs_service in TF" grep -q 'resource "aws_ecr_repository"' "$WORK/ms_tf/main.tf" || fail "v1.2: no aws_ecr_repository in TF" grep -q 'resource "aws_lb"' "$WORK/ms_tf/main.tf" || fail "v1.2: no aws_lb in TF" grep -q 'resource "aws_iam_role"' "$WORK/ms_tf/main.tf" || fail "v1.2: no aws_iam_role in TF" # Check ref translation (interpolations present) grep -q 'aws_ecs_cluster.cluster.arn' "$WORK/ms_tf/main.tf" || fail "v1.2: no cluster.arn interpolation" echo "v1.2 adaptation: OK (11 resources + interpolations in main.tf)" # 9. .ciagent/ consistency grep -q '"milestone": "v1.2"' .ciagent/config.json || fail "config.json: milestone not v1.2" echo ".ciagent/ consistency: OK" echo "" echo "=== Phase 14: VERIFIED ===" echo "l2-microservice composition (6 L1s); contract schema extended; resolver child->child wiring; 11 IR resources; TF valid." exit 0