CBPA — Competency Questions
Workshop: AI-Assisted Ontology Engineering — KGUG Seoul 2026
Author: Dougal Watt, Graph Research Labs
Twelve competency questions covering the canonical use cases of the
Cross-Border Payments and AML Ontology. Each CQ has:
- the plain-language question
- the use case it serves
- the ontology elements it exercises
- a SPARQL skeleton against the CLEAN ontology
The SPARQL skeletons are intentionally sketches; refine them when
generating tests via Artefact 5 in the workshop handout.
Prefixes:
PREFIX cbpa:
PREFIX gist:
PREFIX rdf:
PREFIX rdfs:
PREFIX skos:
PREFIX xsd:
================================================================
CQ1 — Which Accounts are held at Bank K (a specified Bank)?
----------------------------------------------------------------
Use case: morning portfolio attribution, bank-level reconciliation.
Elements: Account, Bank, heldAt.
Skeleton:
SELECT ?account WHERE {
?account a cbpa:Account ;
cbpa:heldAt ?bank .
?bank skos:prefLabel "Bank K"@en .
}
================================================================
CQ2 — Which Customers are currently rated High Risk?
----------------------------------------------------------------
Use case: AML alert triage. Tests gist:Specification + Category.
Elements: Customer, RiskAssessment, RiskRating (HighRisk),
hasRiskAssessment, gist:isCategorizedBy.
Skeleton:
SELECT ?customer WHERE {
?customer a cbpa:Customer ;
cbpa:hasRiskAssessment ?ra .
?ra gist:isCategorizedBy cbpa:HighRisk .
}
================================================================
CQ3 — For each Bank, how many of its Accounts are currently
non-compliant?
----------------------------------------------------------------
Use case: compliance dashboard for the Chief Compliance Officer.
Elements: Bank, Account, heldAt, ComplianceState, ComplianceLevel
(NonCompliant), hasComplianceState, gist:isCategorizedBy.
Skeleton:
SELECT ?bank (COUNT(?account) AS ?nonCompliantCount) WHERE {
?account a cbpa:Account ;
cbpa:heldAt ?bank ;
cbpa:hasComplianceState ?cs .
?cs gist:isCategorizedBy cbpa:NonCompliant .
} GROUP BY ?bank
================================================================
CQ4 — Which Payments were routed via SWIFT?
----------------------------------------------------------------
Use case: channel-driven settlement reporting.
Elements: Payment, ChannelType (SWIFT), viaChannel.
Skeleton:
SELECT ?payment WHERE {
?payment a cbpa:Payment ;
cbpa:viaChannel cbpa:SWIFT .
}
================================================================
CQ5 — Which PaymentInstructions request a CurrencyType that no
Account held by the authorising Customer is denominated in?
----------------------------------------------------------------
Use case: pre-settlement currency-mismatch detection (FX exposure,
AML anomaly). Multi-hop; exposes property-direction errors.
Elements: PaymentInstruction, instructsAmount, gist:Magnitude
(with currency unit), denominatedIn, Account, holdsAccount,
Customer, authorisedBy.
Skeleton:
SELECT ?instruction ?missingCurrency WHERE {
?instruction a cbpa:PaymentInstruction ;
cbpa:authorisedBy ?customer ;
cbpa:instructsAmount ?mag .
?mag cbpa:denominatedIn ?missingCurrency .
FILTER NOT EXISTS {
?customer cbpa:holdsAccount ?account .
?account cbpa:denominatedIn ?missingCurrency .
}
}
================================================================
CQ6 — Which Payments to or from Account ACC-001 cleared in
the last 30 days?
----------------------------------------------------------------
Use case: per-account transaction monitoring.
Elements: Account, Payment, payer, payee, settlementStatus,
SettlementStatus (Cleared), gist:occursIn, gist:TimeInterval.
Skeleton:
SELECT ?payment WHERE {
?payment a cbpa:Payment ;
cbpa:settlementStatus cbpa:Cleared ;
gist:occursIn ?ti .
?ti gist:startDateTime ?start .
FILTER (?start >= "2026-05-25T00:00:00Z"^^xsd:dateTime)
{ ?payment cbpa:payer cbpa:ACC-001 . }
UNION
{ ?payment cbpa:payee cbpa:ACC-001 . }
}
================================================================
CQ7 — Which PaymentInstructions were authorised but never
resulted in a Cleared Payment?
----------------------------------------------------------------
Use case: failed-settlement review, the marquee question that
depends on the plan/occurrence distinction (gist:Task vs gist:Event).
A Cleared SettlementStatus means money moved; any other status
(Pending, Rejected, Returned, Investigated) means the authorised
instruction never produced a real settlement.
Elements: PaymentInstruction, instructionStatus, InstructionStatus
(Authorised), instructionFor, Payment, settlementStatus, Cleared.
Skeleton:
SELECT ?instruction WHERE {
?instruction a cbpa:PaymentInstruction ;
cbpa:instructionStatus cbpa:Authorised ;
cbpa:instructionFor ?payment .
FILTER NOT EXISTS {
?payment cbpa:settlementStatus cbpa:Cleared .
}
}
================================================================
CQ8 — Which Customers are currently rated High Risk and
have an open SuspiciousActivityReport against any of their
Payments?
----------------------------------------------------------------
Use case: AML escalation work-list. Combines classification with
provenance content.
Elements: Customer, RiskAssessment, HighRisk, hasRiskAssessment,
holdsAccount, Account, Payment, payer, SuspiciousActivityReport,
reports.
Skeleton:
SELECT ?customer ?sar WHERE {
?customer a cbpa:Customer ;
cbpa:hasRiskAssessment ?ra ;
cbpa:holdsAccount ?account .
?ra gist:isCategorizedBy cbpa:HighRisk .
?payment cbpa:payer ?account .
?sar a cbpa:SuspiciousActivityReport ;
cbpa:reports ?payment .
}
================================================================
CQ9 — Which Customers underwent a KYCReviewEvent in the last
quarter and are currently rated High or Critical Risk?
----------------------------------------------------------------
Use case: review-cycle follow-up by the compliance team.
Elements: Customer, KYCReviewEvent, reviewsCustomer, gist:occursIn,
RiskAssessment, RiskRating (HighRisk, CriticalRisk),
hasRiskAssessment, gist:isCategorizedBy.
Skeleton:
SELECT ?customer WHERE {
?event a cbpa:KYCReviewEvent ;
cbpa:reviewsCustomer ?customer ;
gist:occursIn ?ti .
?ti gist:startDateTime ?start .
FILTER (?start >= "2026-04-01T00:00:00Z"^^xsd:dateTime
&& ?start < "2026-07-01T00:00:00Z"^^xsd:dateTime)
?customer cbpa:hasRiskAssessment ?ra .
?ra gist:isCategorizedBy ?level .
FILTER (?level IN (cbpa:HighRisk, cbpa:CriticalRisk))
}
================================================================
CQ10 — How many Payments routed via SWIFT and denominated in
USD settled during May 2026?
----------------------------------------------------------------
Use case: regulatory volume reporting, channel-currency analytics.
Elements: Payment, viaChannel, SWIFT, denominatedIn, USD,
gist:occursIn.
Skeleton:
SELECT (COUNT(?payment) AS ?n) WHERE {
?payment a cbpa:Payment ;
cbpa:viaChannel cbpa:SWIFT ;
cbpa:denominatedIn cbpa:USD ;
gist:occursIn ?ti .
?ti gist:startDateTime ?start .
FILTER (?start >= "2026-05-01T00:00:00Z"^^xsd:dateTime
&& ?start < "2026-06-01T00:00:00Z"^^xsd:dateTime)
}
================================================================
CQ11 — Which Banks have more non-compliant Accounts than
compliant Accounts?
----------------------------------------------------------------
Use case: bank-level compliance posture, escalation to regulator
prep. Aggregation across two counts with HAVING.
Elements: Bank, Account, heldAt, ComplianceState, ComplianceLevel
(FullyCompliant vs NonCompliant), hasComplianceState.
Skeleton (use subqueries to avoid the OPTIONAL cross-product trap):
SELECT ?bank ?nNon ?nComp WHERE {
{
SELECT ?bank (COUNT(?acc) AS ?nNon) WHERE {
?acc cbpa:heldAt ?bank ;
cbpa:hasComplianceState ?cs .
?cs gist:isCategorizedBy cbpa:NonCompliant .
} GROUP BY ?bank
}
OPTIONAL {
SELECT ?bank (COUNT(?acc2) AS ?nComp) WHERE {
?acc2 cbpa:heldAt ?bank ;
cbpa:hasComplianceState ?cs2 .
?cs2 gist:isCategorizedBy cbpa:FullyCompliant .
} GROUP BY ?bank
}
FILTER (?nNon > COALESCE(?nComp, 0))
}
================================================================
CQ12 — Which PurposeType categories appear on PaymentInstructions
but have never been carried through to a settled Payment?
----------------------------------------------------------------
Use case: declared-vs-actual purpose anomaly (AML pattern: legal
purpose declared in instruction, never matched by a real-world
settlement). Fleet-level gap analysis.
Elements: PaymentInstruction, declaredPurpose, PurposeType,
instructionFor, Payment, settlementStatus, Cleared.
Skeleton:
SELECT ?purpose WHERE {
?inst a cbpa:PaymentInstruction ;
cbpa:declaredPurpose ?purpose .
FILTER NOT EXISTS {
?inst2 a cbpa:PaymentInstruction ;
cbpa:declaredPurpose ?purpose ;
cbpa:instructionFor ?pay .
?pay cbpa:settlementStatus cbpa:Cleared .
}
}