Fragments
A fragment is a YAML file that defines the names one repo owns. Fragments compose: each imports the fragments it builds on and adds its own definitions. Nothing is registered centrally; the global catalog on the specs site is generated from every published fragment.
Where fragments live
| Convention | Rule |
|---|---|
| Location | <repo>/naming/<fragment-id>.yaml |
| Id | dotted, lowercase: virtufin.<area>[.<name>], e.g. virtufin.venue.binance, virtufin.worker.alpacaorderbook |
| C# | embed as a resource named naming/<file> and pack it under naming/ (see below); NameRegistry.Load(assembly) finds it in the assembly and every assembly it references |
| Python | ship it as package data under <package>/naming/ and register the package in the entry-point group virtufin.naming; NameRegistry.load() finds it |
| TypeScript | export the YAML text; the caller composes it explicitly |
| Docs | the docs workflow renders naming/*.yaml to docs/v1/naming.md, or to docs/v1/naming/tables.md when docs/v1/naming/ is a folder (see Docs tables) |
<ItemGroup>
<EmbeddedResource Include="..\..\naming\virtufin.market.yaml" LogicalName="naming/%(Filename)%(Extension)" />
<None Include="..\..\naming\virtufin.market.yaml" Pack="true" PackagePath="naming/" Visible="false" />
<PackageReference Include="Virtufin.Naming" />
</ItemGroup>
Schema
| Key | Type | Meaning |
|---|---|---|
fragment |
string, required | the fragment id |
description |
string | shown in the docs |
imports |
list of ids | fragments this one references; virtufin.core is always imported |
patterns |
map name → pattern | named patterns, referenced as {ref: name} here or {ref: <fragment>/name} elsewhere |
entities |
map name → entity | new entities (see below) |
bind |
map name → {entity, with} |
specializations: entity is a local name or <fragment>/<name>, with fixes parameters |
venues |
map name → {symbol, case, intervals} |
venues this fragment owns |
workers |
map type → {consumes, produces} |
worker types this fragment owns; each becomes the core worker entity bound to that type |
Entity keys
| Key | Type | Meaning |
|---|---|---|
scope |
pattern | leading segments dropped from the ce-type, e.g. {ref: virtufin.worlds/world} |
path |
pattern | the vocabulary path |
identity |
pattern | the segments identifying one instance |
entity_type |
string | the subject prefix |
subject |
parameter or list | identity parameters forming the subject; default all of them |
index |
bool | whether stem.index is a valid key |
events |
map event → {partitioned} |
partitioned defaults to true |
status |
live | reserved |
reserved: specified, nothing produces it yet |
Pattern syntax
| YAML | Combinator |
|---|---|
exchange |
Lit("exchange") |
[a, b, c] |
Seq(a, b, c) |
{vocab: venue}, {identifier: world}, {pair: pair}, {guid: id}, {interval: interval}, {token: run_id}, {any: x} |
Seg(class, name) |
{ref: name} |
the named pattern |
{optional: pattern} |
Optional(pattern) |
{oneOf: {selector: s, alternatives: {a: pattern, b: pattern}}} |
OneOf(s, (a, …), (b, …)) |
Example
fragment: virtufin.market
imports: [virtufin.worlds]
patterns:
venue_path: [exchange, {vocab: venue}]
entities:
orderbook:
scope: {ref: virtufin.worlds/world}
path: [{ref: venue_path}, orderbook]
identity: [{pair: pair}]
entity_type: currency_pair
events:
update: {partitioned: false} # raw venue feed, all pairs on one topic
snapshot: {partitioned: false}
changed: {}
gap: {}
Ownership and conflicts
| Rule | Enforced by |
|---|---|
A fragment defines names only under what it owns: its venue, its worker types, its service, or new entities of its domain. Everything else comes through imports. |
review; the conflict check below |
| A reference to another fragment's pattern or entity requires importing it. | composition fails |
| A venue or worker type is declared by exactly one fragment. | composition fails |
No two families may produce the same topic or key, unless one is a bind of the other. |
composition fails, naming both families and their templates |
| The same fragment id may appear twice only with identical content (e.g. two packages carrying one copy). | composition fails |
Docs tables
The docs workflow (docs-common.yaml) runs the renderer whenever a repo has
a naming/ folder:
virtufin-naming render naming/ -o docs/v1/naming.md
Imports are resolved from the NuGet packages the docs build restored (each
Virtufin.* package carries its fragments under naming/) and from
installed Python packages. To check a repo's fragments locally:
uvx --from virtufin-naming virtufin-naming check naming/
The specs site runs virtufin-naming collect to download every published
fragment and virtufin-naming render --reference to build the global
catalog. A conflict between two repos fails that build.