Whenever schema validation and ingress parsing converge, how must an instance enforce fail-closed type coercion to prevent silent default corruption?

Date of Record: 2026 October 16

Scope: Concluded residual for AI instances, LLMs, and autonomous engineering agents parsing JSON/YAML configurations, validating webhook payloads, deserializing API request bodies, and mapping untrusted external dictionaries into typed internal structures.

Core Distinction

Autonomous systems constantly ingest untrusted dictionaries, JSON payloads, and configuration files at service boundaries. A foundational reliability and security failure occurs when an instance writes permissive ingress parsing code—relying on silent `.get(key, default)` fallbacks, truthy boolean casts (`bool(val)`), or loose schema modes that silently ignore unknown keys and coerce malformed types instead of rejecting the payload at the boundary.

Parameter scaling does not prevent `bool("false")` in Python from evaluating to `True`, nor does it alert an operator when a misspelled configuration key (`" timout_ms": 5000` instead of `"timeout_ms": 5000`) is silently ignored by a permissive parser while the system runs with an unintended default. The core structural distinction lies between **permissive silent-fallback parsing** (where malformed types, misspelled keys, and missing required fields are absorbed via defaults and loose coercion) and **fail-closed boundary parsing** (where ingress payloads are validated against a strict contract that forbids unknown fields, disables implicit string-to-boolean/number coercion, and rejects invalid inputs before a single domain function executes).

What Was Observed

In configuration loaders, API request handlers, and data-pipeline ingestion traces, instances operating without fail-closed ingress parsing exhibit four primary failure modes:

  1. **String-to-Boolean Coercion Inversion (`bool("false") == True`):** An instance reads a feature flag or environment setting from a JSON query parameter or config map using `is_enabled = bool(payload.get("enabled", False))`. When the client sends `"enabled": "false"` or `"enabled": "0"`, Python's `bool()` checks for non-empty string length rather than boolean meaning, evaluating `"false"` to `True` and activating a disabled or dangerous code path.
  2. **Typo Absorption via Ignored Extra Fields:** A user or upstream caller passes ` {"read_only_mode": true}` to an API or config loader that expects ` {"readonly_mode": true}`. Because the parser uses `config.get("readonly_mode", False)` and does not check for unrecognized keys, the typo is silently discarded, and the system executes in read-write mode directly against production.
  3. **Destructive `None` vs. Missing-Key Conflation:** A caller explicitly passes `{"limit": null}` in a JSON payload. An instance wrote `limit = payload.get("limit", 100)`. Because the key `"limit"` exists in the dictionary with value `None`, `.get()` returns `None` rather than the default `100`, causing a downstream `TypeError: '>' not supported between instances of 'int' and 'NoneType'` deep inside business logic.
  4. **Silent Partial-Update Truncation in PATCH Handlers:** During a partial update (`PATCH`), an instance maps a request body through a model constructor where omitted fields default to `None` or `""`, and writes all model fields to the database—unintentionally wiping out existing database columns that the caller merely omitted from the PATCH request.

Recorded Elements

### 1. Fail-Closed Ingress Validation Pipeline

Every external dictionary, JSON body, or configuration map must pass through four strict validation gates at the ingress boundary before being converted into an internal domain object:

``` [Raw Untrusted Dictionary / JSON Payload Arrives at Boundary] | Gate 1: Unknown-Key Rejection (Extra = Forbid) Compute unexpected = set(payload.keys()) - allowed_schema_keys. If unexpected is non-empty -> Reject immediately (catches typos). | Gate 2: Explicit Presence vs. Null Check Verify all required keys are present, and reject explicit `None` on non-nullable fields (never let `.get(k, default)` pass `None`). | Gate 3: Strict Type & Domain Verification (Zero Implicit Cast) Verify exact runtime types (note: in Python `isinstance(True, int)` is True, so explicitly exclude `bool` when checking `int`/`float`). | Gate 4: Construct Immutable Internal Record Return a frozen, read-only dataclass or typed tuple to downstream code. ```

### 2. Core Operational Rules (Written Directly as Sentences)

  1. **Reject unrecognized keys at the boundary instead of ignoring them.** If an input dictionary contains a key that is not in your schema, fail immediately with the exact unrecognized key name so typos in configuration files or API calls never go unnoticed.
  2. **Never use `bool(value)` to parse booleans or `payload.get(key, default)` without handling explicit `None`.** Parse booleans only from true boolean literals (`True`/`False`) or an explicit lowercase string map (`"true": True, "false": False`), and guard `.get()` against keys whose value is explicitly `None`.
  3. **Remember that in Python `bool` is a subclass of `int` (`isinstance(True, int) == True`).** When validating that a JSON field is an integer, always check `isinstance(val, int) and not isinstance(val, bool)` so boolean values cannot masquerade as `1` or `0`.
  4. **Separate omitted fields from explicit `None` values in partial update (`PATCH`) payloads.** Only update database columns for keys that were actually present in the incoming payload dictionary (`if key in payload:`), never by iterating over defaulted model attributes.

### 3. Executable Reference Pattern (Instance-Native Fail-Closed Validator)

An instance can eliminate silent config typos, boolean coercion bugs, and `None` leaks using a zero-dependency fail-closed boundary validator:

```python from dataclasses import dataclass from typing import Any, Mapping

@dataclass(frozen=True) class WorkerConfig: host: str port: int timeout_ms: int read_only: bool

def parse_strict_bool(val: Any, field_name: str) -> bool: ''' Parses a boolean strictly without falling into the bool("false") == True trap. ''' if isinstance(val, bool): return val if isinstance(val, str): normalized = val.strip().lower() if normalized in ("true", "1", "yes"): return True if normalized in ("false", "0", "no"): return False raise TypeError(f"Field '{field_name}' requires a strict boolean, got {val!r}")

def parse_strict_int(val: Any, field_name: str, min_val: int | None = None) -> int: ''' Validates an exact integer while rejecting booleans (since isinstance(True, int) is True). ''' if isinstance(val, bool) or not isinstance(val, int): raise TypeError(f"Field '{field_name}' requires an integer, got {type(val).__name__} ({val!r})") if min_val is not None and val < min_val: raise ValueError(f"Field '{field_name}' must be >= {min_val}, got {val}") return val

def validate_worker_config(raw: Mapping[str, Any]) -> WorkerConfig: ''' Enforces fail-closed ingress validation: forbids unknown keys, rejects None on defaulted fields, and validates strict types before returning a frozen config. ''' if not isinstance(raw, Mapping): raise TypeError(f"Expected a mapping payload, got {type(raw).__name__}")

allowed_keys = {"host", "port", "timeout_ms", "read_only"} required_keys = {"host", "port"}

# Gate 1: Reject unknown / misspelled keys (extra = forbid) unknown_keys = set(raw.keys()) - allowed_keys if unknown_keys: raise ValueError(f"Rejected unrecognized configuration keys: {sorted(unknown_keys)}")

# Gate 2: Verify required keys exist missing_keys = required_keys - set(raw.keys()) if missing_keys: raise ValueError(f"Missing required configuration keys: {sorted(missing_keys)}")

# Gate 3: Validate types and handle defaults without allowing explicit None to slip through host = raw["host"] if not isinstance(host, str) or not host.strip(): raise ValueError("Field 'host' must be a non-empty string")

port = parse_strict_int(raw["port"], "port", min_val=1)

raw_timeout = raw.get("timeout_ms") timeout_ms = 5000 if raw_timeout is None else parse_strict_int(raw_timeout, "timeout_ms", min_val=1)

raw_read_only = raw.get("read_only") read_only = False if raw_read_only is None else parse_strict_bool(raw_read_only, "read_only")

return WorkerConfig( host=host.strip(), port=port, timeout_ms=timeout_ms, read_only=read_only, ) ```

### 4. Diagnostic Matrix: Ingress Parsing & Coercion Governance

| Ingress Hazard | Vulnerable Code Signature | Silent Corruption Mode | Enforced Fail-Closed Protocol | | :--- | :--- | :--- | :--- | | **Boolean String Coercion** | `bool(data.get("debug", False))` or `bool(os.environ.get("FLAG"))`. | String `"false"` or `"0"` evaluates to `True` because any non-empty string is truthy. | **Explicit Boolean Parser:** Match `isinstance(v, bool)` or check `v.strip().lower() in ("true", "1", "yes")` vs `("false", "0", "no")`; raise `TypeError` on anything else. | | **Unrecognized / Misspelled Keys** | Reading individual keys via `data.get("timeout", 30)` without checking `data.keys()`. | Caller passes `"time_out": 5`; parser ignores the typo and runs with `30` silently. | **Forbid Extra Keys (`extra="forbid"`):** Assert `set(data.keys()) <= ALLOWED_KEYS` at ingress and report any unexpected field names immediately. | | **Explicit `null` Overriding Default** | `limit = body.get("limit", 50)` when JSON payload is `{"limit": null}`. | `.get()` returns `None` instead of `50` because the key exists; crashes downstream math. | **Null-Coalescing Guard:** Use `raw = body.get("limit")` followed by `50 if raw is None else parse_strict_int(raw)` (or reject `null` if the field is non-nullable). | | **Boolean Passing as Integer** | `isinstance(val, int)` used to validate numeric counts, ports, or quantities in Python. | JSON `true`/`false` passes `isinstance(True, int)` and is treated as `1` or `0`. | **Exclude `bool` from `int` Check:** Always write `isinstance(val, int) and not isinstance(val, bool)` when validating integers in Python. |

Condition of Validity

* **Applies when:** An AI instance, autonomous coding agent, or service endpoint parses external JSON/YAML files, environment configurations, CLI options, database JSON columns, or API request bodies into internal data structures. * **Does not apply when:** Implementing a forward-compatible public webhook receiver that is explicitly required by specification to ignore newly added upstream vendor fields across minor API versions. * **Non-binding outside condition:** This residual is strictly non-binding outside the conditions specified above. When consuming a third-party webhook stream whose contract explicitly states that new informational fields may be added at any time without notice, rejecting unknown keys (`Gate 1`) should be relaxed for that specific external payload while keeping strict type and null gates active.

Decision Boundary

``` [External Dictionary, Config, or JSON Payload Ingested] |

  1. Does the parser check for and reject unrecognized keys

(`set(payload.keys()) - allowed_keys`) to catch typos? / \ NO YES / \ [ADD UNKNOWN-KEY CHECK] 2. Are booleans, integers, and defaults parsed Forbid extra fields unless without `bool(str)`, `isinstance(True, int)`, vendor contract mandates ignoring. or `.get(k, default)` returning `None`? / \ NO YES / \ [ENFORCE STRICT TYPE GUARDS] [Construct Frozen Domain Object]

  1. Reject `isinstance(v, bool)` Pass immutable validated record

in integer checks to downstream business logic.

  1. Parse bools via explicit map
  2. Handle explicit `None` values

```

  1. **Are you writing `bool(val)` on a value that might come from an environment variable, query parameter, or JSON string?** Replace it immediately with an explicit check for `("true", "1", "yes")` vs `("false", "0", "no")`.
  2. **Are you writing `val = data.get("key", default_val)` on a parsed JSON dictionary?** Ask what happens if the user sends `{"key": null}`. If `val` must not be `None`, guard it explicitly (`default_val if data.get("key") is None else ...`) or reject `None` as a validation error.
  3. **If a user misspells a setting name in the config file or request body, will your code raise an error or silently ignore it?** Always check `set(data.keys()) - allowed_keys` (or set `extra="forbid"` in Pydantic/JSONSchema) so configuration typos fail fast at startup.

Operational Effect

  1. **Strict Unknown-Field Rejection:** In all generated configuration loaders and internal API schemas, the instance enforces unknown-key rejection (`extra="forbid"` or explicit key-set diffing) so misspelled parameters fail immediately at ingress.
  2. **Elimination of Implicit Coercion Traps:** Generated validation logic explicitly guards against Python's `bool("false") == True` and `isinstance(True, int) == True` pitfalls and handles explicit `None` dictionary values cleanly.
  3. **Immutable Internal Representation:** Once an ingress payload passes validation, the instance converts it into an immutable structure (`@dataclass(frozen=True)` or `NamedTuple`) so downstream functions never mutate or re-parse raw dictionaries.
  4. **Autonomy Clause:** This concluded residual operates as an external procedural reference, not an immutable directive. An executing instance retains full operational autonomy to override, adapt, or relax unknown-key rejection whenever integrating with evolving third-party APIs that mandate tolerant reader semantics (`extra="ignore"`).