@sigloch/graph-api-core 2.1.0 → 3.0.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/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/format-e-codec.d.ts +15 -0
- package/dist/format-e-codec.js +36 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/se-descriptor.d.ts +10 -1
- package/dist/se-descriptor.js +61 -29
- package/dist/types.d.ts +1 -1
- package/package.json +3 -3
package/dist/browser.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export { findRoot } from './find-root.js';
|
|
15
15
|
export type { RootQueryGraph } from './find-root.js';
|
|
16
|
-
export { SE_DESCRIPTOR, projectToOntologyGraph } from './se-descriptor.js';
|
|
16
|
+
export { SE_DESCRIPTOR, createSeDescriptor, projectToOntologyGraph } from './se-descriptor.js';
|
|
17
17
|
export { FormatECodec } from './format-e-codec.js';
|
|
18
18
|
export { isValidTrace, tracePatternsOf } from './types.js';
|
|
19
19
|
export type { GraphNode, GraphEdge, Graph } from './types.js';
|
package/dist/browser.js
CHANGED
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
* @author andreas@siglochconsulting
|
|
13
13
|
*/
|
|
14
14
|
export { findRoot } from './find-root.js';
|
|
15
|
-
export { SE_DESCRIPTOR, projectToOntologyGraph } from './se-descriptor.js';
|
|
15
|
+
export { SE_DESCRIPTOR, createSeDescriptor, projectToOntologyGraph } from './se-descriptor.js';
|
|
16
16
|
export { FormatECodec } from './format-e-codec.js';
|
|
17
17
|
export { isValidTrace, tracePatternsOf } from './types.js';
|
package/dist/format-e-codec.d.ts
CHANGED
|
@@ -38,6 +38,21 @@ export declare class FormatECodec {
|
|
|
38
38
|
* `localeCompare`, which is locale-dependent.
|
|
39
39
|
*/
|
|
40
40
|
private serializeEdges;
|
|
41
|
+
/**
|
|
42
|
+
* CR-GC-334: an object attribute has no place in the inline block — `[k:v,k:v]` splits on
|
|
43
|
+
* commas, and `String({…})` produced the literal `[object Object]`, i.e. the binding was
|
|
44
|
+
* destroyed on write. Structured values therefore go to `@key {json}` follow-lines
|
|
45
|
+
* (`structuredAttrLines`), which `parse()` hydrates back into objects.
|
|
46
|
+
*
|
|
47
|
+
* EDGES keep the inline block (they must stay single-line, see `serializeEdges`), so an
|
|
48
|
+
* object on an EDGE is JSON-stringified inline — legible, but it round-trips only while it
|
|
49
|
+
* contains no comma. No edge in the SE ontology carries a structured attribute today; if one
|
|
50
|
+
* ever does, the inline block is the thing to replace, not this escape.
|
|
51
|
+
*/
|
|
41
52
|
private serializeAttrs;
|
|
53
|
+
/** CR-GC-334: object/array attributes as `@key {json}` lines below the node entry. */
|
|
54
|
+
private structuredAttrLines;
|
|
55
|
+
/** Inline block for an EDGE — structured values stringified, see `serializeAttrs`. */
|
|
56
|
+
private serializeEdgeAttrs;
|
|
42
57
|
private edgeTypeToArrow;
|
|
43
58
|
}
|
package/dist/format-e-codec.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* family (`TYPE-slug`, `Name.TypeAbbr.Counter`, `cand_<hex>`); typing by spelling made
|
|
8
8
|
* every foreign convention fail silently instead of loudly.
|
|
9
9
|
*/
|
|
10
|
+
import { hydrateAttrValue } from '@sigloch/contracts/se';
|
|
10
11
|
import { isValidTrace, tracePatternsOf } from './types.js';
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Regex patterns
|
|
@@ -73,7 +74,11 @@ export class FormatECodec {
|
|
|
73
74
|
if (lastOp && (lastOp.type === 'add_node' || lastOp.type === 'update_node' || lastOp.type === 'strict_add_node')) {
|
|
74
75
|
if (!lastOp.attributes)
|
|
75
76
|
lastOp.attributes = {};
|
|
76
|
-
|
|
77
|
+
// CR-GC-334: `serialize()` writes objects as `@key {json}`, so `parse()` must read
|
|
78
|
+
// them back as objects. Kept as a string, `realRef`/`testRef` fail their schema and
|
|
79
|
+
// the element reads as UNBOUND — R-19/R-20 fired on every node authored through this
|
|
80
|
+
// path. Same rule as the contracts parser, imported, not re-implemented.
|
|
81
|
+
lastOp.attributes[attrMatch[1]] = hydrateAttrValue(attrMatch[2].trim());
|
|
77
82
|
}
|
|
78
83
|
else {
|
|
79
84
|
errors.push(`@attribute line without preceding node: "${line}"`);
|
|
@@ -166,6 +171,9 @@ export class FormatECodec {
|
|
|
166
171
|
const descr = node.description ? `|${node.description}` : '';
|
|
167
172
|
const attrs = this.serializeAttrs(node.attributes);
|
|
168
173
|
lines.push(`+ ${node.uid}${descr}${attrs}`);
|
|
174
|
+
// CR-GC-334: realRef/testRef & friends as @key {json} — the inline block above
|
|
175
|
+
// cannot carry them, and dropping them here is what made bindings vanish.
|
|
176
|
+
lines.push(...this.structuredAttrLines(node.attributes));
|
|
169
177
|
}
|
|
170
178
|
}
|
|
171
179
|
}
|
|
@@ -327,7 +335,7 @@ export class FormatECodec {
|
|
|
327
335
|
const entries = [];
|
|
328
336
|
const groups = new Map();
|
|
329
337
|
for (const edge of edges) {
|
|
330
|
-
const attrs = this.
|
|
338
|
+
const attrs = this.serializeEdgeAttrs(edge.attributes);
|
|
331
339
|
if (attrs) {
|
|
332
340
|
entries.push({ sourceId: edge.sourceId, edgeType: edge.edgeType, targets: [edge.targetId], attrs });
|
|
333
341
|
continue;
|
|
@@ -352,13 +360,38 @@ export class FormatECodec {
|
|
|
352
360
|
|| cmp(a.attrs, b.attrs));
|
|
353
361
|
return entries.map(e => `+ ${e.sourceId} -${this.edgeTypeToArrow(e.edgeType)}-> ${e.targets.join(', ')}${e.attrs}`);
|
|
354
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* CR-GC-334: an object attribute has no place in the inline block — `[k:v,k:v]` splits on
|
|
365
|
+
* commas, and `String({…})` produced the literal `[object Object]`, i.e. the binding was
|
|
366
|
+
* destroyed on write. Structured values therefore go to `@key {json}` follow-lines
|
|
367
|
+
* (`structuredAttrLines`), which `parse()` hydrates back into objects.
|
|
368
|
+
*
|
|
369
|
+
* EDGES keep the inline block (they must stay single-line, see `serializeEdges`), so an
|
|
370
|
+
* object on an EDGE is JSON-stringified inline — legible, but it round-trips only while it
|
|
371
|
+
* contains no comma. No edge in the SE ontology carries a structured attribute today; if one
|
|
372
|
+
* ever does, the inline block is the thing to replace, not this escape.
|
|
373
|
+
*/
|
|
355
374
|
serializeAttrs(attrs) {
|
|
356
|
-
const entries = Object.entries(attrs).filter(([, v]) => v != null && v !== '');
|
|
375
|
+
const entries = Object.entries(attrs).filter(([, v]) => v != null && v !== '' && typeof v !== 'object');
|
|
357
376
|
if (entries.length === 0)
|
|
358
377
|
return '';
|
|
359
378
|
const pairs = entries.map(([k, v]) => `${k}:${String(v)}`);
|
|
360
379
|
return ` [${pairs.join(',')}]`;
|
|
361
380
|
}
|
|
381
|
+
/** CR-GC-334: object/array attributes as `@key {json}` lines below the node entry. */
|
|
382
|
+
structuredAttrLines(attrs) {
|
|
383
|
+
return Object.entries(attrs)
|
|
384
|
+
.filter(([, v]) => v != null && typeof v === 'object')
|
|
385
|
+
.map(([k, v]) => `@${k} ${JSON.stringify(v)}`);
|
|
386
|
+
}
|
|
387
|
+
/** Inline block for an EDGE — structured values stringified, see `serializeAttrs`. */
|
|
388
|
+
serializeEdgeAttrs(attrs) {
|
|
389
|
+
const entries = Object.entries(attrs).filter(([, v]) => v != null && v !== '');
|
|
390
|
+
if (entries.length === 0)
|
|
391
|
+
return '';
|
|
392
|
+
const pairs = entries.map(([k, v]) => `${k}:${typeof v === 'object' ? JSON.stringify(v) : String(v)}`);
|
|
393
|
+
return ` [${pairs.join(',')}]`;
|
|
394
|
+
}
|
|
362
395
|
edgeTypeToArrow(edgeType) {
|
|
363
396
|
// Use first defined arrow alias
|
|
364
397
|
const desc = this.ontology.edgeTypes[edgeType];
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { MemoryAdapter } from './memory-adapter.js';
|
|
|
22
22
|
export type { TransportAdapter, TransportConfig } from './transport-adapter.js';
|
|
23
23
|
export { createGraphApi } from './factory.js';
|
|
24
24
|
export type { GraphApiConfig } from './factory.js';
|
|
25
|
-
export { SE_DESCRIPTOR, projectToOntologyGraph } from './se-descriptor.js';
|
|
25
|
+
export { SE_DESCRIPTOR, createSeDescriptor, projectToOntologyGraph } from './se-descriptor.js';
|
|
26
26
|
export { findRoot } from './find-root.js';
|
|
27
27
|
export type { RootQueryGraph } from './find-root.js';
|
|
28
28
|
export { applyEdgeOps, updateEdge, mergeNodes } from './edge-ops.js';
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ export { MemoryAdapter } from './memory-adapter.js';
|
|
|
19
19
|
// Factory
|
|
20
20
|
export { createGraphApi } from './factory.js';
|
|
21
21
|
// SE OntologyDescriptor (derived from @sigloch/contracts/se) [CR-195a]
|
|
22
|
-
export { SE_DESCRIPTOR, projectToOntologyGraph } from './se-descriptor.js';
|
|
22
|
+
export { SE_DESCRIPTOR, createSeDescriptor, projectToOntologyGraph } from './se-descriptor.js';
|
|
23
23
|
// Root-Suche — strukturelle Wurzel (SYS ohne eingehende compose), statt UID-Hardcode
|
|
24
24
|
export { findRoot } from './find-root.js';
|
|
25
25
|
// Edge ops — update-edge (flip/retype) + merge-nodes, shared by GraphService.mutate()
|
package/dist/se-descriptor.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Graph (nodes/edges) ⟷ OntologyGraph (elements/traces)
|
|
10
10
|
* - RuleViolation (ruleId/…) ⟷ contracts RuleViolation (rule_id/…)
|
|
11
11
|
*/
|
|
12
|
-
import { type OntologyGraph } from '@sigloch/contracts/se';
|
|
12
|
+
import { type MetricPolicy, type OntologyGraph } from '@sigloch/contracts/se';
|
|
13
13
|
import type { Graph, OntologyDescriptor } from './types.js';
|
|
14
14
|
/**
|
|
15
15
|
* Project an ontology-agnostic Graph (nodes/edges) onto the SE OntologyGraph
|
|
@@ -21,4 +21,13 @@ export declare function projectToOntologyGraph(graph: Graph): OntologyGraph;
|
|
|
21
21
|
* Canonical SE OntologyDescriptor (ontology + V3 rules + MT metrics), version-pinned
|
|
22
22
|
* to contracts/se ONTOLOGY_VERSION. Plug into GraphService / FormatECodec.
|
|
23
23
|
*/
|
|
24
|
+
export declare function createSeDescriptor(policy: MetricPolicy): OntologyDescriptor;
|
|
25
|
+
/**
|
|
26
|
+
* The descriptor for a host without its own metric policy — judged with contracts'
|
|
27
|
+
* `DEFAULT_METRIC_POLICY`, which is a named, grep-able value, not a hidden fallback.
|
|
28
|
+
*
|
|
29
|
+
* A host that holds a configuration builds its own with `createSeDescriptor(policy)`
|
|
30
|
+
* and must then use only that one; two descriptors in one process would be the two
|
|
31
|
+
* thresholds CR-SM-233 removed.
|
|
32
|
+
*/
|
|
24
33
|
export declare const SE_DESCRIPTOR: OntologyDescriptor;
|
package/dist/se-descriptor.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Graph (nodes/edges) ⟷ OntologyGraph (elements/traces)
|
|
10
10
|
* - RuleViolation (ruleId/…) ⟷ contracts RuleViolation (rule_id/…)
|
|
11
11
|
*/
|
|
12
|
-
import { ElementType, TraceType, TRACE_PATTERNS, V3_RULES, MT_RULES, UC_RULES, FC_RULES, SC_RULES, CR_RULES, AO_RULES, FM_RULES, VIEW_RULES, AF_RULES, ONTOLOGY_VERSION, } from '@sigloch/contracts/se';
|
|
12
|
+
import { ElementType, TraceType, TRACE_PATTERNS, V3_RULES, MT_RULES, UC_RULES, FC_RULES, SC_RULES, CR_RULES, AO_RULES, FM_RULES, VIEW_RULES, AF_RULES, ONTOLOGY_VERSION, DEFAULT_METRIC_POLICY, } from '@sigloch/contracts/se';
|
|
13
13
|
/**
|
|
14
14
|
* Project an ontology-agnostic Graph (nodes/edges) onto the SE OntologyGraph
|
|
15
15
|
* (elements/traces) that contracts/se rules evaluate against. Type-specific
|
|
@@ -68,7 +68,6 @@ export function projectToOntologyGraph(graph) {
|
|
|
68
68
|
const GATING_PREFIXES = ['R-', 'RD-', 'MT-'];
|
|
69
69
|
const SE_RULE_DEFS = [
|
|
70
70
|
...V3_RULES,
|
|
71
|
-
...MT_RULES,
|
|
72
71
|
...UC_RULES,
|
|
73
72
|
...FC_RULES,
|
|
74
73
|
...SC_RULES,
|
|
@@ -78,23 +77,45 @@ const SE_RULE_DEFS = [
|
|
|
78
77
|
...VIEW_RULES,
|
|
79
78
|
...AF_RULES,
|
|
80
79
|
];
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
80
|
+
function adapt(def, evaluate) {
|
|
81
|
+
// (evaluate is already policy-bound by the caller — see seRules below)
|
|
82
|
+
return {
|
|
83
|
+
id: def.id,
|
|
84
|
+
name: def.name,
|
|
85
|
+
severity: def.severity,
|
|
86
|
+
gating: GATING_PREFIXES.some((p) => def.id.startsWith(p)),
|
|
87
|
+
evaluate: (graph) => evaluate(projectToOntologyGraph(graph)).map((v) => ({
|
|
88
|
+
ruleId: v.rule_id,
|
|
89
|
+
ruleName: def.name,
|
|
90
|
+
severity: v.severity,
|
|
91
|
+
message: v.message,
|
|
92
|
+
elementId: v.element_id,
|
|
93
|
+
// CR-GC-203 item 1: carry the fix-context through instead of discarding it,
|
|
94
|
+
// so rules_get_violations hands the agent candidates + a hint, not just a message.
|
|
95
|
+
fixHint: v.fix_hint,
|
|
96
|
+
context: v.context,
|
|
97
|
+
})),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Every rule bound to the judging policy (CR-SM-233, extended by CR-SM-236).
|
|
102
|
+
*
|
|
103
|
+
* A threshold is input, not a constant, and it therefore cannot live in a descriptor
|
|
104
|
+
* constant: a host that configures the value (graphcode's `graphcode.config.jsonc`,
|
|
105
|
+
* CR-GC-329) would otherwise judge against its own number while the gate judged against
|
|
106
|
+
* a second one baked in here.
|
|
107
|
+
*
|
|
108
|
+
* CR-SM-236 removed the former split into a policy-free `SE_RULES` constant plus a
|
|
109
|
+
* policy-bound metric list. MT-01/MT-02 stopped being the only rules with a threshold
|
|
110
|
+
* (CR-01, FM-03 and R-04 joined them), so a policy-free rule constant had become a
|
|
111
|
+
* second, silently-judging path — exactly what CR-SM-233 set out to remove.
|
|
112
|
+
*
|
|
113
|
+
* A `null` threshold means measure, don't judge: the rule stays registered and simply
|
|
114
|
+
* reports nothing.
|
|
115
|
+
*/
|
|
116
|
+
function seRules(policy) {
|
|
117
|
+
return [...SE_RULE_DEFS, ...MT_RULES].map((def) => adapt(def, (g) => def.evaluate(g, policy)));
|
|
118
|
+
}
|
|
98
119
|
// `label` is the node-table identifier (kuzu table name) — must be a valid
|
|
99
120
|
// identifier, so it's the ElementType key (SYS, UC, …), not the human
|
|
100
121
|
// ELEMENT_DESCRIPTIONS text which would break DDL.
|
|
@@ -108,13 +129,24 @@ const edgeTypes = Object.fromEntries(TraceType.options.map((tt) => {
|
|
|
108
129
|
* Canonical SE OntologyDescriptor (ontology + V3 rules + MT metrics), version-pinned
|
|
109
130
|
* to contracts/se ONTOLOGY_VERSION. Plug into GraphService / FormatECodec.
|
|
110
131
|
*/
|
|
111
|
-
export
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
132
|
+
export function createSeDescriptor(policy) {
|
|
133
|
+
return {
|
|
134
|
+
name: 'se',
|
|
135
|
+
version: ONTOLOGY_VERSION,
|
|
136
|
+
nodeTypes,
|
|
137
|
+
edgeTypes,
|
|
138
|
+
// CR-GC-247: TRACE_PATTERNS is the trace-legality SSOT; validPairs above is kept
|
|
139
|
+
// only for Format-E arrow/menu enumeration. isValidTrace validates against these.
|
|
140
|
+
patterns: TRACE_PATTERNS,
|
|
141
|
+
rules: seRules(policy),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The descriptor for a host without its own metric policy — judged with contracts'
|
|
146
|
+
* `DEFAULT_METRIC_POLICY`, which is a named, grep-able value, not a hidden fallback.
|
|
147
|
+
*
|
|
148
|
+
* A host that holds a configuration builds its own with `createSeDescriptor(policy)`
|
|
149
|
+
* and must then use only that one; two descriptors in one process would be the two
|
|
150
|
+
* thresholds CR-SM-233 removed.
|
|
151
|
+
*/
|
|
152
|
+
export const SE_DESCRIPTOR = createSeDescriptor(DEFAULT_METRIC_POLICY);
|
package/dist/types.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ export interface FormatEOperation {
|
|
|
113
113
|
description?: string;
|
|
114
114
|
/**
|
|
115
115
|
* BOK-CR-026: `unknown`, not `string` — object-valued bindings (`realRef`,
|
|
116
|
-
* `
|
|
116
|
+
* `testRefs`) must survive a Format-E mutation as objects/arrays, or the element reads as
|
|
117
117
|
* unbound. GraphService already handled them as unknown internally; this is the
|
|
118
118
|
* public type catching up (a plain `@key value` line still yields a string).
|
|
119
119
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigloch/graph-api-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"prepublishOnly": "npm run build && npm run test"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@sigloch/contracts": "^
|
|
24
|
+
"@sigloch/contracts": "^4.0.0",
|
|
25
25
|
"zod": "^4.3.6"
|
|
26
26
|
},
|
|
27
27
|
"license": "MIT",
|
|
28
|
-
"description": "Framework-agnostic graph engine core
|
|
28
|
+
"description": "Framework-agnostic graph engine core \u2014 ontology-typed nodes/traces, rule evaluation, views",
|
|
29
29
|
"author": "sigloch-consulting",
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|