The published goal, as a stranger sees it.
The promise, at a distance — and its picture. The goal's name, when it
is, how precisely that date is known, what kind of goal it is, the sport,
the dated history of it changing, and the goal's picture: wonderland
goals.md makes the picture the page's highlight and what the link preview
carries, both sides published, what the goal asks and where the athlete
stands, gap and all. factors is the owner-side shape exactly
(:class:~cheshire.goals.models.GoalFactor): positions on the goal's own
scale, never the readings behind them — a body-read factor publishes as a
position, and the sleep or recovery data underneath it never leaves.
What is absent is still the point. The document body, the checkpoints and
fallbacks, the athlete's reasons — the why and what chose the event stay
theirs to tell (wonderland #45) — and every session id, none of it is here.
Sharing a goal must feel safe; it must never feel like exposing something
internal. Three layers keep it that way: this model is extra="forbid" so
an added field cannot ride along silently, the validator below walks the
serialized payload for forbidden keys and internal markers, and the row is
projected field by named field rather than dumped.
The field list is settled by wonderland goals.md's share-page section
(the human review the earlier note here waited on). Trimming a field is
cheap; un-leaking one is not.