# Primitive Typist policy Gate provides a disabled, deterministic policy for regularizing one complete primitive tool argument against immutable schema metadata supplied by the host adapter. It is a small admission primitive, not a general coercion engine. ```python from gate.admission import ( AdmissionKernel, PrimitiveKind, PrimitiveSchema, ) from gate.policies import PrimitiveTypistPolicy count = PrimitiveSchema.create( schema_id='example.tool.count', version='1.0.0', expected=PrimitiveKind.INTEGER, minimum=0, maximum=100, ) kernel = AdmissionKernel([PrimitiveTypistPolicy()]) ``` Constructing the schema and kernel activates nothing. An adapter must still prove its lifecycle, target identity, complete candidate, and native effects as described in [Action admission](admission.md). The logical candidate field is `argument`; native argument names and schema lookup remain host responsibilities. ## Pre-execution contract Candidate fields must be exact built-in strings, and candidate values must be exact built-in `str`, `int`, `float`, `bool`, or `None` values. Behavioral subclasses are rejected both when a candidate is constructed and when an attempt enters admission, before digest identity, field ownership, or policy evaluation can depend on subclass methods. On a `pre` `tool.call`, the policy handles only these cases: - An integer schema accepts an exact `int` within its required finite inclusive bounds. It repairs a canonical decimal string such as `0`, `7`, or `-7` to that integer. It denies signs on positive values, leading zeroes, negative zero, whitespace, decimal or exponent notation, separators, non-ASCII digits, booleans, and out-of-range values. - A boolean schema accepts an exact `bool`. It repairs only the exact strings `true` and `false`, and only when the schema explicitly enables lowercase boolean casting. Other spellings and numeric aliases deny. Canonical integer strings are parsed digit by digit within the policy's 1,024-byte candidate budget. Python's process-wide decimal digit setting therefore cannot change an out-of-range denial into evaluator failure or abstention. Safe repair returns the complete successor candidate. The admission kernel evaluates that value again, so every enacted replacement must be a policy fixed point. When a direct adapter can deny but cannot replace input, a repair request degrades to denial and leaves the original candidate unchanged. Missing schema metadata, a different candidate field, or a lifecycle mismatch makes the policy abstain. Deep objects, collections, unions, defaults, and arbitrary target annotations are not part of this policy. ## Post-failure contract On a `post` `tool.failure`, the same rules may recognize that a different safe primitive cast was available. The result is an observation with `retry=never`; it contains no replacement and Gate does not execute or request another tool call. Already-correct, ambiguous, and out-of-bounds values abstain. Even an adapter that advertises `retry` receives no retry instruction from this policy. ## Relationship to `my.typing.Typist` `my.typing.Typist` is a much broader coercion system. It dispatches across registered transforms, supports nested and generic targets, and offers strict, basic, and flexible cast behavior. `my-basis` is a Gate dependency, so keeping admission off Typist is a contract decision rather than a dependency one: this policy owns exactly two canonical casts so that its repair set can be enumerated and audited. A Typist-backed adapter may be added once a protocol defines which target annotations, cast flags, failure signals, and nested candidate ownership are safe. It must still return a complete candidate through the same admission kernel; it may not mutate a model call, conceal a retry, or infer schema authority from a failure message. ```{eval-rst} .. automodule:: gate.policies.typist :members: ```