feat(P40): contract interpolation + environment JSON schema
---ci---
project: acdl
phase: 40
milestone: v1.9
status: execute
---/ci---
Phase 40 — contract-interpolation (REQ-103, REQ-104, D-081):
Interpolation:
- core/contract_resolver.py: _expand_vars(value, context) recursively
expands ${env.<field>} + ${contract.<field>} tokens (dotted paths
supported, e.g. ${env.state_backend.bucket}). Unknown tokens raise
ValueError (fail loud). Expansion is post-schema-validation,
pre-IR-resolution.
- resolve() accepts environment_override (D-088) — overrides the
contract's environment field BEFORE schema validation so interpolation
context is consistent.
- env context loaded via _load_env (self-contained, works as script +
package import); 'environment' alias for env 'name' so
${env.environment} resolves.
Environment schema + bindings:
- schemas/environment.schema.json (draft 2020-12): name, account_id,
region, state_backend, network, runner_role_arn, autonomy, confidence_threshold.
- core/environments/qa.json, prod.json, dr.json placeholder bindings
(attested, thresholds 0.75/0.90/0.95, placeholder account_id with
stderr warning at load).
- core/environment_check.py: load(env_name) helper + placeholder warning.
Sample contracts:
- contracts/static-assets.yaml + microservice.yaml use
acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}
naming pattern (region + account id + environment).
Tests: +35 (test_environment_schema.py, test_interpolation.py,
test_sample_contracts_interpolate.py). 406 passed; run_ci.sh green;
run_platform.sh --check-only green. Existing fixture-based tests
preserved (instance.json static fixtures unaffected).
This commit is contained in:
@@ -10,6 +10,7 @@ Usage:
|
||||
python3 core/environment_check.py <contract.yaml>
|
||||
python3 core/environment_check.py --env dev
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -32,6 +33,27 @@ def _contract_environment(contract_path):
|
||||
return contract.get("environment")
|
||||
|
||||
|
||||
def load(env_name, root=None):
|
||||
"""Load and return the parsed environment JSON for env_name.
|
||||
|
||||
Returns the env dict, or raises FileNotFoundError if no <env_name>.json
|
||||
exists. Emits a stderr warning when account_id is the 000000000000
|
||||
placeholder and env_name != 'dev' (prompts real binding).
|
||||
"""
|
||||
env_file = _environments_dir(root) / f"{env_name}.json"
|
||||
if not env_file.is_file():
|
||||
raise FileNotFoundError(f"no environment file for '{env_name}' at {env_file}")
|
||||
with open(env_file) as f:
|
||||
env = json.load(f)
|
||||
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 _onboarding_message(env_name):
|
||||
return (
|
||||
"=== ACDL Environment Onboarding ===\n"
|
||||
|
||||
Reference in New Issue
Block a user