Summary
@required is declared on the field, so it is global to the object. But a response object is often populated by more than one producer — two prompts, two API versions, two callers — and those producers can have genuinely different contracts over the same shape. When they do, the shared object cannot express required-ness at all, and the natural, evidence-driven move actively breaks one of them.
The shape
One response object, two producers:
- Producer A mandates fields
X, Y, Z — present in 100% of observed responses.
- Producer B is explicitly instructed not to emit
X, Y, Z — they are meaningless in its context.
Because @required is global, X/Y/Z cannot be marked. Marking them makes producer B report a lost required field on every single call.
So the fields most worth monitoring on producer A are exactly the ones that must stay unmarked. And the trap is quiet: if you mark them from measured data — 100% present, textbook zero-noise markers, exactly what a "mark @required on evidence, not taste" rule tells you to do — you silently break the other producer. Only reading producer B's instructions reveals it, and nothing in the metadata points you there.
Why this is worse than warning noise
If hasLostRequired() is wired to any remediation — a retry, a model escalation, an alert — then a mismarked field doesn't merely spam warnings, it fires the remediation on every call from the other producer, permanently and invisibly. A loss-detector that cries wolf gets muted; a remediation that fires on a false loss just costs money forever.
Workaround (what we shipped)
Split the root object per producer, with both roots reusing the same child views via @objectRef. Nothing is duplicated — only the root-level field set differs — and each producer then declares an honest required set.
That is arguably the correct model, and I'd recommend it to anyone hitting this. But it is a structural workaround for a vocabulary gap, and it is not discoverable: nothing warns you that the object has two producers, and the metadata gives no hint that marking a field is unsafe.
Ask (any one of)
- Scope required-ness to a named context — e.g.
@requiredIn: [producerA] — resolved at extract time by passing the context.
- Or an extract-time required-set override on
ExtractOptions.
- Or, at minimum, document the "split the root per producer" pattern, since the failure mode is silent and the wrong path is the one the evidence points at.
Related: #199, #201
Summary
@requiredis declared on the field, so it is global to the object. But a response object is often populated by more than one producer — two prompts, two API versions, two callers — and those producers can have genuinely different contracts over the same shape. When they do, the shared object cannot express required-ness at all, and the natural, evidence-driven move actively breaks one of them.The shape
One response object, two producers:
X,Y,Z— present in 100% of observed responses.X,Y,Z— they are meaningless in its context.Because
@requiredis global,X/Y/Zcannot be marked. Marking them makes producer B report a lost required field on every single call.So the fields most worth monitoring on producer A are exactly the ones that must stay unmarked. And the trap is quiet: if you mark them from measured data — 100% present, textbook zero-noise markers, exactly what a "mark
@requiredon evidence, not taste" rule tells you to do — you silently break the other producer. Only reading producer B's instructions reveals it, and nothing in the metadata points you there.Why this is worse than warning noise
If
hasLostRequired()is wired to any remediation — a retry, a model escalation, an alert — then a mismarked field doesn't merely spam warnings, it fires the remediation on every call from the other producer, permanently and invisibly. A loss-detector that cries wolf gets muted; a remediation that fires on a false loss just costs money forever.Workaround (what we shipped)
Split the root object per producer, with both roots reusing the same child views via
@objectRef. Nothing is duplicated — only the root-level field set differs — and each producer then declares an honest required set.That is arguably the correct model, and I'd recommend it to anyone hitting this. But it is a structural workaround for a vocabulary gap, and it is not discoverable: nothing warns you that the object has two producers, and the metadata gives no hint that marking a field is unsafe.
Ask (any one of)
@requiredIn: [producerA]— resolved at extract time by passing the context.ExtractOptions.Related: #199, #201