How the schema reads the CDM
The schema is the Common Domain Model (CDM) that FINOS publishes, at release 8.0.0-dev.13, the newest on FINOS’s master branch. scripts/rosetta_to_linkml.py writes it from two parts of FINOS’s tree: the Rosetta model under rosetta-source/src/main/rosetta/, and the FpML code lists under rosetta-source/src/main/resources/codelist/json/ that the model names. tests/test_converter.py fails when a module differs from what the converter writes.
What each Rosetta construct becomes
Section titled “What each Rosetta construct becomes”| Rosetta | LinkML |
|---|---|
A namespace, such as cdm.base.datetime |
A module, cdm_base_datetime.yaml, which imports the modules its types name. common_domain_model.yaml imports them all. |
type |
A class, with the CDM’s name and description. |
extends |
is_a. |
| An attribute | An attribute of the class, with the CDM’s camelCase name. |
An attribute a subtype declares again, or marks override |
slot_usage on the subtype. |
Cardinality (1..1), (0..*), (2..2) |
required, multivalued, minimum_cardinality and maximum_cardinality. |
choice |
A class with one attribute per option, named after the option’s type, and an exactly_one_of over them. |
enum |
An enumeration. A value with a displayName is keyed by that name, which is what Rune writes in JSON, and lists its Rosetta name under aliases. |
enum ... extends |
The parent’s values repeated, since LinkML enumerations do not inherit. |
typeAlias naming an FpML code list |
An enumeration of the list’s codes, with enum_uri naming the list and see_also the version read. Rosetta checks a code against the list, and so does the enumeration. FpML publishes no IRI for a code, so a value carries no meaning. |
Another typeAlias |
A LinkML type, with its bounds. |
one-of, required choice, optional choice |
exactly_one_of on the class. An optional choice adds a branch in which none is present. |
| A condition on the type’s own attributes | A class expression, or a rule when it starts with if. Rune reads a comparison with an absent value as false, so a comparison on an optional attribute also requires it (value_presence: PRESENT). |
a <> X |
none_of over a = X with a present, since Rune reads null <> X as true: the class’s own none_of for a bare condition, nested where it stands inside an or or a rule. |
[metadata key], [metadata reference], [metadata scheme] and the rest |
The annotation rosetta_metadata, with the whole annotation’s text, so an address keeps its "pointsTo" path. |
[docReference ...] |
The annotation doc_reference, and see_also for a schemeLocation. A provision’s text is left out. |
[deprecated] |
deprecated. |
[rootType] |
The annotation rosetta_root_type. |
A Rosetta condition binds every subtype. The JSON Schema generator applies an ancestor’s rules to a subclass itself, but reads a class expression (all_of, none_of) from the class alone, so the converter states each ancestor’s class expressions again on every subtype, with From <Type>. before its description, and leaves its rules to the generator.
Thirteen attribute names, such as name, description and version, are also slots of LOKF’s schema, under other IRIs. They are top-level slots in common_domain_model_keys.yaml, and each class that uses one gives its description and range in slot_usage, so that lokf adapt can rename them in the copy a knowledge bundle imports.
A name two Rosetta namespaces both declare takes the last part of its namespace as a prefix, because LinkML merges a schema’s imports into one namespace: CsaAdditionalTerminationEvent and IsdaAdditionalTerminationEvent, AssetFloatingRateIndex and CodelistFloatingRateIndex, AssetSettlementRateOption and CodelistSettlementRateOption. Each lists its Rosetta name under aliases.
What LinkML cannot state
Section titled “What LinkML cannot state”About half of the CDM’s conditions are stated. just linkml-report counts them, and a class’s comments name each one that is not, with its Rosetta text. These cannot be stated:
- a condition on a path into another type, such as
relatedAgreements -> agreementDate exists, or on a choice option throughas; - a comparison of two attributes, such as
startDate <= endDate; - a condition over a list’s members, with
count,only exists,contains,allorany; - equality with
TrueorFalse, since LinkML has no boolean slot condition, and JSON Schema compares a string condition with a JSON boolean and never matches; - a strict bound on a decimal, such as
> 0, since LinkML’s bounds are inclusive; - a function call,
switchorto-enum.
Four more things Rosetta states have a partial LinkML counterpart, or none:
- Metadata. A
[metadata reference]attribute may hold a reference to a keyed object instead of the object, and a[metadata scheme]value may carry the scheme it comes from. The schema states the value alone, and the annotation records the metadata. - Subtypes in place of their parent. An attribute declared with a type may hold any of its subtypes, as in Java. The JSON Schema is generated with
include_range_class_descendants, so a value of a subtype validates where its parent is declared; the other generators read the declared type. FINOS’s documents hold 264 such values, whichtests/sample_departures.yamlcounts. - Logic. Functions, qualification functions and reporting rules compute or classify data, and are not data, so they are left out.
- One meaning per name. A Rosetta attribute belongs to its type, so
identifiermay be a string in one type and an object in another. LinkML gives each attribute name one IRI, and the JSON-LD context one term, so the RDF of a document reads everyidentifieralike.
Reading a CDM document
Section titled “Reading a CDM document”Rune writes a CDM object to JSON with keys that carry metadata: @type, @key and its :external and :scoped forms, @ref and its forms, @data and @scheme. It writes a choice by the type the choice holds. tests/rune_json.py puts such a document in the form this schema states: it drops the keys, replaces a reference with the object it names in the same document, unwraps @data, and nests a choice through its options.
tests/test_finos_samples.py reads every CDM document in FINOS’s tree that way, about 900 in all, and holds its shape. Every key must be an attribute of the type at that place, every value must have its attribute’s type, and every enumerated value must be one of its enumeration’s. The test does not hold completeness. FINOS’s ingest writes partial trades from partial FpML, and most of them leave out a required attribute or break a condition. tests/sample_departures.yaml lists the documents whose shape the schema refuses, with the reason for each.
What is left out
Section titled “What is left out”- The CDM’s synonym mappings, which FINOS’s tree no longer holds at this release, and the guessed SSSOM sets this fork used to carry.
- The namespaces that hold only functions and rules and declare no type, such as the FpML ingest under
cdm.ingest. - The descriptions of FpML’s codes, and the text of the ISDA, ICMA and other documents the CDM cites. NOTICE says what the schema carries and under which terms.