Add manual/auto trigger and rework event and action transitions#412
Add manual/auto trigger and rework event and action transitions#412
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors the state model schema to improve the clarity and expressiveness of action and event transitions. It changes the transition structure from arrays of possible target states to a more explicit format that distinguishes between success and failure outcomes for actions, and simplifies events to have a single transition target.
Changes:
- Modified state model JSON schema to change Action transitions from an array to an object with
successandfailureproperties, and added atriggerfield - Modified state model JSON schema to change Event transitions from a plural array field to a singular string field
- Updated the returnables YAML data file to conform to the new schema structure
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| misc/state-model.json | Updates Action schema to use object-based transitions with success/failure outcomes and adds trigger field; changes Event schema to use singular transition string |
| misc/returnables.yaml | Converts all action transitions from array format to object format with success keys; converts all event transitions from plural transitions arrays to singular transition strings |
Comments suppressed due to low confidence (1)
misc/state-model.json:177
- The schema changes in this file will break compatibility with the existing codebase. The OpenAPI schema file
broker/oapi/open-api.yaml(lines 611-641) definesModelActionandModelEventwith the old array-based transitions structure, which is used to generate Go types inbroker/patron_request/proapi/pr-openapi_gen.go. Additionally, the embedded JSON state model filebroker/patron_request/service/statemodels/returnables.jsonstill uses the old schema format.
These files need to be updated in the same PR to maintain consistency:
broker/oapi/open-api.yaml- Update ModelAction and ModelEvent schemas to match the new structurebroker/patron_request/service/statemodels/returnables.json- Regenerate from the updated YAML to use the new schema
Without these updates, the code will fail at runtime when trying to unmarshal the state model JSON because the Go struct types won't match the actual JSON structure.
"Action": {
"type": "object",
"additionalProperties": false,
"description": "Declares an action available while in this state.",
"properties": {
"name": {
"type": "string",
"description": "Name of the action"
},
"desc": {
"type": "string",
"description": "Description of the action"
},
"trigger": {
"type": "string",
"description": "Trigger for the action",
"enum": [
"auto",
"manual"
],
"default": "manual"
},
"transitions": {
"type": "object",
"description": "Action outcome to state transition mapping. When no transition is defined, the action is considered to be non-state-changing.",
"additionalProperties": false,
"properties": {
"success": {
"type": "string",
"description": "Target state when the action succeeds."
},
"failure": {
"type": "string",
"description": "Target state when the action fails."
}
}
}
},
"required": [
"name"
],
"title": "Action"
},
"Event": {
"type": "object",
"additionalProperties": false,
"description": "Declares an event considered for transition while in this state.",
"properties": {
"name": {
"type": "string",
"description": "Name of the event"
},
"desc": {
"type": "string",
"description": "Description of the event"
},
"transition": {
"type": "string",
"description": "State transition after event has occurred. When no transition is defined, the event is considered to be non-state-changing."
}
},
"required": [
"name"
],
"title": "Event"
}
| ], | ||
| "default": "manual" |
There was a problem hiding this comment.
The trigger field in the Action schema has a default value of "manual", but JSON Schema's default keyword is only advisory for documentation purposes - it doesn't actually set default values during validation or parsing.
If you want actions to have a default trigger of "manual", you'll need to handle this in the application code that reads the state model. Alternatively, if the trigger field should be required, add it to the required array on line 150.
| ], | |
| "default": "manual" | |
| ] |
| @@ -21,7 +22,8 @@ states: | |||
| actions: | |||
| - name: send-request | |||
| desc: Send ISO18626 request to the supplier or broker | |||
| transitions: [SENT] | |||
| transitions: | |||
| success: SENT | |||
|
|
|||
| - name: SENT | |||
| display: Sent | |||
| @@ -30,19 +32,19 @@ states: | |||
| events: | |||
| - name: expect-to-supply | |||
| desc: Supplier indicates an intention to supply (ISO18626 ExpectToSupply) | |||
| transitions: [SUPPLIER_LOCATED] | |||
| transition: SUPPLIER_LOCATED | |||
| - name: will-supply | |||
| desc: Supplier will supply without conditions (ISO18626 WillSupply) | |||
| transitions: [WILL_SUPPLY] | |||
| transition: WILL_SUPPLY | |||
| - name: will-supply-conditional | |||
| desc: Supplier will supply with conditions (ISO18626 WillSupply with conditions) | |||
| transitions: [CONDITION_PENDING] | |||
| transition: CONDITION_PENDING | |||
| - name: loaned | |||
| desc: Supplier shipped the item (ISO18626 Loaned) | |||
| transitions: [SHIPPED] | |||
| transition: SHIPPED | |||
| - name: unfilled | |||
| desc: Supplier cannot supply (ISO18626 Unfilled) | |||
| transitions: [UNFILLED] | |||
| transition: UNFILLED | |||
|
|
|||
| - name: SUPPLIER_LOCATED | |||
| display: Supplier Located | |||
| @@ -51,17 +53,18 @@ states: | |||
| actions: | |||
| - name: cancel-request | |||
| desc: Send ISO18626 Cancel request to supplier | |||
| transitions: [CANCEL_PENDING] | |||
| transitions: | |||
| success: CANCEL_PENDING | |||
| events: | |||
| - name: will-supply | |||
| desc: Supplier will supply without conditions (ISO18626 WillSupply) | |||
| transitions: [WILL_SUPPLY] | |||
| transition: WILL_SUPPLY | |||
| - name: will-supply-conditional | |||
| desc: Supplier will supply with conditions (ISO18626 WillSupply with conditions) | |||
| transitions: [CONDITION_PENDING] | |||
| transition: CONDITION_PENDING | |||
| - name: unfilled | |||
| desc: Supplier cannot supply (ISO18626 Unfilled) | |||
| transitions: [UNFILLED] | |||
| transition: UNFILLED | |||
|
|
|||
| - name: CONDITION_PENDING | |||
| display: Condition Pending | |||
| @@ -70,10 +73,12 @@ states: | |||
| actions: | |||
| - name: accept-condition | |||
| desc: Accept supplier conditions (ISO18626 Notification) | |||
| transitions: [WILL_SUPPLY] | |||
| transitions: | |||
| success: WILL_SUPPLY | |||
| - name: reject-condition | |||
| desc: Reject supplier conditions (ISO18626 Cancel) | |||
| transitions: [CANCEL_PENDING] | |||
| transitions: | |||
| success: CANCEL_PENDING | |||
|
|
|||
| - name: WILL_SUPPLY | |||
| display: Will Supply | |||
| @@ -82,14 +87,15 @@ states: | |||
| actions: | |||
| - name: cancel-request | |||
| desc: Send ISO18626 Cancel to supplier | |||
| transitions: [CANCEL_PENDING] | |||
| transitions: | |||
| success: CANCEL_PENDING | |||
| events: | |||
| - name: loaned | |||
| desc: Supplier shipped the item (ISO18626 Loaned) | |||
| transitions: [SHIPPED] | |||
| transition: SHIPPED | |||
| - name: unfilled | |||
| desc: Supplier cannot supply (ISO18626 Unfilled) | |||
| transitions: [UNFILLED] | |||
| transition: UNFILLED | |||
|
|
|||
| - name: SHIPPED | |||
| display: Shipped | |||
| @@ -98,7 +104,8 @@ states: | |||
| actions: | |||
| - name: receive | |||
| desc: Receive and accept item in local ILS (via NCIP AcceptItem if enabled); send ISO18626 Received | |||
| transitions: [RECEIVED] | |||
| transitions: | |||
| success: RECEIVED | |||
|
|
|||
| - name: RECEIVED | |||
| display: Received | |||
| @@ -107,7 +114,8 @@ states: | |||
| actions: | |||
| - name: check-out | |||
| desc: Check out item to patron (NCIP CheckOutItem) | |||
| transitions: [CHECKED_OUT] | |||
| transitions: | |||
| success: CHECKED_OUT | |||
|
|
|||
| - name: CHECKED_OUT | |||
| display: Checked Out | |||
| @@ -116,7 +124,8 @@ states: | |||
| actions: | |||
| - name: check-in | |||
| desc: Check the item back-in (NCIP CheckInItem) | |||
| transitions: [CHECKED_IN] | |||
| transitions: | |||
| success: CHECKED_IN | |||
|
|
|||
| - name: CHECKED_IN | |||
| display: Checked In | |||
| @@ -125,7 +134,8 @@ states: | |||
| actions: | |||
| - name: ship-return | |||
| desc: Send ISO18626 ShippedReturn and delete the temporary item (NCIP DeleteItem) | |||
| transitions: [SHIPPED_RETURNED] | |||
| transitions: | |||
| success: SHIPPED_RETURNED | |||
|
|
|||
| - name: SHIPPED_RETURNED | |||
| display: Shipped Returned | |||
| @@ -134,7 +144,7 @@ states: | |||
| events: | |||
| - name: completed | |||
| desc: Supplier/broker signals loan/copy completion | |||
| transitions: [COMPLETED] | |||
| transition: COMPLETED | |||
|
|
|||
| - name: CANCEL_PENDING | |||
| display: Cancel Pending | |||
| @@ -143,7 +153,7 @@ states: | |||
| events: | |||
| - name: cancel-accepted | |||
| desc: Supplier accepts cancellation | |||
| transitions: [CANCELLED] | |||
| transition: CANCELLED | |||
|
|
|||
| - name: COMPLETED | |||
| display: Completed | |||
| @@ -171,7 +181,8 @@ states: | |||
| actions: | |||
| - name: validate | |||
| desc: Validate the request, e.g institutional patron via NCIP LookupUser, if enabled | |||
| transitions: [VALIDATED] | |||
| transitions: | |||
| success: VALIDATED | |||
|
|
|||
| - name: VALIDATED | |||
| display: Validated | |||
| @@ -180,17 +191,20 @@ states: | |||
| actions: | |||
| - name: will-supply | |||
| desc: Indicate supplier will supply and send ISO18626 WillSupply | |||
| transitions: [WILL_SUPPLY] | |||
| transitions: | |||
| success: WILL_SUPPLY | |||
| - name: cannot-supply | |||
| desc: Indicate cannot supply and send ISO18626 Unfilled | |||
| transitions: [UNFILLED] | |||
| transitions: | |||
| success: UNFILLED | |||
| - name: add-condition | |||
| desc: Indicate will supply with conditions and send ISO18626 WillSupply | |||
| transitions: [CONDITION_PENDING] | |||
| transitions: | |||
| success: CONDITION_PENDING | |||
| events: | |||
| - name: cancel-request | |||
| desc: Requester sent ISO18626 Cancel | |||
| transitions: [CANCEL_REQUESTED] | |||
| transition: CANCEL_REQUESTED | |||
|
|
|||
| - name: WILL_SUPPLY | |||
| display: Will Supply | |||
| @@ -199,17 +213,20 @@ states: | |||
| actions: | |||
| - name: add-condition | |||
| desc: Add conditions and notify requester | |||
| transitions: [CONDITION_PENDING] | |||
| transitions: | |||
| success: CONDITION_PENDING | |||
| - name: ship | |||
| desc: Mark shipped; send ISO Loaned; NCIP CheckOutItem | |||
| transitions: [SHIPPED] | |||
| transitions: | |||
| success: SHIPPED | |||
| - name: cannot-supply | |||
| desc: Indicate cannot supply | |||
| transitions: [UNFILLED] | |||
| transitions: | |||
| success: UNFILLED | |||
| events: | |||
| - name: cancel-request | |||
| desc: Requester sends ISO Cancel | |||
| transitions: [CANCEL_REQUESTED] | |||
| transition: CANCEL_REQUESTED | |||
|
|
|||
| - name: CONDITION_PENDING | |||
| display: Condition Pending | |||
| @@ -218,17 +235,18 @@ states: | |||
| actions: | |||
| - name: cannot-supply | |||
| desc: Indicate cannot supply | |||
| transitions: [UNFILLED] | |||
| transitions: | |||
| success: UNFILLED | |||
| events: | |||
| - name: conditions-accepted | |||
| desc: Requester accepts conditions | |||
| transitions: [CONDITION_ACCEPTED] | |||
| transition: CONDITION_ACCEPTED | |||
| - name: condition-rejected | |||
| desc: Requester rejects conditions (auto-responder may mark unfilled) | |||
| transitions: [UNFILLED] | |||
| transition: UNFILLED | |||
| - name: cancel-request | |||
| desc: Requester sends ISO Cancel | |||
| transitions: [CANCEL_REQUESTED] | |||
| transition: CANCEL_REQUESTED | |||
|
|
|||
| - name: CONDITION_ACCEPTED | |||
| display: Condition Accepted | |||
| @@ -237,14 +255,16 @@ states: | |||
| actions: | |||
| - name: ship | |||
| desc: Mark shipped; send ISO Loaned; NCIP CheckOutItem | |||
| transitions: [SHIPPED] | |||
| transitions: | |||
| success: SHIPPED | |||
| - name: cannot-supply | |||
| desc: Indicate cannot supply | |||
| transitions: [UNFILLED] | |||
| transitions: | |||
| success: UNFILLED | |||
| events: | |||
| - name: cancel-request | |||
| desc: Requester sends ISO Cancel | |||
| transitions: [CANCEL_REQUESTED] | |||
| transition: CANCEL_REQUESTED | |||
|
|
|||
| - name: SHIPPED | |||
| display: Shipped | |||
| @@ -253,7 +273,7 @@ states: | |||
| events: | |||
| - name: shipped-return | |||
| desc: Requester sends ISO ShippedReturn | |||
| transitions: [SHIPPED_RETURN] | |||
| transition: SHIPPED_RETURN | |||
|
|
|||
| - name: SHIPPED_RETURN | |||
| display: Shipped Return | |||
| @@ -262,7 +282,8 @@ states: | |||
| actions: | |||
| - name: mark-received | |||
| desc: Mark returned item received and complete (CheckInItem if configured) | |||
| transitions: [COMPLETED] | |||
| transitions: | |||
| success: COMPLETED | |||
|
|
|||
| - name: CANCEL_REQUESTED | |||
| display: Cancel Requested | |||
| @@ -271,10 +292,12 @@ states: | |||
| actions: | |||
| - name: mark-cancelled | |||
| desc: Confirm cancellation | |||
| transitions: [CANCELLED] | |||
| transitions: | |||
| success: CANCELLED | |||
| - name: will-supply | |||
| desc: Resume supplying despite cancel request | |||
| transitions: [WILL_SUPPLY] | |||
| transitions: | |||
| success: WILL_SUPPLY | |||
There was a problem hiding this comment.
All actions in the YAML file only use the success transition, with no actions using the failure transition. This suggests that failure handling might not be fully designed yet. Consider whether:
- Actions can actually fail and transition to different states (e.g., validation failure, network errors during send-request)
- If failures should be handled differently (e.g., staying in the same state, transitioning to an error state)
- Whether the schema should require at least one of
successorfailureto be present if transitions are defined
This is worth reviewing to ensure the new schema fully supports the intended workflow model.
| "trigger": { | ||
| "type": "string", | ||
| "description": "Trigger for the action", | ||
| "enum": [ | ||
| "auto", | ||
| "manual" | ||
| ], | ||
| "default": "manual" | ||
| }, |
There was a problem hiding this comment.
The new trigger field is added to the Action schema but is not currently used anywhere in the codebase. The field distinguishes between "auto" (automatically triggered) and "manual" (manually triggered by a user) actions.
Since this field is not currently utilized, consider:
- Adding documentation or comments explaining the intended use case for this field
- Ensuring that when this field is eventually used, the default value of "manual" is properly applied in the code that reads the state model (as JSON Schema defaults are not automatically enforced during deserialization)
- Whether any existing actions should be marked as "auto" to reflect their intended behavior
If this is being added for future functionality, that's fine, but it should be clearly documented.
No description provided.