@weftlet/toolkit 0.6.1 → 0.7.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.
- package/README.md +191 -18
- package/THIRD_PARTY_NOTICES.md +3 -1
- package/dist/application/application.d.ts +10 -0
- package/dist/application/application.js +20 -0
- package/dist/application/document-code-bindings.d.ts +11 -0
- package/dist/application/document-code-bindings.js +25 -0
- package/dist/application/document-obligations.d.ts +8 -0
- package/dist/application/document-obligations.js +11 -0
- package/dist/application/draft-facts.d.ts +3 -0
- package/dist/application/draft-facts.js +37 -0
- package/dist/application/extraction-identity.d.ts +2 -2
- package/dist/application/extraction-identity.js +7 -1
- package/dist/application/extractor-results.d.ts +6 -0
- package/dist/application/extractor-results.js +6 -0
- package/dist/application/hydrator.js +38 -18
- package/dist/application/mapping-proposals.d.ts +108 -0
- package/dist/application/mapping-proposals.js +142 -0
- package/dist/application/mapping-service.d.ts +2 -0
- package/dist/application/mapping-service.js +5 -0
- package/dist/application/overlay.js +43 -29
- package/dist/application/saved-code-coverage.d.ts +40 -0
- package/dist/application/saved-code-coverage.js +20 -0
- package/dist/application/saved-compatibility.d.ts +38 -0
- package/dist/application/saved-compatibility.js +20 -0
- package/dist/application/saved-evidence.d.ts +17 -11
- package/dist/application/saved-evidence.js +44 -40
- package/dist/application/saved-exploration.d.ts +57 -0
- package/dist/application/saved-exploration.js +21 -0
- package/dist/application/saved-paths.d.ts +58 -0
- package/dist/application/saved-paths.js +20 -0
- package/dist/application/semantic-run.d.ts +1 -1
- package/dist/extraction/call-syntax.d.ts +18 -0
- package/dist/extraction/call-syntax.js +61 -0
- package/dist/extraction/canonical-document-links.d.ts +5 -1
- package/dist/extraction/canonical-document-links.js +4 -4
- package/dist/extraction/code-inventory.d.ts +6 -0
- package/dist/extraction/code-inventory.js +26 -0
- package/dist/extraction/document-code-bindings.d.ts +14 -0
- package/dist/extraction/document-code-bindings.js +121 -0
- package/dist/extraction/document-obligations.d.ts +12 -0
- package/dist/extraction/document-obligations.js +112 -0
- package/dist/extraction/mapping-candidates.d.ts +13 -0
- package/dist/extraction/mapping-candidates.js +46 -0
- package/dist/extraction/mapping-output.d.ts +75 -0
- package/dist/extraction/mapping-output.js +53 -0
- package/dist/extraction/mapping-plan.d.ts +7 -0
- package/dist/extraction/mapping-plan.js +117 -0
- package/dist/extraction/mapping-prompt.d.ts +2 -0
- package/dist/extraction/mapping-prompt.js +17 -0
- package/dist/extraction/mapping-provider.d.ts +15 -0
- package/dist/extraction/mapping-provider.js +60 -0
- package/dist/extraction/mapping-request.d.ts +3 -0
- package/dist/extraction/mapping-request.js +32 -0
- package/dist/extraction/ontology.d.ts +2 -0
- package/dist/extraction/ontology.js +28 -13
- package/dist/extraction/routing.js +5 -20
- package/dist/extraction/scip-occurrences.d.ts +3 -0
- package/dist/extraction/scip-occurrences.js +102 -0
- package/dist/extraction/scip-ranges.d.ts +6 -0
- package/dist/extraction/scip-ranges.js +31 -0
- package/dist/extraction/scip-runtime.d.ts +39 -0
- package/dist/extraction/scip-runtime.js +8 -0
- package/dist/extraction/scip-symbols.d.ts +21 -0
- package/dist/extraction/scip-symbols.js +91 -0
- package/dist/extraction/semantic.d.ts +1 -1
- package/dist/extraction/semantic.js +5 -17
- package/dist/extraction/static-calls.d.ts +10 -0
- package/dist/extraction/static-calls.js +133 -0
- package/dist/extraction/static.d.ts +3 -20
- package/dist/extraction/static.js +8 -84
- package/dist/extraction/symbol-resolution.d.ts +12 -0
- package/dist/extraction/symbol-resolution.js +51 -0
- package/dist/extraction/symbol-selectors.d.ts +11 -0
- package/dist/extraction/symbol-selectors.js +51 -0
- package/dist/graph/binding-rdf.d.ts +7 -0
- package/dist/graph/binding-rdf.js +109 -0
- package/dist/graph/call-rdf.d.ts +4 -0
- package/dist/graph/call-rdf.js +94 -0
- package/dist/graph/call-shapes.d.ts +2 -0
- package/dist/graph/call-shapes.js +28 -0
- package/dist/graph/code-coverage-projection.d.ts +9 -0
- package/dist/graph/code-coverage-projection.js +117 -0
- package/dist/graph/code-coverage-renderer.d.ts +2 -0
- package/dist/graph/code-coverage-renderer.js +15 -0
- package/dist/graph/code-coverage-request.d.ts +6 -0
- package/dist/graph/code-coverage-request.js +19 -0
- package/dist/graph/code-coverage.d.ts +6 -0
- package/dist/graph/code-coverage.js +54 -0
- package/dist/graph/code-description.d.ts +4 -0
- package/dist/graph/code-description.js +24 -0
- package/dist/graph/code-rdf.d.ts +6 -0
- package/dist/graph/code-rdf.js +79 -0
- package/dist/graph/compatibility-context.d.ts +2 -0
- package/dist/graph/compatibility-context.js +18 -0
- package/dist/graph/compatibility-renderer.d.ts +2 -0
- package/dist/graph/compatibility-renderer.js +45 -0
- package/dist/graph/compatibility-request.d.ts +3 -0
- package/dist/graph/compatibility-request.js +18 -0
- package/dist/graph/compatibility.d.ts +7 -0
- package/dist/graph/compatibility.js +67 -0
- package/dist/graph/constraint-comparison.d.ts +7 -0
- package/dist/graph/constraint-comparison.js +49 -0
- package/dist/graph/coverage.d.ts +2 -2
- package/dist/graph/coverage.js +8 -3
- package/dist/graph/diagnostics.d.ts +1 -1
- package/dist/graph/diagnostics.js +10 -6
- package/dist/graph/evidence-description.d.ts +3 -0
- package/dist/graph/evidence-description.js +13 -0
- package/dist/graph/identity-preflight.js +1 -1
- package/dist/graph/neighborhood-renderer.d.ts +2 -0
- package/dist/graph/neighborhood-renderer.js +38 -0
- package/dist/graph/neighborhood-request.d.ts +9 -0
- package/dist/graph/neighborhood-request.js +37 -0
- package/dist/graph/neighborhood.d.ts +8 -0
- package/dist/graph/neighborhood.js +100 -0
- package/dist/graph/obligation-rdf.d.ts +5 -0
- package/dist/graph/obligation-rdf.js +67 -0
- package/dist/graph/obligation-shapes.d.ts +2 -0
- package/dist/graph/obligation-shapes.js +32 -0
- package/dist/graph/partitioned-shacl.d.ts +14 -0
- package/dist/graph/partitioned-shacl.js +66 -0
- package/dist/graph/path-request.d.ts +11 -0
- package/dist/graph/path-request.js +24 -0
- package/dist/graph/path-search.d.ts +45 -0
- package/dist/graph/path-search.js +101 -0
- package/dist/graph/paths-renderer.d.ts +2 -0
- package/dist/graph/paths-renderer.js +36 -0
- package/dist/graph/paths.d.ts +7 -0
- package/dist/graph/paths.js +74 -0
- package/dist/graph/query.js +23 -6
- package/dist/graph/rdf-partitions.d.ts +24 -0
- package/dist/graph/rdf-partitions.js +170 -0
- package/dist/graph/rdf-projection.d.ts +7 -0
- package/dist/graph/rdf-projection.js +27 -0
- package/dist/graph/rdf-records.d.ts +12 -0
- package/dist/graph/rdf-records.js +90 -0
- package/dist/graph/rdf.d.ts +10 -10
- package/dist/graph/rdf.js +84 -89
- package/dist/graph/shacl-shapes.js +70 -0
- package/dist/graph/snapshot-context.d.ts +3 -0
- package/dist/graph/snapshot-context.js +8 -0
- package/dist/graph/validation-progress.d.ts +4 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.js +22 -0
- package/dist/infrastructure/json-digest.d.ts +3 -0
- package/dist/infrastructure/json-digest.js +3 -0
- package/dist/infrastructure/unique-json.d.ts +2 -0
- package/dist/infrastructure/unique-json.js +20 -0
- package/dist/interfaces/cli.js +33 -1
- package/dist/interfaces/code-coverage.d.ts +46 -0
- package/dist/interfaces/code-coverage.js +18 -0
- package/dist/interfaces/graph-compatibility.d.ts +35 -0
- package/dist/interfaces/graph-compatibility.js +21 -0
- package/dist/interfaces/graph-exploration.d.ts +59 -0
- package/dist/interfaces/graph-exploration.js +27 -0
- package/dist/interfaces/graph-paths.d.ts +77 -0
- package/dist/interfaces/graph-paths.js +31 -0
- package/dist/interfaces/graph-query-args.d.ts +2 -0
- package/dist/interfaces/graph-query-args.js +25 -0
- package/dist/interfaces/mapping-proposals.d.ts +204 -0
- package/dist/interfaces/mapping-proposals.js +74 -0
- package/dist/interfaces/mcp.js +31 -3
- package/dist/storage/mapping-proposals.d.ts +9 -0
- package/dist/storage/mapping-proposals.js +42 -0
- package/dist/storage/storage.d.ts +3 -0
- package/dist/storage/storage.js +37 -13
- package/dist/storage/streaming-json.d.ts +5 -0
- package/dist/storage/streaming-json.js +45 -0
- package/dist/visualization/evidence-sources.d.ts +6 -0
- package/dist/visualization/evidence-sources.js +19 -0
- package/dist/visualization/viewer-interaction.d.ts +5 -8
- package/dist/visualization/viewer-interaction.js +46 -44
- package/dist/visualization/visualization.js +14 -5
- package/docs/1.0-WORK-QUEUE.md +48 -0
- package/docs/ADR-029-exact-graph-neighborhoods.md +70 -0
- package/docs/ADR-030-bounded-evidence-paths.md +97 -0
- package/docs/ADR-031-code-extractor-selection.md +91 -0
- package/docs/ADR-032-scip-code-evidence.md +73 -0
- package/docs/ADR-033-document-symbol-bindings.md +83 -0
- package/docs/ADR-034-mapping-gaps.md +80 -0
- package/docs/ADR-035-static-call-evidence.md +78 -0
- package/docs/ADR-036-contract-obligation-declarations.md +124 -0
- package/docs/ADR-037-selected-contract-compatibility.md +93 -0
- package/docs/ADR-038-monorepo-code-coverage.md +105 -0
- package/docs/ADR-039-mapping-proposals.md +119 -0
- package/docs/ADR-040-bounded-graph-io.md +90 -0
- package/docs/GRAPHIFY-EVALUATION.md +21 -4
- package/docs/PRE-1.0-BASELINE.md +49 -2
- package/docs/RELEASE-1.0-PLAN.md +14 -2
- package/docs/RELEASING.md +3 -3
- package/docs/ROADMAP.md +27 -6
- package/docs/VALIDATION.md +521 -14
- package/docs/benchmarks/large-graph-2026-11-02/result.json +156 -0
- package/docs/extraction-manifest.json +266 -23
- package/package.json +10 -4
- package/templates/context-graph-development/SKILL.md +30 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { DataFactory, Store } from 'n3';
|
|
2
|
+
import { contextPackEvidenceAuthority } from './authority.js';
|
|
3
|
+
import { stableJson } from '../infrastructure/util.js';
|
|
4
|
+
import { CG, RDF, XSD } from './shacl-shapes.js';
|
|
5
|
+
import { addBindingEvidence } from './binding-rdf.js';
|
|
6
|
+
import { addCallEvidence } from './call-rdf.js';
|
|
7
|
+
import { addObligationEvidence } from './obligation-rdf.js';
|
|
8
|
+
import { addCodeEvidence, addCodeNodeEvidence } from './code-rdf.js';
|
|
9
|
+
const { namedNode: iri, literal } = DataFactory;
|
|
10
|
+
export const nodeIri = (id) => `urn:context-graph:node:${encodeURIComponent(id)}`;
|
|
11
|
+
export const factIri = (id) => `urn:context-graph:fact:${encodeURIComponent(id)}`;
|
|
12
|
+
export function addFactRecord(dataset, fact, ordinal) {
|
|
13
|
+
const record = iri(factIri(fact.id));
|
|
14
|
+
const subject = iri(nodeIri(fact.subject.id));
|
|
15
|
+
const object = iri(nodeIri(fact.object.id));
|
|
16
|
+
const predicate = iri(CG + fact.predicate);
|
|
17
|
+
dataset.addQuad(record, iri(RDF + 'type'), iri(RDF + 'Statement'));
|
|
18
|
+
dataset.addQuad(record, iri(CG + 'ordinal'), literal(String(ordinal), iri(XSD + 'integer')));
|
|
19
|
+
for (const [p, value] of [['subject', subject], ['predicate', predicate], ['object', object]]) {
|
|
20
|
+
dataset.addQuad(record, iri(RDF + p), value);
|
|
21
|
+
}
|
|
22
|
+
for (const [p, value] of Object.entries({
|
|
23
|
+
authority: contextPackEvidenceAuthority(fact), path: fact.provenance.path,
|
|
24
|
+
commit: fact.provenance.commitSha, sourceDigest: fact.provenance.digest,
|
|
25
|
+
extractor: `${fact.extractor.id}@${fact.extractor.version}`,
|
|
26
|
+
snapshotId: fact.snapshotId, record: stableJson(fact),
|
|
27
|
+
...(fact.sourceAuthority ? { sourceAuthority: fact.sourceAuthority } : {}),
|
|
28
|
+
...(fact.extractionReview ? { extractionReview: fact.extractionReview } : {}),
|
|
29
|
+
...(fact.sourceRole !== undefined ? { sourceRole: fact.sourceRole } : {}),
|
|
30
|
+
...(fact.sourcePolicyDigest !== undefined ? { sourcePolicyDigest: fact.sourcePolicyDigest } : {}),
|
|
31
|
+
}))
|
|
32
|
+
dataset.addQuad(record, iri(CG + p), literal(value));
|
|
33
|
+
if (fact.sourceOwnership !== undefined) {
|
|
34
|
+
dataset.addQuad(record, iri(CG + 'ownershipStatus'), literal(fact.sourceOwnership.status));
|
|
35
|
+
for (const ownerDocument of fact.sourceOwnership.ownerDocuments) {
|
|
36
|
+
dataset.addQuad(record, iri(CG + 'ownerDocument'), literal(ownerDocument));
|
|
37
|
+
}
|
|
38
|
+
for (const mappingId of fact.sourceOwnership.mappingIds) {
|
|
39
|
+
dataset.addQuad(record, iri(CG + 'ownershipMapping'), literal(mappingId));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const [p, value] of [['startLine', fact.provenance.startLine], ['endLine', fact.provenance.endLine]]) {
|
|
43
|
+
dataset.addQuad(record, iri(CG + p), literal(String(value), iri(XSD + 'integer')));
|
|
44
|
+
}
|
|
45
|
+
dataset.addQuad(record, iri(CG + 'confidence'), literal(String(fact.confidence), iri(XSD + 'decimal')));
|
|
46
|
+
addCodeEvidence(dataset, record, fact, nodeIri, false);
|
|
47
|
+
addBindingEvidence(dataset, record, fact, factIri);
|
|
48
|
+
addCallEvidence(dataset, record, fact, factIri);
|
|
49
|
+
addObligationEvidence(dataset, record, fact);
|
|
50
|
+
}
|
|
51
|
+
export function addNodeRdf(dataset, node) {
|
|
52
|
+
const term = iri(nodeIri(node.id));
|
|
53
|
+
dataset.addQuad(term, iri(RDF + 'type'), iri(CG + 'Node'));
|
|
54
|
+
dataset.addQuad(term, iri(CG + 'identifier'), literal(node.id));
|
|
55
|
+
dataset.addQuad(term, iri(CG + 'kind'), literal(node.kind));
|
|
56
|
+
dataset.addQuad(term, iri(CG + 'label'), literal(node.label));
|
|
57
|
+
addCodeNodeEvidence(dataset, node, nodeIri);
|
|
58
|
+
}
|
|
59
|
+
export function addAttributes(dataset, node, graph = DataFactory.defaultGraph()) {
|
|
60
|
+
for (const [key, value] of Object.entries(node.attributes ?? {})) {
|
|
61
|
+
const datatype = typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'decimal' : 'string';
|
|
62
|
+
dataset.addQuad(iri(nodeIri(node.id)), iri(`${CG}attribute/${encodeURIComponent(key)}`), literal(String(value), iri(XSD + datatype)), graph);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function addFactEdges(dataset, fact) {
|
|
66
|
+
const record = iri(factIri(fact.id));
|
|
67
|
+
dataset.addQuad(iri(nodeIri(fact.subject.id)), iri(CG + fact.predicate), iri(nodeIri(fact.object.id)), record);
|
|
68
|
+
for (const node of [fact.subject, fact.object])
|
|
69
|
+
addAttributes(dataset, node, record);
|
|
70
|
+
}
|
|
71
|
+
export function addManifest(dataset, snapshot) {
|
|
72
|
+
dataset.addQuad(iri('urn:context-graph:snapshot'), iri(CG + 'manifest'), literal(stableJson(snapshot.manifest)));
|
|
73
|
+
for (const scope of snapshot.manifest.scope ?? []) {
|
|
74
|
+
dataset.addQuad(iri('urn:context-graph:snapshot'), iri(CG + 'scope'), literal(scope));
|
|
75
|
+
}
|
|
76
|
+
if (snapshot.manifest.configurationDigest) {
|
|
77
|
+
dataset.addQuad(iri('urn:context-graph:snapshot'), iri(CG + 'configurationDigest'), literal(snapshot.manifest.configurationDigest));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function evidenceDataset(snapshot) {
|
|
81
|
+
const dataset = new Store();
|
|
82
|
+
for (const [ordinal, fact] of snapshot.facts.entries()) {
|
|
83
|
+
addFactRecord(dataset, fact, ordinal);
|
|
84
|
+
addFactEdges(dataset, fact);
|
|
85
|
+
for (const node of [fact.subject, fact.object])
|
|
86
|
+
addNodeRdf(dataset, node);
|
|
87
|
+
}
|
|
88
|
+
addManifest(dataset, snapshot);
|
|
89
|
+
return dataset;
|
|
90
|
+
}
|
package/dist/graph/rdf.d.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
1
2
|
import type { GraphFact, GraphSnapshot } from "@weftlet/core";
|
|
2
3
|
import { type GraphValidationProgress } from './validation-progress.js';
|
|
3
4
|
export { CG } from './shacl-shapes.js';
|
|
4
|
-
export
|
|
5
|
-
export declare const factIri: (id: string) => string;
|
|
5
|
+
export { factIri, nodeIri } from './rdf-records.js';
|
|
6
6
|
/** Lossless RDF dataset: one named graph per cited assertion, with provenance in the default graph. */
|
|
7
7
|
export declare class RdfEvidenceGraph {
|
|
8
8
|
readonly snapshot: GraphSnapshot;
|
|
9
|
-
private
|
|
9
|
+
private indexed?;
|
|
10
10
|
constructor(snapshot: GraphSnapshot);
|
|
11
11
|
validate(options?: {
|
|
12
12
|
readonly onProgress?: (event: GraphValidationProgress) => void;
|
|
13
13
|
}): Promise<{
|
|
14
14
|
conforms: boolean;
|
|
15
|
-
issues:
|
|
16
|
-
category: "extraction-gap";
|
|
17
|
-
focus: string;
|
|
18
|
-
path: string;
|
|
19
|
-
message: string;
|
|
20
|
-
}[];
|
|
15
|
+
issues: import("./partitioned-shacl.js").ShaclIssue[];
|
|
21
16
|
}>;
|
|
22
17
|
select(sparql: string, maxRows?: number): Promise<{
|
|
23
18
|
rows: Record<string, string>[];
|
|
24
19
|
truncated: boolean;
|
|
25
20
|
}>;
|
|
26
|
-
/**
|
|
21
|
+
/** Lossless optimized projection, checked for equivalence with the public SPARQL path. */
|
|
27
22
|
facts(): Promise<readonly GraphFact[]>;
|
|
23
|
+
/** Complete N-Quads in bounded groups; RDF triple order is not a snapshot identity. */
|
|
24
|
+
serializeChunks(): IterableIterator<string>;
|
|
25
|
+
/** Export large datasets with backpressure, without a whole-dataset string/quad array. */
|
|
26
|
+
serializeTo(destination: Writable): Promise<void>;
|
|
27
|
+
/** Compatibility convenience for small exports; use serializeTo for large graphs. */
|
|
28
28
|
serialize(): Promise<string>;
|
|
29
29
|
}
|
package/dist/graph/rdf.js
CHANGED
|
@@ -1,98 +1,67 @@
|
|
|
1
1
|
import { QueryEngine } from '@comunica/query-sparql';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { constants } from 'node:buffer';
|
|
3
|
+
import { pipeline } from 'node:stream/promises';
|
|
4
|
+
import { Readable } from 'node:stream';
|
|
5
|
+
import { Writer } from 'n3';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
|
-
import { CG
|
|
7
|
+
import { CG } from './shacl-shapes.js';
|
|
8
8
|
import { measureValidationPhase } from './validation-progress.js';
|
|
9
|
-
|
|
9
|
+
import { bindingEvidenceIssues } from './binding-rdf.js';
|
|
10
|
+
import { callEvidenceIssues } from './call-rdf.js';
|
|
11
|
+
import { obligationEvidenceIssues } from './obligation-rdf.js';
|
|
12
|
+
import { codeEvidenceIssues, invalidCodeRange } from './code-rdf.js';
|
|
10
13
|
export { CG } from './shacl-shapes.js';
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
import { factIri } from './rdf-records.js';
|
|
15
|
+
import { RdfPartitions } from './rdf-partitions.js';
|
|
16
|
+
import { validatePartitions } from './partitioned-shacl.js';
|
|
17
|
+
import { projectRdfFacts } from './rdf-projection.js';
|
|
18
|
+
export { factIri, nodeIri } from './rdf-records.js';
|
|
13
19
|
const engine = new QueryEngine();
|
|
14
20
|
const SparqlParser = createRequire(import.meta.url)('sparqljs').Parser;
|
|
15
21
|
/** Lossless RDF dataset: one named graph per cited assertion, with provenance in the default graph. */
|
|
16
22
|
export class RdfEvidenceGraph {
|
|
17
23
|
snapshot;
|
|
18
|
-
|
|
24
|
+
indexed;
|
|
19
25
|
constructor(snapshot) {
|
|
20
26
|
this.snapshot = snapshot;
|
|
21
|
-
for (const [ordinal, fact] of snapshot.facts.entries()) {
|
|
22
|
-
const record = iri(factIri(fact.id));
|
|
23
|
-
const subject = iri(nodeIri(fact.subject.id));
|
|
24
|
-
const object = iri(nodeIri(fact.object.id));
|
|
25
|
-
const predicate = iri(CG + fact.predicate);
|
|
26
|
-
this.dataset.addQuad(subject, predicate, object, record);
|
|
27
|
-
this.dataset.addQuad(record, iri(RDF + 'type'), iri(RDF + 'Statement'));
|
|
28
|
-
this.dataset.addQuad(record, iri(CG + 'ordinal'), literal(String(ordinal), iri(XSD + 'integer')));
|
|
29
|
-
for (const [p, value] of [['subject', subject], ['predicate', predicate], ['object', object]]) {
|
|
30
|
-
this.dataset.addQuad(record, iri(RDF + p), value);
|
|
31
|
-
}
|
|
32
|
-
for (const [p, value] of Object.entries({
|
|
33
|
-
authority: contextPackEvidenceAuthority(fact), path: fact.provenance.path,
|
|
34
|
-
commit: fact.provenance.commitSha, sourceDigest: fact.provenance.digest,
|
|
35
|
-
extractor: `${fact.extractor.id}@${fact.extractor.version}`,
|
|
36
|
-
snapshotId: fact.snapshotId, record: stableJson(fact),
|
|
37
|
-
...(fact.sourceAuthority ? { sourceAuthority: fact.sourceAuthority } : {}),
|
|
38
|
-
...(fact.extractionReview ? { extractionReview: fact.extractionReview } : {}),
|
|
39
|
-
...(fact.sourceRole !== undefined ? { sourceRole: fact.sourceRole } : {}),
|
|
40
|
-
...(fact.sourcePolicyDigest !== undefined ? { sourcePolicyDigest: fact.sourcePolicyDigest } : {}),
|
|
41
|
-
}))
|
|
42
|
-
this.dataset.addQuad(record, iri(CG + p), literal(value));
|
|
43
|
-
if (fact.sourceOwnership !== undefined) {
|
|
44
|
-
this.dataset.addQuad(record, iri(CG + 'ownershipStatus'), literal(fact.sourceOwnership.status));
|
|
45
|
-
for (const ownerDocument of fact.sourceOwnership.ownerDocuments) {
|
|
46
|
-
this.dataset.addQuad(record, iri(CG + 'ownerDocument'), literal(ownerDocument));
|
|
47
|
-
}
|
|
48
|
-
for (const mappingId of fact.sourceOwnership.mappingIds) {
|
|
49
|
-
this.dataset.addQuad(record, iri(CG + 'ownershipMapping'), literal(mappingId));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
for (const [p, value] of [['startLine', fact.provenance.startLine], ['endLine', fact.provenance.endLine]]) {
|
|
53
|
-
this.dataset.addQuad(record, iri(CG + p), literal(String(value), iri(XSD + 'integer')));
|
|
54
|
-
}
|
|
55
|
-
this.dataset.addQuad(record, iri(CG + 'confidence'), literal(String(fact.confidence), iri(XSD + 'decimal')));
|
|
56
|
-
for (const node of [fact.subject, fact.object]) {
|
|
57
|
-
const term = iri(nodeIri(node.id));
|
|
58
|
-
this.dataset.addQuad(term, iri(RDF + 'type'), iri(CG + 'Node'));
|
|
59
|
-
this.dataset.addQuad(term, iri(CG + 'identifier'), literal(node.id));
|
|
60
|
-
this.dataset.addQuad(term, iri(CG + 'kind'), literal(node.kind));
|
|
61
|
-
this.dataset.addQuad(term, iri(CG + 'label'), literal(node.label));
|
|
62
|
-
for (const [key, value] of Object.entries(node.attributes ?? {})) {
|
|
63
|
-
const datatype = typeof value === 'boolean' ? 'boolean' : typeof value === 'number' ? 'decimal' : 'string';
|
|
64
|
-
this.dataset.addQuad(term, iri(`${CG}attribute/${encodeURIComponent(key)}`), literal(String(value), iri(XSD + datatype)), record);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
this.dataset.addQuad(iri('urn:context-graph:snapshot'), iri(CG + 'manifest'), literal(stableJson(snapshot.manifest)));
|
|
69
|
-
for (const scope of snapshot.manifest.scope ?? []) {
|
|
70
|
-
this.dataset.addQuad(iri('urn:context-graph:snapshot'), iri(CG + 'scope'), literal(scope));
|
|
71
|
-
}
|
|
72
|
-
if (snapshot.manifest.configurationDigest) {
|
|
73
|
-
this.dataset.addQuad(iri('urn:context-graph:snapshot'), iri(CG + 'configurationDigest'), literal(snapshot.manifest.configurationDigest));
|
|
74
|
-
}
|
|
75
27
|
}
|
|
76
28
|
async validate(options = {}) {
|
|
77
|
-
// These graph-independent shapes already read the dataset as a union. Index
|
|
78
|
-
// that union once so every property lookup avoids scanning one graph per fact.
|
|
79
|
-
// Keep every triple; the original named dataset retains assertion provenance
|
|
80
|
-
// and remains the source for queries and serialization.
|
|
81
29
|
const counts = { factCount: this.snapshot.facts.length };
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
30
|
+
const { partitions, types } = await measureValidationPhase('build-validation-union', counts, options.onProgress, () => {
|
|
31
|
+
const started = performance.now();
|
|
32
|
+
const partitions = new RdfPartitions(this.snapshot);
|
|
33
|
+
return { partitions, types: partitions.types(completed => {
|
|
34
|
+
if (completed % 10 === 0)
|
|
35
|
+
options.onProgress?.({ phase: 'build-validation-union', status: 'progress',
|
|
36
|
+
elapsedMs: Math.round(performance.now() - started), ...counts, completed, total: partitions.count });
|
|
37
|
+
}) };
|
|
87
38
|
});
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
message: result.message.map((message) => message.value).join('; '),
|
|
39
|
+
const started = performance.now();
|
|
40
|
+
const report = await measureValidationPhase('validate-shacl', counts, options.onProgress, () => validatePartitions(partitions, types, completed => {
|
|
41
|
+
if (completed % 10 === 0)
|
|
42
|
+
options.onProgress?.({ phase: 'validate-shacl', status: 'progress',
|
|
43
|
+
elapsedMs: Math.round(performance.now() - started), ...counts, completed, total: partitions.count });
|
|
94
44
|
}));
|
|
45
|
+
const issues = report.issues;
|
|
46
|
+
const byId = new Map(this.snapshot.facts.map(fact => [fact.id, fact]));
|
|
95
47
|
for (const fact of this.snapshot.facts) {
|
|
48
|
+
for (const message of obligationEvidenceIssues(fact, this.snapshot.manifest.repositoryId))
|
|
49
|
+
issues.push({ category: 'extraction-gap',
|
|
50
|
+
focus: factIri(fact.id), path: CG + 'obligationRole', message });
|
|
51
|
+
for (const message of callEvidenceIssues(fact, byId))
|
|
52
|
+
issues.push({ category: 'extraction-gap',
|
|
53
|
+
focus: factIri(fact.id), path: CG + 'callTarget', message });
|
|
54
|
+
for (const message of bindingEvidenceIssues(fact, byId))
|
|
55
|
+
issues.push({ category: 'extraction-gap',
|
|
56
|
+
focus: factIri(fact.id), path: CG + 'bindingDefinition', message });
|
|
57
|
+
for (const message of codeEvidenceIssues(fact))
|
|
58
|
+
issues.push({ category: 'extraction-gap',
|
|
59
|
+
focus: factIri(fact.id), path: CG + 'codeRole', message });
|
|
60
|
+
if (invalidCodeRange(fact.provenance) ||
|
|
61
|
+
(fact.codeOccurrence?.declarationRange && invalidCodeRange(fact.codeOccurrence.declarationRange))) {
|
|
62
|
+
issues.push({ category: 'extraction-gap', focus: factIri(fact.id), path: CG + 'startColumn',
|
|
63
|
+
message: 'Invalid UTF-16 source range' });
|
|
64
|
+
}
|
|
96
65
|
if (fact.provenance.endLine < fact.provenance.startLine) {
|
|
97
66
|
issues.push({ category: 'extraction-gap', focus: factIri(fact.id), path: CG + 'endLine',
|
|
98
67
|
message: 'Citation ends before it starts' });
|
|
@@ -114,7 +83,12 @@ export class RdfEvidenceGraph {
|
|
|
114
83
|
if (ast.type !== 'query' || ast.queryType !== 'SELECT' || ast.from || hasService(ast)) {
|
|
115
84
|
throw new Error('Only local read queries are supported; remote datasets and updates are disabled');
|
|
116
85
|
}
|
|
117
|
-
const
|
|
86
|
+
const indexed = this.indexed ??= new RdfPartitions(this.snapshot);
|
|
87
|
+
const source = {
|
|
88
|
+
match: (s, p, o, g) => Readable.from(indexed.match(s, p, o, g)),
|
|
89
|
+
countQuads: (s, p, o, g) => indexed.countMatches(s, p, o, g),
|
|
90
|
+
};
|
|
91
|
+
const stream = await engine.queryBindings(sparql, { sources: [{ type: 'rdfjs', value: source }], unionDefaultGraph: true });
|
|
118
92
|
const rows = [];
|
|
119
93
|
let truncated = false;
|
|
120
94
|
for await (const binding of stream) {
|
|
@@ -127,18 +101,39 @@ export class RdfEvidenceGraph {
|
|
|
127
101
|
}
|
|
128
102
|
return { rows, truncated };
|
|
129
103
|
}
|
|
130
|
-
/**
|
|
104
|
+
/** Lossless optimized projection, checked for equivalence with the public SPARQL path. */
|
|
131
105
|
async facts() {
|
|
132
|
-
|
|
133
|
-
?fact <${CG}record> ?record; <${CG}ordinal> ?ordinal
|
|
134
|
-
} ORDER BY ?ordinal`, 100_000);
|
|
135
|
-
if (result.truncated)
|
|
136
|
-
throw new Error('Graph exceeds the 100000-fact projection bound');
|
|
137
|
-
return result.rows.map((row) => JSON.parse(row.record));
|
|
106
|
+
return projectRdfFacts(this.snapshot.facts);
|
|
138
107
|
}
|
|
139
|
-
|
|
108
|
+
/** Complete N-Quads in bounded groups; RDF triple order is not a snapshot identity. */
|
|
109
|
+
*serializeChunks() {
|
|
140
110
|
const writer = new Writer({ format: 'N-Quads' });
|
|
141
|
-
|
|
142
|
-
|
|
111
|
+
let buffer = '';
|
|
112
|
+
for (const batch of new RdfPartitions(this.snapshot).named())
|
|
113
|
+
for (const quad of batch) {
|
|
114
|
+
buffer += writer.quadToString(quad.subject, quad.predicate, quad.object, quad.graph);
|
|
115
|
+
if (buffer.length >= 64 * 1024) {
|
|
116
|
+
yield buffer;
|
|
117
|
+
buffer = '';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (buffer)
|
|
121
|
+
yield buffer;
|
|
122
|
+
}
|
|
123
|
+
/** Export large datasets with backpressure, without a whole-dataset string/quad array. */
|
|
124
|
+
async serializeTo(destination) {
|
|
125
|
+
await pipeline(this.serializeChunks(), destination);
|
|
126
|
+
}
|
|
127
|
+
/** Compatibility convenience for small exports; use serializeTo for large graphs. */
|
|
128
|
+
async serialize() {
|
|
129
|
+
const chunks = [];
|
|
130
|
+
let length = 0;
|
|
131
|
+
for (const chunk of this.serializeChunks()) {
|
|
132
|
+
length += chunk.length;
|
|
133
|
+
if (length > constants.MAX_STRING_LENGTH)
|
|
134
|
+
throw new Error('RDF exceeds the JavaScript string limit; use serializeTo() or serializeChunks()');
|
|
135
|
+
chunks.push(chunk);
|
|
136
|
+
}
|
|
137
|
+
return chunks.join('');
|
|
143
138
|
}
|
|
144
139
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Parser } from 'n3';
|
|
2
|
+
import { callShapes } from './call-shapes.js';
|
|
3
|
+
import { obligationShapes } from './obligation-shapes.js';
|
|
2
4
|
export const CG = 'https://context-graph.dev/record#';
|
|
3
5
|
export const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
4
6
|
export const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
@@ -8,6 +10,8 @@ export const evidenceShapes = new Parser().parse(`
|
|
|
8
10
|
@prefix rdf: <${RDF}>.
|
|
9
11
|
@prefix sh: <http://www.w3.org/ns/shacl#>.
|
|
10
12
|
@prefix xsd: <${XSD}>.
|
|
13
|
+
${callShapes}
|
|
14
|
+
${obligationShapes}
|
|
11
15
|
cg:FactShape a sh:NodeShape; sh:targetClass rdf:Statement;
|
|
12
16
|
sh:property [ sh:path cg:record; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string ];
|
|
13
17
|
sh:property [ sh:path rdf:subject; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
@@ -25,6 +29,72 @@ cg:FactShape a sh:NodeShape; sh:targetClass rdf:Statement;
|
|
|
25
29
|
cg:NodeShape a sh:NodeShape; sh:targetClass cg:Node;
|
|
26
30
|
sh:property [ sh:path cg:kind; sh:minCount 1; sh:maxCount 1 ].
|
|
27
31
|
|
|
32
|
+
cg:ColumnsShape a sh:NodeShape;
|
|
33
|
+
sh:targetSubjectsOf cg:startColumn, cg:endColumn, cg:columnEncoding;
|
|
34
|
+
sh:property [ sh:path cg:startColumn; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
35
|
+
sh:property [ sh:path cg:endColumn; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
36
|
+
sh:property [ sh:path cg:columnEncoding; sh:minCount 1; sh:maxCount 1; sh:in ("utf-16") ].
|
|
37
|
+
cg:CodeRangeShape a sh:NodeShape; sh:targetClass cg:CodeRange;
|
|
38
|
+
sh:property [ sh:path cg:startLine; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
39
|
+
sh:property [ sh:path cg:endLine; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
40
|
+
sh:property [ sh:path cg:columnEncoding; sh:minCount 1; sh:hasValue "utf-16" ].
|
|
41
|
+
cg:CodeOccurrenceShape a sh:NodeShape; sh:targetClass cg:CodeOccurrence; sh:targetSubjectsOf cg:codeRole;
|
|
42
|
+
sh:property [ sh:path cg:codeVersion; sh:minCount 1; sh:maxCount 1; sh:hasValue 1 ];
|
|
43
|
+
sh:property [ sh:path cg:codeRole; sh:minCount 1; sh:maxCount 1; sh:in ("definition" "reference") ];
|
|
44
|
+
sh:property [ sh:path cg:codeLocationKind; sh:minCount 1; sh:maxCount 1; sh:in ("name" "zero-width-anchor") ];
|
|
45
|
+
sh:property [ sh:path cg:codeNativeRoles; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 0 ];
|
|
46
|
+
sh:property [ sh:path cg:columnEncoding; sh:minCount 1; sh:hasValue "utf-16" ];
|
|
47
|
+
sh:property [ sh:path cg:codeEnclosure; sh:minCount 1; sh:maxCount 1; sh:in ("native-range" "file" "ambiguous") ];
|
|
48
|
+
sh:property [ sh:path cg:enclosingSymbol; sh:maxCount 1; sh:class cg:CodeSymbol ];
|
|
49
|
+
sh:property [ sh:path cg:declarationRange; sh:maxCount 1; sh:class cg:CodeRange ];
|
|
50
|
+
sh:or (
|
|
51
|
+
[ sh:property [ sh:path cg:codeEnclosure; sh:hasValue "native-range" ]; sh:property [ sh:path cg:enclosingSymbol; sh:minCount 1 ] ]
|
|
52
|
+
[ sh:property [ sh:path cg:codeEnclosure; sh:in ("file" "ambiguous") ]; sh:property [ sh:path cg:enclosingSymbol; sh:maxCount 0 ] ]
|
|
53
|
+
);
|
|
54
|
+
sh:or (
|
|
55
|
+
[ sh:property [ sh:path cg:codeRole; sh:hasValue "definition" ]; sh:property [ sh:path rdf:subject; sh:class cg:CodeSymbol ]; sh:property [ sh:path rdf:predicate; sh:hasValue cg:definedBy ] ]
|
|
56
|
+
[ sh:property [ sh:path cg:codeRole; sh:hasValue "reference" ]; sh:property [ sh:path rdf:object; sh:class cg:CodeSymbol ]; sh:property [ sh:path rdf:predicate; sh:hasValue cg:references ] ]
|
|
57
|
+
).
|
|
58
|
+
cg:CodeSymbolShape a sh:NodeShape; sh:targetClass cg:CodeSymbol;
|
|
59
|
+
sh:property [ sh:path cg:kind; sh:hasValue "CodeSymbol" ];
|
|
60
|
+
sh:property [ sh:path cg:codeVersion; sh:minCount 1; sh:maxCount 1; sh:hasValue 1 ];
|
|
61
|
+
sh:property [ sh:path cg:codeProvider; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
62
|
+
sh:property [ sh:path cg:codeRepository; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
63
|
+
sh:property [ sh:path cg:nativeSymbol; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
64
|
+
sh:property [ sh:path cg:codeResolution; sh:minCount 1; sh:maxCount 1; sh:in ("indexed-definition" "declaration-only" "no-indexed-definition") ];
|
|
65
|
+
sh:property [ sh:path cg:codeIdentityScope; sh:minCount 1; sh:maxCount 1; sh:in ("repository" "index-document") ];
|
|
66
|
+
sh:or (
|
|
67
|
+
[ sh:property [ sh:path cg:codeIdentityScope; sh:hasValue "repository" ]; sh:property [ sh:path cg:codeDocument; sh:maxCount 0 ]; sh:property [ sh:path cg:codeIndex; sh:maxCount 0 ] ]
|
|
68
|
+
[ sh:property [ sh:path cg:codeIdentityScope; sh:hasValue "index-document" ];
|
|
69
|
+
sh:property [ sh:path cg:codeDocument; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
70
|
+
sh:property [ sh:path cg:codeIndex; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ] ]
|
|
71
|
+
).
|
|
72
|
+
|
|
73
|
+
cg:DocumentCodeBindingShape a sh:NodeShape; sh:targetClass cg:DocumentCodeBinding;
|
|
74
|
+
sh:property [ sh:path cg:bindingVersion; sh:minCount 1; sh:maxCount 1; sh:hasValue 1 ];
|
|
75
|
+
sh:property [ sh:path cg:bindingMethod; sh:minCount 1; sh:maxCount 1; sh:hasValue "explicit-markdown" ];
|
|
76
|
+
sh:property [ sh:path <${CG}bindingSelector/path>; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
77
|
+
sh:property [ sh:path <${CG}bindingSelector/symbol>; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
78
|
+
sh:property [ sh:path cg:bindingDocument; sh:minCount 1; sh:class cg:BindingCitation ];
|
|
79
|
+
sh:property [ sh:path cg:bindingSelection; sh:minCount 1; sh:class cg:BindingCitation ];
|
|
80
|
+
sh:property [ sh:path cg:bindingDefinition; sh:minCount 1; sh:class cg:BindingCitation ];
|
|
81
|
+
sh:property [ sh:path cg:bindingSubject; sh:class cg:BindingCitation ];
|
|
82
|
+
sh:property [ sh:path rdf:object; sh:class cg:CodeSymbol ];
|
|
83
|
+
sh:property [ sh:path rdf:predicate; sh:in (cg:references cg:implementedBy cg:verifiedBy) ];
|
|
84
|
+
sh:property [ sh:path cg:authority; sh:in ("inferred" "draft") ];
|
|
85
|
+
sh:property [ sh:path cg:extractionReview; sh:minCount 1; sh:in ("deterministic" "unreviewed") ].
|
|
86
|
+
cg:BindingCitationShape a sh:NodeShape; sh:targetClass cg:BindingCitation;
|
|
87
|
+
sh:property [ sh:path cg:path; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
88
|
+
sh:property [ sh:path cg:digest; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
89
|
+
sh:property [ sh:path cg:commitSha; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
90
|
+
sh:property [ sh:path cg:startLine; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
91
|
+
sh:property [ sh:path cg:endLine; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
92
|
+
sh:property [ sh:path cg:bindingFact; sh:maxCount 1; sh:class rdf:Statement ].
|
|
93
|
+
cg:BindingSelectorPositionShape a sh:NodeShape;
|
|
94
|
+
sh:targetSubjectsOf <${CG}bindingSelector/line>, <${CG}bindingSelector/column>;
|
|
95
|
+
sh:property [ sh:path <${CG}bindingSelector/line>; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
96
|
+
sh:property [ sh:path <${CG}bindingSelector/column>; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ].
|
|
97
|
+
|
|
28
98
|
# Optional source metadata targets only assertions that carry those predicates.
|
|
29
99
|
# Legacy facts do not acquire additional property or ownership consistency checks.
|
|
30
100
|
cg:SourceRoleShape a sh:NodeShape; sh:targetSubjectsOf cg:sourceRole;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The saved identity/scope carried by exact graph queries; never resolve a new head. */
|
|
2
|
+
export function snapshotContext(manifest) {
|
|
3
|
+
return { snapshotId: manifest.snapshotId, commitSha: manifest.commitSha, contentDigest: manifest.contentDigest,
|
|
4
|
+
configurationDigest: manifest.configurationDigest, scope: manifest.scope, baseSha: manifest.baseSha,
|
|
5
|
+
overlayDigest: manifest.overlayDigest, overlayCapture: manifest.overlayCapture,
|
|
6
|
+
extractorVersions: manifest.extractorVersions,
|
|
7
|
+
...(manifest.documentSelection ? { documentSelection: manifest.documentSelection } : {}) };
|
|
8
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export type GraphValidationPhase = 'validate-identities' | 'build-rdf-evidence' | 'build-validation-union' | 'validate-shacl';
|
|
2
2
|
export interface GraphValidationProgress {
|
|
3
3
|
readonly phase: GraphValidationPhase;
|
|
4
|
-
readonly status: 'started' | 'completed' | 'failed';
|
|
4
|
+
readonly status: 'started' | 'completed' | 'failed' | 'progress';
|
|
5
|
+
/** Completed bounded RDF subject groups, when available. */
|
|
6
|
+
readonly completed?: number;
|
|
7
|
+
readonly total?: number;
|
|
5
8
|
/** Wall time for this phase, not a completion estimate or in-phase heartbeat. */
|
|
6
9
|
readonly elapsedMs: number;
|
|
7
10
|
readonly factCount: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -20,3 +20,26 @@ export * from './extraction/document-traversal.js';
|
|
|
20
20
|
export * from './extraction/document-classification.js';
|
|
21
21
|
export * from './extraction/document-evidence.js';
|
|
22
22
|
export type { DocumentTraversalConfig } from './configuration/document-traversal.js';
|
|
23
|
+
export * from './graph/neighborhood.js';
|
|
24
|
+
export * from './graph/neighborhood-request.js';
|
|
25
|
+
export * from './graph/neighborhood-renderer.js';
|
|
26
|
+
export * from './graph/paths.js';
|
|
27
|
+
export * from './graph/path-request.js';
|
|
28
|
+
export * from './graph/paths-renderer.js';
|
|
29
|
+
export * from './extraction/document-code-bindings.js';
|
|
30
|
+
export * from './extraction/document-obligations.js';
|
|
31
|
+
export * from './graph/compatibility.js';
|
|
32
|
+
export * from './graph/compatibility-request.js';
|
|
33
|
+
export * from './graph/compatibility-renderer.js';
|
|
34
|
+
export * from './graph/code-coverage.js';
|
|
35
|
+
export * from './graph/code-coverage-projection.js';
|
|
36
|
+
export * from './graph/code-coverage-request.js';
|
|
37
|
+
export * from './graph/code-coverage-renderer.js';
|
|
38
|
+
export { MappingProposalService } from './application/mapping-proposals.js';
|
|
39
|
+
export { createMappingProposalService } from './application/mapping-service.js';
|
|
40
|
+
export type { MappingOperationOptions } from './application/mapping-proposals.js';
|
|
41
|
+
export { prepareMappingProposal } from './extraction/mapping-plan.js';
|
|
42
|
+
export { createMappingProvider, mappingProviderIdentity } from './extraction/mapping-provider.js';
|
|
43
|
+
export { parseMappingRequest } from './extraction/mapping-request.js';
|
|
44
|
+
export { validateMappingOutput } from './extraction/mapping-output.js';
|
|
45
|
+
export { FileMappingProposalStore } from './storage/mapping-proposals.js';
|
package/dist/index.js
CHANGED
|
@@ -20,3 +20,25 @@ export * from './application/document-coverage.js';
|
|
|
20
20
|
export * from './extraction/document-traversal.js';
|
|
21
21
|
export * from './extraction/document-classification.js';
|
|
22
22
|
export * from './extraction/document-evidence.js';
|
|
23
|
+
export * from './graph/neighborhood.js';
|
|
24
|
+
export * from './graph/neighborhood-request.js';
|
|
25
|
+
export * from './graph/neighborhood-renderer.js';
|
|
26
|
+
export * from './graph/paths.js';
|
|
27
|
+
export * from './graph/path-request.js';
|
|
28
|
+
export * from './graph/paths-renderer.js';
|
|
29
|
+
export * from './extraction/document-code-bindings.js';
|
|
30
|
+
export * from './extraction/document-obligations.js';
|
|
31
|
+
export * from './graph/compatibility.js';
|
|
32
|
+
export * from './graph/compatibility-request.js';
|
|
33
|
+
export * from './graph/compatibility-renderer.js';
|
|
34
|
+
export * from './graph/code-coverage.js';
|
|
35
|
+
export * from './graph/code-coverage-projection.js';
|
|
36
|
+
export * from './graph/code-coverage-request.js';
|
|
37
|
+
export * from './graph/code-coverage-renderer.js';
|
|
38
|
+
export { MappingProposalService } from './application/mapping-proposals.js';
|
|
39
|
+
export { createMappingProposalService } from './application/mapping-service.js';
|
|
40
|
+
export { prepareMappingProposal } from './extraction/mapping-plan.js';
|
|
41
|
+
export { createMappingProvider, mappingProviderIdentity } from './extraction/mapping-provider.js';
|
|
42
|
+
export { parseMappingRequest } from './extraction/mapping-request.js';
|
|
43
|
+
export { validateMappingOutput } from './extraction/mapping-output.js';
|
|
44
|
+
export { FileMappingProposalStore } from './storage/mapping-proposals.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** JSON.parse silently accepts duplicate keys, including differently escaped spellings. */
|
|
2
|
+
export function parseUniqueJson(content) {
|
|
3
|
+
const parsed = JSON.parse(content);
|
|
4
|
+
const objects = [];
|
|
5
|
+
for (const token of content.matchAll(/"(?:\\.|[^"\\])*"|[{}\[\]]/g)) {
|
|
6
|
+
const value = token[0];
|
|
7
|
+
if (value === '{' || value === '[')
|
|
8
|
+
objects.push(value === '{' ? new Set() : undefined);
|
|
9
|
+
else if (value === '}' || value === ']')
|
|
10
|
+
objects.pop();
|
|
11
|
+
else if (/^\s*:/.test(content.slice(token.index + value.length))) {
|
|
12
|
+
const keys = objects.at(-1);
|
|
13
|
+
const key = JSON.parse(value);
|
|
14
|
+
if (keys.has(key))
|
|
15
|
+
throw new Error('Duplicate JSON key');
|
|
16
|
+
keys.add(key);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return parsed;
|
|
20
|
+
}
|
package/dist/interfaces/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Modified for standalone extraction; see docs/extraction-manifest.json.
|
|
3
3
|
import "../../runtime-check.mjs";
|
|
4
|
+
import { runMappingsCommand } from './mapping-proposals.js';
|
|
4
5
|
import { resolve } from 'node:path';
|
|
5
6
|
import process from 'node:process';
|
|
6
7
|
import { createContextGraphApplication } from "../application/application.js";
|
|
@@ -20,6 +21,10 @@ import { adoptSemanticCache } from '../application/cache-adoption.js';
|
|
|
20
21
|
import { SemanticHydrationError } from '../application/hydration-failure.js';
|
|
21
22
|
import { GraphIdentityConflictError } from '../graph/identity-preflight.js';
|
|
22
23
|
import { runDocumentCoverage } from './document-coverage.js';
|
|
24
|
+
import { graphNeighborsRequestFromArgs } from './graph-exploration.js';
|
|
25
|
+
import { graphPathsRequestFromArgs } from './graph-paths.js';
|
|
26
|
+
import { graphCompatibilityRequestFromArgs } from './graph-compatibility.js';
|
|
27
|
+
import { codeCoverageRequestFromArgs } from './code-coverage.js';
|
|
23
28
|
function valueAfter(args, name) {
|
|
24
29
|
const index = args.indexOf(name);
|
|
25
30
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -98,7 +103,7 @@ function formatHydrationPlan(plan) {
|
|
|
98
103
|
async function main() {
|
|
99
104
|
const args = process.argv.slice(2);
|
|
100
105
|
if (args.includes('--help') || !args.length) {
|
|
101
|
-
process.stdout.write('weftlet documents plan|init|config show|config validate|doctor|hydrate|cache adopt|overlay|impact scan|sparql|validate|govern|visualize|diagnostics show|invariant check|clean-compare|ontology compile\nUse --config <file>; queries accept --snapshot <id>. impact scan accepts --changed-file, --capability, --max-facts, --max-depth, --continuation.\ndocuments plan --entry <document> [--entry <document>] [--root <path>] [--document-policy <json-file>] [--ref <commit>] [--json] previews prospective committed link coverage; it does not change hydration inputs or estimate model/cache work. Source classification/ownership completeness is separate from traversal readiness. The preview policy is an operation input. Set documentTraversal in configuration to activate traversal hydration; hydrate --plan describes its execution inputs. Safety limits: --max-read-documents, --max-read-bytes, --max-document-bytes.\nhydrate --plan [--json] [--ref <commit>] [--force-semantic] previews scope, cache and budgets without model calls or graph writes. Traversal coverage and role ambiguity block new model work; direct-source selection retains its existing behavior.\nhydrate --json --quiet emits structured semantic failures on stderr with no progress lines; failure stdout stays empty. hydrate --plan maps opaque source IDs to local document paths.\nhydrate|overlay --validation-details explicitly includes local node/fact identities, extractor names and source citations in identity-conflict errors; default reports use opaque references. This flag writes no diagnostic file. Use --json --quiet for structured identity-conflict stderr and empty failure stdout. Validation
|
|
106
|
+
process.stdout.write('weftlet mappings plan|mappings propose|mappings read|documents plan|init|config show|config validate|doctor|hydrate|cache adopt|overlay|impact scan|graph neighbors|graph paths|graph compatibility|graph coverage|sparql|validate|govern|visualize|diagnostics show|invariant check|clean-compare|ontology compile\nmappings plan|propose --request <json-file> [--allow-model for propose] previews or runs one opt-in proposal; mappings read --snapshot <id> --key <key> reads saved unreviewed results.\nUse --config <file>; queries accept --snapshot <id>. impact scan accepts --changed-file, --capability, --max-facts, --max-depth, --continuation.\ngraph neighbors --snapshot <id> --node <exact-id> [--direction incoming|outgoing|both] [--predicate <relation>] [--max-facts <1..200>] [--continuation <token>] [--json] reads one-hop saved evidence; repeat --predicate to select multiple relations.\ngraph paths --snapshot <id> --from <exact-id> --to <exact-id> [--direction incoming|outgoing|both] [--predicate <relation>] [--max-depth <1..32>] [--max-paths <1..20>] [--max-steps <1..10000>] [--continuation <token>] [--json] explores cited simple paths; incomplete searches report frontier and limits.\ngraph coverage --snapshot <id> [--project <exact-package-root>] [--max-items <1..200>] [--continuation <token>] [--json] pages saved package/file coverage; absence or zero references is not proof of no impact.\ngraph compatibility --snapshot <id> --producer-fact <assertion-id> --consumer-fact <assertion-id> [--json] compares two documented numeric obligations; advisory only, with explicit unknowns and no implementation or CI verdict.\ndocuments plan --entry <document> [--entry <document>] [--root <path>] [--document-policy <json-file>] [--ref <commit>] [--json] previews prospective committed link coverage; it does not change hydration inputs or estimate model/cache work. Source classification/ownership completeness is separate from traversal readiness. The preview policy is an operation input. Set documentTraversal in configuration to activate traversal hydration; hydrate --plan describes its execution inputs. Safety limits: --max-read-documents, --max-read-bytes, --max-document-bytes.\nhydrate --plan [--json] [--ref <commit>] [--force-semantic] previews scope, cache and budgets without model calls or graph writes. Traversal coverage and role ambiguity block new model work; direct-source selection retains its existing behavior.\nhydrate --json --quiet emits structured semantic failures on stderr with no progress lines; failure stdout stays empty. hydrate --plan maps opaque source IDs to local document paths.\nhydrate|overlay --validation-details explicitly includes local node/fact identities, extractor names and source citations in identity-conflict errors; default reports use opaque references. This flag writes no diagnostic file. Use --json --quiet for structured identity-conflict stderr and empty failure stdout. Validation reports phase boundaries, elapsed time and completed groups; group counts are not completion-time estimates.\ncache adopt --from-config <previous.json> [--config <current.json>] [--ref <commit>] [--dry-run] returns JSON and copies only validated compatible artifacts, without model calls or snapshot writes. --dry-run performs no cache writes. Agent configurations accept the same --owner-doc, --task and --capability selection as hydrate.\ninit [--yes] [--directory <project>] [--config <file>] [--repository-id <id>] [--code-root <path>] [--semantic-source <path>] [--evidence-root <path>] [--model <name>] [--no-gitignore]\nSource flags may be repeated. init never overwrites an existing config. See README.md for examples.\n');
|
|
102
107
|
return;
|
|
103
108
|
}
|
|
104
109
|
if (await runDocumentCoverage(args, defaultConfigPath))
|
|
@@ -164,6 +169,13 @@ async function main() {
|
|
|
164
169
|
}
|
|
165
170
|
const application = await createContextGraphApplication(configPath);
|
|
166
171
|
const [command, subcommand] = args;
|
|
172
|
+
if (command === 'mappings') {
|
|
173
|
+
const report = await runMappingsCommand(application.mappingProposalService, args.slice(1));
|
|
174
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
175
|
+
if ('ready' in report && !report.ready)
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
167
179
|
if (command === 'sparql' || command === 'validate') {
|
|
168
180
|
const id = valueAfter(args, '--snapshot');
|
|
169
181
|
const snapshot = id ? await application.snapshotStore.read(id) :
|
|
@@ -235,6 +247,26 @@ async function main() {
|
|
|
235
247
|
process.stdout.write(args.includes('--json') ? `${JSON.stringify(pack, null, 2)}\n` : `${pack.markdown}\n`);
|
|
236
248
|
return;
|
|
237
249
|
}
|
|
250
|
+
if (command === 'graph' && subcommand === 'compatibility') {
|
|
251
|
+
const result = await application.compatibilityService.assess(graphCompatibilityRequestFromArgs(args.slice(2)));
|
|
252
|
+
process.stdout.write(`${args.includes('--json') ? JSON.stringify(result, null, 2) : result.markdown}\n`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (command === 'graph' && subcommand === 'coverage') {
|
|
256
|
+
const result = await application.codeCoverageService.coverage(codeCoverageRequestFromArgs(args.slice(2)));
|
|
257
|
+
process.stdout.write(`${args.includes('--json') ? JSON.stringify(result, null, 2) : result.markdown}\n`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (command === 'graph' && subcommand === 'paths') {
|
|
261
|
+
const result = await application.pathService.paths(graphPathsRequestFromArgs(args.slice(2)));
|
|
262
|
+
process.stdout.write(`${args.includes('--json') ? JSON.stringify(result, null, 2) : result.markdown}\n`);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (command === 'graph' && subcommand === 'neighbors') {
|
|
266
|
+
const result = await application.explorationService.neighbors(graphNeighborsRequestFromArgs(args.slice(2)));
|
|
267
|
+
process.stdout.write(`${args.includes('--json') ? JSON.stringify(result, null, 2) : result.markdown}\n`);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
238
270
|
if (command === 'visualize') {
|
|
239
271
|
const outputPath = valueAfter(args, '--output');
|
|
240
272
|
if (!outputPath)
|