Skip to content

Commit dfe2d5f

Browse files
committed
feat(routines): add offline semantic contract foundation
1 parent bf1c157 commit dfe2d5f

14 files changed

Lines changed: 2393 additions & 23 deletions

.github/workflows/verify.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ jobs:
6161
run: |
6262
python3 -m unittest discover -s tools/lint/tests -v
6363
python3 tools/lint/routine_schemas.py
64+
python3 tools/lint/routine_semantics.py
6465
python3 tools/lint/routines.py
6566
6667
- name: Verify G36 source inventory

SCHEMA.md

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ cxf-library/
2222
├── routines/ # planned control-routine catalog
2323
│ ├── registry.json # canonical class inventory
2424
│ ├── generated-registry.json # executable deployment inventory
25-
│ ├── schemas/ # canonical class/interface input schemas
25+
│ ├── ontology/ # immutable ontology pins and local vocabulary
26+
│ ├── schemas/ # six governed routine contract schemas
2627
│ └── g36/ # G36 pins, source inventory, scope, and coverage
2728
├── tools/verify/ # Rust harness: loads each rule into the engine, runs vectors
2829
```
@@ -55,8 +56,9 @@ next free number, honoring any reservation.
5556
Routine contracts are independent of fault contracts. Nothing in this section
5657
changes a fault schema identifier or fault behavior. The routine catalog is
5758
schema-defined and non-executable. The current contract defines future
58-
canonical class, interface, and specialization input shapes without adding a
59-
production class, source mapping, specialization, or executable deployment.
59+
canonical class, interface, specialization, semantic-profile, and derivation
60+
shapes without adding a production class, source mapping, semantic profile,
61+
derivation manifest, specialization, or executable deployment.
6062

6163
Pin ownership is split by purpose:
6264

@@ -94,20 +96,24 @@ and row schemas are not defined by this version.
9496

9597
### Canonical routine schema resources
9698

97-
This schema set governs four JSON Schema Draft 2020-12 resources:
99+
This schema set governs six JSON Schema Draft 2020-12 resources:
98100

99101
| Path | `$id` |
100102
|---|---|
101103
| `routines/schemas/common.schema.json` | `https://open-control-library.example/schemas/routine-common-v1.json` |
102104
| `routines/schemas/class-manifest.schema.json` | `https://open-control-library.example/schemas/routine-class-manifest-v1.json` |
103105
| `routines/schemas/interface.schema.json` | `https://open-control-library.example/schemas/routine-interface-v2.json` |
104106
| `routines/schemas/specialization.schema.json` | `https://open-control-library.example/schemas/routine-specialization-v1.json` |
107+
| `routines/schemas/routine-semantic-profile.schema.json` | `https://open-control-library.example/schemas/routine-semantic-profile-v1.json` |
108+
| `routines/schemas/routine-derivation-manifest.schema.json` | `https://open-control-library.example/schemas/routine-derivation-manifest-v1.json` |
105109

106110
Each resource declares
107-
`https://json-schema.org/draft/2020-12/schema`. References use only the four
108-
absolute IDs above and resolve from an in-memory registry. Validation performs
109-
no network or filesystem retrieval for schema references. Objects are closed
110-
unless stated otherwise.
111+
`https://json-schema.org/draft/2020-12/schema`. References use same-resource
112+
fragments or the six absolute IDs above and resolve from an in-memory registry.
113+
Validation performs no network or filesystem retrieval for schema references.
114+
Objects are closed unless stated otherwise. Semantic-only definitions belong to
115+
the semantic-profile resource; `routine-common-v1` remains the existing routine
116+
class/interface contract.
111117

112118
Canonical class IDs have the form
113119
`G36-05-(01..22)-<UPPERCASE-HYPHENATED-CLASS-SLUG>`. Scope IDs are invalid
@@ -200,6 +206,86 @@ Specialization is input only. It contains no connector bindings, point IDs,
200206
resolved connector set, source map, generated CXF, runtime state, engine
201207
identity, or deployment identity.
202208

209+
#### Ontology identities and local vocabulary
210+
211+
`routines/ontology/ontology-pins.json` is the sole product ontology-pin record.
212+
It has the closed identifier `cxf-library/ontology-pins/v1` and records these
213+
immutable authorities:
214+
215+
| Authority | Identity |
216+
|---|---|
217+
| Brick | namespace `https://brickschema.org/schema/Brick#`; `BrickSchema/Brick` release `v1.4.4`; commit `4b5be60d27f9b4d96fe477f45513fa71afebe684`; release `Brick.ttl` SHA-256 `b65720b7b9b64c646745c689777e6138c0d59ce0088df0aeb78fbd444d04d8e7` |
218+
| ASHRAE 223 compatibility | core namespace `http://data.ashrae.org/standard223#`; G36 extension `http://data.ashrae.org/standard223/1.0/extensions/g36#`; version `1.0.0-ppr.2.1`; `open223/open223.info` commit `97656845cab16183e64e9611c94f40a6fad95226`; blob `c2ee998a1e0f5cc3e496ff9c20c30e01019ff250`; artifact SHA-256 `1f156f9938c0be430d2216e01e31bb183c438ba318d8d4a23d2f074ebcd6f573` |
219+
| QUDT | quantity-kind namespace `http://qudt.org/vocab/quantitykind/`; unit namespace `http://qudt.org/vocab/unit/`; `qudt/qudt-public-repo` release `v3.1.4`; tag object `e6cba51f5769691a926e000cbeb044d4d5cd754e`; commit `5a19ef66a5b8d8c404f469244304afc7d9f83eaa`; exact quantity-kind and unit paths, blobs, and SHA-256 values in the pin record |
220+
| OCL | namespace `urn:open-control-library:ontology:`; version `0.1.0-draft`; checked-in path `routines/ontology/ocl-vocabulary.ttl`; byte hash in the pin record |
221+
222+
The S223 artifact imports `<http://qudt.org/3.1.8/shacl/qudt-all>`. The pin
223+
record keeps that as a compatibility observation. It does not replace the
224+
Library's QUDT 3.1.4 authority, and the S223 artifact is not represented as the
225+
final published standard.
226+
227+
`ocl-vocabulary.ttl` contains only Library-owned profile, connector-binding,
228+
software-signal, derived-signal, aggregate, derivation, and policy terms used by
229+
the governed fixtures. It has no imports. Its SHA-256 is part of the pin record;
230+
changing the Turtle bytes requires updating that hash in the same change.
231+
232+
#### Routine semantic profiles (`cxf-library/routine-semantic-profile/v1`)
233+
234+
A semantic profile has a stable JSON-LD `@id`, type
235+
`ocl:RoutineSemanticProfile`, canonical class ID and revision, the exact
236+
`routines/ontology/ontology-pins.json` reference, and one or more connector
237+
roles. Its context is one closed embedded object. String, list, nested, remote,
238+
or imported contexts are invalid.
239+
240+
Connector role IDs use the interface connector-ID syntax and are unique. Each
241+
role has a bounded nonempty `semantic_role`, a `mapping_status` of `verified` or
242+
`provisional`, and a closed list of bounded topology requirements. `verified`
243+
means the author reviewed the mapping against the named pin evidence;
244+
`provisional` marks a mapping that still needs review. Neither value certifies a
245+
building instance. A physical role requires at least one location, topology, or
246+
ownership obligation; software and derived roles may use an empty list.
247+
248+
Direction is connector dataflow (`input` or `output`) and does not determine the
249+
S223 property class. For example, an active setpoint may be an input while its
250+
property remains actuatable. Requirement is `R`, `A`, `O`, `N`, `S`, `D`, or
251+
`P`; cardinality records integer `minimum` and `maximum` values with minimum not
252+
greater than maximum. Bindings are a closed union:
253+
254+
- `physical-or-bms-point` carries one
255+
`points/<family>.points.json#<point_key>` reference plus closed Brick and S223
256+
mappings;
257+
- `software-signal` carries an OCL class and no physical ontology mapping; and
258+
- `derived-signal` carries an OCL class, output ID, and local derivation-manifest
259+
reference.
260+
261+
Physical mappings allow only the reviewed directional S223 property classes:
262+
`s223:QuantifiableObservableProperty`,
263+
`s223:QuantifiableActuatableProperty`,
264+
`s223:EnumeratedObservableProperty`, and
265+
`s223:EnumeratedActuatableProperty`. Quantifiable mappings require a QUDT
266+
quantity kind and unit. Enumerated mappings require an enumeration kind. Both
267+
mapping variants record the S223 medium as a CURIE or explicit `null`. Allowed
268+
aspects are `s223:Aspect-Setpoint`, `s223:Aspect-Delta`, and
269+
`s223:Aspect-Maximum`; `s223:EnumeratedProperty` is invalid. Topology strings
270+
are structural authoring obligations, not topology instances or SHACL results.
271+
272+
#### Derivation manifests (`cxf-library/routine-derivation-manifest/v1`)
273+
274+
A derivation manifest identifies one `ocl:DerivedSignal` or
275+
`ocl:DerivedAggregate` output. It records the canonical class revision, an
276+
exact `routines/ontology/ontology-pins.json` reference, an immutable function ID
277+
and version, ordered typed inputs with stable source IDs, stable members,
278+
exclusions, data-quality handling, freshness and alignment limits in seconds,
279+
readiness and in-domain policy, output unit and conversion policy, output scope,
280+
and reset behavior.
281+
282+
Member-linked inputs, exclusions, member output scopes, and source-triggered
283+
resets must resolve inside the manifest. IDs are unique. Data-quality and ready
284+
minimums cannot exceed the member population and must agree. A profile's
285+
derived output ID and manifest fragment must equal the manifest output ID; a
286+
manifest output must be referenced by exactly one derived connector role in the
287+
synthetic fixture pair.
288+
203289
#### Schema validation boundary
204290

205291
The schemas enforce required and closed shapes, discriminators, ID patterns,
@@ -208,7 +294,7 @@ adds deterministic cross-document checks for uniqueness, section coherence,
208294
reference existence and kind, finite and compatible values, dimensions,
209295
rectangular arrays, guards, and specialization completeness. It rejects
210296
duplicate JSON keys and non-finite numbers before schema validation, checks all
211-
four schema resources with `Draft202012Validator.check_schema`, and reports
297+
six schema resources with `Draft202012Validator.check_schema`, and reports
212298
sorted errors without a traceback for expected failures.
213299

214300
The linter validates one coherent fixture set under
@@ -217,6 +303,22 @@ test-only contract evidence. They MUST NOT appear below `routines/g36/` or be
217303
added to a registry, coverage claim, source inventory, book, or production
218304
catalog destination.
219305

306+
`tools/lint/routine_semantics.py` checks the closed pin record, recomputes the
307+
local-vocabulary hash, parses the Turtle from local bytes, applies the same
308+
six-resource in-memory schema registry, rejects unsafe JSON-LD constructs before
309+
RDFLib parsing, and validates semantic and derivation cross-document rules. Its
310+
two fixtures under `tools/lint/tests/fixtures/routine_semantics/` are synthetic.
311+
Their point references are syntax examples and are not resolved against
312+
production dictionaries or routine interfaces.
313+
314+
No external ontology is vendored or fetched. Brick, S223, and QUDT CURIE checks
315+
therefore prove closed syntax and selected S223 class and aspect policy, not that
316+
every external term exists in its pinned ontology. Connector semantic-role and
317+
topology requirements are authoring evidence, not building-instance evidence.
318+
Production profiles must later be paired with typed interfaces, canonical point
319+
dictionaries, ontology-term evidence, and building-instance validation before
320+
any semantic-conformance claim.
321+
220322
### `routines/g36/source-inventory.json` (`cxf-library/g36-source-inventory/v1`)
221323

222324
The source inventory records two independent Git-tree snapshots from
@@ -338,10 +440,11 @@ absent.
338440

339441
### Deferred routine contracts
340442

341-
Production class manifests, interfaces, and specialization inputs remain
342-
deferred, as do source-to-family and class mapping instances, point semantics,
343-
semantic sidecars, a specializer, resolved connectors, generated deployment
344-
bundle schemas and rows, source maps, vectors, generated CXF, and execution.
443+
Production class manifests, interfaces, specialization inputs, semantic
444+
profiles, and derivation manifests remain deferred, as do source-to-family and
445+
class mapping instances, point migrations, a specializer, resolved connectors,
446+
generated deployment bundle schemas and rows, source maps, vectors, generated
447+
CXF, building-instance conformance, and execution.
345448

346449
## Design stance (why the pieces split this way)
347450

routines/README.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ routine inventories:
1515
first production class rows are implemented.
1616
- `generated-registry.json` is the only future executable deployment inventory.
1717
It remains empty until the deployment bundle contract and specializer exist.
18-
- `schemas/` defines future class manifests, typed interfaces, and
19-
specialization inputs. It does not contain production class instances.
18+
- `schemas/` contains six governed schemas for future class manifests, typed
19+
interfaces, specialization inputs, semantic profiles, and derivation
20+
manifests. It contains no production instances.
21+
- `ontology/ontology-pins.json` fixes the Brick 1.4.4, ASHRAE 223
22+
1.0.0-ppr.2.1 compatibility, QUDT 3.1.4, and local OCL identities.
23+
`ontology/ocl-vocabulary.ttl` is the hashed Library-owned vocabulary for
24+
software and derivation concepts.
2025

2126
`g36/coverage.json` references the scope manifest, remains `planned`, and makes
2227
no implementation or completeness claims.
@@ -48,16 +53,19 @@ python3 tools/lint/g36_source.py --check \
4853

4954
Run the remaining catalog gates from the repository root:
5055

51-
`requirements-routine-schemas.txt` pins `jsonschema==4.26.0` and
52-
`referencing==0.37.0`.
56+
`requirements-routine-schemas.txt` pins `jsonschema==4.26.0`,
57+
`referencing==0.37.0`, and `rdflib==7.1.4`.
5358

5459
```sh
5560
python3 -m venv /tmp/cxf-routine-schemas
5661
/tmp/cxf-routine-schemas/bin/python -m pip install \
5762
--requirement tools/lint/requirements-routine-schemas.txt
5863
/tmp/cxf-routine-schemas/bin/python -m unittest \
5964
tools.lint.tests.test_routine_schemas -v
65+
/tmp/cxf-routine-schemas/bin/python -m unittest \
66+
tools.lint.tests.test_routine_semantics -v
6067
/tmp/cxf-routine-schemas/bin/python tools/lint/routine_schemas.py
68+
/tmp/cxf-routine-schemas/bin/python tools/lint/routine_semantics.py
6169
/tmp/cxf-routine-schemas/bin/python -m unittest discover \
6270
-s tools/lint/tests -v
6371
/tmp/cxf-routine-schemas/bin/python tools/lint/routines.py
@@ -69,5 +77,19 @@ variants or source locations. Local types and enums belong to one interface.
6977
The schemas cover scalar and rank-one/rank-two typed values,
7078
parameter-controlled dimensions, stable repeated-member IDs, and
7179
parameter-only optional-connector guards. They do not evaluate guards or
72-
define point semantics, connector bindings, source mapping instances,
73-
production specializations, generated deployments, or executable CXF.
80+
define production connector bindings, source mapping instances,
81+
specializations, generated deployments, or executable CXF.
82+
83+
The semantic and derivation schemas are exercised only by synthetic fixtures
84+
under `tools/lint/tests/fixtures/routine_semantics/`. Validation is local and
85+
network-free. It checks closed syntax, local OCL terms, connector semantic-role,
86+
mapping-status and topology obligations, selected S223 class and aspect policy,
87+
member references, the shared ontology-pin authority, and the
88+
profile-to-derivation relationship. Connector dataflow does not reclassify an
89+
S223 property as observable or actuatable. The topology strings are authoring
90+
requirements, not building-instance certification. Validation does not certify
91+
external ontology term existence, resolve fixture point references against
92+
production dictionaries, compare a profile to a production interface, or
93+
validate a building instance. Production semantic profiles, derivation
94+
manifests, point migrations, SHACL certification, and routine classes remain
95+
deferred.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
@prefix ocl: <urn:open-control-library:ontology:> .
2+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
3+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
4+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
5+
6+
ocl: a owl:Ontology ;
7+
rdfs:label "Open Control Library semantic vocabulary" ;
8+
owl:versionInfo "0.1.0-draft" .
9+
10+
ocl:RoutineSemanticProfile a owl:Class .
11+
ocl:ConnectorSemanticRole a owl:Class .
12+
ocl:PhysicalPointBinding a owl:Class .
13+
ocl:SoftwareSignalBinding a owl:Class .
14+
ocl:DerivedSignalBinding a owl:Class .
15+
ocl:SoftwareSignal a owl:Class .
16+
ocl:DerivedSignal a owl:Class ; rdfs:subClassOf ocl:SoftwareSignal .
17+
ocl:DerivedAggregate a owl:Class ; rdfs:subClassOf ocl:DerivedSignal .
18+
ocl:DerivationManifest a owl:Class .
19+
ocl:DerivationFunction a owl:Class .
20+
ocl:DerivationInput a owl:Class .
21+
ocl:DerivationMember a owl:Class .
22+
ocl:DerivationExclusion a owl:Class .
23+
24+
ocl:hasConnectorRole a owl:ObjectProperty .
25+
ocl:hasBinding a owl:ObjectProperty .
26+
ocl:brickMapping a owl:ObjectProperty .
27+
ocl:s223Mapping a owl:ObjectProperty .
28+
ocl:algorithm a owl:ObjectProperty .
29+
ocl:output a owl:ObjectProperty .
30+
ocl:input a owl:ObjectProperty .
31+
ocl:source a owl:ObjectProperty .
32+
ocl:memberPopulation a owl:ObjectProperty .
33+
ocl:exclusion a owl:ObjectProperty .
34+
ocl:dataQualityPolicy a owl:ObjectProperty .
35+
ocl:readyCondition a owl:ObjectProperty .
36+
ocl:unitPolicy a owl:ObjectProperty .
37+
ocl:outputScope a owl:ObjectProperty .
38+
ocl:resetBehavior a owl:ObjectProperty .
39+
40+
ocl:artifactVersion a owl:DatatypeProperty ; rdfs:range xsd:string .
41+
ocl:canonicalRoutineId a owl:DatatypeProperty ; rdfs:range xsd:string .
42+
ocl:canonicalRoutineRevision a owl:DatatypeProperty ; rdfs:range xsd:integer .
43+
ocl:ontologyPins a owl:DatatypeProperty ; rdfs:range xsd:string .
44+
ocl:connectorId a owl:DatatypeProperty ; rdfs:range xsd:string .
45+
ocl:direction a owl:DatatypeProperty ; rdfs:range xsd:string .
46+
ocl:g36PointRequirement a owl:DatatypeProperty ; rdfs:range xsd:string .
47+
ocl:semanticRole a owl:DatatypeProperty ; rdfs:range xsd:string .
48+
ocl:mappingStatus a owl:DatatypeProperty ; rdfs:range xsd:string .
49+
ocl:topologyRequirement a owl:DatatypeProperty ; rdfs:range xsd:string .
50+
ocl:cardinality a owl:ObjectProperty .
51+
ocl:minimumCardinality a owl:DatatypeProperty ; rdfs:range xsd:integer .
52+
ocl:maximumCardinality a owl:DatatypeProperty ; rdfs:range xsd:integer .
53+
ocl:kind a owl:DatatypeProperty ; rdfs:range xsd:string .
54+
ocl:canonicalPointRef a owl:DatatypeProperty ; rdfs:range xsd:string .
55+
ocl:brickClass a owl:ObjectProperty .
56+
ocl:s223PropertyClass a owl:ObjectProperty .
57+
ocl:quantityKind a owl:ObjectProperty .
58+
ocl:unit a owl:ObjectProperty .
59+
ocl:enumerationKind a owl:ObjectProperty .
60+
ocl:s223Medium a owl:ObjectProperty .
61+
ocl:s223Aspect a owl:ObjectProperty .
62+
ocl:localClass a owl:ObjectProperty .
63+
ocl:outputId a owl:DatatypeProperty ; rdfs:range xsd:string .
64+
ocl:derivationManifestRef a owl:DatatypeProperty ; rdfs:range xsd:string .
65+
ocl:algorithmVersion a owl:DatatypeProperty ; rdfs:range xsd:string .
66+
ocl:sourceId a owl:DatatypeProperty ; rdfs:range xsd:string .
67+
ocl:valueKind a owl:DatatypeProperty ; rdfs:range xsd:string .
68+
ocl:memberId a owl:DatatypeProperty ; rdfs:range xsd:string .
69+
ocl:excludedMember a owl:DatatypeProperty ; rdfs:range xsd:string .
70+
ocl:exclusionReason a owl:DatatypeProperty ; rdfs:range xsd:string .
71+
ocl:freshnessLimitSeconds a owl:DatatypeProperty ; rdfs:range xsd:decimal .
72+
ocl:timeAlignmentWindowSeconds a owl:DatatypeProperty ; rdfs:range xsd:decimal .

0 commit comments

Comments
 (0)