@prefix : <https://ontology.inferal.com/modules/advertising-measurement/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix mod: <https://w3id.org/mod#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix pubacc: <https://ontology.inferal.com/modules/publication-access/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rng: <https://ontology.inferal.com/modules/range/> .
@prefix set: <https://ontology.inferal.com/modules/sets/> .
@prefix vann: <http://purl.org/vocab/vann/> .

<https://ontology.inferal.com/modules/advertising-measurement/owl>
    a owl:Ontology, pubacc:PublicationManagedOntology ;
    dcterms:accessRights pubacc:PublicAccess ;
    owl:imports : , set:owl , rng:owl ;
    dcterms:title "Advertising Measurement Ontology - OWL Addendum" ;
    dcterms:description "OWL class, property, key, and disjointness axioms layered on the RDFS Advertising Measurement Ontology." ;
    dcterms:license <https://creativecommons.org/licenses/by/4.0/> ;
    dcterms:source : ;
    vann:preferredNamespacePrefix "adm" ;
    vann:preferredNamespaceUri "https://ontology.inferal.com/modules/advertising-measurement/" ;
    mod:status "draft" ;
    rdfs:comment "This addendum states identity for safely keyed supporting structures and incompatibility across value kinds. Metric observations and attribution bases deliberately have no OWL keys because their identifying context may be repeatable or incomplete. Consumers that load only the RDFS base see the vocabulary without these entailments." ;
    owl:versionInfo "0.1.0" .


# --- Classes -----------------------------------------------------------------

:MetricObservation a owl:Class .
:ObservationGrain a owl:Class .
:MetricKind a owl:Class .
:AttributedMetricKind a owl:Class .
:ReportingWindow a owl:Class .
:MetricValue a owl:Class .
:CountValue a owl:Class .
:MonetaryValue a owl:Class .
:RatioValue a owl:Class .
:CostRateValue a owl:Class .
:MonetaryAmount a owl:Class .
:AttributionBasis a owl:Class .
:CreditedInteraction a owl:Class .
:AttributionModel a owl:Class .
:Channel a owl:Class .
:HierarchyMembership a owl:Class .
:Breakdown a owl:Class .
:BreakdownDimension a owl:Class .
:PublisherPlatform a owl:Class .
:PlacementSurface a owl:Class .


# --- Object properties -------------------------------------------------------

:observationSubject a owl:ObjectProperty , owl:FunctionalProperty .
:observationGrain a owl:ObjectProperty , owl:FunctionalProperty .
:metricKind a owl:ObjectProperty , owl:FunctionalProperty .
:rateDenominatorMetric a owl:ObjectProperty , owl:FunctionalProperty .
:reportingWindow a owl:ObjectProperty , owl:FunctionalProperty .
:observedValue a owl:ObjectProperty , owl:FunctionalProperty .
:attributionBasis a owl:ObjectProperty , owl:FunctionalProperty .
:observedChannel a owl:ObjectProperty , owl:FunctionalProperty .
:windowStart a owl:ObjectProperty , owl:FunctionalProperty .
:windowEnd a owl:ObjectProperty , owl:FunctionalProperty .
:valueAmount a owl:ObjectProperty , owl:FunctionalProperty .
:usedAttributionModel a owl:ObjectProperty , owl:FunctionalProperty .
:creditedInteraction a owl:ObjectProperty , owl:FunctionalProperty .
:lookbackWindow a owl:ObjectProperty , owl:FunctionalProperty .
:containedIn a owl:ObjectProperty , owl:FunctionalProperty .
:containedResource a owl:ObjectProperty , owl:FunctionalProperty .
:validityWindow a owl:ObjectProperty , owl:FunctionalProperty .

# Deliberately not functional: an observation may be sliced along several
# dimensions at once, for example placement and country together.
:observationBreakdown a owl:ObjectProperty .
:breakdownDimension a owl:ObjectProperty , owl:FunctionalProperty .
:breakdownValue a owl:ObjectProperty , owl:FunctionalProperty .


# --- Datatype properties -----------------------------------------------------

:canonicalMagnitude a owl:DatatypeProperty , owl:FunctionalProperty .
:amountValue a owl:DatatypeProperty , owl:FunctionalProperty .
:currencyCode a owl:DatatypeProperty , owl:FunctionalProperty .

# Spine parents are datatype properties: every provider field beneath them
# carries a literal. They are not functional; a subject may report many
# metrics.
:metricValue a owl:DatatypeProperty .
:countValue a owl:DatatypeProperty .
:monetaryValue a owl:DatatypeProperty .
:ratioValue a owl:DatatypeProperty .
:costRateValue a owl:DatatypeProperty .

# --- Annotation properties ----------------------------------------------------

# Both describe a provider field, so their subject is itself a property. An
# annotation property is the construct that keeps such a statement inside
# OWL DL; a datatype or object property would push the module into OWL Full.
:wireEncoding a owl:AnnotationProperty .
:currencySource a owl:AnnotationProperty .
:lowersBy a owl:DatatypeProperty .
:lowersByCurrencyExponent a owl:DatatypeProperty .
:lowersTo a owl:AnnotationProperty .
:spineTerm a owl:AnnotationProperty .
:SpineComparability a owl:Class .
:comparableAs a owl:AnnotationProperty .

:WireEncoding a owl:Class .
:MajorUnits a owl:NamedIndividual , :WireEncoding .
:MinorUnits a owl:NamedIndividual , :WireEncoding .
:Micros a owl:NamedIndividual , :WireEncoding .
:CountOccurrences a owl:NamedIndividual , :WireEncoding .


# --- Identity ----------------------------------------------------------------

# There is deliberately no key on MetricObservation, and the absence is the
# point rather than an omission.
#
# An observation's identity depends on its set of breakdowns as much as on its
# subject, kind, window, and basis: a total and the placement slices that
# partition it agree on all four and are not the same measurement. A key over
# the four alone makes them identical, which an OWL-RL reasoner then acts on,
# merging the total with every slice and equating their values. That is worse
# than the double counting this module exists to prevent: it asserts the numbers
# are the same rather than merely adding them.
#
# Adding the breakdown property to the key does not help. owl:hasKey compares
# values property by property, and a repeatable property agrees whenever the two
# individuals share any value, so an observation sliced by placement and one
# sliced by placement and country would still merge. Set equality is not
# expressible as a key.
#
# Identity is therefore left to the producer, and comparability, which is the
# question that actually matters, is answered by the queries: comparable
# observations require breakdown-set equality in both directions, and the
# double-count query reports a total paired with each of its slices.
#
# Found by running an OWL-RL reasoner over the examples, which derived
# 121440 owl:sameAs 184203 among others.

# A membership is identified by what was contained, by what, and from when.
# Validity is part of the key because the same pair can recur after a move away
# and back.
:HierarchyMembership
    owl:hasKey ( :containedResource :containedIn :validityWindow ) .

:MonetaryAmount
    owl:hasKey ( :amountValue :currencyCode ) .

# Credited interaction is part of the key: a click-attributed and a
# view-attributed basis at the same lookback are different bases.
# Also deliberately absent. Two of the three components are optional: providers
# report a lookback without naming a model, or a model without an interaction
# kind. owl:hasKey applies only when an individual carries every key property,
# so a key over optional components silently stops applying exactly where two
# bases are least distinguishable, and a permissive implementation instead
# merges every basis that states only a model. Two providers' unstated bases
# are not the same basis: each names its own undisclosed rule.

:Breakdown
    owl:hasKey ( :breakdownDimension :breakdownValue ) .


# --- Incompatibility ---------------------------------------------------------

# The three value kinds are pairwise disjoint. This is what lets a reasoner
# reject a graph that types a return-on-ad-spend figure as a count, and what
# stops an aggregation rule from summing a ratio with a monetary amount.
:CountValue owl:disjointWith :MonetaryValue , :RatioValue , :CostRateValue .
:MonetaryValue owl:disjointWith :RatioValue , :CostRateValue .
:RatioValue owl:disjointWith :CostRateValue .

# An observation is not a value, and a window is not the thing it bounds.
:MetricObservation owl:disjointWith :MetricValue , :HierarchyMembership , :AttributionBasis .
:ReportingWindow owl:disjointWith :MonetaryAmount .
