Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 5 additions & 20 deletions resources/icarReproEmbryoResource.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"description": "Describes an implanted embryo.",

"allOf": [{
"allOf": [
{
"$ref": "../resources/icarResource.json"
},
{
"$ref": "../types/icarReproSireInfoType.json"
},
{
"type": "object",

Expand All @@ -30,25 +34,6 @@
"donorURI": {
"type": "string",
"description": "URI to an AnimalCoreResource for the donor dam."
},
"sireIdentifiers": {
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this properties are replaced, there will be a breaking change!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@AndreasSchultzGEA Thanks for raising this! I totally get why moving the properties into a common type can look like a breaking change at first glance.
If we focus on the actual JSON payloads, nothing really changes. The same properties are still there, at the same level, with the same names and types. From the consumer side, the payload looks exactly the same as before.
So any previously generated code that expects these properties in each schema should continue to work without issues, since the serialized JSON structure hasn’t changed.
Where it might feel like a breaking change is on the code generation side, since the schema structure changes and generators will produce slightly different models. But both the old and the new generated code versions still support the same JSON payload structure. So in terms of the actual data contract, nothing breaks.

That’s why I’d consider this more of a schema refactoring than a real breaking change.

Image

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree it is a schema refactoring and not a breaking change to the schema. But to Andreas' point, how substantial are the changes to the generated code in C# and Java? Because if developers have to change a lot of their code that references the modified classes, it is still a breaking change for them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for your very valuable comments.

To summarize, there are three levels of compatibility we need to consider:

  1. JSON payload – non-breaking → minor version
    The JSON payload remains unchanged — same fields, same structure — so the wire contract is fully backward compatible.

  2. Generated API client/server code – non-breaking → minor version
    The generated API code continues to support the same payload, so from an API usage perspective it also remains backward compatible.

  3. Application internal logic that depends on generated models – potentially breaking → major version
    If an application’s internal logic depends directly on the previously generated model structure (for example, specific class hierarchy, inheritance, database mappings, or integrations with other components), then regenerating the models from the updated schema could introduce breaking changes at compile time. In that scenario, the impact would be considered a major change for those consumers.

@AndreasSchultzGEA you are refering to the third level, right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@AlexeyHardCode Yes, I do.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@AndreasSchultzGEA yes, I fully agree that we should always keep this in mind. So, you propose to keep this refactoring ouside this minor update?
@cookeac I’m wondering what level of compatibility guarantee ICAR ADE itself is expected to provide. Have we formally defined this somewhere?

From my perspective, the scope of compatibility for ICAR ADE updates could be structured as follows:

  1. JSON payload: The external data structure must remain stable — same fields, same structure, same semantics.
  2. Spec-level compatibility: Schema validity must be preserved, including consistent required/optional rules, types, and constraints.
  3. Code generation: At minimum, commonly used generators (e.g., C#, Java) should continue to produce usable output that correctly accepts and produces the same payloads.
  4. Consumer internal logic coupling: The most challenging aspect is applications that tightly couple their internal logic to the generated model hierarchy (e.g., database mappings, reflection usage, inheritance assumptions, etc.).
    While we should acknowledge this risk and try to minimize unnecessary disruption, it may not be realistic to block schema refactoring solely because some internal implementations depend on specific model structures.

Copy link
Collaborator

Choose a reason for hiding this comment

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

At our meetings today we agreed that this can be merged once we have some brief documentation to accompany the 1.6 release so that users know that if they regenerate their code from the schema, they may need to change how they reference fields in these objects.
There will not be a breaking change for users who are interacting with another service as the JSON itself is not changed.

"type": "array",
"items": {
"$ref": "../types/icarAnimalIdentifierType.json"
},
"description": "One or more unique scheme/identifier combinations for the sire."
},
"sireOfficialName": {
"type": "string",
"description": "Official herdbook name of the sire."
},
"sireURI": {
"type": "string",
"description": "URI to an AnimalCoreResource for the sire."
},
"sirePrimaryBreed": {
"$ref": "../types/icarBreedIdentifierType.json",
"description": "ICAR Breed code for the sire. The usage of this property is not reasonable if more than one sire is provided."
}
}
}
Expand Down
25 changes: 5 additions & 20 deletions resources/icarReproInseminationEventResource.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"description": "Event for recording natural or artificial insemination, including embryo transfer.",

"allOf": [{
"allOf": [
{
"$ref": "../resources/icarAnimalEventCoreResource.json"
},
{
"$ref": "../types/icarReproSireInfoType.json"
},
{
"type": "object",

Expand All @@ -19,25 +23,6 @@
"inseminationType": {
"$ref": "../enums/icarReproInseminationType.json"
},
"sireIdentifiers": {
"type": "array",
"items": {
"$ref": "../types/icarAnimalIdentifierType.json"
},
"description": "Unique scheme/identifier combinations for the sire, including official ID and Herdbook."
},
"sireOfficialName": {
"type": "string",
"description": "Official herdbook name of the sire."
},
"sireURI": {
"type": "string",
"description": "URI to an AnimalCoreResource for the sire."
},
"sirePrimaryBreed": {
"$ref": "../types/icarBreedIdentifierType.json",
"description": "ICAR Breed code for the sire. The usage of this property is not reasonable if more than one sire is provided."
},
"straw": {
"$ref": "../resources/icarReproSemenStrawResource.json",
"description": "Details of the straw, which may also include sire details."
Expand Down
25 changes: 5 additions & 20 deletions resources/icarReproSemenStrawResource.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"description": "Describes a semen straw",

"allOf": [{
"allOf": [
{
"$ref": "../resources/icarResource.json"
},
{
"$ref": "../types/icarReproSireInfoType.json"
},
{
"type": "object",

Expand All @@ -24,25 +28,6 @@
"description": "RFC3339 UTC date/time of collection (see https://ijmacd.github.io/rfc3339-iso8601/ for format guidance).",
"$ref": "../types/icarDateTimeType.json"
},
"sireIdentifiers": {
"type": "array",
"items": {
"$ref": "../types/icarAnimalIdentifierType.json"
},
"description": "One or more unique scheme/identifier combinations for the sire."
},
"sireOfficialName": {
"type": "string",
"description": "Official herdbook name of the sire."
},
"sireURI": {
"type": "string",
"description": "URI to an AnimalCoreResource for the sire."
},
"sirePrimaryBreed": {
"$ref": "../types/icarBreedIdentifierType.json",
"description": "ICAR Breed code for the sire. The usage of this property is not reasonable if more than one sire is provided."
},
"preservationType": {
"$ref": "../enums/icarReproSemenPreservationType.json",
"description": "The method of preservation of the semen (liquid, frozen)."
Expand Down
27 changes: 27 additions & 0 deletions types/icarReproSireInfoType.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"description": "Describes sire information related to a reproductive event.",

"type": "object",

"properties": {
"sireIdentifiers": {
"type": "array",
"items": {
"$ref": "../types/icarAnimalIdentifierType.json"
},
"description": "One or more unique scheme/identifier combinations for the sire."
},
"sireOfficialName": {
"type": "string",
"description": "Official herdbook name of the sire."
},
"sireURI": {
"type": "string",
"description": "URI to an AnimalCoreResource for the sire."
},
"sirePrimaryBreed": {
"$ref": "../types/icarBreedIdentifierType.json",
"description": "ICAR Breed code for the sire. The usage of this property is not reasonable if more than one sire is provided."
}
}
}
64 changes: 28 additions & 36 deletions types/icarSireRecommendationType.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
{
"description": "Gives one possible sire recommended to use on an animal.",

"type": "object",

"properties": {
"recommendationType": {
"$ref": "../enums/icarRecommendationType.json"
},
"sireIdentifiers": {
"type": "array",
"items": {
"$ref": "../types/icarAnimalIdentifierType.json"
},
"description": "Unique scheme/identifier combinations for the sire, including official ID and Herdbook."
},
"sireOfficialName": {
"type": "string",
"description": "Official herdbook name of the sire."
},
"sireURI": {
"type": "string",
"description": "URI to an AnimalCoreResource for the sire."
"allOf": [
{
"$ref": "../types/icarReproSireInfoType.json"
},
"isSexedSemen": {
"type": "boolean",
"description": "True if this is sexed semen."
},
"sexedGender": {
"$ref": "../enums/icarAnimalGenderType.json",
"description": "Specify Male or Female for sexed semen only."
},
"parity": {
"type": "integer",
"description": "The parity of the cow for which the recommendation is valid."
},
"sireRank": {
"type": "integer",
"description": "The rank of the sire in the recommendation, 1 = first choice, 2 = second, ...."
{
"type": "object",

"properties": {
"recommendationType": {
"$ref": "../enums/icarRecommendationType.json"
},
"isSexedSemen": {
"type": "boolean",
"description": "True if this is sexed semen."
},
"sexedGender": {
"$ref": "../enums/icarAnimalGenderType.json",
"description": "Specify Male or Female for sexed semen only."
},
"parity": {
"type": "integer",
"description": "The parity of the cow for which the recommendation is valid."
},
"sireRank": {
"type": "integer",
"description": "The rank of the sire in the recommendation, 1 = first choice, 2 = second, ...."
}
}
}
}
]
}