Repository navigation
[Bug] OCSF provenance has two homes, and the mapping's enrichment shape fails OCSF validation #260
Description
What is broken
The OCSF mapping and the Extending OCSF page put provenance in two different places, and the place the mapping requires can't be built as the mapping describes it.
Where
specification/v0.1.0/trace/ocsf-mapping.json (provenance_metadata); docs/spec/trace/extend_ocsf.md (the tool-call example and the Provenance implementation note)
What the specification says, and what happens instead
ocsf-mapping.json, provenance_metadata.description: "the OCSF event MUST carry provenance facts in 'enrichments' (an OCSF-recognized extensibility field). Each enrichment carries name='acs_provenance_*' and value={origin, source_id, ...}." It requires an acs_provenance_origin enrichment.
extend_ocsf.md says the opposite: "Provenance flows onto OCSF events under unmapped.acs.provenance." Its tool-call example does exactly that and carries no enrichments at all. events.md says nothing about provenance on OCSF events, so the two pages are all an implementer has.
The enrichment shape in the mapping also fails OCSF. In 1.9.0, enrichment.value is a string, and data (JSON) is required. I ran the tool-call example through https://schema.ocsf.io/api/v2/validate with an enrichment built the way the mapping describes it, {"name": "acs_provenance_origin", "value": {"origin": ..., "source_id": ...}}. It fails with two errors: enrichments[0].data is missing, and enrichments[0].value has the wrong type. The same event with "value": "user_input" and the provenance object in data passes. I added a device to both tries so the missing-device error from #235 didn't hide the result.
Impact on implementers
An exporter following the mapping writes events OCSF validators reject. An exporter following the docs page fails the mapping's MUST. Two exporters that each follow one source produce provenance a SIEM query can't find in the other's events. ACS-Trace requirement 3 (carry provenance forward onto the Trace event) has no single checkable form on the OCSF side.
Two smaller questions belong in the same fix. When a step carries more than one Provenance object, the mapping doesn't say whether that is one enrichment per object or one per field. It also doesn't say whether provenance_id goes along, which is what lets a reader join cited_provenance_ids on a decision back to its origin.
Proposed direction: pick one home and make the other page match. If it is enrichments, the mapping should say value is the origin string and data holds the Provenance object (provenance_id, origin, source_id), with one enrichment per object. If it is unmapped.acs.provenance, the MUST in the mapping changes to that path. Either way, the example on extend_ocsf.md should validate.
Related: #235 (OCSF required fields), #228 (decision replay facts, including cited_provenance_ids), #234 (OCSF examples on other pages).
Current Priority Scope
Feeds conformance evidence
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsAccepted
Activity
rocklambros commentedon Oct 12, 2026
More detail from reviewing the Trace PRs (#258, #261, and the #228 branch), so whoever picks this up starts from the same facts.
The two homes, confirmed.
ocsf-mapping.jsonprovenance_metadatasays the event "MUST carry provenance facts in 'enrichments'" withname='acs_provenance_*'andvalue={origin, source_id, ...}.extend_ocsf.mdsays "Provenance flows onto OCSF events underunmapped.acs.provenance", and its tool-call example does exactly that.events.mdsays nothing about provenance on OCSF.The required form also loses the join key. The normative enrichment form carries
originandsource_idbut noprovenance_id. The example'sunmapped.acs.provenanceentries do carry it. A decision cites provenance by id (cited_provenance_ids), so only the example form can be joined back to the provenance a decision cited.OCSF rejects the enrichment shape as written. Version 1.9.0 types
enrichment.valueas a string and requiresdata. I checked against the validator: the mapping's shape fails with two errors, andvalueset to the origin string with the Provenance object indatapasses. Fields underunmappedare never validated, which cuts both ways. They always pass, but nothing checks their shape.What the #228 branch does nearby. Every other ACS fact on an OCSF event now rides under
unmapped.acs. That covers the decision's replay fields (acs_fields), the join keys (join_fields,request_idandsession_id), andrequest_id/session_idon every step event. Provenance is the one fact still pointed atenrichments.Proposed direction (for a Spec lead to decide):
provenance_metadatadescription with: "When Provenance is attached to the originating hook, the OCSF event MUST carry each Provenance object under unmapped.acs.provenance as {provenance_id, origin, source_id when present}. Trust classification is computed by the Guardian against local policy and is not a v0.1 field (see §7.1)."required_enrichments/optional_enrichmentswithrequired_fields: ["provenance_id", "origin"]andoptional_fields: ["source_id"].enrichments, the mapping instead needs one enrichment per Provenance object,value= the origin string anddata= the object, andextend_ocsf.mdchanges to match.Decide it together with #262. That issue is the OTel side of the same join: an
acs.provenance.idsarray soacs.cited_provenance_idsresolves on a span. Both are small once the direction is picked. They touchocsf-mapping.json,extend_ocsf.mdandevents.md, so they should land after the #228 PR to avoid conflicts.