How We Model UPSI Data

The last post was about proving nothing's been tampered with after the fact. This one is upstream of that — before you can build a trustworthy audit trail around UPSI (Unpublished Price Sensitive Information), you have to decide how to model the data itself, and that turns out to be a much harder question than "add a sensitivity flag to the table."

UPSI isn't a document type, it's a state

The first mistake is modeling UPSI as a category of document — "financial results," "merger details," "board decisions" — and tagging each with a sensitivity flag. That breaks the moment the same underlying information changes state over its lifecycle: a quarterly result is UPSI while it's being drafted, becomes public the second it's disclosed to the exchange, and the access rules that applied five minutes earlier are now completely irrelevant. If sensitivity lives on the document, you either have to mutate that flag at the exact right moment or you end up with stale records granting or denying access based on where the information used to be, not where it is now. The fix is modeling UPSI as a state that a piece of information passes through, with its own timestamped transitions, rather than a static property of a record.

The access list has to be time-sliced, not current

A related trap: storing "who currently has access to this UPSI item" as a single list you update as people are added or removed. That answers the wrong question for an inspection, which is never "who has access now," it's "who had access on this specific date in the past." If your access model only tracks current state, you've thrown away the ability to answer the question that actually matters — you need every grant and revocation stored as its own timestamped event, so reconstructing "who could see this on March 14th" is a query against history, not something you have to have anticipated and manually snapshotted at the time.

Insiders aren't a fixed list either

The natural next assumption is that at least the list of "who counts as an insider" is comparatively stable — designated employees, board members, key management. It isn't, because insider status is also role- and event-driven: someone becomes a temporary insider the moment they're looped into a specific deal, and stops being one once that deal either closes or is abandoned, regardless of their permanent job title. Modeling "insider" as an attribute of a person rather than a time-bound relationship between a person and a specific piece of UPSI undercounts exactly the temporary-insider cases regulators care most about, because those are the access grants that are easiest to forget to revoke.

Disclosure is a state transition, not a delete

Once information is publicly disclosed, the instinct is to just drop the UPSI restrictions — unlock the record, stop tracking access. That's exactly backwards: the pre-disclosure access history is the most valuable data you have at that point, because it's the record that proves who knew what before the rest of the market did. The structured digital database exists specifically to answer that question after the fact. So disclosure should be modeled as one more state transition on the timeline — UPSI becomes public information at time T — rather than an event that clears the earlier history. The old access grants stay exactly as they were; only the current restriction lifts.

Why this data model outlasts any specific feature

None of this shows up as a visible feature in a demo — nobody screenshots a well-modeled state timeline. It shows up eighteen months later, when a regulator asks a question your schema either answers in one query or requires you to reconstruct by hand from scattered logs. Getting the shape of the data right at the modeling stage — state over category, time-sliced access over current lists, insider status as a relationship over an attribute — is what makes the audit trail from my last post actually possible to build on top of, instead of a system fighting its own schema every time it's asked a real question.