Thursday, July 16, 2026

Profiling AuditEvent seems to be an emerging need

Watching the report outs for the CMS FHIR Connectathon. Many are mentioning that they see a need to profile AuditEvent for their use-case needs to support data access traceability, privacy tracking, and provenance. I very much agree with this. 

IHE has the starter kit with the Basic Audit Log Patterns (BALP)  Implementation Guide defines the basics and has some profiles for common REST interactions.

I often need to remind people that defining AuditEvent profiles can be supported purely as a Query interface. In this case the system keeps their audit log in their native format, but knows how to convert that into the FHIR Standard AuditEvent when queried.

I would be glad to provide pointed and short-term consulting -- see Moehrke Research LLC 

Wednesday, July 15, 2026

proud owner of an OID root

Now that HL7 is bringing back the OID, as CDA can only handle OIDs and not URL system values. I went and registered with iana for my own OID. It is not important to do this, but it is free. Now all of the test IGs that I have in my personal github can have their own OID root so that I don't need to constantly indicate in the ignorewarnings.txt that it is okay that my test IGs don't have OID assignments.

My assigned OID root: 1.3.6.1.4.1.66281

I have been using the official example OID root: 2.999; which is the equivalent of the DNS example.com, or example.org. I have used this 2.999 OID root with the IG publisher, which I felt was an appropriate defiance. Unfortunately, it just changes the warning.

I have a page that I refer to often on creating and using Unique IDs - UUID - OID

On that article I did add comments that explained the 2.999 OID root. -- https://oid-base.com/get/2.999

I have also noted that USA SSN has reserved those SSN numbers starting with 666. I have not seen an official statement to this, but plenty of confirmations. The concept is that they know they can't issue a 666. number to someone as that someone would see it as the USA government labeling them with the mark of the devil. So when I make test patients, I give them SSN starting with 666-.

Tuesday, May 12, 2026

Age services are a no-win

I have written on Age-Services, those theoretical services that can provide age-protected services a way to learn the age of their user without learning their birthday.  Age Verification is much more important than porn

I hear excited proposals that promote that Apple and Google, as platforms, should be the Age service. Each time, I am yelling into the dark at a very specific problem does not get brought into the picture.

The Age service is a thankless service. It would not be able to be a paid service; it won't be able to include advertising. Which is bad enough. But it is also a huge overhead. The API is not hard to implement. The API could be designed in various ways to protect the individual. What is hard to handle is the backend requirements from government subpoena. 

An Age service must know strongly the identity of the individual, and thus they must know the birthdate. This is rather obvious, but this itself puts the Age Service in the tough spot of protecting from accidental exposure, or malicious attacks. Highly valuable data, means expensive protections. Protections that also must include audit logs of all legitimate uses, as well as requests that are blocked as illegitimate.

Age-Service is far more expensive

This is already an expensive service, that I explain has no revenue stream.

The Age service knows which age-limited services that a given user is using. They will get requests, or need to issue assertions, for a targeted age-limited service. Thus, it is possible for Apple / Google to know what age-limited services a given user is using. When, and from where. Could they not save a log? Possibly, but they could be compelled to save a log. And they need a log to protect themselves from age-protected service claims that they were given an age value that was never released. E.g., I dispensed beer because the age-service said the user was 21, but in reality, no such age assertion was ever issued.

E.g., An age-limited service "cannabis-today" needs to know that the user placing an online order is of legal age, so age-service is engaged to determine this. This use of "cannabis-today" is legal in the state where the company and user live. But one time, the user is out-of-state, in a state where cannabis sales are not legal, and now that state issues subpoena for records. The individual may not have even tried using the "cannabis-today" app, but it was on their phone. --- this story is not just about cannabis --

The knowledge of which age-limited services a given individual is using is valuable to governments that want to control population. Further, they will want the full log to find individuals using age-limited services.

Date Of Birth

Different topic on the same subject... an age-limited service can learn the birthdate of an individual by probing every-day. On the day that the age goes up, that is their birthday. Long time ago SAML had an age service, and they noticed this problem, so they indicated that some fuzzing of the birthdate would be used. However, this presents a problem, does the service indicate age transition early and thus is wrong, or does the service indicate late and make the individual angry about not being recognized as 21 on their birthdate.

Conclusion

Will governments continue to ask for such a system, yes. I am not surprised they will ask for this. I would actually think they are wrong to not ask. But because they ask, does not mean that it should be provided. In my other article I express that many of these age-limited services are services that are needed by disenfranchised and powerless.  The age-limited services are often the only way for these individuals to get access to the services they need. If the age-service is compromised, or if the government is able to compel the age-service to give up data, then these individuals are put at risk.

Thursday, April 30, 2026

Considerations for Implementing the SLS RI

In a previous post I introduce a Reference Implementation of a Security Labeling Service. I published this as open-source on the SHIFT SLS RI GitHub Repository. I published the API definition including profile on ValueSet for defining a sensitive tagging ValueSet of codes. With an IG that holds many prototype ValueSets of sensitive topics. I also explain how sensitive topics are a subset of data, distinct from Normal health data.

The SLS Reference Implementation is designed to provide an informative example of how to implement the Security Labeling Service (SLS) for Health Information tagging so that fine grain access controls can be implemented. Data tagging applies a categorization code to a FHIR resource based only on the content of that FHIR resource. The tag does not indicate what kind of access control is applied. The access control rules are separate.

When is tagging needed?

  1. Data does not need to be tagged if there is no access control policies (e.g. Consent, Business Rules, or Regulations) that would apply different rules to different categories of data.
  2. Data does not need to be tagged if the current state of Consent is blanket permit or deny. That is when the Patient Consent has no specific rules per category then the tagging is not needed.
  3. Data need only be tagged sufficient to support the categorization of the access control policies. The SLS RI is configured by loading the SLS Policies as ValueSets
  4. When the tagging policies change (e.g. the SLS ValueSets are updated) then any data that was tagged under the old policy needs to be retagged. The SLS RI implements a timestamp on the tags to allow for not retagging if the SLS policies have not changed since last tagging.
The Reference Implementation of the SLS is designed to provide clarity of the concept of tagging. It is not designed to be fast or efficient. In a real-world system, the tagging of the data would be designed into the system utilizing features of that system (e.g., leveraging database indexing).

When to apply the SLS RI?

Executing the SLS against any data is an expensive operation. This is true as the number of entries in the SLS policies increases. The SLS must look at all codes in the data and detect if any of the codes match any of the configured SLS policies. Thus, the more policies (ValueSets) and the more entries in those ValueSets, the more computationally expensive the tagging process becomes. The SLS RI includes a timestamp so that data are not inspected unless the data timestamp is older than the SLS Policies. See ValueSet Profile

There is a concern with legacy databases not having an element to hold the security tags. Thus there needs to be a way to support SLS in those cases.

There are a few ways to apply the SLS RI:

Executed on all data Creation and Update

This is the most comprehensive approach, ensuring that all data are tagged appropriately. However, it may have performance implications due to the need to tag every resource. It also relies on the system being able to persist the tags with the data. This approach also must retag data when the tagging policy (e.g. SLS ValueSets) changes.

This model likely can be implemented efficiently with a systems design of a SLS into the database. Thus, the use of the SLS RI is not likely directly usable if this is the model desired.


Executed on demand when a Patient's data are accessed


When a Patient's data are accessed, a task examines all of that Patient's data and applies the appropriate tags. This approach allows for dynamic tagging based on the current state of the data and the applicable access control policies. However, it may lead to performance issues due to the need to tag data at the time of access, which could introduce latency. It also relies on the system being able to persist the tags with the data. This approach has the benefit of not changing data to add tags unless that Patient is actively being accessed. Thus historic patients that are no longer being accessed would not need to be tagged.

The system should keep some timestamp at the Patient level to know when the Patient was last tagged, so as to keep from running this task unnecessarily often.



Executed on demand with each Search with writeback


When a search is executed, the SLS RI is executed to inspect the Search Bundle and any new tags are written back to the database. This approach allows for dynamic tagging based on the current state of the data and the applicable access control policies at the time of search. However, it may lead to significant performance issues due to the need to tag data at the time of search, which could introduce latency. It also relies on the system being able to persist the tags with the data. This approach has the benefit of not changing data to add tags unless that data is actively being searched for. This inspection of the Search Bundle would only be done if the Access Control decision has residual rules to further remove categories of sensitive data.

Executed on demand with each Search doing only inline tagging

When a search is executed, the SLS RI is executed to inspect the Search Bundle and any new tags are only added to the Search Bundle in memory and not written back to the database. This approach allows for dynamic tagging based on the current state of the data and the applicable access control policies at the time of search without changing the underlying data. However, it may lead to performance issues due to the need to tag data at the time of search, which could introduce latency. This approach has the benefit of not changing data to add tags unless that data is actively being searched for and does not require that the system be able to persist the tags with the data. This inspection of the Search Bundle would only be done if the Access Control decision has residual rules to further remove categories of sensitive data.


🎁Note, this is one of those projects I do pro bono but would love if someone would care enough about it to contract with me. Sustaining the Work That Sustains Trust: Why I’m Seeking Support for Some of My Standards Efforts

Tuesday, April 28, 2026

Sensitive data as Venn diagram

In Healthcare, Normal data is all data that is linked to an identified Patient and not specifically sensitive. Any data that is sensitive would be Restricted. "Normal" refers to the normal average curve, thus the majority of data. Sensitive data can be categorized into sensitivity topics, and some data may fall into multiple sensitive categories, as illustrated in the Venn diagram below.

Sensitive topics are generally potentially stigmatizing information, for which exposure would present high risk of harm to an individual's reputation and sense of privacy. 

In a data tagging architecture, sensitivity topics are indicated as a "sensitivity" code in the FHIR Resource.meta.security tag of FHIR resources, and can be used for access control decisions in a Privacy Consent driven access control model.

Normal data is often not tagged as Normal, but rather is just the absence of any sensitive tag. This is recognizing that the vast majority of medical data are Normal (algorithmically average). The presence of any sensitive tag would make the data Restricted, indicated as R restricted Confidentiality code.
The data are tagged with the kind of sensitivity purely due to their data content, and not due to any other factors such as the Patient consent status. The labeling does not imply that there is any particular access control policy in place, but rather that the data is sensitive and may require special handling. 

The access control policies would be defined separately and could use the presence of these sensitivity tag to make decisions about who can access the data and under what circumstances. 

For example, when a given patient indicates that broad treatment use of their data is not restricted, but their Sexual Health sensitive data must not be shared beyond their PCP and never with non-Treatment purpose of Use. So, in this case, note that the other sensitive tags beyond Sexual Health have no effect on accessibility. Note that this Consent policy just needs to see the Sexual Health tags, it does not care about Normal vs Restricted. 

Resources:
  • An Implementation Guide with various ValueSet(s) that could be used by a Security Labeling Service (SLS) to tag data according to specific sensitivity. - SLS ValueSets
  • A Reference Implementation (OpenSource) of a Security Labeling Service (SLS) that I created using Vibe coding with AI - SLS RI GitHub Repository
  • An Implementation Guide defining that API, and specifically a Profile on ValueSet to identify sensitivity type and the codes for that type. -- SLS RI Implementation Guide
  • Example Patient Data SHIFT Demo Scenarios IG

🎁Note, this is one of those projects I do pro bono but would love if someone would care enough about it to contract with me. Sustaining the Work That Sustains Trust: Why I’m Seeking Support for Some of My Standards Efforts

Wednesday, February 11, 2026

Consent about AI

There are various use-cases where a Patient might consent or dissent to various uses of AI.

  1. A patient might consent to use of AI for clinical decision support
  2. A patient might deny use of their data for training of AI.
  3. A patient might consent to use of their data in de-identified form for training of AI.

Given the Consent model, the Patient might be indicated in a Consent authorizing either: 

  • Generically allowing or denying AI by PurposeOfUse 
  • Specifically allowing or denying a specific AI by referencing the Device resource for that AI.

PurposeOfUse

The most clean method is to use the PurposeOfUse as the basis for the provision in the Consent. This allows the Consent to be independent of the specific AI system or model, and thus not require updates as new AI systems or models are developed. The PurposeOfUse can be used to indicate the reason for the AI access, such as MLTRAINING for training of AI, or TREATDS for clinical decision support.

Further we look to PurposeOfUse Vocabulary to indicate what the reason the AI is giving for accessing data. For example, the PurposeOfUse of MLTRAINING is defined for when an AI is looking to train on data. The PurposeOfUse of TREATDS is defined for when an AI is looking to provide clinical decision support, or PMTDS when AI is looking to provide analysis for payment decisions.

The use of PurposeOfUse does require that any accesses the AI does, or an agent feeding the AI, must use the given PurposeOfUse code when accessing data. This is a trust model that the AI or the agent feeding the AI will accurately indicate the PurposeOfUse when accessing data. However, this is a common trust model used in many other aspects of healthcare data access and thus is not unique to AI.

Allow AI for ML Training

* provision.type = #permit
* provision.purpose[+] = $purposeOfUse#MLTRAINING

Consent example: Allow ML Training

Deny AI for ML Training

* provision.type = #deny
* provision.purpose[+] = $purposeOfUse#MLTRAINING 

Consent example: Deny ML Training

Allow AI for Clinical Decision Support

* provision.type = #permit
* provision.purpose[+] = $purposeOfUse
#TREATDS 

Consent example: Allow AI for Clinical Decision Support

Deny AI for Clinical Decision Support

* provision.type = #deny
* provision.purpose[+] = $purposeOfUse#TREATDS 

Consent example: Deny AI for Clinical Decision Support

Specific AI Systems or Models

For this we look to current identification of AI as a FHIR Device resource. This Device would be indicated in a Consent when a specific AI system or model is identified in a Consent.provision.agent.reference with a permit or deny provision.

This model requires that all access by an AI are attributed to the FHIR Device describing the AI. This might not be the case given how the AI is orchestrated. This model also is fragile as a new model or software would be a new Device, and thus would require a new provision in the Consent to indicate consent or dissent for that new AI.

Allow a specific AI for a specific purpose

In this case there is simply a provision indicating that the AI is permitted. There is no purposeOfUse indicated, but that could be an additional restriction. There is no other restrictions on the kinds of actions or the kinds of data, but those could also be additional restrictions.

* provision.type = #permit
* provision.agent.reference = Reference(Device/AIdevice) 

Consent example: Allow specific AI for specific purpose

Limitations on AI Access

In the FHIR Permission there is a concept of a "limit" which is limits placed on a permit provision. Where the limit might be an obligation or refrain, might be a specific additional data tag, or might be explicit removal of data elements. I have made an extension to replicate this "limit" concept so that it can be used on a Consent.provision. A "limit" should never be allowed to expose data where that limit can't be enforced. Specifically meaning that the recipient of the data must be trusted to enforce the obligation or refrain indicated. PermissionRuleLimit Extension

In FHIR R6 one could have a Consent that holds the provisions as a Permission resource, and thus the limits capability is available.

Allow AI for ML Training on De-Identified Data

* provision.type = #permit
* provision.purpose[+] = $purposeOfUse#MLTRAINING
* provision.modifierExtension[limit].extension[control].valueCodeableConcept = $obligation#DEID  

Consent example: Allow ML Training on De-Identified Data

Conclusion

The above examples are showing simply how a Consent.provision iteration can carry permit and deny to indicate consent or dissent for AI. The examples are not exhaustive, and there are many other combinations of provisions that could be used to indicate consent or dissent for AI. The examples are also not indicating any specific data elements that are being allowed or denied, but those could be added as additional restrictions on the provision.

The reader should be able to take a quilted Consent that has various provisions indicating consent or dissent for various clinical use (TPO) and add in provisions indicating consent or dissent for various AI use-cases, and thus have a single Consent that indicates the patient's preferences for both traditional clinical use and AI use.

The above examples are available in a draft IG on Consent About AI. That IG might further refine and improve beyond this blog article.


🎁Note, this is one of those projects I do pro bono but would love if someone would care enough about it to contract with me. Sustaining the Work That Sustains Trust: Why I’m Seeking Support for Some of My Standards Efforts

Thursday, February 5, 2026

Security Labeling Service - Reference Implementation

I have spent far too much time with Co-Pilot AI, but I am so happy with the output. I have vibe coded two applications. I wrote in a readme what I wanted done, and co-pilot produced a working application on the first try. I then spent two days improving (adding features and robustness) them. I never needed to touch code, I just typed what I wanted changed, improved, or fixed.

I have insisted that the apps clearly indicate their Provenance: 
This application was developed by GitHub Copilot (Claude Sonnet 4.5) ..., at the direction of John Moehrke of Moehrke Research LLC

SAMHSA ValueSet viewer

The fist vibe coding project I had was to create a github.io app that allows me to see the contents of a given set of ValueSets from SAMHSA. The reason I needed this is because some of these are too big for the IG Publisher to render the expansion. I had asked to have a setting that would set the IG Publisher 1000 entry max to 2000. But this request was rejected. So, this was my inspiration.

All I did was ask co-pilot to make me an application that can use a FHIR defined $expand operation against the tx.fhir.org server, for a list of ValueSets by url; and display the results.  

This was a total of 15 minutes of my time. I then proudly told my family, and my boys proceeded to break it. Turns out a feature I asked was the "Check All Sizes", and that was introduced a bug if run first. So, I told co-pilot about this effect, and it fixed it. Add 5 more minutes.

Try it out at SAMHSA ValueSet Viewer. Don't beat on it too much as it does use tx.fhir.org.

Security Labeling Service - Reference Implementation

This one is far bigger, and I have been thinking of asking AI to make this one for me. I created a github repository, and wrote a README.md with just a few words about what I wanted done. Mostly what you see at the beginning of the current README.md; although this has been touched up as I asked for more features. 

Again, the result of the first try worked. I have since improved it in ways that I failed to explain in my original README.md ask. I failed to explain that I wanted a docker deployable server, that the API must be FHIR $operation compliant, that it needs to support ValueSet with multiple topic values, etc.

I was impressed that it started with a sample ValueSet bundle, and sample data Bundle. Very simplistic, but reasonable. These have since been updated to test some of the features added.

What took the most time is that I wanted to be sure that this SLS worked. For this I needed to have complex ValueSets, and complex Data. In both cases I have been working in SHIFT-Task-Force on these very things. I had an IG that had both together.  First I chose to break the data use-cases out from the SLS and ValueSets. The main reason was that I know there is going to be significant improvement in the data use-cases; and the ValueSets cause the build to be very slow. In the ValueSets, I have many to choose from, but I chose to use the ValueSets that are derived from the existing LEAP SLS Reference Implementation. This is an early open-source and suffers from having the codes hard-coded into the source code. 

So I have the data from the use-case, and it is "in theory" already properly tagged. Turns out, that tagging had some errors. I had ValueSets, but they needed to be rearranged and have topic indications. It is this topic indication that is key. These ValueSets are specific to a kind of sensitive data. That is to say the definition of what is composed in the ValueSet is a bunch of clinical codes or hierarchy of codes. The ValueSet then needs to be identified with the Sensitive code that it represents. That is to say that ValueSet (A) has a topic of "BH" (in the hl7 vocabulary this is behavioral health), and composed in the valueSet is behavioral health indicating codes from loinc, snomed, icd, etc.

Testing these ValueSets and data Bundles did find a few more bugs, and a few more features to add. I do have even bigger ValueSets and data to try, derived from S

I'm not going to go deeper here, as this is available as Open-Source, and there is an Implementation Guide with the defined FHIR Operations.

Conclusion

Next up is to see if my kids can break this.  Another reason to not further explain it here, as any fixes I make will show up on the github.

I will note that my household is odd. My kids hate AI, with a passion. I seem to be doing okay with it. One would expect that the old-man would be the one with an aversion to AI. I am very suspicious, I have seen it really mess up, and I have seen the movies enough to worry about what it might do. But I choose to work with it in order to make it better at helping humans.

🎁Note, this is one of those projects I do pro bono but would love if someone would care enough about it to contract with me. Sustaining the Work That Sustains Trust: Why I’m Seeking Support for Some of My Standards Efforts