Skip to content

@required is a property of (schema × producer), not of the schema — a shared response object cannot express it #202

Description

@dmealing

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions