# Teaching

mximp is taught, never trained. The unit of teaching is a **proposal**: a schema for a bucket, plus the values one message is expected to yield. The moment it is made, the schema is run against the message; what the run does not reproduce is listed as `unreproducible`. Nothing the author read is ever stored as a value; only what the deterministic run produced is.

The author is your agent, using the [`emailimport` skill](/skills/emailimport.md). A hosted author on Cloudflare Workers AI, opt-in per tenant, is designed and not yet built; it makes the same object.

## The loop

1. `get_message` on an unrouted message, or one in a bucket without a schema. It carries a `fingerprint` of its layout.
2. `create_bucket` with a rule if none matches.
3. `propose_schema {message_id, bucket, schema, expected}`. The result has `dry_run.checks` per expected field, `unreproducible`, and `reader_evidence` (where each value was seen: body or which attachment). A task is opened on the message so it stays retained.
4. Fix and propose again until every expected value reproduces, or accept that a field will `requires_human`.
5. `approve_proposal`: the bucket takes the schema (unreproducible fields marked `requires_human`), the message becomes a test case with the reproduced values expected, and it is reprocessed under the new schema. The bucket's existing suite gates the change as `update_bucket` does; `force` applies over failures. `reject_proposal` records a reason and leaves the bucket alone.

`list_proposals` and `get_proposal` show pending, approved and rejected proposals with their dry runs and decisions.

## Fingerprints

Each message's `fingerprint` is structural: the DKIM-aligned sender domain, the MIME shape, the pattern of attachment names, the ordered set of labels, a histogram of line lengths. Two messages from one sender on one template share it. It is computed as the message is processed and carried on proposals and captures; nothing in it is text the message said, and comparing two is equality, not a score. A message on a known fingerprint that stops fitting is a layout change: propose against it, and the new message joins the suite beside the old.
