The UI Policy and Client Script Fighting Over the Same Field
On the Incident form, a UI Policy makes the resolution_notes field mandatory and visible when state = Resolved. A separate onLoad client script sets resolution_notes to read-only when the user lacks the itil role. A third on-change client script clears resolution_notes whenever state changes to anything other than Resolved. Agents report: when resolving an incident, the field is sometimes read-only (blocking submit), sometimes blank despite them typing notes, and the form throws 'mandatory field empty' on submit even though the field looked filled. The behavior varies by user and by the order in which fields are touched.
1. Explain the interaction causing the inconsistent behavior and which component should own each rule.
Read the worked answer
Three components are mutating the same field with different, uncoordinated intentions:
- UI Policy: sets mandatory + visible on Resolved.
- onLoad client script: sets read-only based on role - but onLoad runs once and doesn't re-evaluate when state changes, so a user can end up with the field read-only after the UI Policy made it mandatory.
- onChange client script: clears the field on state change - if the user types notes before changing state to Resolved, the onChange fires and wipes them, or fires after and clears what they just entered.
The 'mandatory empty though it looked filled' is a classic client-side vs server-side timing issue: the client script cleared the value after the UI Policy validated, or the field's displayed value wasn't committed.
Ownership:
- UI Policy should own visibility, mandatory, and read-only based on state - it re-evaluates on change and is declarative.
- The role-based read-only should also be a UI Policy condition (role check) rather than an onLoad script, so it re-evaluates consistently.
- The clearing logic should be a single, deliberate rule: clear only when transitioning away from Resolved, and only if the business truly wants that - otherwise remove it. Implement as a UI Policy action or a well-scoped onChange, not both.
2. The business also wants the rule enforced server-side so API/import updates can't bypass it. What do you add, and how do you avoid conflicts with the client-side rules?
Read the worked answer
Add a before business rule (or a data policy) on Incident that enforces: if state = Resolved, resolution_notes must be non-empty; if a transition away from Resolved occurs, handle clearing per policy. Server-side enforcement is the source of truth; client-side rules are UX only.
To avoid conflicts:
- Single source of truth: server rule defines the invariant; client rules mirror it for UX but never contradict it.
- Consistent conditions: use the same state values and role checks in both layers.
- Don't clear on the client if the server will also clear - pick one layer for the mutation and let the other only display.
- Test the matrix: each role (itil / non-itil) × each state transition × entry point (form, API, import). The server rule must reject the same cases the UI blocks, with a clear error message.
After consolidation, the agent experience is deterministic: field is editable when appropriate, mandatory on Resolve, and submit fails only for a genuine missing value - with the same rule enforced for API callers.