The following sections provide guidance on how to structure properties, relationships, and access control within the Ontology.
Store each fact once. Use derived properties for convenience.
Denormalized data (copying values from linked objects onto a parent object) can be risky. When the data source changes, every copy must be updated. Normalization keeps data consistent, and derived properties give you the convenience of denormalized access without the upkeep.
Not all computed values are the same. The right approach depends on whether a value can be safely pre-computed from stable inputs or whether it needs to stay in sync with dynamic Ontology changes.
| Type | Characteristics | Recommended tool | Example |
|---|---|---|---|
| Pre-computed | Computed from properties on the same object; inputs rarely change or only change due to pipeline ingestion. | Pipeline transform | fullName = firstName + " " + lastName Inputs are stable and updated in the same pipeline, so pre-computing is safe and adds zero runtime overhead. |
| Dynamically derived | Depends on linked objects or values that change via actions, automations, or other Ontology-level operations. | Derived property | directReportCount Employees are reassigned, onboarded, and offboarded through actions. A derived property that counts linked Employee objects stays correct automatically. |
When a value depends on changes made through actions, every action that could affect the value must also update the value. If any action fails to do so, the value will remain incorrect until the discrepancy is identified.
A Manager object type needs to display a count of direct reports:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Manager Manager
- direct_report_count: 5 - direct_report_count (derived):
(manually maintained integer; counts linked Employee objects
must be updated every time → at query time
an employee joins or leaves)
Employee
Employee - manager (link to Manager)
- manager_name: "Alice"
(copied from the linked Manager;
breaks if the manager's name
changes)
Derived properties are evaluated at runtime. The performance characteristics vary by scale:
| Scale | Recommendation |
|---|---|
| Low to moderate (<~10k objects per query) | Use derived properties freely. Runtime evaluation is sufficiently performant for most workflows. |
| High (>~10k objects per query) | Derived properties may introduce latency due to higher-overhead query paths. Denormalization may be an appropriate tradeoff, but it should be a conscious, documented decision and not the default. |
Group semantically related fields into structs.
When a property is naturally multi-field (for example, an address with street, city, state, and postal code), use a struct rather than flattening into separate properties. Structs preserve semantic grouping and enable richer metadata capture.
| Scenario | Example |
|---|---|
| Multi-field values | Address (street, city, state, postal code), coordinates (latitude, longitude) |
| Values with metadata | AI-generated outputs with confidence scores, source references, and reasoning |
| Multi-valued properties with selection logic | Multiple phone numbers where a reducer surfaces the primary one |
Modeling an address on a Facility object type:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Facility Facility
- address_street - address (struct)
- address_city - street
- address_state → - city
- address_postal_code - state
- address_country - postal_code
- country
(Five unrelated properties with a
naming convention as the only link (One semantic concept with a main
between them) field and structured sub-fields)
| Benefit | Details |
|---|---|
| Semantic grouping | An address is one concept, not five unrelated strings. The Ontology reflects this. |
| Metadata capture | Structs can carry source, confidence, and timestamp information alongside the primary value. |
| Reducer support | In multi-valued scenarios, reducers can surface the most relevant value (for example, primary address). |
| Main field behavior | A struct can designate a main field so it behaves like a simple property in interfaces and queries. |
Structs are especially valuable in AI-first workflows where large language model (LLM) outputs have both a primary result and associated metadata (reasoning, source references, confidence scores). Capture these together rather than scattering them across unrelated properties.
Use interfaces to build reusable, future-proof abstractions.
Interfaces are the primary tool for achieving the "Don't repeat yourself" design principle and open/closed extensibility. They define a shared shape (properties, links, actions) that multiple object types can implement, enabling workflows to target the interface rather than individual types.
| Scenario | Example |
|---|---|
| Common properties across types | Inspectable interface with lastInspectionDate and inspectionStatus, implemented by Vehicle, Equipment, Facility |
| Shared workflows | A scheduling workflow targeting SchedulableResource works for arenas, conference rooms, and vehicles without modification |
| Taxonomic grouping | A MilitaryAsset interface implemented by Aircraft, Vessel, GroundVehicle for drilldown aggregation workflows |
| Multi-level abstraction | SchedulableResource extends Trackable, adding scheduling-specific properties to a broader tracking abstraction |
Multiple object types need inspection tracking:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Vehicle Interface: Inspectable
- lastInspectionDate - lastInspectionDate
- inspectionStatus - inspectionStatus
- (duplicate action: Schedule - (shared action: Schedule Inspection)
Vehicle Inspection)
→ Vehicle implements Inspectable
Equipment - make, model, mileage, ...
- lastInspectionDate
- inspectionStatus Equipment implements Inspectable
- (duplicate action: Schedule - serial_number, warranty_expiry, ...
Equipment Inspection)
Facility implements Inspectable
Facility - address, capacity, ...
- lastInspectionDate
- inspectionStatus (One interface, one shared action,
- (duplicate action: Schedule three implementing types)
Facility Inspection)
(Three copies of the same properties
and logic, maintained independently)
Even where current platform tooling does not fully support interface-backed workflows, designing with interfaces establishes a foundation that pays off as support expands.
| Situation | Guidance |
|---|---|
| The interface is fully supported in your workflow | Target the interface directly. A single workflow covers all implementing types. |
| The interface is not yet supported in a specific context | Define the interface now and duplicate the workflow per type as a temporary measure. This approach is no less efficient than working without an interface, and it establishes a clear path to consolidation once support is available. |
Review our interface documentation for current support details.
Inspectable, Schedulable, or Billable. Taxonomic interfaces may include MilitaryAsset or MedicalDevice.Links should represent semantically meaningful relationships.
Every link type should answer a clear domain question, such as:
| Link type | Use when | Example |
|---|---|---|
| Direct link | The relationship is meaningful but carries no metadata of its own. | Employee → Department |
| Object-backed link | The relationship carries its own metadata (dates, roles, status, allocation). | Employee → VentureStaffing → Venture (with role, startDate, allocation) |
Not every linking object needs to be visible in every context. Some workflows care about the join metadata, others just want the direct connection. Object-backed links let you expose either view depending on the workflow.
Modeling the relationship between employees and ventures, where each assignment has a role and start date:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Employee → Venture (direct link) Employee → Venture Staffing → Venture
(no way to capture role,
start date, or allocation → Venture Staffing
per assignment) - role
- start_date
— OR — - allocation_percentage
- status
Employee
- venture_role Workflows can expose either:
- venture_start_date - Direct: Employee → Venture
(ambiguous if employee has - Detailed: Employee → Staffing → Venture
multiple venture assignments)
| Problem | Impact |
|---|---|
| Lost metadata | Direct links cannot capture when, why, or in what capacity a relationship exists. |
| Ambiguous multi-links | Properties like venture_role on the source object become ambiguous when an entity participates in multiple relationships. |
| Meaningless links | Links that exist only because two datasets share a foreign key add noise to the Ontology and confuse navigation. |
Optimize for human readability and agent navigability.
Consistent, descriptive naming is one of the most impactful investments you can make in Ontology quality. Clear names make the Ontology easier for both humans and AI agents to navigate, and they are far harder to correct once the Ontology is in use.
| Element | Convention | Good examples | Bad examples |
|---|---|---|---|
| Object types | Singular, concrete nouns a domain expert would recognize | Patient, WorkOrder, FlightSegment | Data, Item, Record |
| Properties | Concise, self-evident; no encoded type info or implementation details | age, status, lastInspectionDate | dtLastInspMod, nVAL_01, field_x |
| Links | Read naturally from each direction | department (Employee → Dept), employees (Dept → Employee) | related_items, link_1 |
| Dates | Follow a single convention consistently across the Ontology | createdDate, updatedDate, effectiveDate | Mixing createdDate and dateOfCreation |
| Ambiguous terms | Qualify with specific meaning | monetaryValue, quantityOnHand, riskScore | value, quantity, score |
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
Object type: Item → Object type: Product
Property: dtLastInspMod → Property: lastInspectionDate
Property: value → Property: monetaryValue
Property: quantityOnHand
Link: Item → Related Item → Link: Product → Supplier
Link: Employee → Supervisor
createdDate, do not introduce dateOfCreation.monetaryValue, quantityOnHand, and riskScore. Do not use value, quantity, and score.Employee to Department should be department (from the employee's perspective) and employees (from the department's perspective).Design security semantically, following the principle of least privilege.
Security in the Ontology should be expressed in terms that make sense in the domain, not in terms of data infrastructure. Users should be able to look at a security configuration and understand what is protected and why.
Combine row-level and column-level security for fine-grained cell-level access control:
| Security layer | Controls | Example |
|---|---|---|
| Row-level | The objects a user can view | VIP patients are restricted to senior staff |
| Column-level | The properties a user can view on visible objects | Clinical notes are restricted to the care team |
| Cell-level (combined) | The intersection of row and column restrictions | VIP patients' clinical notes are visible only to the senior care team |
Controlling access to sensitive patient data:
✗ Avoid ✓ Prefer
──────────────────────────────────────── ────────────────────────────────────────
PublicPatient (object type) Patient (single object type)
- name - name
- dob - dob
- diagnosis - diagnosis (column-restricted:
care team only)
RestrictedPatient (object type) → - clinical_notes (column-restricted:
- name care team only)
- dob - mental_health_records (column-
- diagnosis restricted: psychiatry team only)
- clinical_notes
- mental_health_records Row-level security:
- VIP patients: senior staff only
(Duplicated schemas; security
achieved by splitting types. Column-level security:
Properties added to one type are - clinical_notes: care team only
easily forgotten on the other.) - mental_health_records: psychiatry only
(One type; security achieved by policy.
Domain boundaries drive access rules.)
| Problem | Impact |
|---|---|
| Duplicated types for security | Schemas drift out of sync; properties added to one type are easily forgotten on the other. Violates the "Don't repeat yourself" design principle. |
| Over-permissive defaults | Starting with broad access and restricting later risks exposing sensitive data before lockdown is complete. |
| Ad-hoc filtering instead of policy | Security logic scattered through application code rather than enforced at the Ontology layer is fragile and difficult to audit. |
| Misaligned boundaries | Security boundaries that do not follow domain boundaries are harder to reason about and more likely to have gaps. |
Use the guidance on this page to ensure security boundaries align with domain boundaries, then refer to our security and governance documentation for configuration details.