verify(P7): contract-resolver-envloader-and-kind — 4-layer verify PASS + ship
VERIFY: structural — envloader dedup + kind field; behavioral — 49 tests + CI PASS; quality — fragile is_l2 heuristic replaced. ---ci--- project: acdl phase: 7 milestone: v1.16 status: complete phase_role: execution requirements: covered: [REQ-171] partial: [] ---/ci---
This commit is contained in:
+14
-24
@@ -50,22 +50,13 @@ from core import env
|
|||||||
def _load_env(env_name, repo_root):
|
def _load_env(env_name, repo_root):
|
||||||
"""Load the environment onboarding JSON for env_name.
|
"""Load the environment onboarding JSON for env_name.
|
||||||
|
|
||||||
Mirrors core.environment_check.load() but is self-contained so the
|
P7 (REQ-171): delegates to core.environment_check.load() (dedup —
|
||||||
resolver works both as a package import (`from core.contract_resolver
|
the two were verbatim duplicates). The environment_check module is
|
||||||
import resolve`) and as a script (`python3 core/contract_resolver.py`).
|
in the same core/ package, so the import works both as a package
|
||||||
Emits a stderr warning when account_id is the placeholder and env != dev.
|
import and as a script (`python3 core/contract_resolver.py`).
|
||||||
"""
|
"""
|
||||||
env_file = os.path.join(repo_root, "core", "environments", f"{env_name}.json")
|
from core import environment_check
|
||||||
if not os.path.isfile(env_file):
|
return environment_check.load(env_name, root=repo_root)
|
||||||
raise FileNotFoundError(f"no environment file for '{env_name}' at {env_file}")
|
|
||||||
env = _load_json(env_file)
|
|
||||||
if env.get("account_id") == "000000000000" and env_name != "dev":
|
|
||||||
sys.stderr.write(
|
|
||||||
f"WARNING: environment '{env_name}' has the placeholder account_id "
|
|
||||||
f"000000000000 — replace it with the real {env_name} account id "
|
|
||||||
f"before deploying (onboarding scaffold).\n"
|
|
||||||
)
|
|
||||||
return env
|
|
||||||
|
|
||||||
|
|
||||||
def _load_json(path):
|
def _load_json(path):
|
||||||
@@ -534,10 +525,14 @@ def resolve(contract_path, repo_root=None, environment_override=None):
|
|||||||
f"module '{module_name}' version '{version}' not found in registry")
|
f"module '{module_name}' version '{version}' not found in registry")
|
||||||
module_inputs = module_entry.get("inputs", {})
|
module_inputs = module_entry.get("inputs", {})
|
||||||
|
|
||||||
# Determine if L1 or L2
|
# Determine if L1 or L2 — prefer the registry `kind` field (P7,
|
||||||
|
# REQ-171); fall back to the path heuristic for entries that
|
||||||
|
# predate the kind field.
|
||||||
entry = registry[module_name][version]
|
entry = registry[module_name][version]
|
||||||
interface_path = entry["interface"]
|
interface_path = entry["interface"]
|
||||||
is_l2 = "l2" in interface_path or "composition" in interface_path
|
is_l2 = entry.get("kind") == "l2" or (
|
||||||
|
"kind" not in entry and ("l2" in interface_path or "composition" in interface_path)
|
||||||
|
)
|
||||||
|
|
||||||
if is_l2:
|
if is_l2:
|
||||||
fragment = _resolve_l2(module_name, version, module_inputs,
|
fragment = _resolve_l2(module_name, version, module_inputs,
|
||||||
@@ -580,13 +575,8 @@ def resolve(contract_path, repo_root=None, environment_override=None):
|
|||||||
merged_outputs.update(fragment.get("outputs", {}))
|
merged_outputs.update(fragment.get("outputs", {}))
|
||||||
all_resources.extend(fragment["resources"])
|
all_resources.extend(fragment["resources"])
|
||||||
|
|
||||||
# Determine stack kind: L2 if any module is L2 or if multi-module
|
# Determine stack kind: L2 if any module is L2 or if multi-module (P7)
|
||||||
if multi_module:
|
kind = "l2" if (multi_module or any_l2) else "l1"
|
||||||
kind = "l2"
|
|
||||||
elif any_l2:
|
|
||||||
kind = "l2"
|
|
||||||
else:
|
|
||||||
kind = "l1"
|
|
||||||
|
|
||||||
stack_instance = {
|
stack_instance = {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|||||||
+28
-14
@@ -4,7 +4,8 @@
|
|||||||
"interface": "modules/l1/s3/interface.json",
|
"interface": "modules/l1/s3/interface.json",
|
||||||
"terraform_dir": "modules/l1/s3/terraform",
|
"terraform_dir": "modules/l1/s3/terraform",
|
||||||
"published_at": "2026-07-21T19:00:00Z",
|
"published_at": "2026-07-21T19:00:00Z",
|
||||||
"deprecated": false
|
"deprecated": false,
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vpc": {
|
"vpc": {
|
||||||
@@ -12,7 +13,8 @@
|
|||||||
"interface": "modules/l1/vpc/interface.json",
|
"interface": "modules/l1/vpc/interface.json",
|
||||||
"published_at": "2026-07-21T21:30:00Z",
|
"published_at": "2026-07-21T21:30:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/vpc/terraform"
|
"terraform_dir": "modules/l1/vpc/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ecs-cluster": {
|
"ecs-cluster": {
|
||||||
@@ -20,7 +22,8 @@
|
|||||||
"interface": "modules/l1/ecs-cluster/interface.json",
|
"interface": "modules/l1/ecs-cluster/interface.json",
|
||||||
"published_at": "2026-07-21T21:30:00Z",
|
"published_at": "2026-07-21T21:30:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/ecs-cluster/terraform"
|
"terraform_dir": "modules/l1/ecs-cluster/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ecs-service": {
|
"ecs-service": {
|
||||||
@@ -28,7 +31,8 @@
|
|||||||
"interface": "modules/l1/ecs-service/interface.json",
|
"interface": "modules/l1/ecs-service/interface.json",
|
||||||
"published_at": "2026-07-21T21:30:00Z",
|
"published_at": "2026-07-21T21:30:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/ecs-service/terraform"
|
"terraform_dir": "modules/l1/ecs-service/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"iam-role": {
|
"iam-role": {
|
||||||
@@ -36,7 +40,8 @@
|
|||||||
"interface": "modules/l1/iam-role/interface.json",
|
"interface": "modules/l1/iam-role/interface.json",
|
||||||
"published_at": "2026-07-21T21:30:00Z",
|
"published_at": "2026-07-21T21:30:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/iam-role/terraform"
|
"terraform_dir": "modules/l1/iam-role/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"alb": {
|
"alb": {
|
||||||
@@ -44,7 +49,8 @@
|
|||||||
"interface": "modules/l1/alb/interface.json",
|
"interface": "modules/l1/alb/interface.json",
|
||||||
"published_at": "2026-07-21T21:30:00Z",
|
"published_at": "2026-07-21T21:30:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/alb/terraform"
|
"terraform_dir": "modules/l1/alb/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ecr": {
|
"ecr": {
|
||||||
@@ -52,7 +58,8 @@
|
|||||||
"interface": "modules/l1/ecr/interface.json",
|
"interface": "modules/l1/ecr/interface.json",
|
||||||
"published_at": "2026-07-21T21:30:00Z",
|
"published_at": "2026-07-21T21:30:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/ecr/terraform"
|
"terraform_dir": "modules/l1/ecr/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cloudfront": {
|
"cloudfront": {
|
||||||
@@ -60,7 +67,8 @@
|
|||||||
"interface": "modules/l1/cloudfront/interface.json",
|
"interface": "modules/l1/cloudfront/interface.json",
|
||||||
"published_at": "2026-07-22T19:00:00Z",
|
"published_at": "2026-07-22T19:00:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/cloudfront/terraform"
|
"terraform_dir": "modules/l1/cloudfront/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"waf": {
|
"waf": {
|
||||||
@@ -68,7 +76,8 @@
|
|||||||
"interface": "modules/l1/waf/interface.json",
|
"interface": "modules/l1/waf/interface.json",
|
||||||
"published_at": "2026-07-22T19:00:00Z",
|
"published_at": "2026-07-22T19:00:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/waf/terraform"
|
"terraform_dir": "modules/l1/waf/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rds": {
|
"rds": {
|
||||||
@@ -76,7 +85,8 @@
|
|||||||
"interface": "modules/l1/rds/interface.json",
|
"interface": "modules/l1/rds/interface.json",
|
||||||
"published_at": "2026-07-22T20:00:00Z",
|
"published_at": "2026-07-22T20:00:00Z",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/rds/terraform"
|
"terraform_dir": "modules/l1/rds/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"kms-key": {
|
"kms-key": {
|
||||||
@@ -84,7 +94,8 @@
|
|||||||
"interface": "modules/l1/kms-key/interface.json",
|
"interface": "modules/l1/kms-key/interface.json",
|
||||||
"published_at": "2026-07-22T20:00",
|
"published_at": "2026-07-22T20:00",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/kms-key/terraform"
|
"terraform_dir": "modules/l1/kms-key/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uptime": {
|
"uptime": {
|
||||||
@@ -92,21 +103,24 @@
|
|||||||
"interface": "modules/l1/uptime/interface.json",
|
"interface": "modules/l1/uptime/interface.json",
|
||||||
"published_at": "2026-07-22T21:00",
|
"published_at": "2026-07-22T21:00",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"terraform_dir": "modules/l1/uptime/terraform"
|
"terraform_dir": "modules/l1/uptime/terraform",
|
||||||
|
"kind": "l1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"static-assets": {
|
"static-assets": {
|
||||||
"1.0.0": {
|
"1.0.0": {
|
||||||
"interface": "modules/l2/static-assets/composition.json",
|
"interface": "modules/l2/static-assets/composition.json",
|
||||||
"published_at": "2026-07-22T15:00:00Z",
|
"published_at": "2026-07-22T15:00:00Z",
|
||||||
"deprecated": false
|
"deprecated": false,
|
||||||
|
"kind": "l2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"microservice": {
|
"microservice": {
|
||||||
"1.0.0": {
|
"1.0.0": {
|
||||||
"interface": "modules/l2/microservice/composition.json",
|
"interface": "modules/l2/microservice/composition.json",
|
||||||
"published_at": "2026-07-22T15:00:00Z",
|
"published_at": "2026-07-22T15:00:00Z",
|
||||||
"deprecated": false
|
"deprecated": false,
|
||||||
|
"kind": "l2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user