RUL-003 — Env config from the active env profile, read at call time — no hardcoding, no literal infra defaults
Ruling
Read env config with inline os.environ.get("X", default) at call time — never a bare os.environ["X"], never a hardcoded literal, and never an import-time constant when the value must be override-able at runtime.
INVERSE for REQUIRED infra endpoint keys (the keys that select which live infra you talk to — REDIS_HOST, REDIS_PORT, KG_ROUTING_URI, KG_URI, KG_DATABASE, MEMGRAPH_URI, CXP_GRPC_PORT, KG_GRPC_PORT): these carry NO default and RAISE when unset. A .get(KEY, default) on them (even "localhost" / "") is FORBIDDEN — an unset key must fail loudly, never silently connect to the wrong server (the classic bug: a default of the PRODUCTION Redis/graph). Route through the raising seams core.graph_factory.resolve_uri/resolve_kg_database and core.redis_factory.resolve_redis_host/resolve_redis_port.
Endpoints come from the active env profile (since the isolated-fleets cutover): ORCHESTRATA_ENV_PROFILE (default test) selects a committed, endpoint-only env/{dev,test,prod}.env, layered over a secrets-only .env by each entrypoint's _load_dotenv() (profile overlays with override=True). Never hardcode an Incus IP; if a container IP changes, only the relevant env/<profile>.env is edited. The suite is hard-pinned to env/test.env by tests/conftest.py (overlay + prod-subnet guard), so tests cannot land on the prod fleet (10.53.1.x) — the authoritative suite target is the isolated test fleet (10.53.2.x).
Evidence
- Memory
project-env-config-call-time:core/infra_config.py's PydanticBaseSettingsconstants are evaluated once at import time, which broke CLI/test env overrides (TestKgContextConnectionFailure,TestSyncCommand.test_sync_connection_failurefailed silently instead of raising) — the fix was call-timeos.environ.get(), not centralizing into more import-time constants. - AGENTS.md Hard Rule 5: "Never hardcode service IPs or ports. All from the active
ORCHESTRATA_ENV_PROFILE(env/{dev,test,prod}.env) layered over.envsecrets." core/standards.pyrule 30d (NO LITERAL FALLBACK FOR REQUIRED INFRA ENDPOINTS) andcore/infra_env_rule.py(the key set + scanner).INFRASTRUCTURE.md"Environment fleets": proddefault(10.53.1.x, HA, never a test target), testorchestrata-test(10.53.2.x), devorchestrata-dev(10.53.3.x).
Enforcement
- gate src/orchestrata_ultimate/prolog/gate_rules.pl bare_os_environ
- gate src/orchestrata_ultimate/prolog/gate_rules.pl env_mutation
- gate src/orchestrata_ultimate/prolog/gate_rules.pl infra_key_with_default
- gate scripts/validate_ci.py infra_env_rule
- gate src/orchestrata_ultimate/core/standards.py 30d
Verification
scripts/code-review.py's BARE_OS_ENVIRON check flags os.environ["X"] subscript reads; its ConnectionStringChecker raises ENV_DEFAULT (ERROR) whenever an env-var read for a known infra key carries a hardcoded default; serialize_codebase_ast.py standards gates bare-env-access as a Key-Rule violation. The no-literal-default inverse is scanned by core.infra_env_rule.find_infra_env_defaults, enforced as the check_infra_env_defaults review check and as scripts/validate_ci.py Gate 12; standards rule 30d states the rule in the rulebase agents load.