@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,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `propagation` — "if I change this field, where does it come out?"
|
|
3
|
+
*
|
|
4
|
+
* §11.9's data-flow query. The honest answer depends entirely on resolution and
|
|
5
|
+
* the tool says so on every call rather than only when it goes wrong.
|
|
6
|
+
*
|
|
7
|
+
* **Field-level propagation requires R3.** §11A.6 is explicit: propagation
|
|
8
|
+
* compares *shapes*, not names, and shapes are what a type checker buys. Below
|
|
9
|
+
* R3 this query still returns something useful — the paths data *can* travel —
|
|
10
|
+
* but "where the `currency` field ends up" and "which functions this value can
|
|
11
|
+
* reach" are different claims, and only the second is provable at R2. The query
|
|
12
|
+
* layer already computes the floor and writes the note; this tool's job is to
|
|
13
|
+
* make sure a caller cannot receive the answer without it, and to refuse to
|
|
14
|
+
* dress a path-level answer up as a field-level one in its headline.
|
|
15
|
+
*
|
|
16
|
+
* ## The empty answer is several different answers
|
|
17
|
+
*
|
|
18
|
+
* The resolution guard above was the only guard here, and it protects the
|
|
19
|
+
* *quality* of a non-empty answer. It says nothing about an empty one.
|
|
20
|
+
*
|
|
21
|
+
* **`PROPAGATES_TO` has no producer.** No adapter emits it, and it is the first
|
|
22
|
+
* of the four edge types this walk follows — five of §11.5's six hops are that
|
|
23
|
+
* type. So on a real graph this tool returned `reached: []` and a headline
|
|
24
|
+
* reading *"X can reach 0 node(s)"*: a user asks what propagates and is told
|
|
25
|
+
* nothing propagates. That is §20.2's fourth category collapsing into its
|
|
26
|
+
* second, in the user-facing surface rather than in an instrument, and it is
|
|
27
|
+
* the same defect `hidden-dependency.ts` carries `analysed` for.
|
|
28
|
+
*
|
|
29
|
+
* So an empty walk is now attributed rather than reported. The tool probes the
|
|
30
|
+
* edges incident to the start node and reports which of the requested types it
|
|
31
|
+
* found. **It deliberately does not claim which cause applies** — a local probe
|
|
32
|
+
* cannot separate *no producer emits this edge type* from *this node has none
|
|
33
|
+
* of them*, and guessing between them would be the same overreach one level
|
|
34
|
+
* down. It names the candidates and says it cannot choose.
|
|
35
|
+
*/
|
|
36
|
+
import { type BriefNode, type NodeCandidates, type ToolDefinition } from "./kit.ts";
|
|
37
|
+
/** A node the data can reach, with how far along the walk it sits. */
|
|
38
|
+
export interface ReachedNode extends BriefNode {
|
|
39
|
+
readonly depth: number;
|
|
40
|
+
readonly score: number;
|
|
41
|
+
}
|
|
42
|
+
export interface PropagationReport {
|
|
43
|
+
readonly from: BriefNode;
|
|
44
|
+
/** Capped by `limit`; `reachedTotal` is the uncapped count. */
|
|
45
|
+
readonly reached: readonly ReachedNode[];
|
|
46
|
+
readonly reachedTotal: number;
|
|
47
|
+
/**
|
|
48
|
+
* True only at R3 and above.
|
|
49
|
+
*
|
|
50
|
+
* False means the answer is *where data can flow*, not *which field arrives
|
|
51
|
+
* where* — the second compares shapes and shapes need a type checker.
|
|
52
|
+
*/
|
|
53
|
+
readonly fieldLevel: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* False when no edge of any walked type touches the start node.
|
|
56
|
+
*
|
|
57
|
+
* **An empty `reached` with `analysed: false` means the walk did not run**,
|
|
58
|
+
* not that nothing propagates. `PROPAGATES_TO` has no producer today, so
|
|
59
|
+
* this is the common case rather than the exotic one.
|
|
60
|
+
*/
|
|
61
|
+
readonly analysed: boolean;
|
|
62
|
+
readonly edgeTypesWalked: readonly string[];
|
|
63
|
+
/** The subset of `edgeTypesWalked` actually found on an edge touching this node. */
|
|
64
|
+
readonly edgeTypesPresent: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* One call, two shapes — narrow on `"from" in data`.
|
|
68
|
+
*
|
|
69
|
+
* `NodeCandidates` arrives when the symbol did not resolve to exactly one
|
|
70
|
+
* node, and nothing was walked.
|
|
71
|
+
*/
|
|
72
|
+
export type PropagationData = PropagationReport | NodeCandidates;
|
|
73
|
+
export declare const propagationTool: ToolDefinition;
|
|
74
|
+
//# sourceMappingURL=propagation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propagation.d.ts","sourceRoot":"","sources":["../../src/tools/propagation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,cAAc,EAEnB,KAAK,cAAc,EACpB,MAAM,UAAU,CAAC;AAGlB,sEAAsE;AACtE,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,oFAAoF;IACpF,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG,cAAc,CAAC;AAsKjE,eAAO,MAAM,eAAe,EAAE,cAY7B,CAAC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `propagation` — "if I change this field, where does it come out?"
|
|
3
|
+
*
|
|
4
|
+
* §11.9's data-flow query. The honest answer depends entirely on resolution and
|
|
5
|
+
* the tool says so on every call rather than only when it goes wrong.
|
|
6
|
+
*
|
|
7
|
+
* **Field-level propagation requires R3.** §11A.6 is explicit: propagation
|
|
8
|
+
* compares *shapes*, not names, and shapes are what a type checker buys. Below
|
|
9
|
+
* R3 this query still returns something useful — the paths data *can* travel —
|
|
10
|
+
* but "where the `currency` field ends up" and "which functions this value can
|
|
11
|
+
* reach" are different claims, and only the second is provable at R2. The query
|
|
12
|
+
* layer already computes the floor and writes the note; this tool's job is to
|
|
13
|
+
* make sure a caller cannot receive the answer without it, and to refuse to
|
|
14
|
+
* dress a path-level answer up as a field-level one in its headline.
|
|
15
|
+
*
|
|
16
|
+
* ## The empty answer is several different answers
|
|
17
|
+
*
|
|
18
|
+
* The resolution guard above was the only guard here, and it protects the
|
|
19
|
+
* *quality* of a non-empty answer. It says nothing about an empty one.
|
|
20
|
+
*
|
|
21
|
+
* **`PROPAGATES_TO` has no producer.** No adapter emits it, and it is the first
|
|
22
|
+
* of the four edge types this walk follows — five of §11.5's six hops are that
|
|
23
|
+
* type. So on a real graph this tool returned `reached: []` and a headline
|
|
24
|
+
* reading *"X can reach 0 node(s)"*: a user asks what propagates and is told
|
|
25
|
+
* nothing propagates. That is §20.2's fourth category collapsing into its
|
|
26
|
+
* second, in the user-facing surface rather than in an instrument, and it is
|
|
27
|
+
* the same defect `hidden-dependency.ts` carries `analysed` for.
|
|
28
|
+
*
|
|
29
|
+
* So an empty walk is now attributed rather than reported. The tool probes the
|
|
30
|
+
* edges incident to the start node and reports which of the requested types it
|
|
31
|
+
* found. **It deliberately does not claim which cause applies** — a local probe
|
|
32
|
+
* cannot separate *no producer emits this edge type* from *this node has none
|
|
33
|
+
* of them*, and guessing between them would be the same overreach one level
|
|
34
|
+
* down. It names the candidates and says it cannot choose.
|
|
35
|
+
*/
|
|
36
|
+
import { dataFlowFrom, DATA_FLOW_EDGE_TYPES } from "@descryy/core";
|
|
37
|
+
import { answer, briefNode, optionalInteger, optionalString, optionalStringArray, ToolInputError, } from "./kit.js";
|
|
38
|
+
import { resolveOneNode } from "./lookup.js";
|
|
39
|
+
const SCHEMA = {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
nodeId: { type: "string", description: "Graph node id to start from." },
|
|
43
|
+
symbol: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Symbol name to start from, when you do not have a node id. Ambiguity is reported rather " +
|
|
46
|
+
"than guessed at — narrow it with \"file\".",
|
|
47
|
+
},
|
|
48
|
+
file: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "Repository-relative path, to disambiguate \"symbol\" or to start from a file.",
|
|
51
|
+
},
|
|
52
|
+
edgeTypes: {
|
|
53
|
+
type: "array",
|
|
54
|
+
items: { type: "string" },
|
|
55
|
+
description: "Restrict the walk. Defaults to PROPAGATES_TO, READS, WRITES and RETURNS — the four that " +
|
|
56
|
+
"carry data rather than control.",
|
|
57
|
+
},
|
|
58
|
+
maxDepth: { type: "integer", minimum: 1, description: "Hop limit. Default unbounded." },
|
|
59
|
+
limit: {
|
|
60
|
+
type: "integer",
|
|
61
|
+
minimum: 1,
|
|
62
|
+
description: "Cap on nodes in the reply. Default 25 (MK-9 — the same walk-cost reduction impact.ts " +
|
|
63
|
+
"applies, for the same reason). A capped reply always discloses shown/total; raise this " +
|
|
64
|
+
"explicitly when the full set is needed.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
additionalProperties: false,
|
|
68
|
+
};
|
|
69
|
+
async function run(args, ctx) {
|
|
70
|
+
const nodeId = optionalString(args, "nodeId");
|
|
71
|
+
const symbol = optionalString(args, "symbol");
|
|
72
|
+
const file = optionalString(args, "file");
|
|
73
|
+
const edgeTypes = optionalStringArray(args, "edgeTypes");
|
|
74
|
+
const maxDepth = optionalInteger(args, "maxDepth", 1);
|
|
75
|
+
const limit = optionalInteger(args, "limit", 1) ?? 25;
|
|
76
|
+
if (nodeId === undefined && symbol === undefined && file === undefined) {
|
|
77
|
+
throw new ToolInputError('give one of "nodeId", "symbol" or "file"');
|
|
78
|
+
}
|
|
79
|
+
const found = resolveOneNode(ctx.session, { nodeId, symbol, file });
|
|
80
|
+
if (found.node === null) {
|
|
81
|
+
const base = ctx.session.provider().baseStamp();
|
|
82
|
+
return answer({
|
|
83
|
+
headline: found.headline,
|
|
84
|
+
state: "refused",
|
|
85
|
+
nameLevel: true,
|
|
86
|
+
resolutionFloor: 0,
|
|
87
|
+
commitSha: base.commitSha,
|
|
88
|
+
graphBuiltAt: base.graphBuiltAt,
|
|
89
|
+
irSchemaVersion: base.irSchemaVersion,
|
|
90
|
+
notes: found.notes,
|
|
91
|
+
data: { candidates: found.candidates.map(briefNode) },
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
ctx.progress(`Following data out of ${found.node.name}`);
|
|
95
|
+
const flow = dataFlowFrom(ctx.session.provider(), found.node.id, {
|
|
96
|
+
...(maxDepth === undefined ? {} : { maxDepth }),
|
|
97
|
+
...(edgeTypes === undefined ? {} : { types: edgeTypes }),
|
|
98
|
+
});
|
|
99
|
+
const reached = flow.data.filter((entry) => entry.node.id !== found.node?.id);
|
|
100
|
+
const shown = reached.slice(0, limit);
|
|
101
|
+
const notes = [...found.notes, ...flow.notes];
|
|
102
|
+
if (shown.length < reached.length) {
|
|
103
|
+
notes.push(`${reached.length - shown.length} further node(s) are on the path but not listed — the reply ` +
|
|
104
|
+
`is capped at ${limit}.`);
|
|
105
|
+
}
|
|
106
|
+
// Which of the walked edge types exist at all around the start node. This is
|
|
107
|
+
// the baseline precondition: with none of them present the walk had nothing
|
|
108
|
+
// to follow, and "reaches 0 nodes" is a statement about the graph's contents
|
|
109
|
+
// rather than about this symbol.
|
|
110
|
+
const walked = edgeTypes ?? DATA_FLOW_EDGE_TYPES;
|
|
111
|
+
const present = new Set();
|
|
112
|
+
for (const edge of [
|
|
113
|
+
...ctx.session.provider().outgoing(found.node.id),
|
|
114
|
+
...ctx.session.provider().incoming(found.node.id),
|
|
115
|
+
]) {
|
|
116
|
+
if (walked.includes(edge.type))
|
|
117
|
+
present.add(edge.type);
|
|
118
|
+
}
|
|
119
|
+
const absent = walked.filter((type) => !present.has(type));
|
|
120
|
+
const analysed = present.size > 0;
|
|
121
|
+
if (absent.length > 0) {
|
|
122
|
+
notes.push(`No ${absent.join(", ")} edge touches this node, so ${absent.length === 1 ? "that type" : "those types"} ` +
|
|
123
|
+
"contributed nothing to this answer.");
|
|
124
|
+
}
|
|
125
|
+
if (!analysed) {
|
|
126
|
+
notes.push(`None of the requested edge types (${walked.join(", ")}) appear on any edge touching this node, ` +
|
|
127
|
+
"so the walk had nothing to follow. That is not a finding that no data leaves this symbol: " +
|
|
128
|
+
"no producer emitting these edge types at all, a graph built without the source that would " +
|
|
129
|
+
"carry them, and a symbol that genuinely propagates nothing are three different situations. " +
|
|
130
|
+
"This probe is local to one node and cannot tell them apart — it reports that the walk did " +
|
|
131
|
+
"not run rather than choosing between them.");
|
|
132
|
+
}
|
|
133
|
+
const fieldLevel = flow.stamp.resolutionFloor >= 3;
|
|
134
|
+
return {
|
|
135
|
+
result: {
|
|
136
|
+
...flow,
|
|
137
|
+
data: {
|
|
138
|
+
from: briefNode(found.node),
|
|
139
|
+
reached: shown.map((entry) => ({
|
|
140
|
+
...briefNode(entry.node),
|
|
141
|
+
depth: entry.depth,
|
|
142
|
+
score: Number(entry.score.toFixed(4)),
|
|
143
|
+
})),
|
|
144
|
+
reachedTotal: reached.length,
|
|
145
|
+
fieldLevel,
|
|
146
|
+
/**
|
|
147
|
+
* False when no edge of any walked type touches the start node.
|
|
148
|
+
*
|
|
149
|
+
* **An empty `reached` with `analysed: false` means the walk did not
|
|
150
|
+
* run, not that nothing propagates.** Mirrors `HiddenDependencyReport`.
|
|
151
|
+
*/
|
|
152
|
+
analysed,
|
|
153
|
+
edgeTypesWalked: walked,
|
|
154
|
+
edgeTypesPresent: [...present].sort(),
|
|
155
|
+
},
|
|
156
|
+
notes,
|
|
157
|
+
},
|
|
158
|
+
...(analysed ? (reached.length === 0 ? { state: "empty" } : {}) : { state: "refused" }),
|
|
159
|
+
// Never name-level, at any resolution.
|
|
160
|
+
//
|
|
161
|
+
// §11A.5's R2 carve-out — class A for "name-level facts only" — is for
|
|
162
|
+
// single assertions about existence: a missing environment variable, a
|
|
163
|
+
// migration head. This tool's claim is that *data* travels a route, and data
|
|
164
|
+
// is a shape concern by nature: a `PROPAGATES_TO` edge derived without a
|
|
165
|
+
// type checker is a weaker fact than the resolved reference underneath it.
|
|
166
|
+
// So R3 and R4 reach A on their own merits and R2 is capped at B, which is
|
|
167
|
+
// the conservative reading and the one "when in doubt, understate" picks.
|
|
168
|
+
nameLevel: false,
|
|
169
|
+
// The headline is the sentence a user acts on, so the not-analysable case
|
|
170
|
+
// gets its own rather than reusing "reaches 0 node(s)" with a note beneath
|
|
171
|
+
// it. A count of zero in the headline reads as a measurement whatever the
|
|
172
|
+
// notes say.
|
|
173
|
+
headline: !analysed
|
|
174
|
+
? `Data flow out of ${found.node.name} was not analysed: the graph holds no ` +
|
|
175
|
+
`${walked.join("/")} edge touching it. This is not a finding that nothing propagates.`
|
|
176
|
+
: fieldLevel
|
|
177
|
+
? `Data from ${found.node.name} reaches ${reached.length} node(s), at field level.`
|
|
178
|
+
: `${found.node.name} can reach ${reached.length} node(s). This is where data *can* flow, ` +
|
|
179
|
+
"not which field arrives where — that needs R3.",
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export const propagationTool = {
|
|
183
|
+
name: "propagation",
|
|
184
|
+
class: "read",
|
|
185
|
+
tier: "evidence",
|
|
186
|
+
version: "1.0.0",
|
|
187
|
+
title: "Where does this data end up?",
|
|
188
|
+
description: "Follow a value from a symbol or field through the graph along the edges that carry data. " +
|
|
189
|
+
"Field-level answers require a type checker (R3); below that the answer is path-level and " +
|
|
190
|
+
"labelled as such rather than overstated.",
|
|
191
|
+
inputSchema: SCHEMA,
|
|
192
|
+
run,
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=propagation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propagation.js","sourceRoot":"","sources":["../../src/tools/propagation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `questions` — TIER-A-2's last mile: a human sees an open question and can
|
|
3
|
+
* answer it, in this conversation.
|
|
4
|
+
*
|
|
5
|
+
* Everything upstream of this tool already existed and was inert together:
|
|
6
|
+
* a refusal carries `attrs.blockedBy` + `attrs.refusalClass` (DEC-242) → the
|
|
7
|
+
* grouper collapses rows sharing both into one question (DEC-243) → a
|
|
8
|
+
* confirmed answer is stored and capped at reliability class B regardless of
|
|
9
|
+
* anything else (DEC-223). Nothing before this tool could show a question to
|
|
10
|
+
* a person or accept an answer back. This is that door — the same role
|
|
11
|
+
* `link_workspace` plays for the workspace-pairing declaration, except this
|
|
12
|
+
* one both reads and writes, because "what's still open" and "record an
|
|
13
|
+
* answer" are one conversation, not two round trips.
|
|
14
|
+
*
|
|
15
|
+
* ## One tool, not two — and not folded into `link_workspace`
|
|
16
|
+
*
|
|
17
|
+
* DEC-243 named two shapes and built neither: a dedicated tool, or extending
|
|
18
|
+
* `link_workspace`'s write pattern to accept a `ConfirmedFact`. Rejected the
|
|
19
|
+
* second explicitly: `session.ts`'s own `writeConfirmedFact` already exists
|
|
20
|
+
* as "a second, narrow writer... so a future field gets a third writer, not
|
|
21
|
+
* a branch in this one" — the identical reasoning applies one layer up.
|
|
22
|
+
* `link_workspace` is about workspace pairing; bolting an unrelated write
|
|
23
|
+
* concern onto it would be the tool-layer version of the shape drift DEC's
|
|
24
|
+
* own `MODEL.fields`/`DTO.fields` incident already cost this project once
|
|
25
|
+
* (§3.1). A dedicated tool that both lists and answers is one coherent
|
|
26
|
+
* concern — "the question queue" — read and write together because a caller
|
|
27
|
+
* asking "what's still open" immediately after recording an answer should
|
|
28
|
+
* see the queue that answer just shrank, not have to call twice.
|
|
29
|
+
*
|
|
30
|
+
* ## Answering re-computes locally rather than re-reading the file
|
|
31
|
+
*
|
|
32
|
+
* `session.config.confirmedFacts` is loaded once at session start and is
|
|
33
|
+
* `readonly` — writing via `writeConfirmedFact` does not update it in
|
|
34
|
+
* memory. Rather than reload `.descry/config.json` from disk mid-call, the
|
|
35
|
+
* just-written fact is merged into a local copy for this response only, the
|
|
36
|
+
* same way `writeConfirmedFact`'s own `replaced` return value already tells
|
|
37
|
+
* a caller what was overwritten without a second read.
|
|
38
|
+
*/
|
|
39
|
+
import type { RefusalDropCounts, RefusalQuestion } from "@descryy/core";
|
|
40
|
+
import type { ConfirmedFact } from "@descryy/ir";
|
|
41
|
+
import { type ToolDefinition } from "./kit.ts";
|
|
42
|
+
/**
|
|
43
|
+
* Both halves of one conversation: the queue, and the answer that just shrank it.
|
|
44
|
+
*
|
|
45
|
+
* Read and write together because a caller asking "what's still open"
|
|
46
|
+
* immediately after recording an answer should see the queue that answer
|
|
47
|
+
* changed, not have to call twice.
|
|
48
|
+
*/
|
|
49
|
+
export interface QuestionsData {
|
|
50
|
+
/**
|
|
51
|
+
* The `ConfirmedFact` written by this call, or null when none was given.
|
|
52
|
+
*
|
|
53
|
+
* A human assertion, not a graph fact: when it is later used to mint an
|
|
54
|
+
* edge, that edge is capped at reliability class B by DEC-223 regardless of
|
|
55
|
+
* anything else about it.
|
|
56
|
+
*/
|
|
57
|
+
readonly recorded: ConfirmedFact | null;
|
|
58
|
+
/**
|
|
59
|
+
* Rows a human could actually resolve, grouped by `blockedBy`.
|
|
60
|
+
*
|
|
61
|
+
* DEC-242's `value-unknown` class only. A reader-capability gap or a
|
|
62
|
+
* per-call value never appears here, because no sentence answers those.
|
|
63
|
+
*/
|
|
64
|
+
readonly questions: readonly RefusalQuestion[];
|
|
65
|
+
/** Every refusal-ledger row, classified or not. The outer denominator. */
|
|
66
|
+
readonly totalRefusalRows: number;
|
|
67
|
+
/**
|
|
68
|
+
* Of those, how many carry `attrs.blockedBy`/`refusalClass` at all.
|
|
69
|
+
*
|
|
70
|
+
* The gap between this and `totalRefusalRows` is rows no adapter classified:
|
|
71
|
+
* never askable, and **not the same population** as "still open".
|
|
72
|
+
*/
|
|
73
|
+
readonly classifiedRows: number;
|
|
74
|
+
/** Rows a stored confirmed fact already answers, so they are not listed as questions. */
|
|
75
|
+
readonly alreadyAnswered: number;
|
|
76
|
+
/** Rows dropped by refusal class, per DEC-242's own rule. */
|
|
77
|
+
readonly dropped: RefusalDropCounts;
|
|
78
|
+
}
|
|
79
|
+
export declare const questionsTool: ToolDefinition;
|
|
80
|
+
//# sourceMappingURL=questions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questions.d.ts","sourceRoot":"","sources":["../../src/tools/questions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EAA4E,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAGzH;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACrC;AAmLD,eAAO,MAAM,aAAa,EAAE,cAiB3B,CAAC"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `questions` — TIER-A-2's last mile: a human sees an open question and can
|
|
3
|
+
* answer it, in this conversation.
|
|
4
|
+
*
|
|
5
|
+
* Everything upstream of this tool already existed and was inert together:
|
|
6
|
+
* a refusal carries `attrs.blockedBy` + `attrs.refusalClass` (DEC-242) → the
|
|
7
|
+
* grouper collapses rows sharing both into one question (DEC-243) → a
|
|
8
|
+
* confirmed answer is stored and capped at reliability class B regardless of
|
|
9
|
+
* anything else (DEC-223). Nothing before this tool could show a question to
|
|
10
|
+
* a person or accept an answer back. This is that door — the same role
|
|
11
|
+
* `link_workspace` plays for the workspace-pairing declaration, except this
|
|
12
|
+
* one both reads and writes, because "what's still open" and "record an
|
|
13
|
+
* answer" are one conversation, not two round trips.
|
|
14
|
+
*
|
|
15
|
+
* ## One tool, not two — and not folded into `link_workspace`
|
|
16
|
+
*
|
|
17
|
+
* DEC-243 named two shapes and built neither: a dedicated tool, or extending
|
|
18
|
+
* `link_workspace`'s write pattern to accept a `ConfirmedFact`. Rejected the
|
|
19
|
+
* second explicitly: `session.ts`'s own `writeConfirmedFact` already exists
|
|
20
|
+
* as "a second, narrow writer... so a future field gets a third writer, not
|
|
21
|
+
* a branch in this one" — the identical reasoning applies one layer up.
|
|
22
|
+
* `link_workspace` is about workspace pairing; bolting an unrelated write
|
|
23
|
+
* concern onto it would be the tool-layer version of the shape drift DEC's
|
|
24
|
+
* own `MODEL.fields`/`DTO.fields` incident already cost this project once
|
|
25
|
+
* (§3.1). A dedicated tool that both lists and answers is one coherent
|
|
26
|
+
* concern — "the question queue" — read and write together because a caller
|
|
27
|
+
* asking "what's still open" immediately after recording an answer should
|
|
28
|
+
* see the queue that answer just shrank, not have to call twice.
|
|
29
|
+
*
|
|
30
|
+
* ## Answering re-computes locally rather than re-reading the file
|
|
31
|
+
*
|
|
32
|
+
* `session.config.confirmedFacts` is loaded once at session start and is
|
|
33
|
+
* `readonly` — writing via `writeConfirmedFact` does not update it in
|
|
34
|
+
* memory. Rather than reload `.descry/config.json` from disk mid-call, the
|
|
35
|
+
* just-written fact is merged into a local copy for this response only, the
|
|
36
|
+
* same way `writeConfirmedFact`'s own `replaced` return value already tells
|
|
37
|
+
* a caller what was overwritten without a second read.
|
|
38
|
+
*/
|
|
39
|
+
import { applyConfirmedFacts, counts, groupRefusalsIntoQuestions } from "@descryy/core";
|
|
40
|
+
import { writeConfirmedFact } from "../session.js";
|
|
41
|
+
import { answer, optionalString, requiredString, ToolInputError } from "./kit.js";
|
|
42
|
+
const SCHEMA = {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
answer: {
|
|
46
|
+
type: "object",
|
|
47
|
+
description: "Record a confirmed value for one question, keyed on the exact blockedBy string a question " +
|
|
48
|
+
"reports. Omit to only list what is still open.",
|
|
49
|
+
properties: {
|
|
50
|
+
blockedBy: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Must equal a question's own \"blockedBy\" field, byte for byte — no fuzzy match.",
|
|
53
|
+
},
|
|
54
|
+
value: { type: "string", description: "The confirmed literal value." },
|
|
55
|
+
environment: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: "Optional. Omit for an unscoped answer (the common case) — never infer one from the value " +
|
|
58
|
+
"itself (a hostname naming \"staging\" is not evidence the caller may read). A second answer " +
|
|
59
|
+
"with a different environment for the same blockedBy is a second fact, not a replacement.",
|
|
60
|
+
},
|
|
61
|
+
confirmedBy: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: "Free text — who or what is asserting this. Defaults to \"user\".",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
required: ["blockedBy", "value"],
|
|
67
|
+
additionalProperties: false,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
};
|
|
72
|
+
async function run(args, ctx) {
|
|
73
|
+
const { session } = ctx;
|
|
74
|
+
const notes = [];
|
|
75
|
+
let facts = session.config.confirmedFacts;
|
|
76
|
+
let recorded = null;
|
|
77
|
+
const answerArg = args["answer"];
|
|
78
|
+
if (answerArg !== undefined) {
|
|
79
|
+
if (typeof answerArg !== "object" || answerArg === null) {
|
|
80
|
+
throw new ToolInputError('"answer" must be an object');
|
|
81
|
+
}
|
|
82
|
+
const a = answerArg;
|
|
83
|
+
const blockedBy = requiredString(a, "blockedBy");
|
|
84
|
+
const value = requiredString(a, "value");
|
|
85
|
+
const environment = optionalString(a, "environment");
|
|
86
|
+
const confirmedBy = optionalString(a, "confirmedBy") ?? "user";
|
|
87
|
+
// "Against what" (see ConfirmedFact.confirmedAtCommit) — the repo's own
|
|
88
|
+
// commit at the moment this answer is given, so a later mint can tell
|
|
89
|
+
// whether the code has moved since a human said this value was correct.
|
|
90
|
+
// Best-effort: a repo path with no git history (a fixture, a non-git
|
|
91
|
+
// checkout) simply cannot supply one, and that is exactly the "unknown"
|
|
92
|
+
// case `confirmedAtCommit` is designed to carry as an absence rather than
|
|
93
|
+
// a guess — never let this recording fail because the disclosure couldn't.
|
|
94
|
+
const confirmedAtCommit = await session
|
|
95
|
+
.root()
|
|
96
|
+
.then((r) => r.commitSha)
|
|
97
|
+
.catch(() => undefined);
|
|
98
|
+
recorded = {
|
|
99
|
+
repo: session.config.repo,
|
|
100
|
+
blockedBy,
|
|
101
|
+
value,
|
|
102
|
+
...(environment === undefined ? {} : { environment }),
|
|
103
|
+
confirmedBy,
|
|
104
|
+
confirmedAt: new Date().toISOString(),
|
|
105
|
+
...(confirmedAtCommit === undefined ? {} : { confirmedAtCommit }),
|
|
106
|
+
};
|
|
107
|
+
ctx.progress(`Recording an answer for ${blockedBy}${environment === undefined ? "" : ` (${environment})`}`);
|
|
108
|
+
const written = await writeConfirmedFact(session.repoPath, recorded);
|
|
109
|
+
const sameKey = (f) => f.repo === recorded?.repo && f.blockedBy === recorded.blockedBy && f.environment === recorded.environment;
|
|
110
|
+
facts = [...facts.filter((f) => !sameKey(f)), recorded];
|
|
111
|
+
notes.push(written.replaced === null
|
|
112
|
+
? `Recorded a new answer for "${blockedBy}"${environment === undefined ? "" : ` in "${environment}"`}.`
|
|
113
|
+
: `Replaced the previous answer for "${blockedBy}"` +
|
|
114
|
+
`${environment === undefined ? "" : ` in "${environment}"`} (was "${written.replaced.value}", ` +
|
|
115
|
+
`confirmed ${written.replaced.confirmedAt}).`);
|
|
116
|
+
}
|
|
117
|
+
ctx.progress("Reading the refusal ledger");
|
|
118
|
+
const provider = session.provider();
|
|
119
|
+
const { refs, truncated } = provider.unresolvedRefs();
|
|
120
|
+
const total = counts(session.store().driver).unresolvedRefs;
|
|
121
|
+
const { answered, stillOpen } = applyConfirmedFacts(refs, facts, session.config.repo);
|
|
122
|
+
const grouped = groupRefusalsIntoQuestions(session.config.repo, stillOpen);
|
|
123
|
+
if (truncated) {
|
|
124
|
+
notes.push("The classified-refusal read was capped and some rows were not examined — this list may be " +
|
|
125
|
+
"incomplete. Re-run with a narrower scope, or treat this as a lower bound.");
|
|
126
|
+
}
|
|
127
|
+
if (total > refs.length) {
|
|
128
|
+
notes.push(`${total - refs.length} of ${total} refusal-ledger row(s) carry no classification at all yet ` +
|
|
129
|
+
"(no adapter has set attrs.blockedBy/refusalClass for them) — never askable, not counted " +
|
|
130
|
+
"above, and not the same population as \"still open\".");
|
|
131
|
+
}
|
|
132
|
+
if (answered.length > 0) {
|
|
133
|
+
notes.push(`${answered.length} previously-open row(s) are already answered by a stored confirmed fact and ` +
|
|
134
|
+
"are not listed as questions.");
|
|
135
|
+
}
|
|
136
|
+
for (const [cls, count] of Object.entries(grouped.dropped)) {
|
|
137
|
+
if (cls === "value-unknown")
|
|
138
|
+
continue; // never dropped under its own class name
|
|
139
|
+
notes.push(`${count} row(s) are "${cls}" — DEC-242's own rule: not askable, never surfaced here.`);
|
|
140
|
+
}
|
|
141
|
+
const headline = grouped.questions.length === 0
|
|
142
|
+
? recorded !== null
|
|
143
|
+
? `Answer recorded. No open questions remain in ${session.config.repo}.`
|
|
144
|
+
: `No open questions in ${session.config.repo}. ${refs.length} classified refusal row(s) examined.`
|
|
145
|
+
: `${grouped.questions.length} open question(s) in ${session.config.repo}, covering ` +
|
|
146
|
+
`${grouped.questions.reduce((n, q) => n + q.sites.length, 0)} call site(s).`;
|
|
147
|
+
return answer({
|
|
148
|
+
headline,
|
|
149
|
+
// Existence of a question is a name-level fact — the expression is
|
|
150
|
+
// present in source or it is not, the same class as a missing
|
|
151
|
+
// environment variable. Whether it has been *answered* is a separate
|
|
152
|
+
// axis this tool never conflates with resolution. `UnresolvedRef` itself
|
|
153
|
+
// carries no resolution level (refusals are not edges and were never
|
|
154
|
+
// scored, per DEC-223's own matching function), so R0 is the honest
|
|
155
|
+
// floor rather than a borrowed number — the same choice `link_workspace`
|
|
156
|
+
// makes for the same reason: this is not a claim resting on graph edges.
|
|
157
|
+
nameLevel: true,
|
|
158
|
+
resolutionFloor: 0,
|
|
159
|
+
commitSha: provider.baseStamp().commitSha,
|
|
160
|
+
graphBuiltAt: provider.baseStamp().graphBuiltAt,
|
|
161
|
+
irSchemaVersion: provider.baseStamp().irSchemaVersion,
|
|
162
|
+
// Empty only for a pure read that found nothing open — the classified
|
|
163
|
+
// population is real (`classifiedRows`). Recording an answer that happens
|
|
164
|
+
// to empty the queue is a successful write, not an empty search.
|
|
165
|
+
...(recorded === null && grouped.questions.length === 0 ? { state: "empty" } : {}),
|
|
166
|
+
notes,
|
|
167
|
+
data: {
|
|
168
|
+
recorded,
|
|
169
|
+
questions: grouped.questions,
|
|
170
|
+
totalRefusalRows: total,
|
|
171
|
+
classifiedRows: refs.length,
|
|
172
|
+
alreadyAnswered: answered.length,
|
|
173
|
+
dropped: grouped.dropped,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* §7's handshake gate. `undefined` means this call has nothing to confirm —
|
|
179
|
+
* a pure read of the open-question queue (no `answer` given) must stay
|
|
180
|
+
* answerable on the first call, or this tool could not answer the first
|
|
181
|
+
* question ever asked of it. Only a call that would actually write a
|
|
182
|
+
* `ConfirmedFact` describes itself, so `resolveActionDispatch` mints a token
|
|
183
|
+
* for that call alone.
|
|
184
|
+
*/
|
|
185
|
+
function describeAction(args) {
|
|
186
|
+
const a = args["answer"];
|
|
187
|
+
if (typeof a !== "object" || a === null)
|
|
188
|
+
return undefined;
|
|
189
|
+
const { blockedBy, value, environment } = a;
|
|
190
|
+
if (typeof blockedBy !== "string" || typeof value !== "string")
|
|
191
|
+
return undefined;
|
|
192
|
+
return (`record a ConfirmedFact: "${blockedBy}" = "${value}"` +
|
|
193
|
+
(typeof environment === "string" ? ` (environment: ${environment})` : "") +
|
|
194
|
+
" — capped at reliability class B (DEC-223) once used.");
|
|
195
|
+
}
|
|
196
|
+
export const questionsTool = {
|
|
197
|
+
name: "questions",
|
|
198
|
+
class: "action",
|
|
199
|
+
tier: "evidence",
|
|
200
|
+
version: "1.0.0",
|
|
201
|
+
title: "See and answer open refusal-ledger questions",
|
|
202
|
+
description: "List every refusal-ledger row a human could actually resolve (DEC-242's \"value-unknown\" " +
|
|
203
|
+
"class only — a reader-capability gap or a per-call value is never surfaced here, because no " +
|
|
204
|
+
"sentence answers those). Pass \"answer\" to record a confirmed value for one question, keyed " +
|
|
205
|
+
"on its exact \"blockedBy\" string within this repository; the answer is capped at reliability " +
|
|
206
|
+
"class B when later used, regardless of anything else about the edge it resolves (DEC-223). " +
|
|
207
|
+
"Recording an answer takes a two-call confirmation: the first call with \"answer\" performs " +
|
|
208
|
+
"nothing and returns a token; call again with \"confirmToken\" to actually record it.",
|
|
209
|
+
inputSchema: SCHEMA,
|
|
210
|
+
run,
|
|
211
|
+
describeAction,
|
|
212
|
+
};
|
|
213
|
+
//# sourceMappingURL=questions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questions.js","sourceRoot":"","sources":["../../src/tools/questions.ts"],"names":[],"mappings":"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"}
|