Skip to content

docs: disclose python-sdk#34, and guard for its fix landing - #14

Open
chaz8081 wants to merge 1 commit into
mainfrom
variant-refs
Open

docs: disclose python-sdk#34, and guard for its fix landing#14
chaz8081 wants to merge 1 commit into
mainfrom
variant-refs

Conversation

@chaz8081

Copy link
Copy Markdown
Owner

Found while sanity-checking upstream for movement. Both pins are current (spec a2d8bf0, python-sdk d650f0b, zero drift) — but python-sdk#34, open since April, describes a defect we reproduce, and it affects consumers today.

The defect

Variant generation rewrites external $refs only inside properties. A schema whose alternatives live in a top-level oneOf/anyOf/allOf keeps its refs pointing at the base response files, so the generated request variant wraps response types:

type FulfillmentDestinationCreateRequest struct {
	RetailLocation      *RetailLocation      `json:"-"`  // want RetailLocationCreateRequest
	ShippingDestination *ShippingDestination `json:"-"`  // want ShippingDestinationCreateRequest
}

ShippingDestination requires id; its request variant does not, because a client creating a destination has no server-assigned id yet. Demonstrated, not inferred:

validate: id: required property is missing

on {"type":"shipping","address":{"country":"US"}} — a spec-valid create request.

Counted precisely

The raw number overstates this three ways, so:

count
refs in variant files pointing at a base schema 12
…where the base actually has a variant (genuinely wrong) 6
…where the variant differs from the base (real consequence) 4

The six message_* refs are correctmessage_error, message_info and message_warning have no request variants, so the base is the only thing to point at. Of the six that are wrong, two are inert: postal_address's variant is identical to its base in both properties and required. The four that matter are fulfillment_destination's create and update variants.

Why we reproduce it rather than fix it

Preprocessor parity is byte-for-byte, so upstream's preprocessing defects are ours until upstream fixes them. Diverging unilaterally would break the parity that makes the committed goldens trustworthy — the same reasoning already applied to the dangling-$ref defect before it was fixed.

Why this needs an explicit guard

The differential harness cannot catch this class, by construction. Validate and the oracle both read the same preprocessed schema, so both are wrong in the same way and agree. "Zero disagreements" is true here and tells you nothing.

It is the clearest example in the repo of why agreement between two implementations is evidence about enforcement and not about meaning — and why preprocessor parity is layer 1 rather than a nicety.

TestVariantUnionRefsStillPointAtBaseSchemas pins the exact set, so upstream's fix arrives as a build failure that says to re-pin and port, rather than as something noticed on the next manual sweep. It fails in both directions: if the set shrinks (fixed upstream) or grows (new case, or a regression).

Upstream status

Two PRs are in motion and they are related, not competing. #35 (April, community) is the preprocessor fix. #83 (opened today by a maintainer) fixes a SyntaxError in their downstream Python codegen that #35's change triggers — longer variant refs push lines past the wrap width and their splice logic emits a double comma; its comment cites "#34/#35" directly. So the path is being cleared for the four-month-old PR.

Only #35 would affect us. When it lands: re-pin goldens, port, and expect a breaking change as those variants start wrapping request types.

Verification

gofmt clean, go build, go vet, root tests and the conformance module all pass. README example re-extracted and run verbatim; output matched.

Upstream variant generation rewrites external $refs only inside
`properties`, so a schema whose alternatives live in a top-level
oneOf/anyOf/allOf keeps refs pointing at the base response files. The
generated request variant then wraps response types:
FulfillmentDestinationCreateRequest holds *ShippingDestination, which
requires `id`, rather than *ShippingDestinationCreateRequest, which does
not. A spec-valid create request is rejected with "id: required property
is missing".

Reported upstream in April 2026 and still open. ucp-go reproduces it
deliberately — preprocessor parity is byte-for-byte, so diverging
unilaterally would break the parity that makes the goldens trustworthy,
the same reasoning already applied to the dangling-$ref defect.

Counted precisely rather than loosely, because the raw number overstates
it three ways. Twelve refs in variant files point at a base schema. Six
are correct: message_error/info/warning have no request variants, so the
base is the only thing to point at. Of the six that are wrong, two are
inert — postal_address's variant is identical to its base in properties
and required — leaving four with a behavioural consequence, all in the
fulfillment_destination create and update variants.

Documented in the gap list rather than only in the upstream history,
because it affects consumers today and that is where someone looks to
find out what does not work.

TestVariantUnionRefsStillPointAtBaseSchemas pins the exact set. The
differential harness structurally cannot catch this class — Validate and
the oracle read the same preprocessed schema, are wrong the same way and
agree, so zero disagreements says nothing here — which makes an explicit
guard the only thing that turns upstream's eventual fix into a build
failure telling us to re-pin and port.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant