@prefix : <https://ontology.inferal.com/profiles/relay-advertising/linkedin/> .
@prefix abg: <https://ontology.inferal.com/modules/advertising-budget/> .
@prefix adel: <https://ontology.inferal.com/modules/advertising-delivery-state/> .
@prefix adm: <https://ontology.inferal.com/modules/advertising-measurement/> .
@prefix aent: <https://ontology.inferal.com/modules/advertising-entity/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix mod: <https://w3id.org/mod#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix prof: <http://www.w3.org/ns/dx/prof/> .
@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 skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix vann: <http://purl.org/vocab/vann/> .
@prefix voaf: <http://purl.org/vocommons/voaf#> .

:
    a owl:Ontology, prof:Profile, mod:SemanticArtefact, voaf:Vocabulary,
      pubacc:PublicationManagedOntology ;
    dcterms:accessRights pubacc:PublicAccess ;
    owl:imports adm: , abg: , adel: , aent: ;
    dcterms:title "Relay Advertising Profile: LinkedIn" ;
    dcterms:description "Maps the values LinkedIn actually sends onto the advertising measurement, budget, and delivery-state vocabularies, including an analytics row that names its subject and grain only through a sponsored-entity pivot value and never names the dimension it is partitioned by." ;
    dcterms:license <https://creativecommons.org/licenses/by/4.0/> ;
    dcterms:source adm: , abg: , adel: , aent: ;
    vann:preferredNamespacePrefix "li-adv" ;
    vann:preferredNamespaceUri "https://ontology.inferal.com/profiles/relay-advertising/linkedin/" ;
    mod:status "draft" ;
    rdfs:comment "LinkedIn agrees with the shared model where it matters most and disagrees where it is least expected. Its delivery reporting already separates what the advertiser intends from whether the entity is serving from the reasons it is held, which is the split the delivery-state module argues for and the only provider that ships it. Its money already pairs an amount with a currency code, which is the shape the measurement module requires. But its analytics rows carry no breakdown dimension and none of the request's facets. A row's pivot values are URNs, which name the measured entity and its tier only when the request pivots by a sponsored account, campaign group, campaign or creative; a row pivoted by a demographic value is not self-describing and cannot be lowered without the query that produced it. It also reports one spend measure twice, in the account currency and in dollars, which are the same measurement rather than two." ;
    owl:versionInfo "0.1.0" .


# --- Row context -------------------------------------------------------------
#
# The finding that generalises beyond this provider.

:rowContextPolicy
    a skos:Concept ;
    rdfs:label "analytics rows are not self-describing" ;
    rdfs:comment "A LinkedIn analytics row carries measures, a date range, and a list of pivot values. When the request pivots by a sponsored account, campaign group, campaign or creative, the one pivot value is that entity's URN, which names the entity measured and, by its kind, the tier that entity occupies. The row never carries the dimension its pivot values belong to or the facets the request filtered by; both are request parameters. A row pivoted by a demographic value, such as a country, therefore names neither the entity measured nor the axis of its value, and an integration that discards the request has irrecoverably lost the meaning of those numbers." ;
    rdfs:seeAlso <https://ontology.inferal.com/modules/advertising-measurement/MetricObservation> .

:pivotValueWithoutDimension
    a skos:Concept ;
    rdfs:label "pivot values arrive without their dimension" ;
    rdfs:comment "The response lists the values a row is partitioned by and never says which axis they came from. A breakdown requires both halves, so a lowering supplies the dimension from the request pivot. This is the case the mandatory dimension-and-value pair was written for: half a pair is not a weaker breakdown, it is an unusable one." .


# --- Money -------------------------------------------------------------------

:moneyAlignment
    a skos:Concept ;
    rdfs:label "money already carries its currency" ;
    rdfs:comment "LinkedIn is the only provider of the three whose monetary fields pair an amount with a currency code on the wire, which is the shape the shared model requires. Its analytics rows are the exception: those carry bare decimal strings whose currency comes from the account." .

:restatedInDollars
    a skos:Concept ;
    rdfs:label "spend restated in dollars" ;
    rdfs:comment "An analytics row reports cost in the account currency and again in dollars. These are one measurement expressed twice, not two measurements, so a lowering emits the account-currency observation and treats the dollar figure as a derived convenience. Emitting both as observations would make them appear in different currency groups and invite a consumer to add them." .

:unstatedBasis
    a adm:AttributionBasis ;
    adm:usedAttributionModel adm:providerProprietaryModel ;
    rdfs:label "LinkedIn attribution basis not reported" ;
    rdfs:comment "Relay's LinkedIn analytics row exposes attributed outcomes without the attribution model, credited interaction, or lookback window that produced them. A lowering records the provider-proprietary model and leaves the other dimensions absent rather than guessing them." .


# --- Delivery state ----------------------------------------------------------
#
# The reference shape. LinkedIn already splits intent from serving from reason,
# which is what the shared module generalises.

:intendedRunStatus
    a adel:DeliveryIntent, skos:Concept ;
    skos:inScheme adel:DeliveryIntentScheme ;
    skos:exactMatch adel:intendToRun ;
    rdfs:label "intended to run" ;
    rdfs:comment "LinkedIn names this field for intent explicitly, which is the distinction the other providers bury in a single status." ;
    skos:hiddenLabel "ACTIVE" .

:intendedHoldStatus
    a adel:DeliveryIntent, skos:Concept ;
    skos:inScheme adel:DeliveryIntentScheme ;
    skos:exactMatch adel:intendToHold ;
    rdfs:label "intended to hold"  ;
    rdfs:comment "The advertiser has switched delivery off, which LinkedIn records separately from whether the entity is serving." ;
    skos:hiddenLabel "PAUSED" .

:unnamedServingHold
    a adel:HoldKind, skos:Concept ;
    skos:inScheme adel:HoldKindScheme ;
    skos:broader adel:unclassifiedHold ;
    rdfs:label "serving hold reason not typed" ;
    rdfs:comment "A LinkedIn hold reason this profile links to no shared hold kind, such as FORM_HOLD, JOB_POSTING_ON_HOLD, PROCESSING_FAILED or STOPPED, or a reason Relay does not publish. A lowering records one hold per such reason with this kind rather than guessing a more specific one." .

:selfOriginatingHold
    a skos:Concept ;
    rdfs:label "hold origin named by tier" ;
    rdfs:comment "LinkedIn's hold reasons name at most the tier a hold comes from, never the resource: twelve of the 21 creative values carry an ACCOUNT_, CAMPAIGN_GROUP_ or CAMPAIGN_ prefix. A lowering resolves the prefix to the creative's account, its campaign's group or its campaign through the URNs the creative and its campaign carry, and sets every other reason's origin to the creative itself. A prefixed reason also originates on the creative, although it is inherited, when the creative names no well-formed URN of that tier, and a CAMPAIGN_GROUP_ reason when the creative's campaign record is absent or its campaign records name different groups." .


# --- Objectives ---------------------------------------------------------------
#
# Each value of LinkedIn's three objective lists, as Relay publishes it, falls
# under one shared objective. The campaign group list is the one the shared
# campaign tier carries; the campaign list and the analytics pivot list spell
# the same objectives with small differences. JOB_APPLICANTS and JOB_APPLICANT
# name a hiring outcome no shared objective covers and stay unmapped.

<https://relay.inferal.com/ontology/linkedin/CampaignGroupObjectiveType/brandAwareness> skos:broadMatch aent:awarenessObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupObjectiveType/engagement> skos:broadMatch aent:engagementObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupObjectiveType/leadGeneration> skos:broadMatch aent:leadObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupObjectiveType/videoViews> skos:broadMatch aent:videoViewsObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupObjectiveType/websiteConversions> skos:broadMatch aent:conversionsObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupObjectiveType/websiteVisit> skos:broadMatch aent:trafficObjective .

<https://relay.inferal.com/ontology/linkedin/CampaignObjectiveType/brandAwareness> skos:broadMatch aent:awarenessObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignObjectiveType/engagement> skos:broadMatch aent:engagementObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignObjectiveType/leadGeneration> skos:broadMatch aent:leadObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignObjectiveType/videoViews> skos:broadMatch aent:videoViewsObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignObjectiveType/websiteConversions> skos:broadMatch aent:conversionsObjective .
<https://relay.inferal.com/ontology/linkedin/CampaignObjectiveType/websiteVisits> skos:broadMatch aent:trafficObjective .

<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/brandAwareness> skos:broadMatch aent:awarenessObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/creativeEngagement> skos:broadMatch aent:engagementObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/engagement> skos:broadMatch aent:engagementObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/leadGeneration> skos:broadMatch aent:leadObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/videoView> skos:broadMatch aent:videoViewsObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/websiteConversion> skos:broadMatch aent:conversionsObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/websiteTraffic> skos:broadMatch aent:trafficObjective .
<https://relay.inferal.com/ontology/linkedin/AdAnalyticsObjectiveTypeValue/websiteVisit> skos:broadMatch aent:trafficObjective .

# --- Hold reasons and serving statuses -----------------------------------------
#
# Each value of LinkedIn's four hold lists whose label names the cause falls
# under one shared hold kind. A start or end date hold is a schedule hold, a
# total budget hold an exhausted allowance, and a hold naming a stopped or
# non-serving account, campaign group or campaign an ancestor hold; the prefix
# names the tier the hold comes from, not its kind. An audience count below
# LinkedIn's threshold is a configuration hold. RUNNABLE is not a hold.
# STOPPED, INTERNAL_HOLD, FORM_HOLD, JOB_POSTING_INVALID, JOB_POSTING_ON_HOLD
# and PROCESSING_FAILED name no cause a shared kind covers, and stay unmapped.

# Linkedin.Creative/servingHoldReasons: why a creative is not serving.
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/accountEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/accountServingHold> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/accountTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignAudienceCountHold> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignGroupEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignGroupStartDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignGroupStatusHold> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignGroupTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignStartDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignStopped> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/campaignTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/processing> skos:broadMatch adel:processingHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/referredContentQualityHold> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/rejected> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/linkedin/CreativeServingHoldReasons/underReview> skos:broadMatch adel:policyReviewHold .

# Linkedin.AdAccount/servingStatuses.
<https://relay.inferal.com/ontology/linkedin/AdAccountServingStatuses/accountEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/AdAccountServingStatuses/accountTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/AdAccountServingStatuses/billingHold> skos:broadMatch adel:billingHold .
<https://relay.inferal.com/ontology/linkedin/AdAccountServingStatuses/restrictedHold> skos:broadMatch adel:accountRestrictionHold .

# Linkedin.CampaignGroup/servingStatuses.
<https://relay.inferal.com/ontology/linkedin/CampaignGroupServingStatuses/accountEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupServingStatuses/accountTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupServingStatuses/billingHold> skos:broadMatch adel:billingHold .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupServingStatuses/campaignGroupEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupServingStatuses/campaignGroupStartDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignGroupServingStatuses/campaignGroupTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .

# Linkedin.Campaign/servingStatuses.
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/accountEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/accountServingHold> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/accountTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignAudienceCountHold> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignGroupEndDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignGroupStartDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignGroupStatusHold> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignGroupTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignStartDateHold> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/linkedin/CampaignServingStatuses/campaignTotalBudgetHold> skos:broadMatch adel:allowanceExhaustedHold .
