# SHACL rules comparison: cog-sail vs other environments

This document compares the sailboat SHACL rules with other rule files in the repo so you can align patterns and debug why rules might not fire.

## Namespace and target class patterns

| Environment   | Prefix | Namespace URL (base) | Example targetClass | How validation is run |
|---------------|--------|----------------------|---------------------|------------------------|
| **cog-sail**  | `sb`   | `http://purl.org/cognite/sailboat/sailboat/` | `sb:NMEATimeSeries`, `sb:PGN`, `sb:SailingBoat` | Whole data model (sailboat, sailboat, v1); one rules file for all views. |
| **cog-ai equipment** | `sp` | `http://purl.org/cognite/sp_enterprise_process_industry/YourOrgEquipment/` | `sp:YourOrgEquipment` | Single view: datamodel = (sp_enterprise_process_industry, **YourOrgEquipment**, v1). |
| **cog-ai operation** | `sp` | `.../YourOrgOperation/` | `sp:YourOrgOperation`, `sp:YourOrgEquipment` | Single view YourOrgOperation; Equipment shape used for cross-reference. |
| **cog-ai maintenance_order** | `sp` | `.../YourOrgMaintenanceOrder/` | `sp:YourOrgMaintenanceOrder` | Single view YourOrgMaintenanceOrder. |
| **cog-ai timeseries** | `cdm_ts` | `http://purl.org/cognite/cdf_cdm/CogniteTimeSeries/` | `cdm_ts:CogniteTimeSeries` | Single view CogniteTimeSeries (cdf_cdm). |
| **abp-dev**   | `ex`   | `http://example.org/ontology#` | `ex:CommissioningPackage` | Example ontology. |

## Differences that can affect whether rules fire

### 1. One namespace for whole model (sailboat) vs one per view (cog-ai)

- **cog-ai**: Each rule file is tied to a **single view**. The namespace URL ends with the **view** name (e.g. `YourOrgEquipment`, `CogniteTimeSeries`). So the type IRI in the graph is typically `.../YourOrgEquipment/YourOrgEquipment` (namespace + local name).
- **cog-sail**: One namespace for the **data model** (`.../sailboat/sailboat/`). All view types live under that base: `sb:NMEATimeSeries` → `.../sailboat/sailboat/NMEATimeSeries`. The RDF extractor (DMSGraphExtractor) might instead emit types like `.../sailboat/sailboat/NMEATimeSeries/NMEATimeSeries` (view name twice) for consistency with single-view behaviour. If so, `sh:targetClass sb:NMEATimeSeries` would not match and no NMEATimeSeries shapes would run.

### 2. Property paths

- **cog-ai**: Properties use the same prefix as the view, e.g. `sp:name`, `sp:asset`, `sp:maintenanceOrder`. So property IRIs are `.../YourOrgEquipment/name`, etc.
- **cog-sail**: Properties use `sb:`, e.g. `sb:name`, `sb:value`, `sb:mmsi`. So we assume property IRIs are `.../sailboat/sailboat/name`, `.../sailboat/sailboat/value`. If the extractor uses view-qualified properties (e.g. `.../sailboat/sailboat/NMEATimeSeries/value`), then `sh:path sb:value` would not match any triple.

### 3. Severity and structure

- **cog-ai** operation/equipment: Mix of `sh:Violation` and `sh:Warning`; some use `sh:datatype`, `sh:minInclusive`, `sh:node` for relations.
- **cog-sail**: Same idea: `sh:Violation` for “must”, `sh:Warning` for “should”; property shapes use `sh:minCount 1`, `sh:path`, and sometimes SPARQL.

## If sailboat rules report 0 violations

1. **Confirm target class in the graph**  
   Run validation with verbose output and check for the existing warning, e.g.:  
   `[WARNING] ... NMEATimeSeriesValueShape targets NMEATimeSeries (0 instances)`.  
   If you see “0 instances” for a shape, that shape’s `sh:targetClass` does not match any node type in the loaded graph.

2. **Align with how the extractor emits IRIs**  
   The extractor (DMSGraphExtractor) decides the actual `rdf:type` and predicate IRIs. If it uses:
   - type = `.../sailboat/sailboat/NMEATimeSeries/NMEATimeSeries` → use that full IRI (or a prefix that expands to it) in `sh:targetClass`.
   - value = `.../sailboat/sailboat/NMEATimeSeries/value` → use that (or a matching prefix) in `sh:path` for the value rule.

3. **Optional: view-qualified namespace (like cog-ai)**  
   You could split sailboat into one TTL per view and use a namespace that ends with the view name (e.g. `.../sailboat/sailboat/NMEATimeSeries/` and `targetClass`/properties under that). That would only help if the extractor actually uses that IRI pattern for types and properties.

## File reference

- Sailboat: `config/environments/cog-sail/shacl_rules/sailboat_data_quality_rules.ttl`
- Equipment: `config/environments/cog-ai/shacl_rules/equipment_shacl_rules.ttl`
- Operation: `config/environments/cog-ai/shacl_rules/operation_shacl_rules.ttl`
- Maintenance order: `config/environments/cog-ai/shacl_rules/maintenance_order_shacl_rules.ttl`
- Timeseries: `config/environments/cog-ai/shacl_rules/timeseries_quality_rules.ttl`
- Commissioning (abp-dev): `config/environments/abp-dev/shacl_rules/commissioning_package_shacl_rules.ttl`
