@sigloch/graph-api-core 0.4.0
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/LICENSE +21 -0
- package/dist/audit.d.ts +103 -0
- package/dist/audit.js +145 -0
- package/dist/browser.d.ts +21 -0
- package/dist/browser.js +17 -0
- package/dist/edge-ops.d.ts +42 -0
- package/dist/edge-ops.js +66 -0
- package/dist/factory.d.ts +26 -0
- package/dist/factory.js +23 -0
- package/dist/find-root.d.ts +34 -0
- package/dist/find-root.js +10 -0
- package/dist/format-e-codec.d.ts +23 -0
- package/dist/format-e-codec.js +296 -0
- package/dist/graph-service.d.ts +37 -0
- package/dist/graph-service.js +597 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +27 -0
- package/dist/memory-adapter.d.ts +28 -0
- package/dist/memory-adapter.js +72 -0
- package/dist/rule-engine.d.ts +33 -0
- package/dist/rule-engine.js +17 -0
- package/dist/schemas.d.ts +97 -0
- package/dist/schemas.js +58 -0
- package/dist/se-descriptor.d.ts +24 -0
- package/dist/se-descriptor.js +84 -0
- package/dist/storage-adapter.d.ts +32 -0
- package/dist/storage-adapter.js +1 -0
- package/dist/test-fixtures.d.ts +42 -0
- package/dist/test-fixtures.js +151 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.js +11 -0
- package/dist/testing/storage-contract-tests.d.ts +2 -0
- package/dist/testing/storage-contract-tests.js +113 -0
- package/dist/transport-adapter.d.ts +13 -0
- package/dist/transport-adapter.js +1 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.js +39 -0
- package/package.json +45 -0
- package/test-fixtures/cr-007-features.format-e.md +22 -0
- package/test-fixtures/empty.format-e.md +6 -0
- package/test-fixtures/rasentraktor.format-e.md +46 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract test suite for StorageAdapter implementations.
|
|
3
|
+
* Every adapter (Neo4j, SQLite, Memory, File) must pass these tests.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
const SCOPE = { workspaceId: 'test', systemId: 'test' };
|
|
7
|
+
function makeNode(uid, type = 'ACT') {
|
|
8
|
+
return {
|
|
9
|
+
uid,
|
|
10
|
+
type,
|
|
11
|
+
name: uid.split('.')[0],
|
|
12
|
+
description: `Test node ${uid}`,
|
|
13
|
+
attributes: {},
|
|
14
|
+
createdAt: new Date().toISOString(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function makeEdge(sourceId, targetId, edgeType = 'FLOWS_TO') {
|
|
18
|
+
return { sourceId, targetId, edgeType, attributes: {} };
|
|
19
|
+
}
|
|
20
|
+
export function runStorageContractTests(factory) {
|
|
21
|
+
describe('StorageAdapter Contract', () => {
|
|
22
|
+
let adapter;
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
adapter = await factory();
|
|
25
|
+
await adapter.initialize();
|
|
26
|
+
});
|
|
27
|
+
afterEach(async () => {
|
|
28
|
+
await adapter.shutdown();
|
|
29
|
+
});
|
|
30
|
+
it('starts with empty graph', async () => {
|
|
31
|
+
const graph = await adapter.loadGraph(SCOPE);
|
|
32
|
+
expect(graph.nodes).toHaveLength(0);
|
|
33
|
+
expect(graph.edges).toHaveLength(0);
|
|
34
|
+
});
|
|
35
|
+
it('saves and loads nodes', async () => {
|
|
36
|
+
const node = makeNode('TestActor.ACT.01');
|
|
37
|
+
await adapter.saveNodes([node]);
|
|
38
|
+
const graph = await adapter.loadGraph(SCOPE);
|
|
39
|
+
expect(graph.nodes).toHaveLength(1);
|
|
40
|
+
expect(graph.nodes[0].uid).toBe('TestActor.ACT.01');
|
|
41
|
+
});
|
|
42
|
+
it('saves and loads edges', async () => {
|
|
43
|
+
const n1 = makeNode('Source.ACT.01');
|
|
44
|
+
const n2 = makeNode('Target.ACT.02');
|
|
45
|
+
await adapter.saveNodes([n1, n2]);
|
|
46
|
+
await adapter.saveEdges([makeEdge('Source.ACT.01', 'Target.ACT.02')]);
|
|
47
|
+
const graph = await adapter.loadGraph(SCOPE);
|
|
48
|
+
expect(graph.edges).toHaveLength(1);
|
|
49
|
+
expect(graph.edges[0].sourceId).toBe('Source.ACT.01');
|
|
50
|
+
});
|
|
51
|
+
it('deletes nodes and cascades edges', async () => {
|
|
52
|
+
const n1 = makeNode('A.ACT.01');
|
|
53
|
+
const n2 = makeNode('B.ACT.02');
|
|
54
|
+
await adapter.saveNodes([n1, n2]);
|
|
55
|
+
await adapter.saveEdges([makeEdge('A.ACT.01', 'B.ACT.02')]);
|
|
56
|
+
await adapter.deleteNodes(['A.ACT.01']);
|
|
57
|
+
const graph = await adapter.loadGraph(SCOPE);
|
|
58
|
+
expect(graph.nodes).toHaveLength(1);
|
|
59
|
+
expect(graph.edges).toHaveLength(0);
|
|
60
|
+
});
|
|
61
|
+
it('deletes edges', async () => {
|
|
62
|
+
const n1 = makeNode('A.ACT.01');
|
|
63
|
+
const n2 = makeNode('B.ACT.02');
|
|
64
|
+
await adapter.saveNodes([n1, n2]);
|
|
65
|
+
await adapter.saveEdges([makeEdge('A.ACT.01', 'B.ACT.02')]);
|
|
66
|
+
await adapter.deleteEdges([{ sourceId: 'A.ACT.01', targetId: 'B.ACT.02', edgeType: 'FLOWS_TO' }]);
|
|
67
|
+
const graph = await adapter.loadGraph(SCOPE);
|
|
68
|
+
expect(graph.nodes).toHaveLength(2);
|
|
69
|
+
expect(graph.edges).toHaveLength(0);
|
|
70
|
+
});
|
|
71
|
+
it('getNode returns null for missing', async () => {
|
|
72
|
+
const result = await adapter.getNode('DoesNotExist.ACT.99');
|
|
73
|
+
expect(result).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
it('getNode returns existing', async () => {
|
|
76
|
+
await adapter.saveNodes([makeNode('Found.ACT.01')]);
|
|
77
|
+
const result = await adapter.getNode('Found.ACT.01');
|
|
78
|
+
expect(result).not.toBeNull();
|
|
79
|
+
expect(result.uid).toBe('Found.ACT.01');
|
|
80
|
+
});
|
|
81
|
+
it('getSubgraph returns correct depth', async () => {
|
|
82
|
+
const nodes = [makeNode('Root.ACT.01'), makeNode('Child.ACT.02'), makeNode('Grand.ACT.03')];
|
|
83
|
+
await adapter.saveNodes(nodes);
|
|
84
|
+
await adapter.saveEdges([
|
|
85
|
+
makeEdge('Root.ACT.01', 'Child.ACT.02'),
|
|
86
|
+
makeEdge('Child.ACT.02', 'Grand.ACT.03'),
|
|
87
|
+
]);
|
|
88
|
+
const depth1 = await adapter.getSubgraph('Root.ACT.01', 1);
|
|
89
|
+
expect(depth1.nodes).toHaveLength(2);
|
|
90
|
+
const depth2 = await adapter.getSubgraph('Root.ACT.01', 2);
|
|
91
|
+
expect(depth2.nodes).toHaveLength(3);
|
|
92
|
+
});
|
|
93
|
+
it('stats returns correct counts', async () => {
|
|
94
|
+
await adapter.saveNodes([makeNode('A.ACT.01'), makeNode('B.ACT.02')]);
|
|
95
|
+
await adapter.saveEdges([makeEdge('A.ACT.01', 'B.ACT.02')]);
|
|
96
|
+
const stats = await adapter.stats();
|
|
97
|
+
expect(stats.nodeCount).toBe(2);
|
|
98
|
+
expect(stats.edgeCount).toBe(1);
|
|
99
|
+
});
|
|
100
|
+
it('upserts nodes (save twice)', async () => {
|
|
101
|
+
const node = makeNode('Upsert.ACT.01');
|
|
102
|
+
await adapter.saveNodes([node]);
|
|
103
|
+
const updated = { ...node, description: 'Updated' };
|
|
104
|
+
await adapter.saveNodes([updated]);
|
|
105
|
+
const graph = await adapter.loadGraph(SCOPE);
|
|
106
|
+
expect(graph.nodes).toHaveLength(1);
|
|
107
|
+
expect(graph.nodes[0].description).toBe('Updated');
|
|
108
|
+
});
|
|
109
|
+
it('isHealthy returns true', async () => {
|
|
110
|
+
expect(await adapter.isHealthy()).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TransportAdapter interface — binds GraphService to HTTP/WS/MCP/CLI frameworks.
|
|
3
|
+
*/
|
|
4
|
+
import type { GraphService } from './graph-service.js';
|
|
5
|
+
export interface TransportConfig {
|
|
6
|
+
port?: number;
|
|
7
|
+
host?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface TransportAdapter {
|
|
10
|
+
mount(service: GraphService, config: TransportConfig): void;
|
|
11
|
+
start(): Promise<void>;
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for graph-api-core — ontology-agnostic.
|
|
3
|
+
* Domains register their node/edge types via OntologyDescriptor.
|
|
4
|
+
*/
|
|
5
|
+
export interface GraphNode {
|
|
6
|
+
uid: string;
|
|
7
|
+
type: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
attributes: Record<string, unknown>;
|
|
11
|
+
createdAt?: string;
|
|
12
|
+
updatedAt?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface GraphEdge {
|
|
15
|
+
sourceId: string;
|
|
16
|
+
targetId: string;
|
|
17
|
+
edgeType: string;
|
|
18
|
+
attributes: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface Graph {
|
|
21
|
+
nodes: GraphNode[];
|
|
22
|
+
edges: GraphEdge[];
|
|
23
|
+
}
|
|
24
|
+
export interface NodeTypeDescriptor {
|
|
25
|
+
label: string;
|
|
26
|
+
requiredAttrs: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface EdgeTypeDescriptor {
|
|
29
|
+
/** Arrow aliases for Format E parsing (e.g. ['compose', 'cp']). */
|
|
30
|
+
arrows: string[];
|
|
31
|
+
/** Valid source→target node type pairs. */
|
|
32
|
+
validPairs: [string, string][];
|
|
33
|
+
}
|
|
34
|
+
export interface TracePattern {
|
|
35
|
+
source: string;
|
|
36
|
+
target: string;
|
|
37
|
+
type: string;
|
|
38
|
+
/** Optional label refinement (e.g. MS→MS relation 'depends-on'). */
|
|
39
|
+
label?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface OntologyDescriptor {
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
nodeTypes: Record<string, NodeTypeDescriptor>;
|
|
45
|
+
edgeTypes: Record<string, EdgeTypeDescriptor>;
|
|
46
|
+
/**
|
|
47
|
+
* Authoritative trace-legality patterns (CR-GC-247). The ONE source the engine
|
|
48
|
+
* validates edges against — supersedes per-edgeType `validPairs`, which is now
|
|
49
|
+
* only a menu/arrow enumeration. Omit to derive patterns from validPairs
|
|
50
|
+
* (foreign ontologies that declare only pairs); see {@link tracePatternsOf}.
|
|
51
|
+
*/
|
|
52
|
+
patterns?: TracePattern[];
|
|
53
|
+
/** Domain-specific rules. */
|
|
54
|
+
rules?: Rule[];
|
|
55
|
+
}
|
|
56
|
+
interface Rule {
|
|
57
|
+
id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
severity: 'error' | 'warning' | 'info';
|
|
60
|
+
evaluate: (graph: Graph) => RuleViolation[];
|
|
61
|
+
}
|
|
62
|
+
interface RuleViolation {
|
|
63
|
+
ruleId: string;
|
|
64
|
+
ruleName: string;
|
|
65
|
+
severity: 'error' | 'warning' | 'info';
|
|
66
|
+
message: string;
|
|
67
|
+
elementId?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface GraphScope {
|
|
70
|
+
workspaceId: string;
|
|
71
|
+
systemId: string;
|
|
72
|
+
}
|
|
73
|
+
export interface GraphQuery {
|
|
74
|
+
type: 'elements' | 'edges' | 'subgraph' | 'view';
|
|
75
|
+
filter?: Record<string, unknown>;
|
|
76
|
+
view?: string;
|
|
77
|
+
root?: string;
|
|
78
|
+
depth?: number;
|
|
79
|
+
format?: 'json' | 'format-e';
|
|
80
|
+
}
|
|
81
|
+
export interface MutationResult {
|
|
82
|
+
applied: number;
|
|
83
|
+
rejected: number;
|
|
84
|
+
violations: RuleViolation[];
|
|
85
|
+
version: number;
|
|
86
|
+
auditId: string;
|
|
87
|
+
}
|
|
88
|
+
export interface BatchResult {
|
|
89
|
+
results: MutationResult[];
|
|
90
|
+
totalApplied: number;
|
|
91
|
+
totalRejected: number;
|
|
92
|
+
}
|
|
93
|
+
export interface HealthStatus {
|
|
94
|
+
status: 'ok' | 'degraded' | 'down';
|
|
95
|
+
storage: string;
|
|
96
|
+
ontologyName: string;
|
|
97
|
+
ontologyVersion: string;
|
|
98
|
+
elementCount: number;
|
|
99
|
+
edgeCount: number;
|
|
100
|
+
violationCount: number;
|
|
101
|
+
}
|
|
102
|
+
export interface FormatEOperation {
|
|
103
|
+
type: 'add_node' | 'remove_node' | 'update_node' | 'add_edge' | 'remove_edge' | 'update_edge' | 'strict_add_node' | 'strict_add_edge' | 'merge_nodes';
|
|
104
|
+
/** Node uid or edge key (source->target). */
|
|
105
|
+
semanticId: string;
|
|
106
|
+
description?: string;
|
|
107
|
+
attributes?: Record<string, string>;
|
|
108
|
+
sourceId?: string;
|
|
109
|
+
targetId?: string;
|
|
110
|
+
edgeType?: string;
|
|
111
|
+
/** Merge operation: source node IDs to merge. */
|
|
112
|
+
sourceIds?: string[];
|
|
113
|
+
/** update_edge: identity is sourceId/targetId/edgeType above; this is the change (CR-198). */
|
|
114
|
+
set?: {
|
|
115
|
+
edgeType?: string;
|
|
116
|
+
flip?: boolean;
|
|
117
|
+
attributes?: Record<string, string>;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export interface FormatEDiff {
|
|
121
|
+
operations: FormatEOperation[];
|
|
122
|
+
errors: string[];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Structural trace-legality check. Ontology-agnostic: matches a trace against
|
|
126
|
+
* TracePattern[] with '*' wildcards on source/target. Both graph-service and
|
|
127
|
+
* format-e-codec route every check through this — validPairs is no longer a
|
|
128
|
+
* parallel re-implementation.
|
|
129
|
+
*
|
|
130
|
+
* A pattern's `label` is descriptive metadata (e.g. MS→MS relation 'depends-on'),
|
|
131
|
+
* NOT a gate: label is trace data that isn't uniformly carried through the
|
|
132
|
+
* Graph/codec pipeline, and the legality this replaces (validPairs) never keyed on
|
|
133
|
+
* it. Enforcing label is a deliberate tightening (needs codec label round-tripping),
|
|
134
|
+
* out of scope for the centralization.
|
|
135
|
+
*/
|
|
136
|
+
export declare function isValidTrace(trace: {
|
|
137
|
+
source: string;
|
|
138
|
+
target: string;
|
|
139
|
+
type: string;
|
|
140
|
+
}, patterns: TracePattern[]): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* The patterns a descriptor validates against: explicit `patterns` (SSOT) if set,
|
|
143
|
+
* else derived from each edgeType's `validPairs` (menu → legality) so foreign
|
|
144
|
+
* ontologies that declare only pairs keep working.
|
|
145
|
+
*/
|
|
146
|
+
export declare function tracePatternsOf(ontology: OntologyDescriptor): TracePattern[];
|
|
147
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for graph-api-core — ontology-agnostic.
|
|
3
|
+
* Domains register their node/edge types via OntologyDescriptor.
|
|
4
|
+
*/
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Trace legality — the ONE checker (CR-GC-247)
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
/**
|
|
9
|
+
* Structural trace-legality check. Ontology-agnostic: matches a trace against
|
|
10
|
+
* TracePattern[] with '*' wildcards on source/target. Both graph-service and
|
|
11
|
+
* format-e-codec route every check through this — validPairs is no longer a
|
|
12
|
+
* parallel re-implementation.
|
|
13
|
+
*
|
|
14
|
+
* A pattern's `label` is descriptive metadata (e.g. MS→MS relation 'depends-on'),
|
|
15
|
+
* NOT a gate: label is trace data that isn't uniformly carried through the
|
|
16
|
+
* Graph/codec pipeline, and the legality this replaces (validPairs) never keyed on
|
|
17
|
+
* it. Enforcing label is a deliberate tightening (needs codec label round-tripping),
|
|
18
|
+
* out of scope for the centralization.
|
|
19
|
+
*/
|
|
20
|
+
export function isValidTrace(trace, patterns) {
|
|
21
|
+
return patterns.some((p) => (p.source === '*' || p.source === trace.source) &&
|
|
22
|
+
(p.target === '*' || p.target === trace.target) &&
|
|
23
|
+
p.type === trace.type);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The patterns a descriptor validates against: explicit `patterns` (SSOT) if set,
|
|
27
|
+
* else derived from each edgeType's `validPairs` (menu → legality) so foreign
|
|
28
|
+
* ontologies that declare only pairs keep working.
|
|
29
|
+
*/
|
|
30
|
+
export function tracePatternsOf(ontology) {
|
|
31
|
+
if (ontology.patterns)
|
|
32
|
+
return ontology.patterns;
|
|
33
|
+
const derived = [];
|
|
34
|
+
for (const [type, desc] of Object.entries(ontology.edgeTypes)) {
|
|
35
|
+
for (const [source, target] of desc.validPairs)
|
|
36
|
+
derived.push({ source, target, type });
|
|
37
|
+
}
|
|
38
|
+
return derived;
|
|
39
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sigloch/graph-api-core",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"test-fixtures"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./browser": "./dist/browser.js",
|
|
15
|
+
"./testing": "./dist/testing/index.js",
|
|
16
|
+
"./test-fixtures": "./dist/test-fixtures.js"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "rm -rf dist && tsc",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@sigloch/contracts": "^0.7.0",
|
|
25
|
+
"zod": "^4.3.6"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"description": "Framework-agnostic graph engine core — ontology-typed nodes/traces, rule evaluation, views",
|
|
29
|
+
"author": "sigloch-consulting",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/andreassigloch/sigloch-modules.git",
|
|
33
|
+
"directory": "packages/graph-api-core"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/andreassigloch/sigloch-modules#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/andreassigloch/sigloch-modules/issues"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Format-E Test Fixture · CR-007 features
|
|
2
|
+
|
|
3
|
+
Exercises the reserved inline attributes from CR-007:
|
|
4
|
+
- Nodes: `notes`
|
|
5
|
+
- Edges: `cardinality`, `constraint`, `notes`
|
|
6
|
+
|
|
7
|
+
Uses the minimal `TEST_ONTOLOGY` shipped from `@sigloch/graph-api-core/test-fixtures`.
|
|
8
|
+
|
|
9
|
+
```format-e
|
|
10
|
+
## Nodes
|
|
11
|
+
+ Mower.PR.01|Riding mower R15 [notes:Phase-2-Vertical-Slice-Wurzel]
|
|
12
|
+
+ Engine.C.01|Combustion engine [power:gas]
|
|
13
|
+
+ Gearbox.C.02|Mowing-deck gearbox family [kind:family,notes:drei Varianten geplant]
|
|
14
|
+
+ DFMEA-Engine-001.FR.01|Not-Stop-Funktion am Motor [external_id:DFMEA-Engine-001]
|
|
15
|
+
+ EmergencyBrake.CTRL.01|Mechanische Bremse Stillstandszeit max 5 sec
|
|
16
|
+
|
|
17
|
+
## Edges
|
|
18
|
+
+ Mower.PR.01 -compose-> Engine.C.01 [cardinality:1..1]
|
|
19
|
+
+ Mower.PR.01 -compose-> Gearbox.C.02 [cardinality:1..n,constraint:mindestens eine Variante je Schnittbreite]
|
|
20
|
+
+ Engine.C.01 -addressed_by-> DFMEA-Engine-001.FR.01 [cardinality:1..n,notes:DFMEA-Hotspot]
|
|
21
|
+
+ DFMEA-Engine-001.FR.01 -addressed_by-> EmergencyBrake.CTRL.01 [cardinality:1..1,constraint:Stillstandszeit <= 5 sec]
|
|
22
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Format-E Test Fixture · Rasentraktor R15 (Subset)
|
|
2
|
+
|
|
3
|
+
Vertical-Slice-Auszug aus dem ontoagent-Trockenlauf v0.3 ("Rasentraktor R15 /
|
|
4
|
+
Mähwerk-Getriebe"). Vollständige Domäne siehe ontoagent
|
|
5
|
+
`docs/examples/format-e-rasentraktor.md`; diese Fixture ist die kompakte,
|
|
6
|
+
sigloch-weit nutzbare Variante für CI-Smokes.
|
|
7
|
+
|
|
8
|
+
Validiert gegen `TEST_ONTOLOGY` aus `@sigloch/graph-api-core/test-fixtures`.
|
|
9
|
+
|
|
10
|
+
```format-e
|
|
11
|
+
## Nodes
|
|
12
|
+
+ Konstruktion.OU.01|Konstruktion
|
|
13
|
+
+ Tooling.OU.02|Tooling
|
|
14
|
+
+ DesignLead.R.01|Design Lead
|
|
15
|
+
+ Tooling.R.02|Tooling
|
|
16
|
+
+ R15.PR.01|Rasentraktor R15 [code:R15]
|
|
17
|
+
+ R15-1000.VAR.01|R15 mit 1000 mm Schnittbreite [attribute_key:Schnittbreite,attribute_value:1000mm]
|
|
18
|
+
+ R15-1500.VAR.02|R15 mit 1500 mm Schnittbreite [attribute_key:Schnittbreite,attribute_value:1500mm]
|
|
19
|
+
+ MaehwerkGetriebe.C.01|Maehwerk-Getriebe Familie [kind:family]
|
|
20
|
+
+ Getriebe-1000.C.02|Getriebe 1000 [kind:variant,part_no:MG-1000]
|
|
21
|
+
+ Getriebe-1500.C.03|Getriebe 1500 [kind:variant,part_no:MG-1500]
|
|
22
|
+
+ UnterschiedlicheMaehbreiten.F.01|Unterschiedliche Maehbreiten [customer_priority:hoch]
|
|
23
|
+
+ DFMEA-MG-001.FR.01|Not-Stop-Funktion [external_id:DFMEA-MG-001,status:verifiziert]
|
|
24
|
+
+ MechBremse.CTRL.01|Mechanische Bremse Stillstandszeit max 5 sec
|
|
25
|
+
+ Stillstandszeitmessung.TC.01|Stillstandszeit-Messung nach Not-Aus [criterion:t_stop <= 5 sec]
|
|
26
|
+
+ WerkzeugSetGehaeuse.TL.01|Werkzeug-Set Gehaeuse Druckguss [material:Aluminium-Druckguss]
|
|
27
|
+
+ M3.MT.01|GO Milestone [sequence_no:3]
|
|
28
|
+
+ PDM.SL.01|PDM-System [type:PLM]
|
|
29
|
+
|
|
30
|
+
## Edges
|
|
31
|
+
+ R15.PR.01 -compose-> MaehwerkGetriebe.C.01 [cardinality:1..1]
|
|
32
|
+
+ MaehwerkGetriebe.C.01 -compose-> Getriebe-1000.C.02 [cardinality:1..n,constraint:eine Variante je Schnittbreite]
|
|
33
|
+
+ MaehwerkGetriebe.C.01 -compose-> Getriebe-1500.C.03 [cardinality:1..n]
|
|
34
|
+
+ R15.PR.01 -has_variant-> R15-1000.VAR.01 [cardinality:1..n]
|
|
35
|
+
+ R15.PR.01 -has_variant-> R15-1500.VAR.02 [cardinality:1..n]
|
|
36
|
+
+ UnterschiedlicheMaehbreiten.F.01 -realized_by-> MaehwerkGetriebe.C.01 [cardinality:1..n]
|
|
37
|
+
+ MaehwerkGetriebe.C.01 -addressed_by-> DFMEA-MG-001.FR.01 [cardinality:1..n]
|
|
38
|
+
+ DFMEA-MG-001.FR.01 -addressed_by-> MechBremse.CTRL.01 [cardinality:1..1,constraint:Stillstandszeit <= 5 sec]
|
|
39
|
+
+ MechBremse.CTRL.01 -verified_by-> Stillstandszeitmessung.TC.01 [cardinality:1..1]
|
|
40
|
+
+ Tooling.OU.02 -responsible_for-> WerkzeugSetGehaeuse.TL.01 [cardinality:1..1]
|
|
41
|
+
+ Konstruktion.OU.01 -responsible_for-> MaehwerkGetriebe.C.01 [cardinality:1..1]
|
|
42
|
+
+ DesignLead.R.01 -within-> Konstruktion.OU.01 [cardinality:1..1]
|
|
43
|
+
+ Tooling.R.02 -within-> Tooling.OU.02 [cardinality:1..1]
|
|
44
|
+
+ M3.MT.01 -requires_document_of_type-> DFMEA-MG-001.FR.01 [cardinality:1..n,notes:GO-Gate verlangt finalisierte D-FMEA]
|
|
45
|
+
+ MaehwerkGetriebe.C.01 -stored_in-> PDM.SL.01 [cardinality:1..1]
|
|
46
|
+
```
|