@descryy/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/action-handshake.d.ts +86 -0
- package/dist/action-handshake.d.ts.map +1 -0
- package/dist/action-handshake.js +144 -0
- package/dist/action-handshake.js.map +1 -0
- package/dist/bin/descry-mcp.d.ts +18 -0
- package/dist/bin/descry-mcp.d.ts.map +1 -0
- package/dist/bin/descry-mcp.js +54 -0
- package/dist/bin/descry-mcp.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/language-guess.d.ts +17 -0
- package/dist/language-guess.d.ts.map +1 -0
- package/dist/language-guess.js +43 -0
- package/dist/language-guess.js.map +1 -0
- package/dist/protocol.d.ts +91 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +127 -0
- package/dist/protocol.js.map +1 -0
- package/dist/registry.d.ts +72 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +136 -0
- package/dist/registry.js.map +1 -0
- package/dist/render.d.ts +275 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +333 -0
- package/dist/render.js.map +1 -0
- package/dist/server.d.ts +42 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +263 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +164 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +302 -0
- package/dist/session.js.map +1 -0
- package/dist/tools/analyze.d.ts +124 -0
- package/dist/tools/analyze.d.ts.map +1 -0
- package/dist/tools/analyze.js +411 -0
- package/dist/tools/analyze.js.map +1 -0
- package/dist/tools/contracts.d.ts +105 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +141 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/cross-pr.d.ts +137 -0
- package/dist/tools/cross-pr.d.ts.map +1 -0
- package/dist/tools/cross-pr.js +216 -0
- package/dist/tools/cross-pr.js.map +1 -0
- package/dist/tools/git-diff.d.ts +29 -0
- package/dist/tools/git-diff.d.ts.map +1 -0
- package/dist/tools/git-diff.js +117 -0
- package/dist/tools/git-diff.js.map +1 -0
- package/dist/tools/git-history.d.ts +27 -0
- package/dist/tools/git-history.d.ts.map +1 -0
- package/dist/tools/git-history.js +91 -0
- package/dist/tools/git-history.js.map +1 -0
- package/dist/tools/history.d.ts +63 -0
- package/dist/tools/history.d.ts.map +1 -0
- package/dist/tools/history.js +114 -0
- package/dist/tools/history.js.map +1 -0
- package/dist/tools/impact.d.ts +81 -0
- package/dist/tools/impact.d.ts.map +1 -0
- package/dist/tools/impact.js +229 -0
- package/dist/tools/impact.js.map +1 -0
- package/dist/tools/index.d.ts +33 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +47 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/kit.d.ts +183 -0
- package/dist/tools/kit.d.ts.map +1 -0
- package/dist/tools/kit.js +117 -0
- package/dist/tools/kit.js.map +1 -0
- package/dist/tools/link-workspace.d.ts +62 -0
- package/dist/tools/link-workspace.d.ts.map +1 -0
- package/dist/tools/link-workspace.js +156 -0
- package/dist/tools/link-workspace.js.map +1 -0
- package/dist/tools/lookup.d.ts +29 -0
- package/dist/tools/lookup.d.ts.map +1 -0
- package/dist/tools/lookup.js +73 -0
- package/dist/tools/lookup.js.map +1 -0
- package/dist/tools/pr-analysis.d.ts +89 -0
- package/dist/tools/pr-analysis.d.ts.map +1 -0
- package/dist/tools/pr-analysis.js +169 -0
- package/dist/tools/pr-analysis.js.map +1 -0
- package/dist/tools/propagation.d.ts +74 -0
- package/dist/tools/propagation.d.ts.map +1 -0
- package/dist/tools/propagation.js +194 -0
- package/dist/tools/propagation.js.map +1 -0
- package/dist/tools/questions.d.ts +80 -0
- package/dist/tools/questions.d.ts.map +1 -0
- package/dist/tools/questions.js +213 -0
- package/dist/tools/questions.js.map +1 -0
- package/dist/tools/refusal-fetch.d.ts +71 -0
- package/dist/tools/refusal-fetch.d.ts.map +1 -0
- package/dist/tools/refusal-fetch.js +137 -0
- package/dist/tools/refusal-fetch.js.map +1 -0
- package/dist/tools/scope.d.ts +60 -0
- package/dist/tools/scope.d.ts.map +1 -0
- package/dist/tools/scope.js +160 -0
- package/dist/tools/scope.js.map +1 -0
- package/dist/tools/similar-incidents.d.ts +105 -0
- package/dist/tools/similar-incidents.d.ts.map +1 -0
- package/dist/tools/similar-incidents.js +228 -0
- package/dist/tools/similar-incidents.js.map +1 -0
- package/dist/tools/validate.d.ts +103 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +176 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tools/verification-status.d.ts +68 -0
- package/dist/tools/verification-status.d.ts.map +1 -0
- package/dist/tools/verification-status.js +179 -0
- package/dist/tools/verification-status.js.map +1 -0
- package/dist/transport.d.ts +58 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +115 -0
- package/dist/transport.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `analyze` — read the repository into the graph.
|
|
3
|
+
*
|
|
4
|
+
* The only tool that writes. Everything else queries what this produced, so its
|
|
5
|
+
* disclosures are the ones that matter most: a query cannot report a gap it was
|
|
6
|
+
* never told about, and this is where the gaps become known.
|
|
7
|
+
*
|
|
8
|
+
* ## What is disclosed, and why each one earns its line
|
|
9
|
+
*
|
|
10
|
+
* - **Sources that would not load.** "No problem found in your Python service"
|
|
11
|
+
* and "your Python adapter did not import" are different statements (§20.2).
|
|
12
|
+
* - **Sources that loaded and did not claim the repository.** The same
|
|
13
|
+
* distinction, one level up: an unanalysed language is *not analysable*, not
|
|
14
|
+
* clean.
|
|
15
|
+
* - **The resolution each source reached.** A run that degraded to R0 because a
|
|
16
|
+
* virtualenv was missing produces a graph that looks identical to a healthy
|
|
17
|
+
* one until you read this number. Principle 3 then caps everything above it.
|
|
18
|
+
* - **Identity collisions.** Two things arrived under one id. There is no
|
|
19
|
+
* correct merge, so the builder reports rather than picks (DEC-024).
|
|
20
|
+
* - **Evicted files.** Rows a previous run owned and this one did not re-supply.
|
|
21
|
+
* They are gone from the graph; a query over them will now find nothing, and
|
|
22
|
+
* nothing would otherwise say why.
|
|
23
|
+
* - **The workspace join.** Zero cross-repo joins looks exactly like success.
|
|
24
|
+
*
|
|
25
|
+
* ## The repo identity warning
|
|
26
|
+
*
|
|
27
|
+
* With no `.descry/config.json`, `repo` defaults to the directory name — and
|
|
28
|
+
* every repo-scoped node id is a hash over it. Clone into a differently-named
|
|
29
|
+
* folder and every id changes, which silently destroys incident links and
|
|
30
|
+
* `CHANGES_WITH` weights. That is DEC-004's failure arriving through the one
|
|
31
|
+
* field a default cannot get right, so it is stated on every unconfigured run.
|
|
32
|
+
*/
|
|
33
|
+
import { applyConfirmedFacts, buildGraph, counts, createGitSource, mintEdgesFromConfirmedFacts, MINT_PRODUCED_BY, persistGraph, summariseRefusals, } from "@descryy/core";
|
|
34
|
+
import { answer, ToolInputError } from "./kit.js";
|
|
35
|
+
import { detectSources, loadSources } from "../registry.js";
|
|
36
|
+
const SCHEMA = {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
includeHistory: {
|
|
40
|
+
type: "boolean",
|
|
41
|
+
description: "Read git history for co-change coupling (CHANGES_WITH edges). Default true. " +
|
|
42
|
+
"Costs a few seconds on a large repository.",
|
|
43
|
+
},
|
|
44
|
+
maxCommits: {
|
|
45
|
+
type: "integer",
|
|
46
|
+
minimum: 1,
|
|
47
|
+
description: "Cap on commits read from history. Default 2000.",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
additionalProperties: false,
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* §5.4's `refusals` field, for this run only — never the graph's whole
|
|
54
|
+
* stored ledger (`refusal_fetch`'s job). `built.unresolved` is what the
|
|
55
|
+
* sources this call just read could not resolve, so it is a fresh
|
|
56
|
+
* population every run rather than accumulated history, and honestly
|
|
57
|
+
* scoped to "what this call found" the way the field's own contract asks.
|
|
58
|
+
*
|
|
59
|
+
* `undefined` on zero rows — the envelope's `refusals` stays `null` rather
|
|
60
|
+
* than carrying a summary with no exemplar or handle to show (matching
|
|
61
|
+
* `summariseRefusals`'s own `count === 0` shape one level up).
|
|
62
|
+
*/
|
|
63
|
+
export function refusalSummaryField(unresolved) {
|
|
64
|
+
const summary = summariseRefusals(unresolved);
|
|
65
|
+
if (summary.count === 0 || summary.exemplar === null || summary.handle === null)
|
|
66
|
+
return undefined;
|
|
67
|
+
return { count: summary.count, exemplar: summary.exemplar, handle: summary.handle };
|
|
68
|
+
}
|
|
69
|
+
async function run(args, ctx) {
|
|
70
|
+
const { session } = ctx;
|
|
71
|
+
const includeHistory = args["includeHistory"] !== false;
|
|
72
|
+
const maxCommits = args["maxCommits"];
|
|
73
|
+
if (maxCommits !== undefined && (typeof maxCommits !== "number" || !Number.isInteger(maxCommits) || maxCommits < 1)) {
|
|
74
|
+
throw new ToolInputError('"maxCommits" must be a positive integer');
|
|
75
|
+
}
|
|
76
|
+
const root = await session.root();
|
|
77
|
+
const notes = [];
|
|
78
|
+
// MK-4: analyze is about to rebuild the graph from source regardless, so a
|
|
79
|
+
// stale IR schema version is repaired here rather than left to refuse —
|
|
80
|
+
// see Session.repairStaleGraph's own doc for why only this tool does this.
|
|
81
|
+
const { rebuilt } = session.repairStaleGraph();
|
|
82
|
+
if (rebuilt) {
|
|
83
|
+
notes.push("The stored graph was written under an older IR schema version. Its derived tables were " +
|
|
84
|
+
"dropped and are rebuilt by this run; earned data (R4 observations, edge corrections, " +
|
|
85
|
+
"incident links) was not affected.");
|
|
86
|
+
}
|
|
87
|
+
if (session.config.configPath === null) {
|
|
88
|
+
notes.push(`No ${".descry/config.json"} was found, so the repository identity defaults to the ` +
|
|
89
|
+
`directory name ("${session.config.repo}"). Every repo-scoped node id is a hash over that ` +
|
|
90
|
+
"string: cloning into a differently-named folder produces a different graph, and incident " +
|
|
91
|
+
"links and co-change weights do not survive the change. Set \"repo\" explicitly.");
|
|
92
|
+
}
|
|
93
|
+
if (session.config.workspace === undefined) {
|
|
94
|
+
notes.push("No workspace is configured, so this repository is its own contract boundary. Endpoints, " +
|
|
95
|
+
"tables and incidents will not join with any other repository's (DEC-054). If there is a " +
|
|
96
|
+
'sibling repository this one should join — a frontend to this backend, for example — ask ' +
|
|
97
|
+
'whether they should share a workspace, and call "link_workspace" once confirmed. Never ' +
|
|
98
|
+
"call it on a guess: a directory sitting next to another is a suggestion, not evidence.");
|
|
99
|
+
}
|
|
100
|
+
// --- sources -------------------------------------------------------------
|
|
101
|
+
const registry = await loadSources(session.config.sources);
|
|
102
|
+
for (const failure of registry.failed) {
|
|
103
|
+
notes.push(`The source "${failure.spec.module}" could not be loaded (${failure.reason}). Anything it ` +
|
|
104
|
+
"would have read is not analysable — not clean.");
|
|
105
|
+
}
|
|
106
|
+
if (session.config.sources.length === 0) {
|
|
107
|
+
notes.push(
|
|
108
|
+
// No example package name here, deliberately, and the boundary lint
|
|
109
|
+
// enforces it. Naming one would make this engine know about a specific
|
|
110
|
+
// language — the exact inversion `registry.ts` exists to prevent — and the
|
|
111
|
+
// list of installed adapters is not something this process can see.
|
|
112
|
+
"No language adapters are configured, so nothing was read from source. Add a \"sources\" " +
|
|
113
|
+
`array to ${".descry/config.json"} listing the adapter packages to load, as module ` +
|
|
114
|
+
"specifiers. This engine does not know the name of any adapter: the IR boundary is a " +
|
|
115
|
+
"dependency direction, so the list has to come from configuration.");
|
|
116
|
+
}
|
|
117
|
+
const { applicable, skipped } = await detectSources(registry.loaded, root);
|
|
118
|
+
for (const entry of skipped) {
|
|
119
|
+
notes.push(`${entry.source.source.id} did not run: it ${entry.reason}. Any code only that adapter ` +
|
|
120
|
+
"could read is not analysable.");
|
|
121
|
+
}
|
|
122
|
+
// --- emit ----------------------------------------------------------------
|
|
123
|
+
const context = {
|
|
124
|
+
root,
|
|
125
|
+
prepareTimeoutMs: 300_000,
|
|
126
|
+
signal: ctx.signal,
|
|
127
|
+
};
|
|
128
|
+
const batches = [];
|
|
129
|
+
const perSource = [];
|
|
130
|
+
/**
|
|
131
|
+
* Resolution levels reached by sources that read **source code**.
|
|
132
|
+
*
|
|
133
|
+
* The floor is drawn from these alone, and the git-history reader is why. It
|
|
134
|
+
* reaches R0 and always will: R0 is what reading a commit log *is*, not a
|
|
135
|
+
* degradation of it. Folding it into a single graph-wide minimum pinned every
|
|
136
|
+
* analyse reply at R0 and therefore at reliability class C — which then
|
|
137
|
+
* described a set of directly counted rows as "a behavioural prediction".
|
|
138
|
+
*
|
|
139
|
+
* DEC-058 already settled the general form of this: an edge carries the
|
|
140
|
+
* resolution of *its own evidence*, not of the run, so a graph has no single
|
|
141
|
+
* floor and each answer computes its own. This is that rule applied one level
|
|
142
|
+
* up. Every source's level is still reported individually in `sources`, and a
|
|
143
|
+
* source that fell short of its own declared ceiling is disclosed separately.
|
|
144
|
+
*/
|
|
145
|
+
const codeResolutions = [];
|
|
146
|
+
const total = applicable.length + (includeHistory ? 1 : 0);
|
|
147
|
+
let done = 0;
|
|
148
|
+
for (const entry of applicable) {
|
|
149
|
+
ctx.progress(`Reading ${entry.source.id}`, done, total);
|
|
150
|
+
const started = Date.now();
|
|
151
|
+
try {
|
|
152
|
+
const batch = await entry.source.emit(context);
|
|
153
|
+
batches.push(batch);
|
|
154
|
+
perSource.push({
|
|
155
|
+
source: batch.producedBy,
|
|
156
|
+
files: batch.sourceFiles.length,
|
|
157
|
+
nodes: batch.nodes.length,
|
|
158
|
+
edges: batch.edges.length,
|
|
159
|
+
unresolved: batch.unresolved.length,
|
|
160
|
+
skippedFiles: batch.skippedFiles.length,
|
|
161
|
+
reachedResolution: batch.reachedResolution,
|
|
162
|
+
ms: Date.now() - started,
|
|
163
|
+
});
|
|
164
|
+
// The declared ceiling versus what this run actually reached. A gap is the
|
|
165
|
+
// honest-degradation case: the adapter can do better and something in this
|
|
166
|
+
// repository stopped it.
|
|
167
|
+
const ceiling = entry.adapter?.capabilities().maxResolution;
|
|
168
|
+
if (ceiling !== undefined)
|
|
169
|
+
codeResolutions.push(batch.reachedResolution);
|
|
170
|
+
if (ceiling !== undefined && batch.reachedResolution < ceiling) {
|
|
171
|
+
notes.push(`${entry.source.id} reached R${batch.reachedResolution} where it is capable of ` +
|
|
172
|
+
`R${ceiling}. Findings resting on its edges are capped accordingly, and shape-level ` +
|
|
173
|
+
"checks (contract matching, field propagation) need R3.");
|
|
174
|
+
}
|
|
175
|
+
if (batch.skippedFiles.length > 0) {
|
|
176
|
+
const byReason = new Map();
|
|
177
|
+
for (const skipped of batch.skippedFiles) {
|
|
178
|
+
byReason.set(skipped.reason, (byReason.get(skipped.reason) ?? 0) + 1);
|
|
179
|
+
}
|
|
180
|
+
const summary = [...byReason.entries()].map(([reason, count]) => `${count} ${reason}`).join(", ");
|
|
181
|
+
notes.push(`${entry.source.id} could not analyse ${batch.skippedFiles.length} file(s) it attempted ` +
|
|
182
|
+
`(${summary}). Not analysable — absent from the graph, not confirmed clean.`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
notes.push(`${entry.source.id} failed while reading this repository (${error.message}). ` +
|
|
187
|
+
"Everything it covers is not analysable.");
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
// `dispose` is a `LanguageAdapter` obligation, not an `IRSource` one — a
|
|
191
|
+
// language server is a long-lived child process and leaking one costs
|
|
192
|
+
// hundreds of megabytes per repo. Sources with no processes to release
|
|
193
|
+
// (the git reader) have no method and need none.
|
|
194
|
+
await entry.adapter?.dispose();
|
|
195
|
+
done += 1;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (includeHistory) {
|
|
199
|
+
ctx.progress("Reading git history", done, total);
|
|
200
|
+
const historyStarted = Date.now();
|
|
201
|
+
try {
|
|
202
|
+
const history = await createGitSource({
|
|
203
|
+
repo: root.repo,
|
|
204
|
+
cwd: session.repoPath,
|
|
205
|
+
...(typeof maxCommits === "number" ? { maxCommits } : {}),
|
|
206
|
+
}).emit(context);
|
|
207
|
+
batches.push(history);
|
|
208
|
+
perSource.push({
|
|
209
|
+
source: history.producedBy,
|
|
210
|
+
files: history.sourceFiles.length,
|
|
211
|
+
nodes: history.nodes.length,
|
|
212
|
+
edges: history.edges.length,
|
|
213
|
+
unresolved: history.unresolved.length,
|
|
214
|
+
skippedFiles: history.skippedFiles.length,
|
|
215
|
+
reachedResolution: history.reachedResolution,
|
|
216
|
+
ms: Date.now() - historyStarted,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
notes.push(`Git history was not read (${error.message}), so co-change coupling is absent ` +
|
|
221
|
+
"and blast radii will not include historically coupled files.");
|
|
222
|
+
}
|
|
223
|
+
done += 1;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
notes.push("Git history was skipped by request, so no CHANGES_WITH edges were produced and the blast " +
|
|
227
|
+
"radius will miss files that historically change together.");
|
|
228
|
+
}
|
|
229
|
+
// --- build and store -----------------------------------------------------
|
|
230
|
+
ctx.progress("Merging into the graph", done, total);
|
|
231
|
+
const built = buildGraph(batches, {
|
|
232
|
+
nodeExists: (id) => session.provider().node(id) !== undefined,
|
|
233
|
+
});
|
|
234
|
+
const persisted = persistGraph(session.store().driver, batches, built);
|
|
235
|
+
for (const collision of built.collisions) {
|
|
236
|
+
notes.push(`Two different things claimed node id ${collision.nodeId}: a ${collision.kept.type} from ` +
|
|
237
|
+
`${collision.kept.producedBy} and a ${collision.discarded.type} from ` +
|
|
238
|
+
`${collision.discarded.producedBy}. They are not the same symbol and there is no correct ` +
|
|
239
|
+
"merge, so the second was discarded (DEC-024).");
|
|
240
|
+
}
|
|
241
|
+
if (built.droppedEdges > 0) {
|
|
242
|
+
notes.push(`${built.droppedEdges} edge(s) were dropped because an endpoint did not resolve to a real ` +
|
|
243
|
+
"node. They are never stubbed into existence — a name-matched guess belongs in the " +
|
|
244
|
+
"unresolved-reference ledger, not in the graph.");
|
|
245
|
+
}
|
|
246
|
+
if (built.rejections.length > 0) {
|
|
247
|
+
notes.push(`${built.rejections.length} item(s) were turned away at the IR boundary as malformed. They ` +
|
|
248
|
+
"are not in the graph and nothing above will see them.");
|
|
249
|
+
}
|
|
250
|
+
if (persisted.evictedFiles.length > 0) {
|
|
251
|
+
notes.push(`${persisted.evictedFiles.length} file(s) covered by a previous run were not re-supplied by ` +
|
|
252
|
+
"this one; their rows have been removed. A query about them will now find nothing because " +
|
|
253
|
+
"nothing is stored, not because there is nothing there.");
|
|
254
|
+
}
|
|
255
|
+
for (const warning of built.warnings)
|
|
256
|
+
notes.push(warning.detail);
|
|
257
|
+
if (built.unresolved.length > 0) {
|
|
258
|
+
notes.push(`${built.unresolved.length} reference(s) could not be resolved to a target and are recorded ` +
|
|
259
|
+
"in the ledger rather than guessed at. They are the measured recall gap, not an error.");
|
|
260
|
+
}
|
|
261
|
+
// --- mint edges from confirmed facts --------------------------------------
|
|
262
|
+
//
|
|
263
|
+
// DEC-223's answer half, minting side (DEC-138) — sequenced after the base
|
|
264
|
+
// graph above is already persisted, because a confirmed answer joins
|
|
265
|
+
// against a real, stored `API_ENDPOINT` row: `EndpointLookup.node(id)` is
|
|
266
|
+
// backed by the SQL reader, not by `built`'s in-memory result, so the
|
|
267
|
+
// endpoint has to already exist as a row for the lookup to find it.
|
|
268
|
+
ctx.progress("Minting edges from confirmed facts", done, total);
|
|
269
|
+
const provider = session.provider();
|
|
270
|
+
const { refs: ledgerRefs } = provider.unresolvedRefs();
|
|
271
|
+
const { answered } = applyConfirmedFacts(ledgerRefs, session.config.confirmedFacts, session.config.repo);
|
|
272
|
+
const scope = {
|
|
273
|
+
repo: session.config.repo,
|
|
274
|
+
...(session.config.workspace === undefined ? {} : { workspace: session.config.workspace }),
|
|
275
|
+
};
|
|
276
|
+
const mintResult = mintEdgesFromConfirmedFacts(answered, provider, scope, MINT_PRODUCED_BY, root.commitSha);
|
|
277
|
+
// The invalidation key (DEC-015: "producedBy + sourceFiles"). Scoped to
|
|
278
|
+
// every file carrying an *askable* ("value-unknown") row this run, not
|
|
279
|
+
// only the files a fact happened to answer. That distinction is what makes
|
|
280
|
+
// a re-run after a changed or removed answer safe: the run id is derived
|
|
281
|
+
// from (producedBy, repo, commitSha, sourceFiles), so a re-run at the same
|
|
282
|
+
// commit with the same askable domain lands on the *same* run id, and the
|
|
283
|
+
// writer's own self-clean pass (`writer.ts` rule 3) retires whatever this
|
|
284
|
+
// run no longer supplies — the edge from a superseded answer does not
|
|
285
|
+
// survive next to a new one. Scoping to the *answered* subset instead
|
|
286
|
+
// would let a file drop out of `sourceFiles` the moment its one answer was
|
|
287
|
+
// removed, and a stale edge for it would then never be found as a
|
|
288
|
+
// prior-run to retire at all.
|
|
289
|
+
const mintFiles = [
|
|
290
|
+
...new Set(ledgerRefs.flatMap((ref) => ref.attrs?.["refusalClass"] === "value-unknown" && typeof ref.file === "string" ? [ref.file] : [])),
|
|
291
|
+
].sort();
|
|
292
|
+
const mintBatch = {
|
|
293
|
+
repo: session.config.repo,
|
|
294
|
+
...(session.config.workspace === undefined ? {} : { workspace: session.config.workspace }),
|
|
295
|
+
commitSha: root.commitSha,
|
|
296
|
+
producedBy: MINT_PRODUCED_BY,
|
|
297
|
+
sourceFiles: mintFiles,
|
|
298
|
+
skippedFiles: [],
|
|
299
|
+
reachedResolution: 2,
|
|
300
|
+
nodes: [],
|
|
301
|
+
edges: mintResult.minted.map((m) => m.edge),
|
|
302
|
+
unresolved: [],
|
|
303
|
+
};
|
|
304
|
+
const mintBuilt = buildGraph([mintBatch], {
|
|
305
|
+
nodeExists: (id) => provider.node(id) !== undefined,
|
|
306
|
+
});
|
|
307
|
+
const mintPersisted = persistGraph(session.store().driver, [mintBatch], mintBuilt);
|
|
308
|
+
const stored = counts(session.store().driver);
|
|
309
|
+
if (mintResult.minted.length > 0) {
|
|
310
|
+
notes.push(`${mintResult.minted.length} human-confirmed answer(s) minted a USES_API edge this run. Every ` +
|
|
311
|
+
"one is capped at reliability class B regardless of the resolution it would otherwise earn " +
|
|
312
|
+
"(DEC-223) — a confirmed value is testimony, not a structural read.");
|
|
313
|
+
const stale = mintResult.minted.filter((m) => m.edge.attrs?.["staleFact"] === true).length;
|
|
314
|
+
if (stale > 0) {
|
|
315
|
+
notes.push(`${stale} of those edge(s) rest on an answer not affirmatively current for this commit — either ` +
|
|
316
|
+
"given against a different commit, or given before this system recorded which commit an answer " +
|
|
317
|
+
"was confirmed against. Not re-verified against live code (there is no live re-verification " +
|
|
318
|
+
"mechanism yet); disclosed on the edge's attrs.confirmedFacts[].staleness so a consumer can see " +
|
|
319
|
+
"it rather than treat an old answer as unconditionally current.");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (mintResult.orphaned.length > 0) {
|
|
323
|
+
notes.push(`${mintResult.orphaned.length} confirmed answer(s) named a path/method that matches no known ` +
|
|
324
|
+
"endpoint, so no edge was minted for them — never guessed into existence: " +
|
|
325
|
+
mintResult.orphaned.map((o) => `${o.method} ${o.path}`).join(", ") +
|
|
326
|
+
".");
|
|
327
|
+
}
|
|
328
|
+
if (mintResult.unjoinable.length > 0) {
|
|
329
|
+
notes.push(`${mintResult.unjoinable.length} confirmed answer(s) apply to a row with no resolved ` +
|
|
330
|
+
"path/method to join against at all, so no edge was minted for those either.");
|
|
331
|
+
}
|
|
332
|
+
if (mintPersisted.evictedFiles.length > 0) {
|
|
333
|
+
notes.push(`${mintPersisted.evictedFiles.length} file(s) that previously grounded a minted edge were not ` +
|
|
334
|
+
"in this run's askable set (their confirmed answer was removed, or the row it answered " +
|
|
335
|
+
"changed) — the edges they previously grounded have been retired, not left to coexist with " +
|
|
336
|
+
"whatever this run minted instead.");
|
|
337
|
+
}
|
|
338
|
+
// No code-reading source ran, so there is no level to report and nothing to
|
|
339
|
+
// rest a claim on. R0 rather than a cheerful default.
|
|
340
|
+
const floor = (codeResolutions.length === 0
|
|
341
|
+
? 0
|
|
342
|
+
: Math.min(...codeResolutions));
|
|
343
|
+
if (codeResolutions.length > 1 && new Set(codeResolutions).size > 1) {
|
|
344
|
+
notes.push(`Sources reached different resolution levels (R${Math.min(...codeResolutions)}-` +
|
|
345
|
+
`R${Math.max(...codeResolutions)}). The floor quoted here is the lowest of them, but an ` +
|
|
346
|
+
"individual answer computes its own from the edges it actually traversed, so a query " +
|
|
347
|
+
"confined to well-resolved code is not capped by the weakest source in the graph.");
|
|
348
|
+
}
|
|
349
|
+
const headline = batches.length === 0
|
|
350
|
+
? `Nothing was read from ${session.config.repo}.`
|
|
351
|
+
: `Analysed ${session.config.repo} at ${root.commitSha.slice(0, 12)}: ` +
|
|
352
|
+
`${stored.nodes} nodes, ${stored.edges} edges, ${stored.unresolvedRefs} disclosed gaps ` +
|
|
353
|
+
`across ${batches.length} source(s).`;
|
|
354
|
+
const refusalSummary = refusalSummaryField(built.unresolved);
|
|
355
|
+
return answer({
|
|
356
|
+
headline,
|
|
357
|
+
state: batches.length === 0 ? "refused" : "ok",
|
|
358
|
+
nameLevel: true,
|
|
359
|
+
resolutionFloor: floor,
|
|
360
|
+
commitSha: root.commitSha,
|
|
361
|
+
graphBuiltAt: Date.now(),
|
|
362
|
+
irSchemaVersion: session.provider().baseStamp().irSchemaVersion,
|
|
363
|
+
notes,
|
|
364
|
+
...(refusalSummary === undefined ? {} : { refusalSummary }),
|
|
365
|
+
data: {
|
|
366
|
+
repo: session.config.repo,
|
|
367
|
+
workspace: session.config.workspace ?? null,
|
|
368
|
+
commitSha: root.commitSha,
|
|
369
|
+
graphPath: session.graphPath,
|
|
370
|
+
sources: perSource,
|
|
371
|
+
sourcesFailed: registry.failed.map((f) => ({ module: f.spec.module, reason: f.reason })),
|
|
372
|
+
sourcesSkipped: skipped.map((s) => ({ source: s.source.source.id, reason: s.reason })),
|
|
373
|
+
stored,
|
|
374
|
+
merge: {
|
|
375
|
+
mergedNodes: built.mergedNodes,
|
|
376
|
+
mergedEdges: built.mergedEdges,
|
|
377
|
+
collisions: built.collisions.length,
|
|
378
|
+
droppedEdges: built.droppedEdges,
|
|
379
|
+
rejections: built.rejections.length,
|
|
380
|
+
},
|
|
381
|
+
joins: built.joins,
|
|
382
|
+
written: {
|
|
383
|
+
nodes: persisted.nodesWritten,
|
|
384
|
+
edges: persisted.edgesWritten,
|
|
385
|
+
unresolved: persisted.unresolvedWritten,
|
|
386
|
+
orphanedEdges: persisted.orphanedEdges,
|
|
387
|
+
evictedFiles: persisted.evictedFiles.length,
|
|
388
|
+
},
|
|
389
|
+
minted: {
|
|
390
|
+
edges: mintResult.minted.length,
|
|
391
|
+
orphaned: mintResult.orphaned.length,
|
|
392
|
+
unjoinable: mintResult.unjoinable.length,
|
|
393
|
+
evictedFiles: mintPersisted.evictedFiles.length,
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
export const analyzeTool = {
|
|
399
|
+
name: "analyze",
|
|
400
|
+
class: "stateful-read",
|
|
401
|
+
tier: "evidence",
|
|
402
|
+
version: "1.0.0",
|
|
403
|
+
title: "Analyse a repository into the code graph",
|
|
404
|
+
description: "Read the repository with every configured adapter and store the result as a code graph. " +
|
|
405
|
+
"Run this before any other Descry tool, and again after the working tree changes. Reports " +
|
|
406
|
+
"what it read, what it could not read, and the resolution level each adapter reached — the " +
|
|
407
|
+
"last one caps how strongly anything built on this graph may be stated.",
|
|
408
|
+
inputSchema: SCHEMA,
|
|
409
|
+
run,
|
|
410
|
+
};
|
|
411
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/tools/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `contracts` — "does the caller agree with the thing it is calling?"
|
|
3
|
+
*
|
|
4
|
+
* §13, in two halves that fail independently.
|
|
5
|
+
*
|
|
6
|
+
* **The path half runs today.** A call that reaches no route, a route nothing
|
|
7
|
+
* calls. Name-level facts, so R2 evidence supports them at class A.
|
|
8
|
+
*
|
|
9
|
+
* **The shape half needs both producers to attach something they do not attach
|
|
10
|
+
* yet**, and it names exactly what — see `engine.ts`. It reports
|
|
11
|
+
* `refused` with those names rather than an empty mismatch list, because
|
|
12
|
+
* "no contract mismatches found" is a false statement when nothing was compared.
|
|
13
|
+
*
|
|
14
|
+
* ## Why the tool is `ok` when only the path half ran
|
|
15
|
+
*
|
|
16
|
+
* The path half produced a real answer over real evidence. Marking the whole
|
|
17
|
+
* call `refused` because a second check did not run would hide a genuine
|
|
18
|
+
* finding behind a caveat about a different question. The shape half's status is
|
|
19
|
+
* carried in `data.shapes.ran` and in the blockers, where a reader can act on it.
|
|
20
|
+
*
|
|
21
|
+
* The one case that *is* `refused` outright: no endpoints in the graph.
|
|
22
|
+
* Then neither half looked at anything.
|
|
23
|
+
*/
|
|
24
|
+
import type { ContractCheck, ContractFindingKind, EndpointKey, NearMissKind, ShapeDifference, ShapeDirection } from "@descryy/core";
|
|
25
|
+
import type { ResolutionLevel } from "@descryy/ir";
|
|
26
|
+
import { type BriefNode, type ToolDefinition } from "./kit.ts";
|
|
27
|
+
/** A call that reaches no route, or a route nothing calls. */
|
|
28
|
+
export interface ContractPathFinding {
|
|
29
|
+
readonly kind: ContractFindingKind;
|
|
30
|
+
readonly method: string;
|
|
31
|
+
/** The normalised path template, not the raw literal. */
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly detail: string;
|
|
34
|
+
/** Lowest resolution among the edges this finding rests on. Caps its class. */
|
|
35
|
+
readonly resolution: ResolutionLevel;
|
|
36
|
+
/**
|
|
37
|
+
* Absent when nothing on the other side resembles this endpoint.
|
|
38
|
+
*
|
|
39
|
+
* Its absence is what separates a typo from a call into a service outside
|
|
40
|
+
* this graph — the second is disclosed as unanalysed, never reported broken.
|
|
41
|
+
*/
|
|
42
|
+
readonly nearMiss?: {
|
|
43
|
+
readonly kind: NearMissKind;
|
|
44
|
+
readonly against: EndpointKey;
|
|
45
|
+
};
|
|
46
|
+
/** Capped at five. Populated for a call that reaches no route. */
|
|
47
|
+
readonly callers: readonly BriefNode[];
|
|
48
|
+
/** Capped at five. Populated for a route nothing calls. */
|
|
49
|
+
readonly routes: readonly BriefNode[];
|
|
50
|
+
}
|
|
51
|
+
/** A field one side reads that the other does not send. Requires R3. */
|
|
52
|
+
export interface ContractShapeMismatchReport {
|
|
53
|
+
readonly endpoint: string;
|
|
54
|
+
readonly direction: ShapeDirection;
|
|
55
|
+
/** The side a missing field breaks. */
|
|
56
|
+
readonly reader: BriefNode;
|
|
57
|
+
/** The side that declares the shape. */
|
|
58
|
+
readonly writer: BriefNode;
|
|
59
|
+
readonly differences: readonly ShapeDifference[];
|
|
60
|
+
readonly resolution: ResolutionLevel;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The shape half's own status, carried in the payload rather than in the
|
|
64
|
+
* envelope.
|
|
65
|
+
*
|
|
66
|
+
* The call is `ok` when only the path half ran, because the path half produced
|
|
67
|
+
* a real answer over real evidence; marking the whole reply degraded because a
|
|
68
|
+
* second check did not run would hide a genuine finding behind a caveat about
|
|
69
|
+
* a different question. So `ran` is where a reader looks, and `blockers` names
|
|
70
|
+
* exactly what has to be attached before it can be true.
|
|
71
|
+
*/
|
|
72
|
+
export interface ContractShapeStatus {
|
|
73
|
+
readonly ran: boolean;
|
|
74
|
+
readonly comparable: number;
|
|
75
|
+
/** Endpoints with a shape on the consumer side only. */
|
|
76
|
+
readonly consumerOnly: number;
|
|
77
|
+
/** Endpoints with a shape on the provider side only. */
|
|
78
|
+
readonly providerOnly: number;
|
|
79
|
+
/** Routes naming a DTO with no request/response role, so direction is unknown. */
|
|
80
|
+
readonly unroledDtos: number;
|
|
81
|
+
/** Never empty when `ran` is false. */
|
|
82
|
+
readonly blockers: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* One shape, always.
|
|
86
|
+
*
|
|
87
|
+
* The counts in `checked` describe the **whole graph** even when `paths` was
|
|
88
|
+
* given: a denominator that shrank with the filter would make a narrow query
|
|
89
|
+
* look like a healthy repository. The two lists describe the filter.
|
|
90
|
+
*/
|
|
91
|
+
export interface ContractsData {
|
|
92
|
+
readonly findings: readonly ContractPathFinding[];
|
|
93
|
+
readonly shapeMismatches: readonly ContractShapeMismatchReport[];
|
|
94
|
+
readonly checked: ContractCheck["paths"]["checked"];
|
|
95
|
+
readonly shapes: ContractShapeStatus;
|
|
96
|
+
/**
|
|
97
|
+
* Unmatched callers with nothing on the provider side resembling them.
|
|
98
|
+
*
|
|
99
|
+
* Not findings. This is the size of the region the analysis could not speak
|
|
100
|
+
* about at all.
|
|
101
|
+
*/
|
|
102
|
+
readonly unmatchedWithoutNearMiss: number;
|
|
103
|
+
}
|
|
104
|
+
export declare const contractsTool: ToolDefinition;
|
|
105
|
+
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/tools/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,eAAe,EACf,cAAc,EACf,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAIL,KAAK,SAAS,EAEd,KAAK,cAAc,EACpB,MAAM,UAAU,CAAC;AAGlB,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC;IACnF,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;CACvC;AAED,wEAAwE;AACxE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wDAAwD;IACxD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAClD,QAAQ,CAAC,eAAe,EAAE,SAAS,2BAA2B,EAAE,CAAC;IACjE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC;CAC3C;AA0HD,eAAO,MAAM,aAAa,EAAE,cAe3B,CAAC"}
|