The problem
PII in v2 is currently a column-level boolean (pii: true on 5 columns of Personnel). That model has two limits the spec can't paper over:
- Conditional sensitivity.
ContactDetails.Contact_Value is PII when Personnel_ID is set, public when Organization_ID is set (sponsor mailbox). A static column flag forces both rows to be treated the same.
- Composite sensitivity.
OtherSupport rows are individually mundane (a sponsor name, a dollar amount, a date range). The disclosure property emerges from the chain: a Personnel_ID is attached + an amount is recorded + the disclosure is tied to a specific investigator. Same goes for COI financial disclosures, Effort charged amounts, etc. The PII signal lives in the row, not the column.
The idea
We already have a polymorphic Classification table. Today it carries science codes, sponsor categories, and similar scheme-bound labels. The pattern fits a Scheme = 'DataClassification' use case cleanly:
Classification_ID: 'cls-001'
Related_Entity_Type: 'OtherSupport'
Related_Entity_ID: 'os-12345'
Scheme: 'DataClassification'
Value_Code: 'PII'
Value_Label: 'Personally Identifiable Information'
Or richer, if institutions want finer classes:
Scheme: 'DataClassification'
Value_Code: 'HR_Confidential' // or 'FERPA', 'HIPAA', 'Sponsor_Confidential', etc.
That lets the model express:
- Row-level scope (only the rows that actually carry sensitive data are marked, instead of every Contact_Value row inheriting the flag from the column).
- Multiple overlapping regimes (a row can carry FERPA AND HR_Confidential without us inventing a new column type).
- Time-bound classifications (Classification rows are already attached to entities; effective dates could be added if needed).
Tradeoffs
Pros
- No contortion of the column model for conditional/composite cases.
- Reuses an existing universal pattern (polymorphic attachment), no new tables.
- Lets institutions carry their own classification vocabulary in
Value_Code without spec changes.
- Plays well with the existing AllowedValues mechanism for sites that want a controlled vocabulary.
Cons
- Consumers have to join through Classification to know what's sensitive, instead of reading a column flag. More expensive at query time, more complex for naive consumers.
- The column-level flag is gone or duplicated. Either we keep both (drift hazard) or drop the boolean (breaking change).
- Population is harder. Column-level flags are static, declared once in the schema. Row-level Classification rows have to be created at insert time and maintained as data changes (e.g., a Personnel record going from external to internal might change the classification).
- Doesn't help the "free text column might contain PII" case (Communication.Body_Text, Action.Description, ActivityLog.Old_Value). Those would still need a column-level signal.
What this issue is asking
Not a decision. Just a parking spot for the idea.
Two reasonable interim positions:
- Keep the column-level boolean, widen its coverage to the obvious omissions (Home_Organization_Identifier, ContactDetails.Contact_Value, PersonnelCredential.Credential_Value, OtherSupport amounts, ConflictOfInterest financial fields, Effort charged amounts). Cheapest, no model change.
- Hybrid: keep the column flag for the "always PII" cases (names, ORCID, email), use Classification rows for conditional/composite cases. Documents that the column flag is the floor, not the ceiling.
If we ever do (2) or pure row-level, it's likely a v3 conversation because it changes the consumer contract.
Related
- The polymorphic Classification table itself is at
vignettes/udm-v2-schema.md (see Classification section).
- Current PII flags: Personnel.First_Name, Middle_Name, Last_Name, Primary_Email, ORCID.
- The flag is a signal only; what consumers do with it (mask, redact, RBAC) is institutional per scope statement.
The problem
PII in v2 is currently a column-level boolean (
pii: trueon 5 columns of Personnel). That model has two limits the spec can't paper over:ContactDetails.Contact_Valueis PII whenPersonnel_IDis set, public whenOrganization_IDis set (sponsor mailbox). A static column flag forces both rows to be treated the same.OtherSupportrows are individually mundane (a sponsor name, a dollar amount, a date range). The disclosure property emerges from the chain: a Personnel_ID is attached + an amount is recorded + the disclosure is tied to a specific investigator. Same goes for COI financial disclosures, Effort charged amounts, etc. The PII signal lives in the row, not the column.The idea
We already have a polymorphic
Classificationtable. Today it carries science codes, sponsor categories, and similar scheme-bound labels. The pattern fits aScheme = 'DataClassification'use case cleanly:Or richer, if institutions want finer classes:
That lets the model express:
Tradeoffs
Pros
Value_Codewithout spec changes.Cons
What this issue is asking
Not a decision. Just a parking spot for the idea.
Two reasonable interim positions:
If we ever do (2) or pure row-level, it's likely a v3 conversation because it changes the consumer contract.
Related
vignettes/udm-v2-schema.md(see Classification section).