## AirField 0.4.0: All metadata is typed, all of it

Every `AirField()` parameter now produces a typed, frozen dataclass in `field_info.metadata`. `primary_key`, `autofocus`, `label`, `widget`, `type`, `placeholder`, `help_text`, `choices` are all discoverable with `isinstance` checks, the same way Pydantic discovers `annotated-types` constraints. `json_schema_extra` is no longer written by AirField.

```
pip install --upgrade AirField
```

### What's new

- **`PrimaryKey` type.** Primary key fields affect presentation across every context: hidden in create forms, read-only in edit, displayed as links in tables. `PrimaryKey` is now a first-class `BasePresentation` type that consumers find with `isinstance(m, PrimaryKey)`.

- **`Autofocus` type.** A renderer-agnostic focus hint. In a form it sets the autofocus attribute; in a CLI it's the first prompted field; in a TUI it receives initial widget focus.

### What's changed

- **AirField no longer writes to `json_schema_extra`.** All presentation metadata lives in `field_info.metadata` as typed objects. Consumers that were reading `json_schema_extra` for label, widget, autofocus, or primary_key need to switch to `isinstance` checks on `field_info.metadata`. If you pass `json_schema_extra` explicitly, it still flows through to Pydantic as a standard Field parameter.

- **Unknown kwargs go straight to Pydantic.** AirField no longer sorts kwargs into "Pydantic-known" and "extra" buckets. Everything AirField doesn't recognize passes directly to `pydantic.Field()`. Pydantic v2 issues a deprecation warning for unrecognized kwargs; Pydantic v3 will raise. The `_PYDANTIC_FIELD_PARAMS` frozenset that had to track every Pydantic release is gone.

- **The `type="email"` encoding bug is fixed.** Previously, `AirField(type="email")` stored `{"email": True}` in `json_schema_extra`. Now it produces `Widget(kind="email")` in metadata, which is what consumers actually need.

- **Both declaration paths converge.** `AirField(type="email", label="Email")` and `Annotated[str, Widget("email"), Label("Email")]` produce identical metadata. One `isinstance` loop finds everything regardless of how the field was declared.

### Contributors

[@audreyfeldroy](https://github.com/audreyfeldroy) ([Audrey M. Roy Greenfeld](https://audrey.feldroy.com/)) designed and built this release: the typed metadata architecture, PrimaryKey and Autofocus types, and the elimination of json_schema_extra.
