@unrdf/knowledge-engine 5.0.1

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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/package.json +64 -0
  4. package/src/browser-shims.mjs +343 -0
  5. package/src/browser.mjs +910 -0
  6. package/src/canonicalize.mjs +414 -0
  7. package/src/condition-cache.mjs +109 -0
  8. package/src/condition-evaluator.mjs +722 -0
  9. package/src/dark-matter-core.mjs +742 -0
  10. package/src/define-hook.mjs +213 -0
  11. package/src/effect-sandbox-browser.mjs +283 -0
  12. package/src/effect-sandbox-worker.mjs +170 -0
  13. package/src/effect-sandbox.mjs +517 -0
  14. package/src/engines/index.mjs +11 -0
  15. package/src/engines/rdf-engine.mjs +299 -0
  16. package/src/file-resolver.mjs +387 -0
  17. package/src/hook-executor-batching.mjs +277 -0
  18. package/src/hook-executor.mjs +870 -0
  19. package/src/hook-management.mjs +150 -0
  20. package/src/index.mjs +93 -0
  21. package/src/ken-parliment.mjs +119 -0
  22. package/src/ken.mjs +149 -0
  23. package/src/knowledge-engine/builtin-rules.mjs +190 -0
  24. package/src/knowledge-engine/inference-engine.mjs +418 -0
  25. package/src/knowledge-engine/knowledge-engine.mjs +317 -0
  26. package/src/knowledge-engine/pattern-dsl.mjs +142 -0
  27. package/src/knowledge-engine/pattern-matcher.mjs +215 -0
  28. package/src/knowledge-engine/rules.mjs +184 -0
  29. package/src/knowledge-engine.mjs +319 -0
  30. package/src/knowledge-hook-engine.mjs +360 -0
  31. package/src/knowledge-hook-manager.mjs +469 -0
  32. package/src/knowledge-substrate-core.mjs +927 -0
  33. package/src/lite.mjs +222 -0
  34. package/src/lockchain-writer-browser.mjs +414 -0
  35. package/src/lockchain-writer.mjs +602 -0
  36. package/src/monitoring/andon-signals.mjs +775 -0
  37. package/src/observability.mjs +531 -0
  38. package/src/parse.mjs +290 -0
  39. package/src/performance-optimizer.mjs +678 -0
  40. package/src/policy-pack.mjs +572 -0
  41. package/src/query-cache.mjs +116 -0
  42. package/src/query-optimizer.mjs +1051 -0
  43. package/src/query.mjs +306 -0
  44. package/src/reason.mjs +350 -0
  45. package/src/resolution-layer.mjs +506 -0
  46. package/src/schemas.mjs +1063 -0
  47. package/src/security/error-sanitizer.mjs +257 -0
  48. package/src/security/path-validator.mjs +194 -0
  49. package/src/security/sandbox-restrictions.mjs +331 -0
  50. package/src/security-validator.mjs +389 -0
  51. package/src/store-cache.mjs +137 -0
  52. package/src/telemetry.mjs +167 -0
  53. package/src/transaction.mjs +810 -0
  54. package/src/utils/adaptive-monitor.mjs +746 -0
  55. package/src/utils/circuit-breaker.mjs +513 -0
  56. package/src/utils/edge-case-handler.mjs +503 -0
  57. package/src/utils/memory-manager.mjs +498 -0
  58. package/src/utils/ring-buffer.mjs +282 -0
  59. package/src/validate.mjs +319 -0
  60. package/src/validators/index.mjs +338 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * @file Standalone Hook Management Functions
3
+ * @module hook-management
4
+ *
5
+ * @description
6
+ * Provides standalone functions for hook management as expected by the README API.
7
+ * These functions wrap the class methods for easier usage.
8
+ */
9
+
10
+ import { defineHook } from './define-hook.mjs';
11
+ import { KnowledgeHookManager } from './knowledge-hook-manager.mjs';
12
+
13
+ // Global hook manager instance for standalone functions
14
+ let globalHookManager = null;
15
+
16
+ /**
17
+ * Initialize the global hook manager if not already initialized
18
+ * @param {Object} options - Options for the hook manager
19
+ * @returns {KnowledgeHookManager} The global hook manager
20
+ */
21
+ function getGlobalHookManager(options = {}) {
22
+ if (!globalHookManager) {
23
+ globalHookManager = new KnowledgeHookManager(options);
24
+ }
25
+ return globalHookManager;
26
+ }
27
+
28
+ /**
29
+ * Register a knowledge hook globally
30
+ * @param {Object} hook - The knowledge hook to register
31
+ * @param {Object} options - Manager options (if manager needs initialization)
32
+ * @throws {Error} If hook is invalid or already exists
33
+ *
34
+ * @example
35
+ * const hook = defineHook({
36
+ * meta: { name: 'test-hook', description: 'Test hook' },
37
+ * when: { kind: 'sparql-ask', query: 'ASK { ?s ?p ?o }' },
38
+ * run: async (event) => console.log('Hook triggered')
39
+ * });
40
+ *
41
+ * await registerHook(hook);
42
+ */
43
+ export async function registerHook(hook, options = {}) {
44
+ const manager = getGlobalHookManager(options);
45
+
46
+ // Validate hook if it's not already validated
47
+ const validatedHook = typeof hook === 'object' && !hook._validated ? defineHook(hook) : hook;
48
+
49
+ return manager.addKnowledgeHook(validatedHook);
50
+ }
51
+
52
+ /**
53
+ * Deregister (remove) a knowledge hook globally
54
+ * @param {string} hookName - The name of the hook to remove
55
+ * @returns {boolean} True if hook was removed, false if not found
56
+ *
57
+ * @example
58
+ * const removed = await deregisterHook('test-hook');
59
+ * console.log('Hook removed:', removed);
60
+ */
61
+ export async function deregisterHook(hookName) {
62
+ if (!globalHookManager) {
63
+ return false;
64
+ }
65
+
66
+ return globalHookManager.removeKnowledgeHook(hookName);
67
+ }
68
+
69
+ /**
70
+ * Manually evaluate a hook against given data
71
+ * @param {Object} hook - The hook to evaluate
72
+ * @param {Store} store - The RDF store to evaluate against
73
+ * @param {Object} context - Additional context for evaluation
74
+ * @returns {Object} Evaluation result
75
+ *
76
+ * @example
77
+ * const result = await evaluateHook(hook, store, { timestamp: Date.now() });
78
+ * console.log('Hook evaluation result:', result);
79
+ */
80
+ export async function evaluateHook(hook, store, context = {}) {
81
+ // Validate hook if needed
82
+ const validatedHook = typeof hook === 'object' && !hook._validated ? defineHook(hook) : hook;
83
+
84
+ // Create a temporary manager for evaluation
85
+ const tempManager = new KnowledgeHookManager({ enableKnowledgeHooks: true });
86
+
87
+ try {
88
+ // Add hook temporarily
89
+ tempManager.addKnowledgeHook(validatedHook);
90
+
91
+ // Evaluate the hook
92
+ const event = {
93
+ store,
94
+ context,
95
+ timestamp: Date.now(),
96
+ hookName: validatedHook.meta.name,
97
+ };
98
+
99
+ // Run the hook evaluation logic
100
+ const conditionResult = await tempManager.conditionEvaluator.isSatisfied(
101
+ validatedHook.when,
102
+ store,
103
+ context
104
+ );
105
+
106
+ event.result = conditionResult;
107
+ event.satisfied = conditionResult === true;
108
+
109
+ // Execute hook if condition is satisfied
110
+ if (event.satisfied && validatedHook.run) {
111
+ event.output = await validatedHook.run(event);
112
+ }
113
+
114
+ return event;
115
+ } catch (error) {
116
+ return {
117
+ error: error.message,
118
+ hookName: validatedHook.meta.name,
119
+ timestamp: Date.now(),
120
+ };
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Get all registered hooks
126
+ * @returns {Array} Array of registered hook names
127
+ */
128
+ export function getRegisteredHooks() {
129
+ if (!globalHookManager) {
130
+ return [];
131
+ }
132
+
133
+ return Array.from(globalHookManager.knowledgeHooks.keys());
134
+ }
135
+
136
+ /**
137
+ * Reset the global hook manager
138
+ * Useful for testing or cleanup
139
+ */
140
+ export function resetGlobalHookManager() {
141
+ globalHookManager = null;
142
+ }
143
+
144
+ export default {
145
+ registerHook,
146
+ deregisterHook,
147
+ evaluateHook,
148
+ getRegisteredHooks,
149
+ resetGlobalHookManager,
150
+ };
package/src/index.mjs ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @file Central Knowledge Engine Index
3
+ * @module knowledge-engine
4
+ *
5
+ * @description
6
+ * Centralized export hub for the entire knowledge engine system.
7
+ * This provides a single import point for all functionality.
8
+ */
9
+
10
+ // Core Engine Components
11
+ export { KnowledgeHookManager } from './knowledge-hook-manager.mjs';
12
+ export { TransactionManager } from './transaction.mjs';
13
+
14
+ // Hook System
15
+ export { defineHook } from './define-hook.mjs';
16
+ export { createHookExecutor } from './hook-executor.mjs';
17
+ export { createConditionEvaluator } from './condition-evaluator.mjs';
18
+ export {
19
+ registerHook,
20
+ deregisterHook,
21
+ evaluateHook,
22
+ getRegisteredHooks,
23
+ resetGlobalHookManager,
24
+ } from './hook-management.mjs';
25
+
26
+ // Knowledge Substrate Core (80/20 Framework)
27
+ export {
28
+ KnowledgeSubstrateCore,
29
+ createKnowledgeSubstrateCore,
30
+ KnowledgeSubstrateFactory,
31
+ // Legacy compatibility
32
+ DarkMatterCore,
33
+ createDarkMatterCore,
34
+ DarkMatterFactory,
35
+ } from './knowledge-substrate-core.mjs';
36
+
37
+ // Storage & Persistence
38
+ export { LockchainWriter, createLockchainWriter } from './lockchain-writer.mjs';
39
+ export { ResolutionLayer } from './resolution-layer.mjs';
40
+
41
+ // Query & Optimization
42
+ export { QueryOptimizer } from './query-optimizer.mjs';
43
+ export { query } from './query.mjs';
44
+
45
+ // Utilities
46
+ export { parseTurtle, toTurtle, toNQuads, parseJsonLd, toJsonLd } from './parse.mjs';
47
+ export {
48
+ validateShacl,
49
+ validateShaclMultiple,
50
+ formatValidationReport,
51
+ hasValidationErrors,
52
+ getValidationErrors,
53
+ getValidationWarnings,
54
+ } from './validate.mjs';
55
+ export {
56
+ canonicalize,
57
+ isIsomorphic,
58
+ getCanonicalHash,
59
+ groupByIsomorphism,
60
+ findDuplicates,
61
+ getCanonicalizationStats,
62
+ createCanonicalizationSession,
63
+ } from './canonicalize.mjs';
64
+ export {
65
+ reason,
66
+ reasonMultiple,
67
+ extractInferred,
68
+ getReasoningStats,
69
+ validateRules,
70
+ createReasoningSession,
71
+ } from './reason.mjs';
72
+ export {
73
+ resolveFileUri,
74
+ calculateFileHash,
75
+ loadFileWithHash,
76
+ loadSparqlFile,
77
+ } from './file-resolver.mjs';
78
+
79
+ // Security & Sandbox
80
+ export { EffectSandbox } from './effect-sandbox.mjs';
81
+
82
+ // Policy Management
83
+ export { PolicyPackManager, PolicyPack } from './policy-pack.mjs';
84
+
85
+ // Observability System
86
+ export {
87
+ ObservabilityManager,
88
+ createObservabilityManager,
89
+ defaultObservabilityManager,
90
+ } from './observability.mjs';
91
+
92
+ // Consolidated Schemas (single source of truth)
93
+ export * from './schemas.mjs';
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @file ken-parliament-debug.mjs
3
+ * @description Debugging version of Parliamentary Swarm Demo with Robert's Rules
4
+ */
5
+
6
+ import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
7
+ import { createStore } from '@unrdf/oxigraph'; // TODO: Replace with Oxigraph Store
8
+ import { TransactionManager, printReceipt } from './knowledge-engine.mjs';
9
+
10
+ const { namedNode, literal, quad } = DataFactory;
11
+
12
+ async function main() {
13
+ console.log('🏛️ Starting Parliamentary Swarm Demo (Debug Mode)...\n');
14
+
15
+ const store = createStore();
16
+ const tx = new TransactionManager();
17
+ const ex = 'http://example.org/';
18
+
19
+ // === Hooks ===
20
+ tx.addHook({
21
+ id: 'motion-must-be-seconded',
22
+ mode: 'pre',
23
+ condition: async (store, delta) => {
24
+ const adoptions = delta.additions.filter(q => q.predicate.value === `${ex}adoptMotion`);
25
+ for (const adoption of adoptions) {
26
+ const motion = adoption.subject;
27
+ const seconds = store.getQuads(motion, namedNode(`${ex}secondedBy`), null, null);
28
+ console.log(`🔎 Hook check: ${motion.value} has ${seconds.length} seconds in store.`);
29
+ if (seconds.length === 0) return false;
30
+ }
31
+ return true;
32
+ },
33
+ effect: 'veto',
34
+ });
35
+
36
+ tx.addHook({
37
+ id: 'vote-before-adoption',
38
+ mode: 'pre',
39
+ condition: async (store, delta) => {
40
+ const adoptions = delta.additions.filter(q => q.predicate.value === `${ex}adoptMotion`);
41
+ for (const adoption of adoptions) {
42
+ const motion = adoption.subject;
43
+ const votes = store.getQuads(motion, namedNode(`${ex}votedBy`), null, null);
44
+ console.log(`🔎 Hook check: ${motion.value} has ${votes.length} votes in store.`);
45
+ if (votes.length === 0) return false;
46
+ }
47
+ return true;
48
+ },
49
+ effect: 'veto',
50
+ });
51
+
52
+ tx.addHook({
53
+ id: 'audit-log',
54
+ mode: 'post',
55
+ condition: async () => true,
56
+ effect: async (_store, delta) => {
57
+ delta.additions.forEach(q => {
58
+ console.log(`🪵 Audit: ${q.subject.value} ${q.predicate.value} ${q.object.value}`);
59
+ });
60
+ },
61
+ });
62
+
63
+ // === Helper to apply commits ===
64
+ async function commit(description, additions, actor) {
65
+ console.log(`\n🤖 ${description}`);
66
+ const delta = { additions, removals: [] };
67
+ const { receipt, store: updatedStore } = await tx.apply(store, delta, {
68
+ actor,
69
+ });
70
+
71
+ // Dump motion state after each commit
72
+ const motion1Quads = updatedStore.getQuads(namedNode(`${ex}motion1`), null, null, null);
73
+ console.log('📊 Current motion1 state:');
74
+ motion1Quads.forEach(q =>
75
+ console.log(` • ${q.subject.value} ${q.predicate.value} ${q.object.value}`)
76
+ );
77
+
78
+ // Use the new printReceipt helper
79
+ printReceipt(receipt, { verbose: true });
80
+ }
81
+
82
+ // === Scenario ===
83
+ await commit(
84
+ 'PlannerAgent proposes: Introduce motion1: fund AI project',
85
+ [quad(namedNode(`${ex}motion1`), namedNode(`${ex}introducedBy`), literal('PlannerAgent'))],
86
+ 'PlannerAgent'
87
+ );
88
+
89
+ await commit(
90
+ 'ResearchAgent proposes: Second motion1',
91
+ [quad(namedNode(`${ex}motion1`), namedNode(`${ex}secondedBy`), literal('ResearchAgent'))],
92
+ 'ResearchAgent'
93
+ );
94
+
95
+ await commit(
96
+ 'CoderAgent proposes: Vote YES on motion1',
97
+ [quad(namedNode(`${ex}motion1`), namedNode(`${ex}votedBy`), literal('CoderAgent'))],
98
+ 'CoderAgent'
99
+ );
100
+
101
+ await commit(
102
+ 'PlannerAgent proposes: Adopt motion1',
103
+ [quad(namedNode(`${ex}motion1`), namedNode(`${ex}adoptMotion`), literal('PlannerAgent'))],
104
+ 'PlannerAgent'
105
+ );
106
+
107
+ await commit(
108
+ 'AdversarialAgent proposes: Adopt motion2 (no process)',
109
+ [quad(namedNode(`${ex}motion2`), namedNode(`${ex}adoptMotion`), literal('AdversarialAgent'))],
110
+ 'AdversarialAgent'
111
+ );
112
+
113
+ console.log('\n✅ Debug demo complete.');
114
+ }
115
+
116
+ main().catch(err => {
117
+ console.error('❌ Demo failed:', err);
118
+ process.exit(1);
119
+ });
package/src/ken.mjs ADDED
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @file Knowledge Engine Bulk Example with Assertions
3
+ */
4
+
5
+ import {
6
+ _parseTurtle,
7
+ _toTurtle,
8
+ query,
9
+ validateShacl,
10
+ reason,
11
+ canonicalize,
12
+ isIsomorphic,
13
+ TransactionManager,
14
+ } from './knowledge-engine.mjs';
15
+
16
+ import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
17
+ import { createStore } from '@unrdf/oxigraph'; // TODO: Replace with Oxigraph Store
18
+ import { faker } from '@faker-js/faker';
19
+ import assert from 'assert';
20
+
21
+ const { namedNode, literal, quad } = DataFactory;
22
+
23
+ async function generatePeople(count) {
24
+ const store = createStore();
25
+ const ex = 'http://example.org/';
26
+
27
+ for (let i = 0; i < count; i++) {
28
+ const id = faker.string.uuid();
29
+ const iri = namedNode(`${ex}person-${id}`);
30
+ const name = literal(faker.person.firstName());
31
+ const age = literal(
32
+ faker.number.int({ min: 18, max: 90 }).toString(),
33
+ namedNode('http://www.w3.org/2001/XMLSchema#integer')
34
+ );
35
+
36
+ store.addQuad(iri, namedNode(`${ex}type`), namedNode(`${ex}Person`));
37
+ store.addQuad(iri, namedNode(`${ex}name`), name);
38
+ store.addQuad(iri, namedNode(`${ex}age`), age);
39
+
40
+ if (i > 0 && Math.random() > 0.5) {
41
+ const otherIndex = Math.floor(Math.random() * i);
42
+ const otherIri = namedNode(`${ex}person-${otherIndex}`);
43
+ store.addQuad(iri, namedNode(`${ex}knows`), otherIri);
44
+ }
45
+ }
46
+
47
+ return store;
48
+ }
49
+
50
+ async function main() {
51
+ const bulkStore = await generatePeople(50);
52
+ console.log('Generated bulk store size:', bulkStore.size);
53
+
54
+ // === Assertion 1: Store has expected number of quads ===
55
+ assert(bulkStore.size >= 150, 'Store should have at least 3 triples per person');
56
+
57
+ // === SPARQL Query ===
58
+ const rows = await query(
59
+ bulkStore,
60
+ `
61
+ PREFIX ex: <http://example.org/>
62
+ SELECT ?person ?name ?age WHERE {
63
+ ?person ex:name ?name ;
64
+ ex:age ?age .
65
+ } LIMIT 5
66
+ `
67
+ );
68
+ console.log('SPARQL query results:', rows);
69
+ assert(rows.length > 0, 'SPARQL query should return at least 1 result');
70
+ rows.forEach(r => {
71
+ console.log('Row:', r);
72
+ assert(r.name && r.name !== '[object Object]', 'Each row should have a name');
73
+ assert(r.age && r.age !== '[object Object]', 'Each row should have an age');
74
+ });
75
+
76
+ // === SHACL Validation ===
77
+ const shapesTtl = `
78
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
79
+ @prefix ex: <http://example.org/> .
80
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
81
+
82
+ ex:PersonShape a sh:NodeShape ;
83
+ sh:targetClass ex:Person ;
84
+ sh:property [
85
+ sh:path ex:name ;
86
+ sh:datatype xsd:string ;
87
+ sh:minCount 1
88
+ ] ;
89
+ sh:property [
90
+ sh:path ex:age ;
91
+ sh:datatype xsd:integer ;
92
+ sh:minInclusive 0
93
+ ] .
94
+ `;
95
+ const report = validateShacl(bulkStore, shapesTtl);
96
+ console.log('SHACL validation report:', report);
97
+ // SHACL validation may return undefined for conforms, so we check that there are no results
98
+ assert(report.conforms !== false, 'SHACL validation should not have violations');
99
+ assert(report.results.length === 0, 'SHACL validation should have no validation results');
100
+
101
+ // === Reasoning ===
102
+ const rulesTtl = `
103
+ @prefix ex: <http://example.org/> .
104
+ { ?x ex:knows ?y } => { ?y ex:knows ?x } .
105
+ `;
106
+ const reasonedStore = await reason(bulkStore, rulesTtl);
107
+ assert(reasonedStore.size >= bulkStore.size, 'Reasoned store should be same size or larger');
108
+
109
+ // === Canonicalization & Isomorphism ===
110
+ const canonical = await canonicalize(bulkStore);
111
+ assert(canonical.length > 0, 'Canonicalization should produce non-empty output');
112
+
113
+ const copy = createStore(bulkStore.getQuads());
114
+ const iso = await isIsomorphic(bulkStore, copy);
115
+ assert.strictEqual(iso, true, 'Copy of store should be isomorphic');
116
+
117
+ // === Transactions ===
118
+ const tx = new TransactionManager();
119
+ tx.addHook({
120
+ id: 'no-teenagers',
121
+ mode: 'pre',
122
+ condition: async (_store, delta) => {
123
+ return !delta.additions.some(
124
+ q => q.predicate.value.endsWith('age') && parseInt(q.object.value) < 18
125
+ );
126
+ },
127
+ effect: 'veto',
128
+ });
129
+
130
+ const delta = {
131
+ additions: [
132
+ quad(
133
+ namedNode('http://example.org/person-extra'),
134
+ namedNode('http://example.org/age'),
135
+ literal('15')
136
+ ),
137
+ ],
138
+ removals: [],
139
+ };
140
+ const { receipt } = await tx.apply(bulkStore, delta);
141
+ assert.strictEqual(receipt.committed, false, 'Transaction with underage person should be vetoed');
142
+
143
+ console.log('✅ All assertions passed successfully.');
144
+ }
145
+
146
+ main().catch(err => {
147
+ console.error('❌ Assertion failed:', err.message);
148
+ process.exit(1);
149
+ });
@@ -0,0 +1,190 @@
1
+ /**
2
+ * @file Built-in RDFS Inference Rules
3
+ * @module @unrdf/knowledge-engine/builtin-rules
4
+ */
5
+
6
+ import { defineRule } from './rules.mjs';
7
+
8
+ /**
9
+ * RDFS SubClass inference rule
10
+ * If A rdfs:subClassOf B and X rdf:type A, then infer X rdf:type B
11
+ */
12
+ export const rdfsSubClassRule = defineRule({
13
+ name: 'rdfs:subClassOf',
14
+ description: 'Infer type from subclass hierarchy',
15
+ pattern: [
16
+ { subject: '?subClass', predicate: 'rdfs:subClassOf', object: '?superClass' },
17
+ { subject: '?instance', predicate: 'rdf:type', object: '?subClass' },
18
+ ],
19
+ consequent: {
20
+ subject: '?instance',
21
+ predicate: 'rdf:type',
22
+ object: '?superClass',
23
+ },
24
+ salience: 80,
25
+ });
26
+
27
+ /**
28
+ * RDFS SubProperty inference rule
29
+ * If P rdfs:subPropertyOf Q and X P Y, then infer X Q Y
30
+ */
31
+ export const rdfsSubPropertyRule = defineRule({
32
+ name: 'rdfs:subPropertyOf',
33
+ description: 'Infer property from subproperty hierarchy',
34
+ pattern: [
35
+ { subject: '?subProp', predicate: 'rdfs:subPropertyOf', object: '?superProp' },
36
+ { subject: '?x', predicate: '?subProp', object: '?y' },
37
+ ],
38
+ consequent: {
39
+ subject: '?x',
40
+ predicate: '?superProp',
41
+ object: '?y',
42
+ },
43
+ salience: 75,
44
+ });
45
+
46
+ /**
47
+ * RDFS Domain inference rule
48
+ * If P rdfs:domain C and X P Y, then infer X rdf:type C
49
+ */
50
+ export const rdfsDomainRule = defineRule({
51
+ name: 'rdfs:domain',
52
+ description: 'Infer type from property domain',
53
+ pattern: [
54
+ { subject: '?property', predicate: 'rdfs:domain', object: '?class' },
55
+ { subject: '?x', predicate: '?property', object: '?y' },
56
+ ],
57
+ consequent: {
58
+ subject: '?x',
59
+ predicate: 'rdf:type',
60
+ object: '?class',
61
+ },
62
+ salience: 70,
63
+ });
64
+
65
+ /**
66
+ * RDFS Range inference rule
67
+ * If P rdfs:range C and X P Y, then infer Y rdf:type C
68
+ */
69
+ export const rdfsRangeRule = defineRule({
70
+ name: 'rdfs:range',
71
+ description: 'Infer type from property range',
72
+ pattern: [
73
+ { subject: '?property', predicate: 'rdfs:range', object: '?class' },
74
+ { subject: '?x', predicate: '?property', object: '?y' },
75
+ ],
76
+ consequent: {
77
+ subject: '?y',
78
+ predicate: 'rdf:type',
79
+ object: '?class',
80
+ },
81
+ salience: 70,
82
+ });
83
+
84
+ /**
85
+ * OWL Transitive Property rule
86
+ * If P rdf:type owl:TransitiveProperty and X P Y and Y P Z, then infer X P Z
87
+ */
88
+ export const owlTransitiveRule = defineRule({
89
+ name: 'owl:TransitiveProperty',
90
+ description: 'Apply transitive property closure',
91
+ pattern: [
92
+ { subject: '?property', predicate: 'rdf:type', object: 'owl:TransitiveProperty' },
93
+ { subject: '?x', predicate: '?property', object: '?y' },
94
+ { subject: '?y', predicate: '?property', object: '?z' },
95
+ ],
96
+ consequent: {
97
+ subject: '?x',
98
+ predicate: '?property',
99
+ object: '?z',
100
+ },
101
+ salience: 60,
102
+ });
103
+
104
+ /**
105
+ * OWL Symmetric Property rule
106
+ * If P rdf:type owl:SymmetricProperty and X P Y, then infer Y P X
107
+ */
108
+ export const owlSymmetricRule = defineRule({
109
+ name: 'owl:SymmetricProperty',
110
+ description: 'Apply symmetric property',
111
+ pattern: [
112
+ { subject: '?property', predicate: 'rdf:type', object: 'owl:SymmetricProperty' },
113
+ { subject: '?x', predicate: '?property', object: '?y' },
114
+ ],
115
+ consequent: {
116
+ subject: '?y',
117
+ predicate: '?property',
118
+ object: '?x',
119
+ },
120
+ salience: 65,
121
+ });
122
+
123
+ /**
124
+ * OWL Inverse Property rule
125
+ * If P owl:inverseOf Q and X P Y, then infer Y Q X
126
+ */
127
+ export const owlInverseRule = defineRule({
128
+ name: 'owl:inverseOf',
129
+ description: 'Apply inverse property',
130
+ pattern: [
131
+ { subject: '?p', predicate: 'owl:inverseOf', object: '?q' },
132
+ { subject: '?x', predicate: '?p', object: '?y' },
133
+ ],
134
+ consequent: {
135
+ subject: '?y',
136
+ predicate: '?q',
137
+ object: '?x',
138
+ },
139
+ salience: 65,
140
+ });
141
+
142
+ /**
143
+ * Collection of all built-in RDFS/OWL rules
144
+ */
145
+ export const builtinRules = [
146
+ rdfsSubClassRule,
147
+ rdfsSubPropertyRule,
148
+ rdfsDomainRule,
149
+ rdfsRangeRule,
150
+ owlTransitiveRule,
151
+ owlSymmetricRule,
152
+ owlInverseRule,
153
+ ];
154
+
155
+ /**
156
+ * Get all built-in rules
157
+ *
158
+ * @returns {Object[]} Array of built-in rules
159
+ *
160
+ * @example
161
+ * const rules = getBuiltinRules();
162
+ * addRules(engine, rules);
163
+ */
164
+ export function getBuiltinRules() {
165
+ return builtinRules;
166
+ }
167
+
168
+ /**
169
+ * Get RDFS rules only (no OWL)
170
+ *
171
+ * @returns {Object[]} Array of RDFS rules
172
+ *
173
+ * @example
174
+ * const rdfsRules = getRDFSRules();
175
+ */
176
+ export function getRDFSRules() {
177
+ return [rdfsSubClassRule, rdfsSubPropertyRule, rdfsDomainRule, rdfsRangeRule];
178
+ }
179
+
180
+ /**
181
+ * Get OWL rules only
182
+ *
183
+ * @returns {Object[]} Array of OWL rules
184
+ *
185
+ * @example
186
+ * const owlRules = getOWLRules();
187
+ */
188
+ export function getOWLRules() {
189
+ return [owlTransitiveRule, owlSymmetricRule, owlInverseRule];
190
+ }