From 93ae9e4a3972c8986168fad64deefdcd0ba15970 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Sat, 1 Aug 2026 12:38:56 +0000 Subject: [PATCH] =?UTF-8?q?verify(P7):=20contract-resolver-envloader-and-k?= =?UTF-8?q?ind=20=E2=80=94=204-layer=20verify=20PASS=20+=20ship?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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--- --- core/contract_resolver.py | 38 +++++++++++++---------------------- modules/registry.json | 42 ++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/core/contract_resolver.py b/core/contract_resolver.py index 691fb73..4e88f9b 100644 --- a/core/contract_resolver.py +++ b/core/contract_resolver.py @@ -50,22 +50,13 @@ from core import env def _load_env(env_name, repo_root): """Load the environment onboarding JSON for env_name. - Mirrors core.environment_check.load() but is self-contained so the - resolver works both as a package import (`from core.contract_resolver - import resolve`) and as a script (`python3 core/contract_resolver.py`). - Emits a stderr warning when account_id is the placeholder and env != dev. + P7 (REQ-171): delegates to core.environment_check.load() (dedup — + the two were verbatim duplicates). The environment_check module is + in the same core/ package, so the import works both as a package + import and as a script (`python3 core/contract_resolver.py`). """ - env_file = os.path.join(repo_root, "core", "environments", f"{env_name}.json") - if not os.path.isfile(env_file): - 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 + from core import environment_check + return environment_check.load(env_name, root=repo_root) 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") 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] 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: 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", {})) all_resources.extend(fragment["resources"]) - # Determine stack kind: L2 if any module is L2 or if multi-module - if multi_module: - kind = "l2" - elif any_l2: - kind = "l2" - else: - kind = "l1" + # Determine stack kind: L2 if any module is L2 or if multi-module (P7) + kind = "l2" if (multi_module or any_l2) else "l1" stack_instance = { "version": "1.0.0", diff --git a/modules/registry.json b/modules/registry.json index bc78ccc..24f697e 100644 --- a/modules/registry.json +++ b/modules/registry.json @@ -4,7 +4,8 @@ "interface": "modules/l1/s3/interface.json", "terraform_dir": "modules/l1/s3/terraform", "published_at": "2026-07-21T19:00:00Z", - "deprecated": false + "deprecated": false, + "kind": "l1" } }, "vpc": { @@ -12,7 +13,8 @@ "interface": "modules/l1/vpc/interface.json", "published_at": "2026-07-21T21:30:00Z", "deprecated": false, - "terraform_dir": "modules/l1/vpc/terraform" + "terraform_dir": "modules/l1/vpc/terraform", + "kind": "l1" } }, "ecs-cluster": { @@ -20,7 +22,8 @@ "interface": "modules/l1/ecs-cluster/interface.json", "published_at": "2026-07-21T21:30:00Z", "deprecated": false, - "terraform_dir": "modules/l1/ecs-cluster/terraform" + "terraform_dir": "modules/l1/ecs-cluster/terraform", + "kind": "l1" } }, "ecs-service": { @@ -28,7 +31,8 @@ "interface": "modules/l1/ecs-service/interface.json", "published_at": "2026-07-21T21:30:00Z", "deprecated": false, - "terraform_dir": "modules/l1/ecs-service/terraform" + "terraform_dir": "modules/l1/ecs-service/terraform", + "kind": "l1" } }, "iam-role": { @@ -36,7 +40,8 @@ "interface": "modules/l1/iam-role/interface.json", "published_at": "2026-07-21T21:30:00Z", "deprecated": false, - "terraform_dir": "modules/l1/iam-role/terraform" + "terraform_dir": "modules/l1/iam-role/terraform", + "kind": "l1" } }, "alb": { @@ -44,7 +49,8 @@ "interface": "modules/l1/alb/interface.json", "published_at": "2026-07-21T21:30:00Z", "deprecated": false, - "terraform_dir": "modules/l1/alb/terraform" + "terraform_dir": "modules/l1/alb/terraform", + "kind": "l1" } }, "ecr": { @@ -52,7 +58,8 @@ "interface": "modules/l1/ecr/interface.json", "published_at": "2026-07-21T21:30:00Z", "deprecated": false, - "terraform_dir": "modules/l1/ecr/terraform" + "terraform_dir": "modules/l1/ecr/terraform", + "kind": "l1" } }, "cloudfront": { @@ -60,7 +67,8 @@ "interface": "modules/l1/cloudfront/interface.json", "published_at": "2026-07-22T19:00:00Z", "deprecated": false, - "terraform_dir": "modules/l1/cloudfront/terraform" + "terraform_dir": "modules/l1/cloudfront/terraform", + "kind": "l1" } }, "waf": { @@ -68,7 +76,8 @@ "interface": "modules/l1/waf/interface.json", "published_at": "2026-07-22T19:00:00Z", "deprecated": false, - "terraform_dir": "modules/l1/waf/terraform" + "terraform_dir": "modules/l1/waf/terraform", + "kind": "l1" } }, "rds": { @@ -76,7 +85,8 @@ "interface": "modules/l1/rds/interface.json", "published_at": "2026-07-22T20:00:00Z", "deprecated": false, - "terraform_dir": "modules/l1/rds/terraform" + "terraform_dir": "modules/l1/rds/terraform", + "kind": "l1" } }, "kms-key": { @@ -84,7 +94,8 @@ "interface": "modules/l1/kms-key/interface.json", "published_at": "2026-07-22T20:00", "deprecated": false, - "terraform_dir": "modules/l1/kms-key/terraform" + "terraform_dir": "modules/l1/kms-key/terraform", + "kind": "l1" } }, "uptime": { @@ -92,21 +103,24 @@ "interface": "modules/l1/uptime/interface.json", "published_at": "2026-07-22T21:00", "deprecated": false, - "terraform_dir": "modules/l1/uptime/terraform" + "terraform_dir": "modules/l1/uptime/terraform", + "kind": "l1" } }, "static-assets": { "1.0.0": { "interface": "modules/l2/static-assets/composition.json", "published_at": "2026-07-22T15:00:00Z", - "deprecated": false + "deprecated": false, + "kind": "l2" } }, "microservice": { "1.0.0": { "interface": "modules/l2/microservice/composition.json", "published_at": "2026-07-22T15:00:00Z", - "deprecated": false + "deprecated": false, + "kind": "l2" } } }