glossarist 0.4.33 → 0.4.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/concept-parser.js +1 -1
- package/src/diff/concept-diff.js +6 -6
- package/src/diff/diff-renderer.js +11 -3
- package/src/models/abstract-hyperedge.js +2 -2
- package/src/models/concept.js +2 -2
- package/src/models/generic-member.js +74 -7
- package/src/models/hyperedge-member.js +20 -25
- package/src/models/index.js +4 -4
- package/src/models/partitive-member.js +38 -9
- package/src/rdf/gloss-partitive-relation.js +1 -1
- package/src/validators/ref-keys.js +2 -2
- /package/src/migration/{partitive-relation-migrator.js → hyperedge-migrator.js} +0 -0
package/package.json
CHANGED
package/src/concept-parser.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as yaml from 'js-yaml';
|
|
|
2
2
|
import { Concept } from './models/concept.js';
|
|
3
3
|
import { RelatedConcept } from './models/related-concept.js';
|
|
4
4
|
import { HyperedgeRegistry } from './models/hyperedge-registry.js';
|
|
5
|
-
import { migrateHyperedgeToRelation } from './migration/
|
|
5
|
+
import { migrateHyperedgeToRelation } from './migration/hyperedge-migrator.js';
|
|
6
6
|
import { InvalidInputError, YamlParseError } from './errors.js';
|
|
7
7
|
|
|
8
8
|
// Structural keys are reserved at the concept level and excluded
|
package/src/diff/concept-diff.js
CHANGED
|
@@ -101,7 +101,7 @@ export class ConceptLevelDiff extends GlossaristModel {
|
|
|
101
101
|
this._sources = wrapListDiff(data.sources);
|
|
102
102
|
this._dates = wrapListDiff(data.dates);
|
|
103
103
|
this._relatedConcepts = wrapListDiff(data.relatedConcepts ?? data.related_concepts);
|
|
104
|
-
// Unified
|
|
104
|
+
// Unified hyperedge diff. Accepts:
|
|
105
105
|
// - data.relations (new unified shape)
|
|
106
106
|
// - data.partitiveRelations /
|
|
107
107
|
// data.partitive_relations /
|
|
@@ -127,7 +127,7 @@ export class ConceptLevelDiff extends GlossaristModel {
|
|
|
127
127
|
get sources() { return this._sources; }
|
|
128
128
|
get dates() { return this._dates; }
|
|
129
129
|
get relatedConcepts() { return this._relatedConcepts; }
|
|
130
|
-
/** Unified
|
|
130
|
+
/** Unified hyperedge diff (PartitiveHyperedge + GenericHyperedge). */
|
|
131
131
|
get relations() { return this._relations; }
|
|
132
132
|
/**
|
|
133
133
|
* Filtered view of `relations` containing only PartitiveHyperedge
|
|
@@ -465,7 +465,7 @@ function diffConceptLevel(oldConcept, newConcept) {
|
|
|
465
465
|
sources: diffSources(oldConcept.sources ?? [], newConcept.sources ?? []),
|
|
466
466
|
dates: diffDates(oldConcept.dates ?? [], newConcept.dates ?? []),
|
|
467
467
|
relatedConcepts: diffRelatedConcepts(oldConcept.relatedConcepts ?? [], newConcept.relatedConcepts ?? []),
|
|
468
|
-
relations:
|
|
468
|
+
relations: diffHyperedges(
|
|
469
469
|
oldConcept.relations ?? [],
|
|
470
470
|
newConcept.relations ?? [],
|
|
471
471
|
),
|
|
@@ -565,13 +565,13 @@ function diffRelatedConcepts(oldRC, newRC) {
|
|
|
565
565
|
});
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
-
// Diff two unified
|
|
568
|
+
// Diff two unified hyperedge arrays. Identity is polymorphic —
|
|
569
569
|
// dispatches via value.constructor.identityOf so PartitiveHyperedge
|
|
570
|
-
// and GenericHyperedge (and any future
|
|
570
|
+
// and GenericHyperedge (and any future hyperedge subclass) coexist in
|
|
571
571
|
// the same list. Cross-type entries with matching identity are still
|
|
572
572
|
// treated as different (because their constructor differs and they
|
|
573
573
|
// live under different wire keys).
|
|
574
|
-
function
|
|
574
|
+
function diffHyperedges(oldR, newR) {
|
|
575
575
|
return diffSet(oldR, newR, {
|
|
576
576
|
identityKey: relationIdentityOf,
|
|
577
577
|
textKey: relationText,
|
|
@@ -125,10 +125,10 @@ function renderConceptLevel(diff, colors) {
|
|
|
125
125
|
lines.push(...renderListDiff('Sources', diff.sources, colors, itemLabel));
|
|
126
126
|
lines.push(...renderListDiff('Dates', diff.dates, colors, itemLabel));
|
|
127
127
|
lines.push(...renderListDiff('Related', diff.relatedConcepts, colors, itemLabel));
|
|
128
|
-
// Unified
|
|
128
|
+
// Unified hyperedge section. Replaces the per-type sections
|
|
129
129
|
// (Partitive relations, Generic relations) — the underlying diff
|
|
130
130
|
// is a single ListDiff over the unified .relations array.
|
|
131
|
-
lines.push(...renderListDiff('
|
|
131
|
+
lines.push(...renderListDiff('Hyperedges', diff.relations, colors, relationLabel));
|
|
132
132
|
lines.push(...renderListDiff('Groups', diff.groups, colors, itemLabel));
|
|
133
133
|
lines.push(...renderListDiff('Sections', diff.sections, colors, itemLabel));
|
|
134
134
|
lines.push(...renderListDiff('Tags', diff.tags, colors, itemLabel));
|
|
@@ -214,8 +214,16 @@ function relationLabel(r) {
|
|
|
214
214
|
const ref = m?.ref ?? m ?? {};
|
|
215
215
|
let tail = '';
|
|
216
216
|
const mult = resolveMultiplicity(m);
|
|
217
|
-
if (mult && mult !== 'compulsory') tail
|
|
217
|
+
if (mult && mult !== 'compulsory') tail += ` (${mult})`;
|
|
218
|
+
// PartitiveMember uses is_delimiting (boolean flag).
|
|
218
219
|
if (m?.is_delimiting === true) tail += ' ⊘';
|
|
220
|
+
// GenericMember uses delimitingCharacteristic (string value per
|
|
221
|
+
// ISO 704:2022 §5.5.4.2.1) — show the delimiting characteristic
|
|
222
|
+
// text so reviewers can see the intension difference.
|
|
223
|
+
if (m?.delimitingCharacteristic) {
|
|
224
|
+
const c = Object.values(m.delimitingCharacteristic)[0];
|
|
225
|
+
if (typeof c === 'string' && c.length > 0) tail += ` ⟨${c}⟩`;
|
|
226
|
+
}
|
|
219
227
|
return `${ref.id ?? ref.source ?? ref.text ?? '?'}${tail}`;
|
|
220
228
|
}).join(', ')
|
|
221
229
|
: '';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// AbstractHyperedge — shared base for
|
|
1
|
+
// AbstractHyperedge — shared base for directed 1→N hyperedges
|
|
2
2
|
// relations (PartitiveHyperedge, GenericHyperedge, future
|
|
3
3
|
// SequentialRelation, AssociativeRelation).
|
|
4
4
|
//
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// - sources / notes / status: administrative metadata
|
|
11
11
|
//
|
|
12
12
|
// Concrete leaves add type-specific fields if needed (currently none).
|
|
13
|
-
// See docs/design/abstract-
|
|
13
|
+
// See docs/design/abstract-hyperedge.md (concept-model repo).
|
|
14
14
|
|
|
15
15
|
import { GlossaristModel } from './base.js';
|
|
16
16
|
import { ConceptRef } from './concept-ref.js';
|
package/src/models/concept.js
CHANGED
|
@@ -4,7 +4,7 @@ import { RelatedConcept } from './related-concept.js';
|
|
|
4
4
|
import { PartitiveHyperedge } from './partitive-hyperedge.js';
|
|
5
5
|
import { AbstractHyperedge } from './abstract-hyperedge.js';
|
|
6
6
|
import { HyperedgeRegistry, groupHyperedgesByWireKey } from './hyperedge-registry.js';
|
|
7
|
-
import { migrateHyperedgeToRelation } from '../migration/
|
|
7
|
+
import { migrateHyperedgeToRelation } from '../migration/hyperedge-migrator.js';
|
|
8
8
|
import { ConceptReference } from './concept-reference.js';
|
|
9
9
|
import { ConceptDate } from './concept-date.js';
|
|
10
10
|
import { ConceptSource } from './concept-source.js';
|
|
@@ -36,7 +36,7 @@ export class Concept extends GlossaristModel {
|
|
|
36
36
|
|
|
37
37
|
this.relatedConcepts = _mapInstances(data.relatedConcepts ?? data.related ?? data.related_concepts ?? [], RelatedConcept);
|
|
38
38
|
|
|
39
|
-
// Unified hyperedge array. Every
|
|
39
|
+
// Unified hyperedge array. Every hyperedge (PartitiveHyperedge,
|
|
40
40
|
// GenericHyperedge, future TemporalHyperedge / AssociativeHyperedge /
|
|
41
41
|
// SequentialHyperedge) lives here. The single public API is
|
|
42
42
|
// `.relations`; external systems that need to filter by type use
|
|
@@ -1,15 +1,82 @@
|
|
|
1
|
-
// GenericMember — one member of a GenericHyperedge.
|
|
2
|
-
// ISO 704:2022 MECE shape from HyperedgeMember. Declared as a
|
|
3
|
-
// distinct leaf class for type safety and to leave room for
|
|
4
|
-
// generic-specific extensions.
|
|
1
|
+
// GenericMember — one member of a GenericHyperedge.
|
|
5
2
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
3
|
+
// Per ISO 704:2022 §5.5.4.2.1 (Generic relations and general concepts):
|
|
4
|
+
//
|
|
5
|
+
// "In a generic relation, the intension of the subordinate concept
|
|
6
|
+
// includes the intension of the superordinate concept plus at least
|
|
7
|
+
// one additional delimiting characteristic."
|
|
8
|
+
//
|
|
9
|
+
// In hyperedge terms: when a GenericHyperedge has comprehensive=computer mouse
|
|
10
|
+
// and criterion=means of movement detection, each member (mechanical mouse,
|
|
11
|
+
// optomechanical mouse, optical mouse) carries a delimitingCharacteristic —
|
|
12
|
+
// the value of the criterion for that specific concept:
|
|
13
|
+
//
|
|
14
|
+
// mechanical mouse → 'detecting movement by means of rollers'
|
|
15
|
+
// optomechanical mouse → 'detecting movement by means of rollers and light sensors'
|
|
16
|
+
// optical mouse → 'detecting movement by means of light sensors'
|
|
17
|
+
//
|
|
18
|
+
// Multidimensionality (§5.6.3): the same comprehensive can be the
|
|
19
|
+
// '1' side of multiple generic hyperedges simultaneously, each by a
|
|
20
|
+
// different criterion. computer mouse is also comprehensive of
|
|
21
|
+
// {wired mouse, wireless mouse} under criterion=computer connection.
|
|
22
|
+
// That second hyperedge's members carry their own delimitingCharacteristic
|
|
23
|
+
// values ('using a corded electrical connection', 'using a cordless
|
|
24
|
+
// light or sound connection').
|
|
25
|
+
//
|
|
26
|
+
// delimitingCharacteristic is REQUIRED on GenericMember. Without it,
|
|
27
|
+
// the member is just a coordinate concept with no semantic content
|
|
28
|
+
// tying it to the criterion — ISO 704 says the relation is meaningless
|
|
29
|
+
// without the delimiting characteristic.
|
|
30
|
+
//
|
|
31
|
+
// LocalizedString shape (mirrors criterion on the parent hyperedge):
|
|
32
|
+
// { eng: 'detecting movement by means of light sensors' }
|
|
33
|
+
// { eng: '...', fra: '...' } — multiple languages supported
|
|
8
34
|
|
|
9
35
|
import { HyperedgeMember } from './hyperedge-member.js';
|
|
10
36
|
|
|
11
37
|
export class GenericMember extends HyperedgeMember {
|
|
12
|
-
|
|
38
|
+
constructor(data = {}) {
|
|
39
|
+
super(data);
|
|
40
|
+
this.delimitingCharacteristic = _resolveDelimitingCharacteristic(data.delimitingCharacteristic);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toJSON() {
|
|
44
|
+
const base = super.toJSON();
|
|
45
|
+
base.delimitingCharacteristic = { ...this.delimitingCharacteristic };
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function _resolveDelimitingCharacteristic(value) {
|
|
51
|
+
if (value == null) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
'GenericMember.delimitingCharacteristic is required per ISO 704:2022 §5.5.4.2.1 ' +
|
|
54
|
+
'(the intension of a subordinate concept must include at least one additional ' +
|
|
55
|
+
'delimiting characteristic beyond the superordinate).',
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (typeof value === 'string') {
|
|
59
|
+
if (value.length === 0) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
'GenericMember.delimitingCharacteristic cannot be empty (ISO 704:2022 §5.5.4.2.1)',
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return { default: value };
|
|
65
|
+
}
|
|
66
|
+
if (typeof value === 'object') {
|
|
67
|
+
const entries = Object.entries(value).filter(([, v]) => typeof v === 'string' && v.length > 0);
|
|
68
|
+
if (entries.length === 0) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
'GenericMember.delimitingCharacteristic must have at least one non-empty string ' +
|
|
71
|
+
'value (ISO 704:2022 §5.5.4.2.1)',
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return Object.fromEntries(entries);
|
|
75
|
+
}
|
|
76
|
+
throw new Error(
|
|
77
|
+
`GenericMember.delimitingCharacteristic must be a string or a language-keyed object; ` +
|
|
78
|
+
`got ${typeof value}`,
|
|
79
|
+
);
|
|
13
80
|
}
|
|
14
81
|
|
|
15
82
|
export default GenericMember;
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
// HyperedgeMember — abstract base shape for members of any
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// HyperedgeMember — abstract base shape for the members of any directed
|
|
2
|
+
// 1→N hyperedge (PartitiveMember, GenericMember, future AssociativeMember,
|
|
3
|
+
// SequentialMember).
|
|
4
4
|
//
|
|
5
|
-
// Carries the shared
|
|
6
|
-
//
|
|
5
|
+
// Carries ONLY the dimensions shared by every hyperedge member type:
|
|
6
|
+
// ref — ConceptRef [1] (the member concept)
|
|
7
|
+
// presence — 'required' | 'optional' (default: required)
|
|
8
|
+
// count — 'exactly_one' | 'at_least_one' | 'multiple' (default: exactly_one)
|
|
7
9
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
10
|
+
// These three form the ISO 704:2022 MECE pair (presence × count). The
|
|
11
|
+
// pair is the shared invariant across all hyperedge types — that's
|
|
12
|
+
// why it lives on the base.
|
|
13
|
+
//
|
|
14
|
+
// Type-specific extensions live on the leaves:
|
|
15
|
+
// PartitiveMember — is_delimiting (rake-diagram semantics, ISO 704 §5.5.4.2.2)
|
|
16
|
+
// GenericMember — delimitingCharacteristic (intension difference, ISO 704 §5.5.4.2.1)
|
|
17
|
+
//
|
|
18
|
+
// See docs/design/abstract-hyperedge.md (concept-model repo).
|
|
11
19
|
|
|
12
20
|
import { GlossaristModel } from './base.js';
|
|
13
21
|
import { ConceptRef } from './concept-ref.js';
|
|
@@ -30,14 +38,12 @@ export class HyperedgeMember extends GlossaristModel {
|
|
|
30
38
|
this.ref = _ensureRef(data.ref);
|
|
31
39
|
this.presence = _resolvePresence(data.presence);
|
|
32
40
|
this.count = _resolveCount(data.count);
|
|
33
|
-
this.is_delimiting = _resolveDelimiting(data.is_delimiting);
|
|
34
41
|
|
|
35
42
|
_assertValidPair(this.presence, this.count);
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
get isRequired() { return this.presence === PARTITIVE_PRESENCE.REQUIRED; }
|
|
39
46
|
get isOptional() { return this.presence === PARTITIVE_PRESENCE.OPTIONAL; }
|
|
40
|
-
get isDelimiting() { return this.is_delimiting === true; }
|
|
41
47
|
|
|
42
48
|
identity() {
|
|
43
49
|
return HyperedgeMember.identityOf(this);
|
|
@@ -47,7 +53,6 @@ export class HyperedgeMember extends GlossaristModel {
|
|
|
47
53
|
const obj = { ref: this.ref.toJSON() };
|
|
48
54
|
if (this.presence !== DEFAULT_PRESENCE) obj.presence = this.presence;
|
|
49
55
|
if (this.count !== DEFAULT_COUNT) obj.count = this.count;
|
|
50
|
-
if (this.is_delimiting) obj.is_delimiting = true;
|
|
51
56
|
return obj;
|
|
52
57
|
}
|
|
53
58
|
|
|
@@ -95,20 +100,10 @@ function _resolveCount(value) {
|
|
|
95
100
|
return c;
|
|
96
101
|
}
|
|
97
102
|
|
|
98
|
-
function _resolveDelimiting(value) {
|
|
99
|
-
if (value == null) return false;
|
|
100
|
-
if (typeof value !== 'boolean') {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`HyperedgeMember.is_delimiting must be boolean; got ${typeof value}`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
return value;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
103
|
function _assertValidPair(presence, count) {
|
|
109
|
-
// Delegate to the multiplicity SSOT
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
104
|
+
// Delegate to the multiplicity SSOT. The canonical error string
|
|
105
|
+
// lives in one place: multiplicity.js. Calling multiplicityFromPair
|
|
106
|
+
// throws on the invalid combination; we don't need to duplicate the
|
|
107
|
+
// error message here.
|
|
113
108
|
multiplicityFromPair(presence, count);
|
|
114
109
|
}
|
package/src/models/index.js
CHANGED
|
@@ -32,9 +32,9 @@ export {
|
|
|
32
32
|
isValidPluralityMarker,
|
|
33
33
|
} from './plurality-marker.js';
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
35
|
+
// PartitiveHyperedge models. The wire format (partitive_relations)
|
|
36
|
+
// is unchanged from earlier versions; the v1 wire key (partitive_hyperedges)
|
|
37
|
+
// is parsed on input and migrated to v2 shape via hyperedge-migrator.js.
|
|
38
38
|
export { PartitiveHyperedge } from './partitive-hyperedge.js';
|
|
39
39
|
export { PartitiveMember } from './partitive-member.js';
|
|
40
40
|
|
|
@@ -89,7 +89,7 @@ export {
|
|
|
89
89
|
export {
|
|
90
90
|
migrateHyperedgeToRelation,
|
|
91
91
|
downgradeRelationToHyperedge,
|
|
92
|
-
} from '../migration/
|
|
92
|
+
} from '../migration/hyperedge-migrator.js';
|
|
93
93
|
|
|
94
94
|
export { makeEnum } from './enum.js';
|
|
95
95
|
export { resolveHyperedgeColor } from './hyperedge-colors.js';
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
// PartitiveMember — one member of a PartitiveHyperedge.
|
|
2
|
-
// ISO 704:2022 MECE shape from HyperedgeMember; the `comprehensive`
|
|
3
|
-
// of its parent PartitiveHyperedge denotes the whole concept.
|
|
1
|
+
// PartitiveMember — one member of a PartitiveHyperedge.
|
|
4
2
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Adds to HyperedgeMember the partitive-specific `is_delimiting` flag
|
|
4
|
+
// from ISO 704:2022 §5.5.4.2.2 (rake diagram semantics):
|
|
5
|
+
//
|
|
6
|
+
// "Delimiting" parts (bold/3x-width line in source diagrams) behave
|
|
7
|
+
// like delimiting characteristics — they distinguish the comprehensive
|
|
8
|
+
// from coordinate concepts. Whether a part is delimiting depends on
|
|
9
|
+
// the concept system, the coordinate concepts, the inheritance
|
|
10
|
+
// principle, and the criterion of subdivision used.
|
|
11
|
+
//
|
|
12
|
+
// `is_delimiting` lives here on PartitiveMember, not on the base
|
|
13
|
+
// HyperedgeMember, because it is partitive-specific. GenericMember
|
|
14
|
+
// carries `delimitingCharacteristic` instead (the intension-difference
|
|
15
|
+
// value per §5.5.4.2.1, which always applies to every generic member).
|
|
7
16
|
//
|
|
8
17
|
// Matches concept-model/models/concepts/PartitiveMember.lutaml exactly:
|
|
9
18
|
// +ref — ConceptRef [1]
|
|
@@ -13,14 +22,34 @@
|
|
|
13
22
|
//
|
|
14
23
|
// The combination (optional, at_least_one) is invalid: if a part is
|
|
15
24
|
// optional, the at-least-one constraint is vacuous and collapses to
|
|
16
|
-
// (optional, multiple). Rejected at construction
|
|
25
|
+
// (optional, multiple). Rejected at construction by HyperedgeMember's
|
|
26
|
+
// delegate to multiplicityFromPair.
|
|
17
27
|
|
|
18
28
|
import { HyperedgeMember } from './hyperedge-member.js';
|
|
19
29
|
|
|
20
30
|
export class PartitiveMember extends HyperedgeMember {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
constructor(data = {}) {
|
|
32
|
+
super(data);
|
|
33
|
+
this.is_delimiting = _resolveDelimiting(data.is_delimiting);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get isDelimiting() { return this.is_delimiting === true; }
|
|
37
|
+
|
|
38
|
+
toJSON() {
|
|
39
|
+
const base = super.toJSON();
|
|
40
|
+
if (this.is_delimiting) base.is_delimiting = true;
|
|
41
|
+
return base;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function _resolveDelimiting(value) {
|
|
46
|
+
if (value == null) return false;
|
|
47
|
+
if (typeof value !== 'boolean') {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`PartitiveMember.is_delimiting must be boolean; got ${typeof value}`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
24
53
|
}
|
|
25
54
|
|
|
26
55
|
export default PartitiveMember;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
//
|
|
15
15
|
// The carrying concept links via `gloss:hasPartitiveRelation`.
|
|
16
16
|
//
|
|
17
|
-
//
|
|
17
|
+
// Per
|
|
18
18
|
// TODO.partitive-relation-v2 item 01.
|
|
19
19
|
// Cross-repo alignment with glossarist-ruby's Rdf::GlossPartitiveRelation.
|
|
20
20
|
//
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Shared identity-key helpers for cross-relation validators.
|
|
2
2
|
//
|
|
3
|
-
// Extracted from
|
|
4
|
-
// BinaryHasPartRedundancyRule
|
|
3
|
+
// Extracted from HyperedgeCoherenceRule and
|
|
4
|
+
// BinaryHasPartRedundancyRule.
|
|
5
5
|
// Eliminates drift: both rules now use the same notion of "same ref"
|
|
6
6
|
// and "same criterion" instead of each defining its own _refKey and
|
|
7
7
|
// _criterionKey with subtly different behaviors.
|
|
File without changes
|