@weftlet/toolkit 0.6.0 → 0.7.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/README.md +168 -1
- package/THIRD_PARTY_NOTICES.md +1 -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 +20 -3
- 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 +36 -22
- 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/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.js +2 -2
- 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 +33 -104
- 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 +5 -0
- package/dist/graph/code-rdf.js +72 -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/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.js +26 -0
- 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/index.d.ts +23 -0
- package/dist/index.js +22 -0
- package/dist/infrastructure/artifact-paths.d.ts +4 -0
- package/dist/infrastructure/artifact-paths.js +14 -0
- package/dist/infrastructure/json-digest.d.ts +2 -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.js +41 -13
- 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 +38 -0
- package/docs/ADR-028-bounded-artifact-paths.md +58 -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/CONSUMER-TRIAL.md +6 -4
- package/docs/GRAPHIFY-EVALUATION.md +87 -0
- package/docs/PRE-1.0-BASELINE.md +141 -0
- package/docs/RELEASE-1.0-PLAN.md +37 -15
- package/docs/RELEASING.md +3 -3
- package/docs/ROADMAP.md +39 -11
- package/docs/VALIDATION.md +501 -0
- package/docs/assessments/pre-1.0-2026-10-28.json +200 -0
- package/docs/extraction-manifest.json +258 -23
- package/package.json +8 -4
- package/templates/context-graph-development/SKILL.md +30 -1
|
@@ -1,45 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
let truncated = false;
|
|
7
|
-
for (let cursor = 0; cursor < queue.length; cursor++) {
|
|
8
|
-
const current = queue[cursor];
|
|
9
|
-
if (current === target) {
|
|
10
|
-
const edgeIds = [];
|
|
11
|
-
let node = target;
|
|
12
|
-
while (parents.has(node)) {
|
|
13
|
-
const parent = parents.get(node);
|
|
14
|
-
edgeIds.unshift(parent.edge);
|
|
15
|
-
node = parent.node;
|
|
16
|
-
}
|
|
17
|
-
return { found: true, edgeIds, truncated };
|
|
18
|
-
}
|
|
19
|
-
for (const edge of edges.filter((item) => item.from === current)) {
|
|
20
|
-
if (visited.has(edge.to))
|
|
21
|
-
continue;
|
|
22
|
-
if (visited.size >= maxVisited) {
|
|
23
|
-
truncated = true;
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
visited.add(edge.to);
|
|
27
|
-
parents.set(edge.to, { node: current, edge: edge.id });
|
|
28
|
-
queue.push(edge.to);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return { found: false, edgeIds: [], truncated };
|
|
1
|
+
import { searchEvidencePaths } from '../graph/path-search.js';
|
|
2
|
+
/** First deterministic simple path over displayed facts; shares the agent search engine. */
|
|
3
|
+
export function findEvidencePath(edges, start, target, maxSteps = 1000) {
|
|
4
|
+
const result = searchEvidencePaths(edges, start, target, { maxDepth: 32, maxPaths: 1, maxSteps });
|
|
5
|
+
return { found: result.paths.length > 0, edgeIds: result.paths[0]?.factIds ?? [], truncated: result.search.truncated };
|
|
32
6
|
}
|
|
33
7
|
export function viewerScript() {
|
|
34
8
|
return `
|
|
35
9
|
(() => {
|
|
36
|
-
const
|
|
10
|
+
const searchPaths = ${searchEvidencePaths.toString()};
|
|
37
11
|
const model = JSON.parse(document.getElementById('visual-model').textContent);
|
|
38
12
|
const search = document.getElementById('graph-search');
|
|
39
13
|
const cluster = document.getElementById('graph-cluster');
|
|
40
14
|
const detail = document.getElementById('node-detail');
|
|
41
15
|
const target = document.getElementById('path-target');
|
|
42
16
|
const status = document.getElementById('path-status');
|
|
17
|
+
const nextPath = document.getElementById('next-path');
|
|
18
|
+
const depth = document.getElementById('path-depth');
|
|
19
|
+
const direction = document.getElementById('path-direction');
|
|
20
|
+
const predicate = document.getElementById('path-predicate');
|
|
21
|
+
let pathOffset = 0;
|
|
22
|
+
const clearPath = () => { pathOffset = 0; nextPath.disabled = true; pathIds.clear(); status.textContent = ''; };
|
|
43
23
|
const layers = [...document.querySelectorAll('[data-layer]')];
|
|
44
24
|
const edges = [...document.querySelectorAll('[data-visual-edge]')];
|
|
45
25
|
const nodes = [...document.querySelectorAll('[data-visual-node]')];
|
|
@@ -74,7 +54,7 @@ export function viewerScript() {
|
|
|
74
54
|
document.getElementById('visible-count').textContent = count + ' visible relationships from this page';
|
|
75
55
|
};
|
|
76
56
|
const select = (id) => {
|
|
77
|
-
selected = id;
|
|
57
|
+
selected = id; clearPath();
|
|
78
58
|
detail.replaceChildren();
|
|
79
59
|
const node = model.nodes.find(node => node.id === id);
|
|
80
60
|
const heading = document.createElement('strong');
|
|
@@ -88,6 +68,12 @@ export function viewerScript() {
|
|
|
88
68
|
source.textContent = edge.provenance + ' @ ' + edge.source.commitSha.slice(0,12);
|
|
89
69
|
if (edge.sourceUrl) { source.href = edge.sourceUrl; source.target = '_blank'; source.rel = 'noopener noreferrer'; }
|
|
90
70
|
item.append(document.createElement('br'), source);
|
|
71
|
+
for (const citation of edge.bindingSources || []) {
|
|
72
|
+
const link = document.createElement(citation.sourceUrl ? 'a' : 'code');
|
|
73
|
+
link.textContent = citation.provenance;
|
|
74
|
+
if (citation.sourceUrl) { link.href = citation.sourceUrl; link.target = '_blank'; link.rel = 'noopener noreferrer'; }
|
|
75
|
+
item.append(document.createElement('br'), link);
|
|
76
|
+
}
|
|
91
77
|
const focus = document.createElement('button'); focus.textContent = 'Show source relationships';
|
|
92
78
|
focus.addEventListener('click', () => { search.value = edge.source.path; update(); });
|
|
93
79
|
item.append(document.createElement('br'), focus); detail.append(item);
|
|
@@ -98,21 +84,37 @@ export function viewerScript() {
|
|
|
98
84
|
node.addEventListener('click', () => select(node.dataset.nodeId));
|
|
99
85
|
node.addEventListener('keydown', event => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); select(node.dataset.nodeId); } });
|
|
100
86
|
});
|
|
101
|
-
|
|
87
|
+
const showPath = (resume) => {
|
|
102
88
|
if (!selected) { status.textContent = 'Select a start node first.'; return; }
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
89
|
+
if (!resume) pathOffset = 0;
|
|
90
|
+
try {
|
|
91
|
+
const input = enabledEdges().filter(edge => !predicate.value || edge.label === predicate.value).flatMap(edge => {
|
|
92
|
+
const forward = { id: edge.id, from: edge.from, to: edge.to };
|
|
93
|
+
const reverse = { id: edge.id, from: edge.to, to: edge.from };
|
|
94
|
+
return direction.value === 'incoming' ? [reverse] : direction.value === 'outgoing' || edge.from === edge.to ? [forward] : [forward, reverse];
|
|
95
|
+
});
|
|
96
|
+
const result = searchPaths(input, selected, target.value, { maxDepth: Number(depth.value), maxPaths: 1, maxSteps: 1000, offset: pathOffset }, new Set(model.nodes.map(node => node.id)));
|
|
97
|
+
pathOffset = result.search.totalSteps;
|
|
98
|
+
nextPath.disabled = result.search.exhaustedWithinDepth || result.search.stopReason === 'search-limit';
|
|
99
|
+
pathIds = new Set(result.paths[0]?.factIds || []);
|
|
100
|
+
status.textContent = result.paths.length ? 'One cited path: ' + result.paths[0].factIds.length + ' relationships.' : 'No path returned on this search page.';
|
|
101
|
+
status.textContent += ' Displayed facts and selected authority/relations only; ' + result.search.stopReason + '.';
|
|
102
|
+
if (!nextPath.disabled) status.textContent += ' Continue to examine remaining branches.';
|
|
103
|
+
if (result.search.depthLimitReached) status.textContent += ' Depth limit reached; increase depth and restart.';
|
|
104
|
+
if (result.search.stopReason === 'search-limit') status.textContent += ' Narrow the selection or choose an intermediate node.';
|
|
105
|
+
status.textContent += ' Pending prefixes: ' + result.frontier.pending.length + '; depth-limited extensions: ' + result.frontier.depthLimited.count + '.';
|
|
106
|
+
search.value = ''; cluster.value = ''; document.getElementById('neighbors-only').checked = false;
|
|
107
|
+
update();
|
|
108
|
+
} catch (error) { clearPath(); status.textContent = error.message; update(); }
|
|
109
|
+
};
|
|
110
|
+
document.getElementById('highlight-path').addEventListener('click', () => showPath(false));
|
|
111
|
+
nextPath.addEventListener('click', () => showPath(true));
|
|
112
|
+
[target, depth, direction, predicate].forEach(item => item.addEventListener('change', () => { clearPath(); update(); }));
|
|
111
113
|
search.addEventListener('input', update); cluster.addEventListener('change', update);
|
|
112
114
|
document.getElementById('neighbors-only').addEventListener('change', update);
|
|
113
|
-
layers.forEach(item => item.addEventListener('change', () => {
|
|
115
|
+
layers.forEach(item => item.addEventListener('change', () => { clearPath(); update(); }));
|
|
114
116
|
document.getElementById('reset-filters').addEventListener('click', () => {
|
|
115
|
-
search.value = ''; cluster.value = ''; selected = undefined;
|
|
117
|
+
search.value = ''; cluster.value = ''; selected = undefined; clearPath();
|
|
116
118
|
document.getElementById('neighbors-only').checked = false;
|
|
117
119
|
layers.forEach(item => { item.checked = true; });
|
|
118
120
|
detail.textContent = 'Select a node to inspect its cited relationships.'; status.textContent = ''; update();
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// Modified for standalone extraction; see docs/extraction-manifest.json.
|
|
2
|
+
import { factEvidenceDescription } from '../graph/evidence-description.js';
|
|
3
|
+
import { evidenceSources } from './evidence-sources.js';
|
|
4
|
+
import { sourceLocation } from '@weftlet/core';
|
|
2
5
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
6
|
import { dirname, extname, resolve } from 'node:path';
|
|
4
7
|
import { repositoryFileNode } from '@weftlet/core';
|
|
@@ -136,11 +139,13 @@ function visualModel(pack, sourceUrlTemplate) {
|
|
|
136
139
|
to: fact.object.id,
|
|
137
140
|
label: fact.predicate,
|
|
138
141
|
authority: contextPackEvidenceAuthority(fact),
|
|
139
|
-
provenance: `${fact.provenance
|
|
140
|
-
detail: `confidence ${fact.confidence}; ${fact.extractor.id}@${fact.extractor.version}; source ${fact.sourceAuthority ?? 'see citation'}; extraction ${fact.extractionReview ?? 'unspecified'}` +
|
|
142
|
+
provenance: `${sourceLocation(fact.provenance)}`,
|
|
143
|
+
detail: (factEvidenceDescription(fact) ? `${factEvidenceDescription(fact)}; ` : '') + `confidence ${fact.confidence}; ${fact.extractor.id}@${fact.extractor.version}; source ${fact.sourceAuthority ?? 'see citation'}; extraction ${fact.extractionReview ?? 'unspecified'}` +
|
|
141
144
|
(sourceDescription ? `; ${sourceDescription}` : ''),
|
|
142
145
|
source: fact.provenance,
|
|
143
146
|
sourceUrl: sourceLink(fact.provenance, sourceUrlTemplate),
|
|
147
|
+
...(fact.codeBinding || fact.codeCall || fact.contractObligation ? { bindingSources: evidenceSources(fact).map(({ role, provenance }) => ({ provenance: `${role}: ${sourceLocation(provenance)} @ ${provenance.commitSha}`,
|
|
148
|
+
sourceUrl: sourceLink(provenance, sourceUrlTemplate) })) } : {}),
|
|
144
149
|
});
|
|
145
150
|
}
|
|
146
151
|
return {
|
|
@@ -330,7 +335,7 @@ export function renderContextPackHtml(pack, sourceUrlTemplate) {
|
|
|
330
335
|
const target = nodes.get(edge.to);
|
|
331
336
|
const sourceLabel = source?.label ?? edge.from;
|
|
332
337
|
const targetLabel = target?.label ?? edge.to;
|
|
333
|
-
return `<tr data-relationship-row data-edge-id="${escapeXml(edge.id)}" data-authority="${edge.authority}" data-search="${escapeXml(`${sourceLabel} ${edge.from} ${targetLabel} ${edge.to} ${edge.label} ${edge.provenance} ${edge.detail}`.toLowerCase())}"><td><span class="layer layer-${edge.authority}">${edge.authority}</span></td><td><strong>${escapeXml(sourceLabel)}</strong><br /><code>${escapeXml(edge.from)}</code></td><td>${escapeXml(edge.label)}</td><td><strong>${escapeXml(targetLabel)}</strong><br /><code>${escapeXml(edge.to)}</code></td><td>${edge.sourceUrl ? `<a href="${escapeXml(edge.sourceUrl)}" target="_blank" rel="noopener noreferrer">${escapeXml(edge.provenance)}</a>` : escapeXml(edge.provenance)}</td></tr>`;
|
|
338
|
+
return `<tr data-relationship-row data-edge-id="${escapeXml(edge.id)}" data-authority="${edge.authority}" data-search="${escapeXml(`${sourceLabel} ${edge.from} ${targetLabel} ${edge.to} ${edge.label} ${edge.provenance} ${edge.detail}`.toLowerCase())}"><td><span class="layer layer-${edge.authority}">${edge.authority}</span></td><td><strong>${escapeXml(sourceLabel)}</strong><br /><code>${escapeXml(edge.from)}</code></td><td>${escapeXml(edge.label)}</td><td><strong>${escapeXml(targetLabel)}</strong><br /><code>${escapeXml(edge.to)}</code></td><td>${edge.sourceUrl ? `<a href="${escapeXml(edge.sourceUrl)}" target="_blank" rel="noopener noreferrer">${escapeXml(edge.provenance)}</a>` : escapeXml(edge.provenance)}${(edge.bindingSources ?? []).map(citation => `<br />${citation.sourceUrl ? `<a href="${escapeXml(citation.sourceUrl)}" target="_blank" rel="noopener noreferrer">${escapeXml(citation.provenance)}</a>` : escapeXml(citation.provenance)}`).join('')}</td></tr>`;
|
|
334
339
|
})
|
|
335
340
|
.join('');
|
|
336
341
|
const controls = Object.keys(authorityColors)
|
|
@@ -397,8 +402,12 @@ export function renderContextPackHtml(pack, sourceUrlTemplate) {
|
|
|
397
402
|
${controls}
|
|
398
403
|
<label>Cluster <select id="graph-cluster"><option value="">All</option>${[...new Set(model.nodes.map(node => node.cluster))].sort().map(cluster => `<option value="${escapeXml(cluster)}">${escapeXml(cluster)}</option>`).join('')}</select></label>
|
|
399
404
|
<label><input type="checkbox" id="neighbors-only" /> Selected node and neighbors</label>
|
|
400
|
-
<label>Path target <select id="path-target">${model.nodes.map(node => `<option value="${escapeXml(node.id)}">${escapeXml(node.label)}</option>`).join('')}</select></label>
|
|
401
|
-
<
|
|
405
|
+
<label>Path target <select id="path-target">${model.nodes.map(node => `<option value="${escapeXml(node.id)}">${escapeXml(node.label)} · ${escapeXml(node.id)}</option>`).join('')}</select></label>
|
|
406
|
+
<label>Direction <select id="path-direction"><option value="outgoing">Outgoing</option><option value="incoming">Incoming</option><option value="both">Both</option></select></label>
|
|
407
|
+
<label>Relation <select id="path-predicate"><option value="">All</option>${[...new Set(model.edges.map(edge => edge.label))].sort().map(predicate => `<option value="${escapeXml(predicate)}">${escapeXml(predicate)}</option>`).join('')}</select></label>
|
|
408
|
+
<label>Max depth <input id="path-depth" type="number" min="1" max="32" value="8" /></label>
|
|
409
|
+
<button id="highlight-path" type="button">Highlight cited path</button>
|
|
410
|
+
<button id="next-path" type="button" disabled>Continue path search</button>
|
|
402
411
|
<span id="path-status" aria-live="polite"></span>
|
|
403
412
|
<button id="reset-filters" type="button">Reset</button>
|
|
404
413
|
<span id="visible-count" aria-live="polite"></span>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Remaining 1.0 work
|
|
2
|
+
|
|
3
|
+
This queue tracks implementation increments for [B1–B6](PRE-1.0-BASELINE.md), whose acceptance
|
|
4
|
+
boundaries remain canonical. It supersedes the earlier instruction to rerun the private consumer
|
|
5
|
+
immediately after every patch. On 2026-10-28 the maintainer reported that the filename issue was
|
|
6
|
+
believed to be TradePilot's main blocker and requested the next live test after a new candidate.
|
|
7
|
+
That report is not a recorded private hydration/repeat or product-usefulness pass.
|
|
8
|
+
|
|
9
|
+
Work in small reviewed increments. Keep a minor candidate version PR open while these changes
|
|
10
|
+
accumulate; publish the next candidate when the agreed scope is ready, then run live acceptance.
|
|
11
|
+
Do not publish official 1.0 solely because deterministic tests or graph hydration succeed.
|
|
12
|
+
|
|
13
|
+
Maintainer disposition, 2026-11-02: publish **0.7.0** for TradePilot acceptance now. The optional
|
|
14
|
+
B3b proposal feature's live validation is **tentative and deferred**, not a publication blocker
|
|
15
|
+
for this candidate. Prior consumer Codex hydration remains evidence for the established extraction
|
|
16
|
+
flow; it does not validate the new proposal operation. No further feature milestone is scheduled
|
|
17
|
+
before this candidate. B6b and the explicit official 1.0 decision remain open.
|
|
18
|
+
|
|
19
|
+
| Task | Status / dependency | Deliverable and check |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| **B1a — Exact node neighborhoods** | Implemented; next candidate pending. Validation in ADR 029 and the change PR | `graph.neighbors` through the shared public API, CLI and MCP. Exact snapshot/node IDs, direction/relation filters, cited assertion pagination, remaining-neighbor counts, further-expansion hints and shared evidence state. Check duplicate labels, cycles, self-links, parallel evidence, missing/deleted nodes, stale/tampered cursors, dirty overlays and real extracted cross-service facts. |
|
|
22
|
+
| **B1b — Bounded dependency paths** | Implemented; next candidate pending. Validation in ADR 030 and the change PR | `graph.paths` enumerates cited simple paths through API/CLI/MCP, with depth/work/output limits, continuation and explicit pending/depth-cut frontier. The offline viewer uses the same search function on displayed facts. Check competing branches, cycles, deep paths, scope omissions and all 4,096 directed four-node graphs against an independent oracle. |
|
|
23
|
+
| **B2a — Freeze code-graph comparison** | Frozen; verifier and fixture typechecks pass | 51 labeled code cases, three explicit gaps, unchanged A1–A3/dispatch controls, eight scenarios, pinned tools and bounded metrics in `evaluations/code-graph`. Read-only verification rejects input/label drift and supports immutable Git refs. No comparative execution or private/model inputs. |
|
|
24
|
+
| **B2b — Run comparison and decide** | Measured; [ADR 031](ADR-031-code-extractor-selection.md) selects richer SCIP projection | Compare current projection, richer raw SCIP and pinned Graphify static extraction. Record correctness, citations, identity stability, cold/edit/repeat cost and packaging. Make an evidence-backed keep/improve/replace decision before B3's code-entity schema. |
|
|
25
|
+
| **B3a — Explicit rule-to-symbol resolution** | Implemented in two increments ([ADR 032](ADR-032-scip-code-evidence.md), [ADR 033](ADR-033-document-symbol-bindings.md)); next candidate pending | Retain local/private symbols, same-file references and repeated source occurrences before resolving explicit document paths/symbol references. Include aliases, overloads, duplicate names, rename/delete and unresolved targets; retain both source spans/revisions and mapping authority. Follow the canonical [same-file acceptance boundary](PRE-1.0-BASELINE.md#same-file-exploration-acceptance). |
|
|
26
|
+
| **B3b — Assess missing mappings** | Deterministic assessment complete ([ADR 034](ADR-034-mapping-gaps.md)); bounded opt-in implementation complete ([ADR 039](ADR-039-mapping-proposals.md)); live validation tentative and deferred by the maintainer for 0.7.0 | Identify gaps remaining after explicit resolution. Evaluate a bounded inference proposal only if justified, with an approved model budget before paid work. Never infer owner approval or silently convert proposed mappings into proven behavior. Record any scoped deferral for maintainer review. |
|
|
27
|
+
| **B3c — Same-file call exploration** | Implemented ([ADR 035](ADR-035-static-call-evidence.md)); next candidate pending | Select and test static call analysis, preserving caller/callee/callsite and unresolved targets. Distinguish direct calls from references and callback registration; never claim observed execution. Meet the public large-file extraction/query acceptance in the canonical boundary, including recursion, unrelated functions, shadowed names, repeated sites and cross-file callers. No duplicate-behavior equivalence or mandatory second indexer. |
|
|
28
|
+
| **B4a — Producer/consumer obligations** | Implemented for explicit declarations ([ADR 036](ADR-036-contract-obligation-declarations.md)); next candidate pending | Represent and retrieve cited guarantees/requirements on queue and stored-data contracts, with domain, stage, units, freshness and version where documented. Keep absent fields unknown. |
|
|
29
|
+
| **B4b — Compatibility acceptance** | Implemented for selected explicit numeric declarations ([ADR 037](ADR-037-selected-contract-compatibility.md)); next candidate pending | Public queue/stored-data cases cover subset, insufficient guarantee, disjoint limits, revalidation and unknowns. Shared `graph.compatibility` retains two cited assertions and follow-up IDs. This is advisory; hard failures require approved deterministic policy. |
|
|
30
|
+
| **B5 — Monorepo coverage** | Implemented for saved TypeScript-family inventory and package boundaries ([ADR 038](ADR-038-monorepo-code-coverage.md)); next candidate pending | `graph.coverage` pages selected/requested/indexed files and package connections; shared overview distinguishes saved scope from returned-page counts. Real barrels, aliases, TSX, independent/omitted services, declaration-only and unresolved external targets are tested. Unknown/zero observations never prove no impact. |
|
|
31
|
+
| **B6a — Candidate qualification** | B1–B5 decisions/increments reviewed | Freeze tasks and expected downstream obligations before measuring. Run public end-to-end, fresh-install and supported Windows/Linux release gates. Publish a minor acceptance candidate with versioned evidence and limitations. |
|
|
32
|
+
| **B6b — Live consumer and 1.0 decision** | Published candidate | TradePilot runs real hydration/repeat and agent follow-up tasks; retain private requests/citations/timings locally and share a sanitized result. Assess usefulness and misses separately from pipeline success. Fix blockers, then explicitly review official 1.0. |
|
|
33
|
+
|
|
34
|
+
B1a/B1b mechanisms are implemented; candidate qualification and live product usefulness remain B6.
|
|
35
|
+
The measured decision retains SCIP and improves its projection; Graphify is not a runtime dependency. TypeScript/TSX remains the
|
|
36
|
+
tested indexing scope. Browser interaction and live provider quality remain separate evidence;
|
|
37
|
+
the website, bulk documentation generation, approval/backfill workflows and hosted AI remain
|
|
38
|
+
in the [2.0 plan](WEFTLET-2.0-PLAN.md).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# ADR 028: bounded physical artifact names
|
|
2
|
+
|
|
3
|
+
Status: implemented; release status is recorded in [validation](VALIDATION.md).
|
|
4
|
+
|
|
5
|
+
The consumer reported that long physical artifact/temp names block the traversal → unchanged
|
|
6
|
+
repeat → clean-comparison sequence on Windows. A public regression using traversal, routing and
|
|
7
|
+
an empty runtime-evidence revision reproduces `ENAMETOOLONG` in real SCIP during clean comparison
|
|
8
|
+
on Linux too. Appending `.scip.<UUID>.tmp` to the complete logical identity exceeds the common
|
|
9
|
+
255-byte filename-component limit. RDF and optional OML work directories also embedded the entire
|
|
10
|
+
identity. This is a physical storage defect, not a graph identity, business-rule or SHACL defect.
|
|
11
|
+
|
|
12
|
+
## Physical names and compatibility
|
|
13
|
+
|
|
14
|
+
Keep portable literal artifact keys of at most 128 ASCII characters. Longer/nonportable keys
|
|
15
|
+
use `~` followed by the full SHA-256 of the logical key. The `~` namespace is excluded from
|
|
16
|
+
literal logical storage identifiers, preventing a hash from aliasing a user-supplied short key.
|
|
17
|
+
Windows device names are also hashed. Existing logical identifier validation and its 256-character
|
|
18
|
+
limit remain intact; no snapshot, fact, provenance, extractor or cache identity is shortened.
|
|
19
|
+
|
|
20
|
+
Snapshot JSON, heads, semantic cache storage and SCIP output use this mapping. Generated semantic
|
|
21
|
+
cache keys are already 64-character digests and retain their names. Snapshot reads fall back to
|
|
22
|
+
the old literal filename if the bounded path is absent. Semantic reads retain explicit legacy
|
|
23
|
+
root handling. Skip legacy components that cannot exist within the filename limit (and Windows
|
|
24
|
+
device names on Windows), but propagate other I/O and corrupt-JSON errors.
|
|
25
|
+
|
|
26
|
+
Existing legacy immutable snapshots/artifacts are checked before publication and retained byte
|
|
27
|
+
for byte. A different content/output digest for the same identity remains an error. Updating a
|
|
28
|
+
long legacy head writes the new bounded head and gives it precedence without modifying history.
|
|
29
|
+
No bulk cache migration, forced extraction or automatic deletion is required. Older toolkit
|
|
30
|
+
versions cannot necessarily read newly hashed long-name entries; use supported store/CLI queries
|
|
31
|
+
with the full logical ID rather than constructing a filename from it.
|
|
32
|
+
|
|
33
|
+
Staging names are independent UUIDs in the destination directory, preserving same-filesystem
|
|
34
|
+
atomic link/rename publication. Cross-process immutable winner and head replacement semantics
|
|
35
|
+
remain unchanged. SCIP staging files are cleaned after success or failure. RDF/optional OML work
|
|
36
|
+
directories need only a backend prefix and UUID; RDF output digests do not depend on their names.
|
|
37
|
+
The optional OML generated document filenames remain their existing semantic digest keys.
|
|
38
|
+
|
|
39
|
+
This bounds toolkit-generated components; it does not promise that arbitrary storage-root lengths
|
|
40
|
+
or user source filenames work with every external program's total-path restrictions. The original
|
|
41
|
+
working checkout is not moved or cleaned. Full logical IDs remain in snapshots, head records,
|
|
42
|
+
facts and query responses, and saved evidence remains queryable without providers.
|
|
43
|
+
|
|
44
|
+
## Validation boundary
|
|
45
|
+
|
|
46
|
+
The public sequence uses the unchanged Codex adapter with its offline grammar runner, real SCIP,
|
|
47
|
+
RDF/SHACL, document traversal, configured routing and an injected empty runtime provider. First
|
|
48
|
+
hydration extracts six semantic documents; repeat and clean comparison reuse all six. The clean
|
|
49
|
+
identity retains traversal/clean/runtime suffixes and exceeds 215 characters. Content digests and
|
|
50
|
+
all facts/provenance except the containing snapshot ID agree; the original head stays unchanged.
|
|
51
|
+
Generated components are bounded and no staging files remain. The exact sequence is part of the
|
|
52
|
+
existing native Windows traversal suite as well as the Linux suite.
|
|
53
|
+
|
|
54
|
+
Storage regressions cover 256-character snapshot/artifact/head keys, concurrent immutable writes,
|
|
55
|
+
concurrent head replacement, legacy reads without rewriting bytes, legacy cache roots, collisions
|
|
56
|
+
and unsafe input rejection. Existing cross-process publication tests remain required. Live provider
|
|
57
|
+
calls, private TradePilot acceptance and live openCAESAR compilation are separate; this patch does
|
|
58
|
+
not claim them or change validation constraints, graph semantics or evidence authority.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# ADR 029: exact graph neighborhoods
|
|
2
|
+
|
|
3
|
+
Status: B1a implemented and locally checked; hosted/merge evidence is recorded in the change PR.
|
|
4
|
+
Not yet published in a candidate. B1b path exploration remains open.
|
|
5
|
+
|
|
6
|
+
`impact.scan` discovers relevant evidence with text/file selectors and bounded traversal. Agents
|
|
7
|
+
also need a precise follow-up from a returned node ID. Reusing a node ID as a search term can
|
|
8
|
+
match another node's label or citation and widen the result unexpectedly.
|
|
9
|
+
|
|
10
|
+
## Contract
|
|
11
|
+
|
|
12
|
+
Add `GraphExplorationService.neighbors`, `weftlet graph neighbors` and the read-only MCP tool
|
|
13
|
+
`graph.neighbors`. Require an explicit saved `snapshotId` and exact, case-sensitive `nodeId`.
|
|
14
|
+
Never resolve a new default/owner head during follow-up. Missing snapshots fail; missing node
|
|
15
|
+
IDs return `absent-from-snapshot`, meaning only that no assertion in this saved scope mentions
|
|
16
|
+
the ID. This does not prove the code/entity is absent from the repository or deleted.
|
|
17
|
+
|
|
18
|
+
Direction is incoming, outgoing or both (default). Empty predicate selection means all relations;
|
|
19
|
+
nonempty selection is an OR filter using the core predicate vocabulary. Unknown fields/relations,
|
|
20
|
+
invalid bounds and unsupported CLI arguments fail. A page defaults to 60 assertions, with a
|
|
21
|
+
maximum of 200. Snapshot IDs are bounded to 256 characters, node IDs to 8192 and continuations
|
|
22
|
+
to 2048. Exact IDs are operation inputs, not labels, shell commands or SPARQL fragments.
|
|
23
|
+
|
|
24
|
+
Read the same lossless RDF/SPARQL projection used by impact queries. Do not refresh, validate
|
|
25
|
+
the full graph again, call a provider or change any snapshot/artifact. Preserve each GraphFact
|
|
26
|
+
byte-for-value, including source and assertion authority, review state, confidence, citations,
|
|
27
|
+
document ownership and node attributes. Multiple citations of an edge remain separate facts;
|
|
28
|
+
labels and attributes from different assertions are not silently merged into an authoritative node.
|
|
29
|
+
Duplicate fact identities fail rather than being dropped during pagination.
|
|
30
|
+
|
|
31
|
+
## Bounds and continuation
|
|
32
|
+
|
|
33
|
+
Order by fact ID with locale-independent string comparison. A continuation binds the operation
|
|
34
|
+
version, normalized selectors/page size, snapshot manifest and actual projected facts. Reject
|
|
35
|
+
changed snapshots, filters, corrupted cursors, invalid offsets and stale versions. The token is
|
|
36
|
+
an integrity binding for query consistency, not an authentication or authorization credential.
|
|
37
|
+
|
|
38
|
+
Report total incident assertions, selected assertions, filtered assertions, page offset and
|
|
39
|
+
remaining assertions. Preserve complete assertions even when several share the same endpoints.
|
|
40
|
+
Self-links appear once and do not create a new neighbor. `truncated` describes pending pages of
|
|
41
|
+
the selected one-hop neighborhood; it never means the transitive product graph is exhausted.
|
|
42
|
+
|
|
43
|
+
Return a bounded frontier for neighbors on the current page, their supporting returned fact IDs,
|
|
44
|
+
and a count of their other incident assertions that do not touch the focus. Those counts ignore
|
|
45
|
+
the request's filters to make further branches visible. Also report how many distinct selected
|
|
46
|
+
neighbors have not appeared across this and earlier pages; continuation reaches their evidence.
|
|
47
|
+
The frontier does not recursively expand those nodes. Call the same operation with a returned
|
|
48
|
+
neighbor ID and the same snapshot to inspect another area. B1b owns multi-hop paths and budgets.
|
|
49
|
+
|
|
50
|
+
Responses reuse impact coverage semantics and the exact same checkout/overlay freshness helper.
|
|
51
|
+
Diagnostics match exact focus/returned-neighbor IDs or overlapping returned citations, with the
|
|
52
|
+
same per-kind bounds and explicit omitted/legacy counts as impact reports. A missing node can
|
|
53
|
+
still have a relevant extraction-gap diagnostic; unknown legacy text is counted, not dumped.
|
|
54
|
+
Historical evidence remains readable, excluded working changes remain explicit, and saved
|
|
55
|
+
evidence cannot satisfy a current-diff validation gate. Page coverage is not a repository coverage
|
|
56
|
+
percentage or proof of behavior. Extraction gaps and partial document scope remain visible.
|
|
57
|
+
|
|
58
|
+
## Compatibility and validation
|
|
59
|
+
|
|
60
|
+
This is an additive query API. Extraction, storage, semantic cache identity and existing
|
|
61
|
+
`impact.scan` behavior stay unchanged. The core predicate list becomes the shared runtime/type
|
|
62
|
+
vocabulary, frozen at runtime; semantic schema ordering and contents stay identical. No new
|
|
63
|
+
backend or language support is introduced. Existing snapshots can be explored without rebuilding.
|
|
64
|
+
|
|
65
|
+
Use focused graph tests for branching/cycles, exact IDs vs duplicate labels, direction/relations,
|
|
66
|
+
parallel provenance, self-links, page/frontier completeness and cursor rejection. Use actual
|
|
67
|
+
extraction/SCIP/RDF from the public monorepo fixture for cross-service follow-up and real CLI/MCP
|
|
68
|
+
transport. Verify dirty checkout/overlay state and provider-unavailable saved reads. Packed-consumer
|
|
69
|
+
tests must discover and call the new tool. B1a does not establish autonomous-agent usefulness,
|
|
70
|
+
private consumer acceptance, automatic rule-to-function binding or complete path exploration.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# ADR 030: bounded cited dependency paths
|
|
2
|
+
|
|
3
|
+
Status: B1b implemented for the next candidate. Hosted validation and merge identity are recorded
|
|
4
|
+
in the change PR; this entry does not announce npm publication or private consumer acceptance.
|
|
5
|
+
|
|
6
|
+
## Meaning and scope
|
|
7
|
+
|
|
8
|
+
`GraphPathQueryService.paths`, `weftlet graph paths` and MCP `graph.paths` take an explicit saved
|
|
9
|
+
snapshot ID and exact `fromNodeId`/`toNodeId`. They enumerate simple paths of cited assertions:
|
|
10
|
+
no node repeats, a target ends a path, parallel assertions produce distinct alternatives, and
|
|
11
|
+
self-links do not create cycles. Equal endpoints that occur in the saved graph yield one
|
|
12
|
+
zero-length identity path with no supporting assertion, even if a relation filter excludes all
|
|
13
|
+
their edges. An absent endpoint never establishes a path or absence from the actual product.
|
|
14
|
+
|
|
15
|
+
Outgoing (default), incoming and both directions refer to assertion subject/object order.
|
|
16
|
+
Following incoming or undirected evidence does not reverse or rewrite the original assertion.
|
|
17
|
+
An empty predicate list selects all relations; a nonempty list is an OR filter. Paths establish
|
|
18
|
+
cited associations, not causality, compatible business obligations or behavior verification.
|
|
19
|
+
They preserve authority, review state, source citations and node variants on every returned fact.
|
|
20
|
+
|
|
21
|
+
Read the same lossless RDF/SPARQL projection as other queries. Preserve its existing explicit
|
|
22
|
+
100,000-fact projection ceiling; exceeding it fails rather than truncating silently. No model,
|
|
23
|
+
indexer, SHACL rerun or graph write is involved. Duplicate fact IDs and mismatched stored snapshot
|
|
24
|
+
IDs fail. Responses reuse coverage, scoped diagnostic and checkout/overlay-state helpers.
|
|
25
|
+
Coverage describes the page's supporting evidence, not a repository completion percentage;
|
|
26
|
+
historical/draft evidence cannot validate the current diff. Document selection omissions remain
|
|
27
|
+
in snapshot metadata. An exhausted search says nothing about excluded or unextracted dependencies.
|
|
28
|
+
|
|
29
|
+
## Enumeration, work and continuation
|
|
30
|
+
|
|
31
|
+
Use deterministic depth-first traversal with adjacency sorted by assertion ID, independent of
|
|
32
|
+
locale. This is not a shortest-path or importance ranking: alternatives reached later can be
|
|
33
|
+
shorter or more relevant. Do not interpret the first path as the preferred design.
|
|
34
|
+
|
|
35
|
+
Defaults are depth 8 (maximum 32), five paths per page (maximum 20) and 1,000 new candidate-edge
|
|
36
|
+
examinations per page (maximum 10,000). Every considered edge counts, including cycles and depth
|
|
37
|
+
cuts. A search has a hard total ceiling of 100,000 examinations across continuations. Graph
|
|
38
|
+
loading, RDF projection and adjacency preparation are separate work, not included in that
|
|
39
|
+
candidate count. Adjacency sorts are O(E log E); the existing RDF projection also orders facts.
|
|
40
|
+
There is no wall-clock latency guarantee.
|
|
41
|
+
|
|
42
|
+
Continuations bind the operation version, normalized selectors and page budgets, saved manifest,
|
|
43
|
+
actual facts and diagnostics. A cursor carries only a step offset, never an external stack or
|
|
44
|
+
assertions. Bounded replay reconstructs state and verifies the offset is a valid page boundary.
|
|
45
|
+
Responses report replayed and new steps separately. Replay is at most the total ceiling; a DFS
|
|
46
|
+
stack is at most depth + 1. This trades bounded repeated CPU work for stateless continuation
|
|
47
|
+
without snapshot/cache writes or a large serialized queue. Tokens provide query consistency,
|
|
48
|
+
not authentication. Changing selectors, depth, budgets or saved evidence requires restarting.
|
|
49
|
+
Cumulative cost over many tiny pages can exceed one search's ceiling because replay is repeated;
|
|
50
|
+
clients should normally retain the default work budget.
|
|
51
|
+
|
|
52
|
+
The page includes only its completed paths and the union of their unchanged supporting facts.
|
|
53
|
+
Work-limited pages may be empty and still have a continuation. Returned path count is not a
|
|
54
|
+
count of all possible paths. A continuation can lead to a final empty page after dead ends/cycles.
|
|
55
|
+
|
|
56
|
+
Report every active DFS prefix with its fact-ID prefix, next candidate fact ID and remaining
|
|
57
|
+
adjacency-candidate count. These are not counts of valid paths. Depth cuts retain a total count,
|
|
58
|
+
up to 20 concrete extension examples and an explicit omitted-example count. Frontier IDs refer
|
|
59
|
+
to saved assertions; use `graph.neighbors` at that node/snapshot to retrieve their full citations.
|
|
60
|
+
|
|
61
|
+
`truncated` is true if pending work or any depth cut remains. A page/path limit supplies a
|
|
62
|
+
continuation. Exhausting the search within the requested depth can still have `truncated: true`
|
|
63
|
+
and no continuation: increase depth and restart, or explore a frontier node separately. Reaching
|
|
64
|
+
the total work ceiling likewise retains frontier and says `search-limit`, without continuation;
|
|
65
|
+
narrow relations or choose an intermediate node. None of these states silently reports no impact.
|
|
66
|
+
|
|
67
|
+
## Viewer parity and compatibility
|
|
68
|
+
|
|
69
|
+
The offline HTML viewer embeds the same dependency-free search function used by the service.
|
|
70
|
+
It searches only the displayed Context Pack and selected authority/relation layers; it cannot
|
|
71
|
+
fetch the full snapshot or turn a filtered page into complete repository evidence. Its first/next
|
|
72
|
+
path controls use one result per page, 1,000 new examinations, selectable direction/relation/depth
|
|
73
|
+
and the same total ceiling. Changing selection resets continuation. Targets show exact IDs next
|
|
74
|
+
to labels. Each highlighted edge is an unchanged fact from that displayed pack.
|
|
75
|
+
|
|
76
|
+
The prior viewer-only shortest-path implementation is replaced by shared deterministic
|
|
77
|
+
enumeration; labels now say "cited path" rather than promising a shortest route. `impact.scan`
|
|
78
|
+
and `graph.neighbors` remain unchanged. No extraction identity, semantic artifact/cache key,
|
|
79
|
+
snapshot format, dependency, rule policy or language support changes.
|
|
80
|
+
|
|
81
|
+
## Validation boundary
|
|
82
|
+
|
|
83
|
+
Compare against an independent oracle on every directed four-node graph; test parallel
|
|
84
|
+
assertions, cycles, self-links, competing branches, deep paths, relation/direction filters,
|
|
85
|
+
empty work pages, truncated depth, bounded frontier examples and the cumulative ceiling.
|
|
86
|
+
Reject malformed/stale/non-boundary continuations. Compare supporting facts with RDF queries
|
|
87
|
+
and preserve snapshots with deleted or excluded endpoints.
|
|
88
|
+
|
|
89
|
+
Exercise actual public prose extraction, SCIP and RDF/SHACL across services through CLI/MCP,
|
|
90
|
+
including unavailable providers/indexers, dirty checkouts and captured/stale overlays. Verify
|
|
91
|
+
fresh installed CLI/MCP assets and continuation. Execute rendered viewer controls in a small
|
|
92
|
+
DOM test harness and compare every highlighted path with the RDF service; this is script and
|
|
93
|
+
projection parity, not interactive browser rendering or autonomous-agent usefulness evidence.
|
|
94
|
+
|
|
95
|
+
B1a/B1b mechanisms are implemented; qualification and live product usefulness remain B6. B2's
|
|
96
|
+
Graphify/SCIP comparison is next. No backend replacement or business compatibility inference
|
|
97
|
+
is implied by paths through the existing evidence graph.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ADR 031: retain SCIP and expose its code occurrences
|
|
2
|
+
|
|
3
|
+
Status: B2b decision recorded on 2026-10-29. Implementation belongs to B3a; no production
|
|
4
|
+
extractor, public schema, dependency or published package changes in this experiment.
|
|
5
|
+
|
|
6
|
+
## Decision
|
|
7
|
+
|
|
8
|
+
Keep SCIP TypeScript as the default. Build a versioned, richer projection of its declarations
|
|
9
|
+
and reference occurrences for explicit rule-to-symbol resolution. Do not replace it with
|
|
10
|
+
Graphify or require both indexers. Preserve an adapter seam for a future producer with a
|
|
11
|
+
measured capability that justifies its installation and maintenance cost.
|
|
12
|
+
|
|
13
|
+
The current Weftlet projection discards useful information already present in the index.
|
|
14
|
+
Improving it addresses the immediate need for cited function identities and document bindings
|
|
15
|
+
without introducing another runtime. SCIP references do not prove calls, execution, data flow
|
|
16
|
+
or business intent. Native calls remain unsupported by this projection; a separate measured
|
|
17
|
+
producer could address that gap later.
|
|
18
|
+
|
|
19
|
+
## Evidence and interpretation
|
|
20
|
+
|
|
21
|
+
Inputs were frozen at `f1844f31717341f5ff95314a68def80eae509734`; the unchanged baseline engine
|
|
22
|
+
is `f3b0f99cc7f01227925bf7372f3ab7a60f0de62c`. See the [complete measurement record](../evaluations/code-graph-results/2026-10-29/README.md),
|
|
23
|
+
including pinned versions, commands, exported native artifacts, exact citations, per-case results,
|
|
24
|
+
costs, retained failed attempts and scoring amendments. No paid/model calls or private inputs.
|
|
25
|
+
|
|
26
|
+
Cold results combine two public corpora, without counting repeats as more independent cases:
|
|
27
|
+
|
|
28
|
+
| Evidence requested | Current Weftlet projection | Richer raw SCIP | Pinned Graphify static API |
|
|
29
|
+
| --- | --- | --- | --- |
|
|
30
|
+
| Declaration families, 15 positive cases | Exact track unsupported; 7 coarse candidates | 15/15 | 14/15 |
|
|
31
|
+
| References, 16 positive cases | Exact track unsupported; 12 coarse candidates | 16/16 | 8/16, including one ambiguous re-export counted as missing |
|
|
32
|
+
| Native calls, 10 positive cases | Unsupported | Unsupported | 7/10; retains native inferred/extracted tags |
|
|
33
|
+
| Ten named false-join negatives | Unsupported in exact track | None asserted | None asserted |
|
|
34
|
+
| Citation/identity failures in these scored outputs | 0 | 0 | 0 |
|
|
35
|
+
|
|
36
|
+
These are labeled-case results, not whole-graph precision estimates. Hundreds of other references
|
|
37
|
+
are unjudged. Graphify's line-only evidence receives source credit only where the labeled token
|
|
38
|
+
has an unambiguous native target; it does not acquire column precision. Its overload implementation
|
|
39
|
+
counts as a family, while two missing signature spans remain missing. The ambient vendor declaration
|
|
40
|
+
is absent. Other misses include type-use occurrences, test top-level calls and an execution call;
|
|
41
|
+
raw artifacts retain coarser import edges even when exact-use credit is unavailable.
|
|
42
|
+
|
|
43
|
+
Graphify is faster and lighter on these tiny TypeScript fixtures. For the 21-file business corpus,
|
|
44
|
+
two-sample median extraction phases were 0.808 s for SCIP indexing and 0.035 s for Graphify static
|
|
45
|
+
extraction. Whole worker times were 2.056 s and 1.087 s respectively, including startup; the SCIP
|
|
46
|
+
worker also assembles the unchanged baseline graph. Sampled aggregate process RSS was about
|
|
47
|
+
335 MiB versus 75 MiB, with shared pages potentially counted more than once. Cgroup peaks are
|
|
48
|
+
recorded separately. Small unequal sample counts, warm host caches and different phase boundaries
|
|
49
|
+
do not establish production speed ratios or large-monorepo behavior.
|
|
50
|
+
|
|
51
|
+
All 96 corrected experimental graph assemblies pass strict SHACL and exact RDF/SPARQL fact
|
|
52
|
+
projection parity. Every arm retrieves the documented collection → execution → notifications →
|
|
53
|
+
mobile chain, relevant test and both freshness rules, and loses the chain when its handoff sentence
|
|
54
|
+
is removed. Billing remains unrelated. Shared Status connects API and mobile in every arm.
|
|
55
|
+
Fixed-document/routing dispatch retrieves 16/16 expected files with zero of seven named distractions;
|
|
56
|
+
code-only retrieves 13/16. Some dispatch queries retain explicit continuation after the three-page
|
|
57
|
+
budget: these are successful labeled retrievals, not exhaustive graph searches.
|
|
58
|
+
|
|
59
|
+
The fixed business layer is identical across arms. Its documents are declared fixture intent;
|
|
60
|
+
grammar-derived assertions remain inferred/unreviewed. None of these results proves model
|
|
61
|
+
extraction quality, rule compatibility, delivery over a queue, or a function implementing a rule.
|
|
62
|
+
Both tools leave dynamic-target and undeclared-queue gaps silent. Only the richer SCIP adapter
|
|
63
|
+
explicitly reports the external implementation as declaration-only. B3–B5 must address binding,
|
|
64
|
+
obligations and coverage rather than treating absent edges as zero impact.
|
|
65
|
+
|
|
66
|
+
Repeat and dirty committed-source runs preserve normalized content and identities. Graphify's raw
|
|
67
|
+
dirty output differs only in its absolute `extracted_sources` inventory; nodes/edges are unchanged.
|
|
68
|
+
Edits preserve unrelated identities, rename/delete remove old current spans, omitted worker inputs
|
|
69
|
+
are explicitly excluded, and old snapshots remain unchanged. This tests full re-extraction with
|
|
70
|
+
cached document artifacts, not incremental code indexing. Graphify's pinned JS/TS path does not
|
|
71
|
+
prove useful incremental parse reuse merely because it accepts a cache directory.
|
|
72
|
+
|
|
73
|
+
## Limits and next implementation boundary
|
|
74
|
+
|
|
75
|
+
The comparison used Linux, Python 3.12.14, Node 24.19.0, SCIP TypeScript 0.4.0, and pinned Graphify
|
|
76
|
+
source `0a8cd4e1e342235fe53e881fb5d591bf0460071f`. Its source API imports with 30 locked runtime
|
|
77
|
+
distributions; the manifest/lock project-version mismatch is explicitly handled without installing
|
|
78
|
+
a project distribution. This is not a Graphify package, Windows/macOS, multi-language or managed
|
|
79
|
+
service validation. No upstream code or dependency enters the npm packages.
|
|
80
|
+
|
|
81
|
+
B3a will add first-class code entities and cited occurrences with stable identities, containing
|
|
82
|
+
file/project, declaration spans, references and explicit unresolved/declaration-only states. It
|
|
83
|
+
must retain canonical physical-file kinds, distinguish overload families from spans, and avoid
|
|
84
|
+
joining duplicate names. Explicit document bindings must preserve both source revisions/spans,
|
|
85
|
+
source approval and assertion-review authority. Rename/delete, dirty overlays, cache/version
|
|
86
|
+
identity, historical snapshots, RDF/query parity and fresh installation need regressions before
|
|
87
|
+
publication. Do not copy this experiment's legacy file-to-symbol projection into the public schema
|
|
88
|
+
and call that function-level binding. B3b separately assesses remaining inferred-mapping needs.
|
|
89
|
+
|
|
90
|
+
The next candidate remains unreleased until the agreed B1–B5 increments and B6 qualification.
|
|
91
|
+
This decision does not mark official 1.0 or private consumer acceptance complete.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ADR 032: Preserve native SCIP symbols and occurrences
|
|
2
|
+
|
|
3
|
+
Status: accepted for B3a's first increment. Explicit document-to-symbol bindings and static
|
|
4
|
+
call analysis remain separate work. This implements the projection decision in ADR 031;
|
|
5
|
+
Graphify does not become a runtime dependency.
|
|
6
|
+
|
|
7
|
+
## Evidence model
|
|
8
|
+
|
|
9
|
+
`@weftlet/core` exposes `CodeSymbol`, its descriptor, `CodeOccurrence`, `CodeRange` and the
|
|
10
|
+
`codeSymbolNode` factory. The neutral package adds no dependencies. Global symbol IDs hash
|
|
11
|
+
provider, repository identity and the native SCIP symbol. Native `local N` IDs additionally
|
|
12
|
+
include the document path and normalized SCIP index digest: native local ordinals cannot be
|
|
13
|
+
trusted across index revisions. Labels and resolution status are evidence, not ID inputs.
|
|
14
|
+
Renames, package-version changes and tool-native symbol changes can change global IDs; this
|
|
15
|
+
is not automatic identity continuity across refactors.
|
|
16
|
+
|
|
17
|
+
The toolkit retains every distinct native definition/reference occurrence. Definitions connect
|
|
18
|
+
`CodeSymbol —definedBy→ physical file`. References connect the narrowest unambiguous native
|
|
19
|
+
declaration range's symbol to the target; without such a range, the subject is the cited file
|
|
20
|
+
and enclosure is `file` or `ambiguous`. Multiple spans, overload signatures, recursive references,
|
|
21
|
+
private/local symbols and repeated same-line uses remain separate assertions. Exact duplicate
|
|
22
|
+
native entries deduplicate. Existing file-to-Contract relationships remain for compatibility.
|
|
23
|
+
This is additive evidence, not a claim that the two node types are interchangeable.
|
|
24
|
+
|
|
25
|
+
Citations carry one-based UTF-16 start/end columns with an exclusive end, committed source digest
|
|
26
|
+
and SHA. A leading UTF-8 BOM stripped by TypeScript is mapped back into committed first-line
|
|
27
|
+
columns. Source files are read as UTF-8; UTF-16 here describes column units, not file encoding.
|
|
28
|
+
Native declaration/body ranges are retained separately; arrow initializer extents may
|
|
29
|
+
exclude the variable name. A zero-width module anchor can precede
|
|
30
|
+
its declaration extent; `locationKind: zero-width-anchor` distinguishes it from an actual name.
|
|
31
|
+
Invalid source ranges fail extraction. Test files retain canonical Evidence identity; static
|
|
32
|
+
inspection is `implemented`/`deterministic`, not proof of a passed test. Overlays are `draft`.
|
|
33
|
+
|
|
34
|
+
Resolution is `indexed-definition`, `declaration-only` or `no-indexed-definition`. The latter
|
|
35
|
+
includes external or unselected implementations; it does not assert that the target is missing
|
|
36
|
+
from the product. Enclosure is lexical, not execution: SCIP 0.4.0 supplies no declaration extent
|
|
37
|
+
for some local arrow variables, so a nested reference may be attributed to the enclosing outer
|
|
38
|
+
range. Neither a function kind nor a call is inferred from hover text or symbol spelling.
|
|
39
|
+
|
|
40
|
+
## Shared queries, validation and limits
|
|
41
|
+
|
|
42
|
+
The complete typed JSON facts and queryable RDF properties use the same snapshot. SHACL checks
|
|
43
|
+
code metadata, scopes, resolution, predicate/role/enclosure structure and column completeness;
|
|
44
|
+
deterministic consistency checks verify role flags, canonical cited files, range ordering and
|
|
45
|
+
zero-width anchor consistency. Existing kind cardinality and intent authority constraints remain intact.
|
|
46
|
+
The optimized union and original named-dataset paths agree on new shape failures.
|
|
47
|
+
|
|
48
|
+
`graph.neighbors` and `graph.paths` expose exact symbols, spans and bounded continuation through
|
|
49
|
+
the existing API/CLI/MCP. The viewer and Markdown show columns and static-evidence labels.
|
|
50
|
+
Automatic `impact.scan` leaves unresolved code targets terminal, so shared built-ins do not
|
|
51
|
+
create a false impact path between co-users. It reports `codeTraversalVersion: indexed-symbols-v1`
|
|
52
|
+
and `unexpandedCodeTargetCount`, with at most 100 `unexpandedCodeTargets` example IDs and an
|
|
53
|
+
explicit truncation flag; exact neighborhood/path exploration remains available. Continuation
|
|
54
|
+
identity includes this traversal policy. Shared unresolved import behavior is otherwise unchanged.
|
|
55
|
+
|
|
56
|
+
Occurrence retention increases graph size and can require more query pages. The existing
|
|
57
|
+
100,000-fact projection ceiling still fails explicitly rather than truncating; this is not
|
|
58
|
+
qualification for arbitrary monorepos. Indexing remains full, not incremental SCIP or incremental
|
|
59
|
+
SHACL. B5/B6 must assess project coverage, volume and useful bounded retrieval on the candidate.
|
|
60
|
+
|
|
61
|
+
## Compatibility and validation
|
|
62
|
+
|
|
63
|
+
`scip-symbol-extractor` advances from 1.1.0 to 2.0.0 and graph assembly from 7 to 8. Existing saved
|
|
64
|
+
snapshots remain readable, but freshness checks require refresh for current validation. Semantic
|
|
65
|
+
extractor/cache identity is unchanged. Protocol loading, symbol projection and range handling are
|
|
66
|
+
separate modules behind the retained `static.ts` exports; runtime assets are checked in packed installs.
|
|
67
|
+
|
|
68
|
+
Tests use actual committed public source, real SCIP, hydration, strict RDF/SHACL, SPARQL projection,
|
|
69
|
+
agent-facade pagination and paths, unchanged repeat, dirty saved querying and draft rename/delete.
|
|
70
|
+
The 3,000-line fixture uses explicit comment padding around meaningful functions; it is a location
|
|
71
|
+
and isolation regression, not a production-size performance claim. Unit negatives cover malformed
|
|
72
|
+
ranges, ambiguous scopes, missing targets, native local identity and invalid metadata. The prior
|
|
73
|
+
frozen comparison and scores are unchanged. See VALIDATION.md for executed gates.
|