@prefix : <https://ontology.inferal.com/profiles/relay-advertising/googleads/> .
@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 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 rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@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#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:
    a owl:Ontology, prof:Profile, mod:SemanticArtefact, voaf:Vocabulary,
      pubacc:PublicationManagedOntology ;
    dcterms:accessRights pubacc:PublicAccess ;
    owl:imports adm: , abg: , adel: ;
    dcterms:title "Relay Advertising Profile: Google Ads" ;
    dcterms:description "Maps the values Google Ads actually sends onto the advertising measurement, budget, and delivery-state vocabularies, including its decomposed budget and attribution configuration omitted by the selected aggregate report projection." ;
    dcterms:license <https://creativecommons.org/licenses/by/4.0/> ;
    dcterms:source adm: , abg: , adel: ;
    vann:preferredNamespacePrefix "gads-adv" ;
    vann:preferredNamespaceUri "https://ontology.inferal.com/profiles/relay-advertising/googleads/" ;
    mod:status "draft" ;
    rdfs:comment "Google Ads disagrees with the other providers in ways that shaped the shared model. Its budget is already decomposed into amount, period, delivery method, type, and status, which is the reference shape the budget module argues for. Its sharing is reported as a flag and a reference count with the referenced campaigns unnamed, which is why a covered set may be unenumerated rather than empty. Its periods are a day or a custom span with no lifetime. The selected aggregate report projection omits effective attribution model, lookback and interaction applicability. ConversionAction exposes attributionModelSettings, clickThroughLookbackWindowDays and viewThroughLookbackWindowDays in the retained API schema; a current action configuration does not establish what applied to every contribution in a historical aggregate. Projected aggregate figures therefore retain an unstated basis until report-scoped evidence qualifies them." ;
    owl:versionInfo "0.1.0" .


# --- Protocol sentinels ------------------------------------------------------
#
# Every Google enumeration carries two members that are not domain values: one
# meaning the field was never set and one meaning the client is older than the
# value. A lowering must drop them rather than mint concepts for them, because
# a sentinel in a controlled vocabulary would be indistinguishable from a real
# category and would silently join query results.

:protocolSentinelPolicy
    a skos:Concept ;
    rdfs:label "protocol sentinel handling" ;
    rdfs:comment "Values meaning unspecified or unknown are protocol artefacts, not categories. A lowering omits the corresponding property rather than mapping them, so an unset delivery method produces a budget with no delivery method rather than one paced in an unknown way." ;
    skos:hiddenLabel "UNSPECIFIED", "UNKNOWN" .


# --- Budget ------------------------------------------------------------------
#
# The reference decomposition. Google separates the parts the other providers
# collapse, and the shared module's shape is drawn from it.

:dailyBudgetPeriod
    a abg:BudgetPeriod, skos:Concept ;
    skos:inScheme abg:BudgetPeriodScheme ;
    skos:exactMatch abg:dailyPeriod ;
    rdfs:label "daily"  ;
    rdfs:comment "A recurring per-day allowance, resetting at the account time zone's day boundary." ;
    skos:hiddenLabel "DAILY" .

:customBudgetPeriod
    a abg:BudgetPeriod, skos:Concept ;
    skos:inScheme abg:BudgetPeriodScheme ;
    skos:exactMatch abg:customPeriod ;
    rdfs:label "custom period" ;
    rdfs:comment "Google offers no lifetime period. A budget spanning a whole flight is expressed as a custom span, and the span itself lives on the effective window rather than in this value." ;
    skos:hiddenLabel "CUSTOM_PERIOD" .

:standardPacing
    a abg:DeliveryMethod, skos:Concept ;
    skos:inScheme abg:DeliveryMethodScheme ;
    skos:exactMatch abg:standardDelivery ;
    rdfs:label "standard"  ;
    rdfs:comment "Spending is paced evenly across the period." ;
    skos:hiddenLabel "STANDARD" .

:acceleratedPacing
    a abg:DeliveryMethod, skos:Concept ;
    skos:inScheme abg:DeliveryMethodScheme ;
    skos:exactMatch abg:acceleratedDelivery ;
    rdfs:label "accelerated"  ;
    rdfs:comment "Spending proceeds as fast as inventory allows and may exhaust the allowance before the period ends." ;
    skos:hiddenLabel "ACCELERATED" .


# --- Attribution -------------------------------------------------------------
#
# The selected aggregate projection does not retain report-scoped attribution
# configuration. ConversionAction exposes current model/lookback fields; their
# historical applicability to aggregate contributions is not established here.

:unstatedBasis
    a adm:AttributionBasis ;
    rdfs:label "Google Ads, attribution not reported" ;
    rdfs:comment "Marks attribution configuration omitted by this aggregate projection. Equal unknown marker identities establish no historical model, lookback, interaction or action-report-time equivalence. A current ConversionAction configuration cannot qualify all contributions in a historical aggregate. Retained report-scoped declarations can be assessed separately; native historical applicability remains unqualified." ;
    adm:usedAttributionModel adm:providerProprietaryModel .


# --- Outcome kinds -----------------------------------------------------------
#
# Google reports conversions as a typed field rather than an open bag, and the
# count is fractional because credit is apportioned across touchpoints.

:conversionOutcome
    a adm:AttributedMetricKind, skos:Concept ;
    skos:inScheme adm:MetricKindScheme ;
    skos:broader adm:conversions ;
    rdfs:label "conversions" ;
    rdfs:comment "Fractional by construction: Google apportions credit rather than assigning it whole." ;
    skos:definition "A count, possibly fractional, of credited outcomes within the reporting window." ;
    skos:hiddenLabel "conversions" .

:conversionValueOutcome
    a adm:AttributedMetricKind, skos:Concept ;
    skos:inScheme adm:MetricKindScheme ;
    skos:broader adm:conversionValue ;
    rdfs:label "conversion value"  ;
    rdfs:comment "The monetary worth Google attributes to credited outcomes, apportioned by the same undisclosed rule as the counts." ;
    skos:definition "A monetary quantity attributed to credited outcomes within the reporting window." ;
    skos:hiddenLabel "conversions_value" .

:viewableVideoOutcome
    a adm:MetricKind, skos:Concept ;
    skos:inScheme adm:MetricKindScheme ;
    skos:broader adm:videoView ;
    rdfs:label "video views" ;
    rdfs:comment "Counted against a Google-specific completion threshold that is not the same threshold another provider uses for the same word." ;
    skos:definition "A count of qualifying video views within the reporting window." ;
    skos:hiddenLabel "video_trueview_views" .


# --- Devices -----------------------------------------------------------------
#
# Google returns the device a report row's figures apply to in the row's
# segments.device field. The five device values are declared here with their
# wire tokens and matched to the codes Relay publishes for that field. The
# enumeration's UNSPECIFIED and UNKNOWN members are protocol sentinels and have
# no concept here.

:DeviceScheme
    a skos:ConceptScheme ;
    rdfs:label "Google Ads device scheme" ;
    rdfs:comment "The device values Google Ads returns in the segments.device field of a report row." ;
    skos:prefLabel "Google Ads devices" .

:mobileDevice
    a skos:Concept ;
    skos:inScheme :DeviceScheme ;
    skos:exactMatch <https://relay.inferal.com/ontology/googleads/SegmentsDevice/mobile> ;
    rdfs:label "mobile" ;
    rdfs:comment "Mobile devices with full browsers, as Google defines the value." ;
    skos:hiddenLabel "MOBILE" .

:desktopDevice
    a skos:Concept ;
    skos:inScheme :DeviceScheme ;
    skos:exactMatch <https://relay.inferal.com/ontology/googleads/SegmentsDevice/desktop> ;
    rdfs:label "desktop" ;
    rdfs:comment "Computers, as Google defines the value." ;
    skos:hiddenLabel "DESKTOP" .

:tabletDevice
    a skos:Concept ;
    skos:inScheme :DeviceScheme ;
    skos:exactMatch <https://relay.inferal.com/ontology/googleads/SegmentsDevice/tablet> ;
    rdfs:label "tablet" ;
    rdfs:comment "Tablets with full browsers, as Google defines the value." ;
    skos:hiddenLabel "TABLET" .

:connectedTvDevice
    a skos:Concept ;
    skos:inScheme :DeviceScheme ;
    skos:exactMatch <https://relay.inferal.com/ontology/googleads/SegmentsDevice/connectedTv> ;
    rdfs:label "connected TV" ;
    rdfs:comment "Smart TVs and game consoles, as Google defines the value." ;
    skos:hiddenLabel "CONNECTED_TV" .

:otherDevice
    a skos:Concept ;
    skos:inScheme :DeviceScheme ;
    skos:exactMatch <https://relay.inferal.com/ontology/googleads/SegmentsDevice/other> ;
    rdfs:label "other device" ;
    rdfs:comment "Other device types, as Google defines the value. A reported category, distinct from the UNKNOWN sentinel." ;
    skos:hiddenLabel "OTHER" .


# --- Delivery state ----------------------------------------------------------
#
# Google splits an advertiser status from a serving status and a primary status
# with its reasons, which is the right shape. The reasons are linked to shared
# hold kinds below; a hold whose reason is linked to none takes this kind.

:unmodelledServingHold
    a adel:HoldKind, skos:Concept ;
    skos:inScheme adel:HoldKindScheme ;
    skos:broader adel:unclassifiedHold ;
    rdfs:label "serving hold not classified" ;
    rdfs:comment "A Google hold whose reason this profile links to no shared hold kind: a primary status reason such as APP_NOT_RELEASED, AD_GROUP_PAUSED_DUE_TO_LOW_ACTIVITY, a booking reason or CAMPAIGN_DRAFT on a campaign, a serving status other than ENDED, or a not-serving entity that lists no reason giving a hold. It falls under the shared unclassified hold and under no more specific kind: guessing which one would route the hold to the wrong owner." .

:removedEntityState
    a adel:LifecycleState, skos:Concept ;
    skos:inScheme adel:LifecycleStateScheme ;
    skos:exactMatch adel:removedEntity ;
    rdfs:label "removed" ;
    rdfs:comment "Google marks entities removed rather than deleting them, and removed entities keep returning in reports. Their historical measurements stay valid while the entity cannot be restarted." ;
    skos:hiddenLabel "REMOVED" .


# --- Connector row fields ----------------------------------------------------
#
# Properties a connector wrote on a flat Google Ads metrics row for the
# customer, campaign and date segment the row reports. Relay emits a report row
# as a GoogleAdsRow nesting its resources, segments and metrics instead, and the
# properties are deprecated.

:reportCustomerId
    a rdf:Property ;
    owl:deprecated true ;
    rdfs:label "report customer ID" ;
    rdfs:comment "Deprecated. Named the numeric ID of the Google Ads customer whose account a flat metrics row reports. Relay emits a report row as a GoogleAdsRow nesting the customer, and the Google Ads mapping no longer reads this property." ;
    rdfs:range xsd:long .

:reportCampaignId
    a rdf:Property ;
    owl:deprecated true ;
    rdfs:label "report campaign ID" ;
    rdfs:comment "Deprecated. Named the numeric ID of the Google Ads campaign a flat metrics row reports. Relay emits a report row as a GoogleAdsRow nesting the campaign, and the Google Ads mapping no longer reads this property." ;
    rdfs:range xsd:long .

:reportDate
    a rdf:Property ;
    owl:deprecated true ;
    rdfs:label "report date" ;
    rdfs:comment "Deprecated. Named the calendar date segment of a flat Google Ads metrics row, as a string in year-month-day form. Relay emits a report row as a GoogleAdsRow whose segments carry the date, and the Google Ads mapping no longer reads this property." ;
    rdfs:range xsd:string .

# --- Serving status and primary status reasons ------------------------------
#
# Each value of Google's campaign serving status and of the campaign, ad group
# and ad primary status reasons whose definition in Google's API reference names
# a cause falls under one shared hold kind. A start or end in the past or future
# is a schedule hold; a paused, removed or draft ancestor an ancestor hold; a
# disapproval or pending review a policy review; and a missing or misconfigured
# setting, or children that are all paused or absent, a configuration hold.
# Limitation reasons (BUDGET_CONSTRAINED, BIDDING_STRATEGY_LEARNING and the
# like) describe an entity that serves, the reasons restating the entity's own
# pause or removal are its intent rather than a hold, CAMPAIGN_DRAFT on a
# campaign is the campaign's own draft standing, and app release, booking,
# low-activity, appeal and pending ad-generation reasons name no cause a shared
# kind covers. All of these, and the UNSPECIFIED and UNKNOWN sentinels, stay
# unmapped.

# Googleads.Campaign/servingStatus. Its values carry only their names, so only
# ENDED, which has one reading for a campaign, is linked.
<https://relay.inferal.com/ontology/googleads/CampaignServingStatus/ended> skos:broadMatch adel:outsideScheduleHold .

# Googleads.Campaign/primaryStatusReasons.
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/adGroupsPaused> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/adGroupAdsPaused> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/assetGroupsPaused> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/biddingStrategyMisconfigured> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/budgetMisconfigured> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/callExtensionDisapproved> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/callExtensionUnderReview> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/campaignEnded> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/campaignGroupAllGroupBudgetsEnded> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/campaignGroupPaused> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/campaignPending> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/hasAdsDisapproved> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/hasAssetGroupsDisapproved> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/keywordsPaused> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/leadFormExtensionDisapproved> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/leadFormExtensionUnderReview> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/missingCallExtension> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/missingLeadFormExtension> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/missingLocationTargeting> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/mostAdsUnderReview> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/mostAssetGroupsUnderReview> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/noAdGroups> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/noAdGroupAds> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/noAssetGroups> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/noKeywords> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/CampaignPrimaryStatusReasons/noMobileApplicationAdGroupCriteria> skos:broadMatch adel:configurationHold .

# Googleads.AdGroup/primaryStatusReasons. A CAMPAIGN_ reason names the ad
# group's campaign.
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/adGroupAdsPaused> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/adGroupIncomplete> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/campaignDraft> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/campaignEnded> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/campaignPaused> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/campaignPending> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/campaignRemoved> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/hasAdsDisapproved> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/keywordsPaused> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/mostAdsUnderReview> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/noAdGroupAds> skos:broadMatch adel:configurationHold .
<https://relay.inferal.com/ontology/googleads/AdGroupPrimaryStatusReasons/noKeywords> skos:broadMatch adel:configurationHold .

# Googleads.AdGroupAd/primaryStatusReasons. A CAMPAIGN_ reason names the
# ad's campaign, and AD_GROUP_PAUSED and AD_GROUP_REMOVED its ad group.
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/adGroupAdDisapproved> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/adGroupAdUnderReview> skos:broadMatch adel:policyReviewHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/adGroupPaused> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/adGroupRemoved> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/campaignEnded> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/campaignPaused> skos:broadMatch adel:ancestorHeldHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/campaignPending> skos:broadMatch adel:outsideScheduleHold .
<https://relay.inferal.com/ontology/googleads/AdGroupAdPrimaryStatusReasons/campaignRemoved> skos:broadMatch adel:ancestorHeldHold .
