tbox: v2.2 - polymorphisme declare sur 19 proprietes, 17 domaines poses, provenance portee par les classes concretes, GovernanceLayerObject rattachee, affectations de gouvernance completes (12 completees, 10 SDO, 1 PO, 16 stewards par objet metier), Panel Coverage gouverne. Validation SHACL sans violation bloquante

This commit is contained in:
Bastien Gourdon
2026-08-07 10:31:16 +02:00
parent d90d2a316d
commit 0b7d3834d2
29 changed files with 3274 additions and 274 deletions
+48 -24
View File
@@ -17,7 +17,7 @@
meta:
title: Pernod Ricard Data MetaModel — T-Box Rulebook
version: "1.2"
version: "1.4"
status: Draft for review
date: "2026-08-03"
scope: >
@@ -249,8 +249,9 @@ rules:
statement: >
The local name of an object property begins with a verb, in lower case. Both
the active form and the passive or participial form are admitted: a past
participle is a verb in first position. No relation begins with a
preposition or with a noun.
participle is a verb in first position. An adverb qualifying that verb is
transparent and may precede it. No relation begins with a preposition or
with a noun.
scope: [object_property]
severity: BLOCKING
control: {tier: script, executor: check_tbox_naming.py, procedure: null}
@@ -258,12 +259,14 @@ rules:
rationale: >
A relation reads as a verb and an attribute reads as a noun. The distinction
is what lets a reader tell an edge from a field without opening the
declaration. The explicit clause on participial forms is required: read
literally, a verb-first rule would condemn a whole family of sound relations
such as computedBy, storedIn and derivedFrom.
declaration. Two clauses are stated rather than left implicit, because a
literal reading would condemn sound relations: the participial one, which
covers a whole family such as computedBy, storedIn and derivedFrom, and the
adverbial one, which covers a relation whose verb is qualified rather than
replaced.
examples:
- {from: "pr:inDatabase", to: "pr:isInDatabase", note: a preposition is not a verb}
- {from: "pr:primaryLocation", to: "pr:primarilyStoredIn", note: a noun is not a verb}
- {from: "pr:primaryLocation", to: "pr:primarilyStoredIn", note: "a noun is not a verb; the adverb is transparent and the verb follows"}
- {from: "pr:computedBy", to: "pr:computedBy", note: participial form is conforming}
- id: TN-010
@@ -596,9 +599,9 @@ rules:
title: Every property declares its domain and range
statement: >
rdfs:domain and rdfs:range are mandatory on every property, EXCEPT where the
property is deliberately polymorphic. A polymorphic property states so in
its comment and has its scope declared in SHACL. Silent absence is a
violation; documented absence is not.
property is deliberately polymorphic. A polymorphic property declares
pr:polymorphic true and has its scope declared in SHACL. Silent absence is a
violation; declared absence is not.
scope: [object_property, datatype_property]
severity: BLOCKING
control: {tier: [script, human], executor: check_tbox_naming.py, procedure: null}
@@ -608,30 +611,51 @@ rules:
properties are polymorphic by design, their scope controlled class by class
in SHACL rather than by twin properties; giving those an rdfs:domain would
trigger the RDFS retyping described in TN-028. The rule therefore separates
the two cases rather than demanding a domain everywhere.
the two cases rather than demanding a domain everywhere. The distinction is
carried by an axiom and not by a sentence in the comment: a checker looking
for a phrase in prose fails the moment someone words it differently, and
what matters is declared rather than read, exactly as for abstractness.
examples:
- {from: a polymorphic property with no domain and no comment, to: violation, note: silence is indistinguishable from omission}
- {from: a polymorphic property with no domain, documented, to: conforming, note: scope declared in SHACL}
- {from: a property with no domain and no declaration, to: violation, note: silence is indistinguishable from omission}
- {from: "a property with no domain, declaring pr:polymorphic true", to: conforming, note: scope declared in SHACL}
- id: TN-026
category: Declaration
title: Every term declares how it was authored
title: Every concrete class declares how its instances are produced
statement: >
pr:authoringMode is mandatory on every term. pr:harvestSource is mandatory
if and only if the mode is HARVESTED.
scope: [class, object_property, datatype_property, annotation_property]
Every CONCRETE CLASS declares pr:authoringMode, stating whether its
instances are ASSERTED by governance or HARVESTED from a system.
pr:harvestSource is mandatory if and only if the mode is HARVESTED. The
declared mode agrees with the provenance axis the class descends from: a
class under CapturedObject declares HARVESTED, one under DefinedObject
declares ASSERTED. Nothing else carries the property: not an abstract class,
not a property, not a term of the vocabulary in its own right.
scope: [class]
severity: BLOCKING
control: {tier: script, executor: check_tbox_naming.py, procedure: null}
filiation: null
rationale: >
Provenance decides who may edit a term and what a divergence means. A term
stating where its data comes from without stating that it is harvested, or
declaring itself harvested without naming a source, is half-declared in a
way no control can catch. Declared symmetrically, provenance also makes a
harvester specifiable from the model itself rather than from a side
document.
A term of the vocabulary is declared, always and by definition; recording
that on every term would repeat one fact a hundred times and say nothing. It
is the INSTANCES that have a provenance, and the class is where the model
states which one: a governance object is asserted by a domain, a physical
column is harvested from a system. The distinction matters because a class
can be declared and describe captured things at once — CapturedObject itself
is a declared term naming harvested instances, and conflating the two is
what once put a harvesting mode on an abstraction.
Nothing is inherited. A subclass declares its own mode rather than taking
its parent's, so that the declaration is read where the instances are typed
and not chased up a chain. The agreement clause is what keeps that free of
contradiction: the axis says what kind of thing the class describes, the
mode says how those things arrive, and a class under CapturedObject
declaring ASSERTED is stating both at once.
Declared this way, provenance also makes a harvester specifiable from the
model itself rather than from a side document.
examples:
- {from: harvestSource present, authoringMode absent, to: "authoringMode HARVESTED", note: null}
- {from: "authoringMode on an abstract class", to: nothing, note: an abstraction has no instances to produce}
- {from: "a class under CapturedObject declaring ASSERTED", to: violation, note: the mode contradicts the axis}
- {from: "authoringMode HARVESTED, harvestSource absent", to: harvestSource declared, note: null}
- id: TN-027