The proposed change looks harmless in a pull request: add a delivery date, introduce a “preorder” status, and add an optional region field. Gemini still returns valid JSON. The new service accepts it. Yet an older inventory exporter rejects the unfamiliar status, a dashboard treats a missing date as immediately available, and a replay worker validates last month's records against this week's schema. This is a contract migration problem, even when every individual model response satisfies its requested schema.
Consider this article a design review for an existing Gemini structured-output integration. The hypothetical application already reads supplier availability bulletins and produces records used by an inventory dashboard, a CSV exporter, and a historical replay worker. The review concerns how version two reaches those consumers without rewriting the meaning of version one. For initial extraction configuration, the existing Gemini JSON extraction tutorial covers that earlier task. Here, a successful first extraction is a prerequisite, not the destination.
The proposed contract, stated precisely
Version one has three availability states: available, unavailable, and unknown. Version two adds preorder and a nullable expected date. It also permits an optional region field for suppliers that explicitly identify a market. The generated record is only an observation about the bulletin. It cannot allocate inventory, accept a preorder, or change a fulfillment promise. Separating those business actions from the observation allows a consumer to reject an unfamiliar interpretation without losing the original evidence or triggering a transaction.
The migration owner should publish a field-level meaning alongside the schema. “Unknown date” means the producer has not established a source-supported date; it does not mean immediate delivery. “Region absent” means the record does not supply region information. Absence alone does not identify the producer version or prove that the bulletin lacks a region; a supplied region must be source-supported. If the application needs to distinguish missing, ambiguous, and explicitly not applicable, a single nullable string is insufficient. Add a separate reason field in a planned version instead of allowing each consumer to invent its own interpretation.
Google's structured output documentation describes its JSON Schema subset and the current response-format envelope. That contract controls the shape of the generated answer. It does not decide whether a new enum value is safe for an old exporter or whether a nullable date should block a sales workflow. Those are compatibility commitments between your producer and consumers, and they belong in the review even when the API accepts the schema without complaint.
| Proposed change | Old reader risk | Review decision |
|---|---|---|
| Add preorder enum value | Exhaustive switch fails or misclassifies | Update readers before producing it |
| Add required nullable expected_date | Closed old schema rejects the new key | Use versioned envelopes or a legacy projection |
| Add optional region | Closed old readers reject the added key; missing differs from null | Document both presence and value semantics |
| Rename item_id to sku | Join key disappears | Keep the identifier stable during this rollout |
Nullable and optional answer different questions
A nullable field allows the JSON value null. An optional property allows the key to be absent. A required nullable property must appear and may contain null. An optional non-nullable property can be omitted, but must contain the declared non-null value when present. The official JSON Schema null reference distinguishes null from absence; the object reference explains how properties and required keys interact. Review these as two independent choices for every changed field.
In this example, expected_date is required and nullable in version two because every new observation should explicitly record whether a date was established. Region is a new optional, non-nullable field: a version-two producer may omit it, but a producer that includes it must supply a string. Do not serialize every missing optional value to null merely for convenience. That transformation changes the data contract and can fail validation even though a Python dictionary or database column makes the two cases look similar.
Pydantic users should inspect generated schemas during review. The Pydantic field documentation explains default-value behavior: a nullable type annotation by itself does not establish an omitted-field default. A declaration such as str | None and one with = None can therefore describe different presence rules. The review artifact should include the emitted JSON Schema, rather than only a screenshot of the Python model, because the schema is what the Gemini request actually receives.
Also inspect what happens after validation. Some serializers omit unset fields, some omit null values, and some include defaults. An object can pass the producer's validation and still change shape when serialized onto a queue. Capture the exact bytes of representative outbound messages in your compatibility fixtures. This catches disagreements between the generation schema, the application model, and the wire representation before they become a debugging exercise involving three teams and several deployment versions.
Separate the API migration from the business-schema migration
The reference implementation uses native Gemini Interactions. Google's current overview recommends it for new projects and keeps the older generateContent interface supported. If your service also changes API surfaces, split that transport change from the availability-schema rollout. First establish equivalent version-one behavior on the chosen transport. Then introduce version two. Otherwise a failed replay could come from a response parser change, an enum change, or a missing-field change, all within the same release.
The official Interactions migration guide describes the changed request and response structures. The current structured response configuration is a top-level response_format containing type, mime_type, and schema. Avoid carrying old generation configuration names into the new call. The existing Gemini parameter migration article is adjacent background on request evolution; it should not substitute for checking the exact interface and schema version used by this service.
Below is a bounded upstream reference request. It requires a Google API key, an account-available model selected through the environment, and the jsonschema package for local contract validation. The fixture bulletin is invented and the script makes a paid API call if executed. Its purpose is to show where version selection, native response handling, and local validation meet. It does not claim that a gateway implements Interactions or that a particular model identifier is available in every account.
The producer supplies the envelope's contract identifier after validation. The generated schema_version field must agree with the requested schema, but it does not select its own validator. Choose the validator from the job configuration first, validate the response against it, then attach provenance. Otherwise a model-generated version number could route an invalid record to a more permissive reader. Retain the requested schema digest and prompt version with the job so a later replay can explain which contract actually governed generation.
Review compatibility in both directions
Ask whether an old reader can consume a new record and whether a new reader can consume an old record. These are different tests. A new optional field may seem additive, yet an old reader using additionalProperties false will reject it. A new required nullable field lets the new producer represent uncertainty but causes historical records without that key to fail the new schema. An expanded enum widens producer behavior while potentially breaking consumer code that assumes the earlier finite set.
Do not resolve those failures by turning off validation everywhere. Retain closed validation within each version and introduce an explicit dispatch boundary that recognizes supported envelopes. A version-two consumer may support a version-one adapter, but it should not reinterpret arbitrary unversioned objects as current data. The event-sourcing discussion is useful for replay design: preserve the original event and record the adaptation separately, so historical interpretation remains inspectable.
A legacy projection is sometimes necessary while a consumer waits for an update. Its mapping must be approved by the business owner. In this example, preorder maps to unknown for the old dashboard, with an explicit loss marker outside the legacy payload. It must never map to available because the bulletin has not established immediate stock. If the old consumer cannot handle unknown safely, the correct behavior is to hold the record, not invent a more convenient old value.
This adapter assumes the incoming version-two record has already passed its complete schema validator. It illustrates a semantic projection, not a substitute validator. Its loss metadata travels through an administrative envelope, while the legacy consumer receives only the legacy record. The original observation remains unchanged. Document that split in the consumer contract so a queue integration does not accidentally send the adapter's entire wrapper to a reader expecting the smaller version-one object.
The rollout decision should name every reader
Build a compatibility matrix using actual deployed reader versions. Include the CSV exporter, dashboard, archive loader, replay worker, and any manual download tool that parses these records. Give each a clear state: understands version two, accepts the approved projection, or must not receive version two. “The backend is updated” is insufficient when a scheduled job still ships an older validator. Identify the owner of each reader and the deployment condition required before the producer changes its output.
Deploy readers first, then run version-two generation in a shadow path on approved inputs. Shadow results should be compared and stored without replacing the operational record. Compare disagreements by meaning: newly detected preorder, newly explicit null date, omitted region, and identifier drift. The existing validation framework offers broader output-review context, but this rollout should measure contract transitions rather than an undifferentiated accuracy score.
When switching the producer, keep version-one read support for the period required by retained records and delayed messages. Rollback means routing new jobs back to the earlier producer contract; it does not mean overwriting already emitted version-two records with version one. Track which job configuration created each object and avoid rerunning successful jobs simply because the schema changed. A deliberate backfill is a separate operation with its own source selection, output version, and consumer acceptance plan.
Before approving removal of version one, replay representative archived records through the remaining supported paths. Include omitted optional fields, explicit nulls, an unknown enum value, unexpected extra properties, and a malformed date. The jsonschema validation documentation explains why format checking requires explicit configuration. Your compatibility suite should detect failures that the generation service never sees, including serialization, dispatch, projections, and downstream assumptions about missing values.
Reserve a clear response for an unsupported future version. A reader that understands versions one and two should quarantine version three with its original envelope intact, rather than trying version two and ignoring unknown fields. That behavior matters during partial deployments and emergency rollbacks. Include it in the acceptance matrix so the organization can distinguish an intentional compatibility stop from data corruption or an intermittent model failure.
Approve the migration with a concrete pilot
The review can close when the meaning of each changed field is agreed, every consumer has a supported route, and rollback preserves record history. Assign each consumer an owner and record the producer contract, consumer version, and projection applied to every rejected record. The gateway governance guide supplies the wider ownership context; those version fields make a migration failure actionable without exposing the full bulletin in ordinary logs. A small migration with an explicit legacy projection is easier to inspect than a broad cleanup that simultaneously renames fields, changes prompts, changes models, and replaces the endpoint.
To evaluate this contract through 4SAPI, inspect account model access at 4SAPI and confirm the exact structured-output format in the API documentation. The Gemini endpoint comparison provides integration context, while the native example above remains a separate credential and transport path. Start with one synthetic bulletin, validate the returned version, then run the same record through every named consumer before enabling version-two writes.




