Skip to content

fix: enforce uniqueItems on generated array fields - #59

Merged
damaz91 merged 2 commits into
Universal-Commerce-Protocol:mainfrom
XiaolongZhang-TT:fix/enforce-unique-items
Aug 3, 2026
Merged

fix: enforce uniqueItems on generated array fields#59
damaz91 merged 2 commits into
Universal-Commerce-Protocol:mainfrom
XiaolongZhang-TT:fix/enforce-unique-items

Conversation

@XiaolongZhang-TT

Copy link
Copy Markdown
Contributor

Description

datamodel-code-generator drops uniqueItems, so generated list fields accept duplicate entries in violation of the schema. Three UCP array properties declare uniqueItems: true at the 2026-04-08 release this SDK targets: context.eligibility, card_payment_instrument.brands, and identity_linking.required_claims.

This extends postprocess_models.py to collect array property names declared with uniqueItems and inject a field_validator(mode="after") into each generated class that declares a matching list field. The check uses equality (item in seen) rather than a set, so it holds for both hashable (str) and unhashable (Pydantic model) items. It mirrors the data-driven, idempotent approach already used for minProperties (#55), and complements the open contains work in #57 — the third constraint the generator drops.

Two generated models carry the affected list fields and gain the validator: Context.eligibility and Constraints.brands. required_claims has no generated typed field (ScopePolicy is extra="allow" free-form, so the field is an untyped extra key), so it is not enforceable and is skipped. Verified against the real release/2026-04-08 schemas that exactly these two models are touched on a fresh tree.

Note: like #57, this modifies postprocess_models.py, so it may need a rebase if #57 lands first.

Category (Required)

Please select one or more categories that apply to this change.

  • Core Protocol: Changes to the base communication layer, global context, or breaking refactors. (Requires Technical Council approval)
  • Governance/Contributing: Updates to GOVERNANCE.md, CONTRIBUTING.md, or CODEOWNERS. (Requires Governance Council approval)
  • Capability: New schemas (Discovery, Cart, etc.) or extensions. (Requires Maintainer approval)
  • Documentation: Updates to README, or documentations regarding schema or capabilities. (Requires Maintainer approval)
  • Infrastructure: CI/CD, Linters, or build scripts. (Requires DevOps Maintainer approval)
  • Maintenance: Version bumps, lockfile updates, or minor bug fixes. (Requires DevOps Maintainer approval)
  • SDK: Language-specific SDK updates and releases. (Requires DevOps Maintainer approval)
  • Samples / Conformance: Maintaining samples and the conformance suite. (Requires Maintainer approval)
  • UCP Schema: Changes to the ucp-schema tool (resolver, linter, validator). (Requires Maintainer approval)
  • Community Health (.github): Updates to templates, workflows, or org-level configs. (Requires DevOps Maintainer approval)

Related Issues

None. (Follow-up to the constraint-enforcement work in #55; complements the open contains enforcement in #57.)

Checklist

  • I have followed the Contributing Guide (including Conventional Commits title requirements and ! for breaking changes).
  • I have updated the documentation (if applicable).
  • My changes pass all local linting and formatting checks.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • (For Core/Capability) I have included/updated the relevant JSON schemas.
  • I have regenerated Python Pydantic models by running generate_models.sh under python_sdk.

Screenshots / Logs (if applicable)

The injected validator (e.g. Constraints.brands):

@field_validator("brands", mode="after")def_enforce_unique_items_brands(cls, value): # noqa: N805"""JSON Schema uniqueItems: reject duplicate entries."""ifvalueisNone:
returnvalueseen= []
foriteminvalue:
ifiteminseen:
raiseValueError("Items must be unique (schema uniqueItems=true)")
seen.append(item)
returnvalue

Before: Constraints(brands=["visa", "visa"]) was accepted. After: it raises ValidationError ("Items must be unique").

postprocess run reports: uniqueItems fields ['brands', 'eligibility', 'required_claims'] -> 2 module(s) patched (context.py, card_payment_instrument.py).

Full suite green as CI runs it (python -m unittest discover -s tests -p "test_*.py"): 35 passed, 0 failed. ruff (--ignore D,E501, matching the pre-commit hook), ruff format, and codespell are clean.

@damaz91damaz91 added status:needs-triage Signal that the PR is ready for human triage status:under-review and removed status:needs-triage Signal that the PR is ready for human triage labels Aug 3, 2026
datamodel-code-generator drops `uniqueItems`, so generated list fields
accept duplicate entries in violation of the schema. Three UCP array
properties declare `uniqueItems: true` at 2026-04-08: context.eligibility,
card_payment_instrument.brands, and identity_linking.required_claims.
Extend postprocess_models.py to collect array property names declared with
`uniqueItems` and inject a `field_validator(mode="after")` into each
generated class that declares a matching list field. The check uses
equality (`item in seen`) so it holds for both hashable (str) and
unhashable (model) items. Mirrors the data-driven, idempotent approach used
for minProperties (Universal-Commerce-Protocol#55).
Two generated models carry the affected list fields and gain the
validator: Context.eligibility and Constraints.brands. required_claims has
no generated typed field (ScopePolicy is extra="allow" free-form), so it is
not enforceable and is skipped.
Add UniqueItemsInjectorTest (scan walks nested properties and ignores
non-arrays; injection targets only matching list fields, is idempotent, and
enforces uniqueness when exec'd) and UniqueItemsSemanticTest (Constraints
rejects duplicate brands, accepts unique/None).
@damaz91
damaz91force-pushed the fix/enforce-unique-items branch from 55d3608 to 0be0897CompareAugust 3, 2026 08:57

@damaz91damaz91 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebased on main to resolve conflicts with #57 (contains validation). Verified all tests pass. Approving.

@damaz91
damaz91 merged commit ba23d97 into Universal-Commerce-Protocol:mainAug 3, 2026
14 checks passed
@XiaolongZhang-TT
XiaolongZhang-TT deleted the fix/enforce-unique-items branch August 7, 2026 09:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@XiaolongZhang-TT@damaz91