How role diffs are computed
computeRoleDiff() semantics — profile edges, reclassifications, IRI/ICI shifts, flow-stage reorders — the schema-stability tier, and the change log.
computeRoleDiff() — the underlying function
Role diff is a pure function over two published roles, A and B. It returns a structured RoleDiff package with six top-level sections — added profile edges, removed profile edges, reclassifications, profile-edge IRI/ICI deltas, flow-stage changes — plus a summary aggregate. Pure means: same inputs always produce the same output, no DB lookups inside the function, safe to call from server components without extra plumbing.
Profile edges — added / removed
Each role carries a set of profile-edge attachments: (profile_id, classification, iri, ici). The diff classifies each edge as added (present on B, not A), removed (present on A, not B), or common (present on both).
Reclassifications
Profiles present on both A and B where the classification changed (e.g. supporting → primary). The diff carries (profile, classificationA, classificationB) so the UI can render the before/after pair.
ΔIRI — IRI shift per profile edge
IRI ranges 0–3 per profile per role. For common profile edges, the per-edge delta is B.iri − A.iri. Per-edge deltas are summed into iriShiftTotal for the summary bar. A positive total means the future-ready role demands more information across its profiles.
ΔICI — ICI shift per profile edge
ICI ranges 0–3 per profile per role. For common profile edges, the per-edge delta is B.ici − A.ici. Per-edge deltas are summed into iciShiftTotal. A positive total means the future-ready role demands more competency depth across its profiles.
Flow stage changes
Each role carries an ordered list of flow stages. The diff classifies each stage as added (on B not A), removed (on A not B), or reordered (on both with a different ordinal position).
Reorders are typically the most informative category for transformation framing — they show how the flow's centre of gravity moves. A future-ready BIM Manager that surfaces "information validation" before "model coordination" is a different kind of role than one that surfaces them the other way around.
The summary aggregate
Every RoleDiff package carries a summary with seven counts: commonProfiles, addedProfiles, removedProfiles, classificationChanges, iriShiftTotal, iciShiftTotal, flowReorders. The summary bar at the top of RoleDiffView reads these and renders the seven counts as the at-a-glance shape of the transformation.
Edge cases
- Comparing a role to itself returns the self-compare empty state — the diff is not meaningful. The route's empty state offers a "change ?vs=" CTA.
- If a role has no successor pointer and the standalone route is opened without ?vs=, the empty state explains the convention and offers a comparison-target picker.
- Drafts are excluded. Both A and B must be published for the diff to compute.
- Profile edges with no IRI on either side render as "—" and contribute 0 to the iriShiftTotal.
- Profile edges with no ICI on either side render as "—" and contribute 0 to the iciShiftTotal.
Jurisdiction-agnostic math, jurisdiction-aware catalogue
The diff math is jurisdiction-agnostic — given A and B, the function returns the same RoleDiff package regardless of who's reading. What is jurisdiction-aware is which canonical future-ready role a given org-fork compares against; that decision lives upstream of the diff, in the role-archetype surface.
Stability tier
The RoleDiff package schema is at stability tier beta. The shape may evolve in minor versions until 1.0; breaking shape changes will bump the schemaVersion in the package envelope and the change will be called out in the change log.