@descryy/mcp 0.5.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.
Files changed (260) hide show
  1. package/dist/action-handshake.d.ts +8 -75
  2. package/dist/action-handshake.d.ts.map +1 -1
  3. package/dist/action-handshake.js +9 -79
  4. package/dist/action-handshake.js.map +1 -1
  5. package/dist/bin/descry-mcp.d.ts +4 -15
  6. package/dist/bin/descry-mcp.d.ts.map +1 -1
  7. package/dist/bin/descry-mcp.js +12 -42
  8. package/dist/bin/descry-mcp.js.map +1 -1
  9. package/dist/browser/driver.d.ts +62 -178
  10. package/dist/browser/driver.d.ts.map +1 -1
  11. package/dist/browser/driver.js +14 -46
  12. package/dist/browser/driver.js.map +1 -1
  13. package/dist/browser/evidence.d.ts +11 -35
  14. package/dist/browser/evidence.d.ts.map +1 -1
  15. package/dist/browser/evidence.js +25 -51
  16. package/dist/browser/evidence.js.map +1 -1
  17. package/dist/browser/fake-driver.d.ts +12 -16
  18. package/dist/browser/fake-driver.d.ts.map +1 -1
  19. package/dist/browser/fake-driver.js +24 -17
  20. package/dist/browser/fake-driver.js.map +1 -1
  21. package/dist/browser/graph-write.d.ts +4 -45
  22. package/dist/browser/graph-write.d.ts.map +1 -1
  23. package/dist/browser/graph-write.js +8 -53
  24. package/dist/browser/graph-write.js.map +1 -1
  25. package/dist/browser/playwright-driver.d.ts +17 -67
  26. package/dist/browser/playwright-driver.d.ts.map +1 -1
  27. package/dist/browser/playwright-driver.js +169 -166
  28. package/dist/browser/playwright-driver.js.map +1 -1
  29. package/dist/browser/provider.d.ts +5 -34
  30. package/dist/browser/provider.d.ts.map +1 -1
  31. package/dist/browser/provider.js +4 -24
  32. package/dist/browser/provider.js.map +1 -1
  33. package/dist/browser/registry.d.ts +26 -106
  34. package/dist/browser/registry.d.ts.map +1 -1
  35. package/dist/browser/registry.js +20 -77
  36. package/dist/browser/registry.js.map +1 -1
  37. package/dist/browser/scenario-resolve.d.ts +10 -44
  38. package/dist/browser/scenario-resolve.d.ts.map +1 -1
  39. package/dist/browser/scenario-resolve.js +10 -41
  40. package/dist/browser/scenario-resolve.js.map +1 -1
  41. package/dist/browser/scenario-runner.d.ts +12 -70
  42. package/dist/browser/scenario-runner.d.ts.map +1 -1
  43. package/dist/browser/scenario-runner.js +33 -91
  44. package/dist/browser/scenario-runner.js.map +1 -1
  45. package/dist/browser/stack-parser.d.ts +4 -28
  46. package/dist/browser/stack-parser.d.ts.map +1 -1
  47. package/dist/browser/stack-parser.js +12 -39
  48. package/dist/browser/stack-parser.js.map +1 -1
  49. package/dist/browser/tool-support.d.ts +20 -67
  50. package/dist/browser/tool-support.d.ts.map +1 -1
  51. package/dist/browser/tool-support.js +22 -66
  52. package/dist/browser/tool-support.js.map +1 -1
  53. package/dist/browser/url-scheme.d.ts +14 -0
  54. package/dist/browser/url-scheme.d.ts.map +1 -0
  55. package/dist/browser/url-scheme.js +38 -0
  56. package/dist/browser/url-scheme.js.map +1 -0
  57. package/dist/cancellation.d.ts +11 -46
  58. package/dist/cancellation.d.ts.map +1 -1
  59. package/dist/cancellation.js +11 -46
  60. package/dist/cancellation.js.map +1 -1
  61. package/dist/capped.d.ts +17 -0
  62. package/dist/capped.d.ts.map +1 -0
  63. package/dist/capped.js +15 -0
  64. package/dist/capped.js.map +1 -0
  65. package/dist/disclosure-ledger.d.ts +6 -30
  66. package/dist/disclosure-ledger.d.ts.map +1 -1
  67. package/dist/disclosure-ledger.js +4 -26
  68. package/dist/disclosure-ledger.js.map +1 -1
  69. package/dist/index.d.ts +10 -26
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +7 -17
  72. package/dist/index.js.map +1 -1
  73. package/dist/module-trust.d.ts +24 -0
  74. package/dist/module-trust.d.ts.map +1 -0
  75. package/dist/module-trust.js +60 -0
  76. package/dist/module-trust.js.map +1 -0
  77. package/dist/path-confinement.d.ts +31 -0
  78. package/dist/path-confinement.d.ts.map +1 -0
  79. package/dist/path-confinement.js +44 -0
  80. package/dist/path-confinement.js.map +1 -0
  81. package/dist/protocol.d.ts +10 -53
  82. package/dist/protocol.d.ts.map +1 -1
  83. package/dist/protocol.js +14 -60
  84. package/dist/protocol.js.map +1 -1
  85. package/dist/registry.d.ts +10 -58
  86. package/dist/registry.d.ts.map +1 -1
  87. package/dist/registry.js +38 -90
  88. package/dist/registry.js.map +1 -1
  89. package/dist/render.d.ts +79 -11
  90. package/dist/render.d.ts.map +1 -1
  91. package/dist/render.js +126 -14
  92. package/dist/render.js.map +1 -1
  93. package/dist/runtime-registry.d.ts +8 -49
  94. package/dist/runtime-registry.d.ts.map +1 -1
  95. package/dist/runtime-registry.js +72 -63
  96. package/dist/runtime-registry.js.map +1 -1
  97. package/dist/scenarios/index.d.ts +1 -1
  98. package/dist/scenarios/index.d.ts.map +1 -1
  99. package/dist/scenarios/index.js +1 -1
  100. package/dist/scenarios/index.js.map +1 -1
  101. package/dist/scenarios/parse.d.ts +4 -18
  102. package/dist/scenarios/parse.d.ts.map +1 -1
  103. package/dist/scenarios/parse.js +14 -34
  104. package/dist/scenarios/parse.js.map +1 -1
  105. package/dist/scenarios/scenario.d.ts +18 -74
  106. package/dist/scenarios/scenario.d.ts.map +1 -1
  107. package/dist/scenarios/scenario.js +7 -34
  108. package/dist/scenarios/scenario.js.map +1 -1
  109. package/dist/scenarios/storage.d.ts +11 -41
  110. package/dist/scenarios/storage.d.ts.map +1 -1
  111. package/dist/scenarios/storage.js +57 -47
  112. package/dist/scenarios/storage.js.map +1 -1
  113. package/dist/server.d.ts.map +1 -1
  114. package/dist/server.js +55 -13
  115. package/dist/server.js.map +1 -1
  116. package/dist/session.d.ts +69 -239
  117. package/dist/session.d.ts.map +1 -1
  118. package/dist/session.js +76 -231
  119. package/dist/session.js.map +1 -1
  120. package/dist/tools/analyze.d.ts +27 -101
  121. package/dist/tools/analyze.d.ts.map +1 -1
  122. package/dist/tools/analyze.js +58 -148
  123. package/dist/tools/analyze.js.map +1 -1
  124. package/dist/tools/browser-click.d.ts +3 -21
  125. package/dist/tools/browser-click.d.ts.map +1 -1
  126. package/dist/tools/browser-click.js +10 -31
  127. package/dist/tools/browser-click.js.map +1 -1
  128. package/dist/tools/browser-close-session.d.ts +4 -13
  129. package/dist/tools/browser-close-session.d.ts.map +1 -1
  130. package/dist/tools/browser-close-session.js +4 -13
  131. package/dist/tools/browser-close-session.js.map +1 -1
  132. package/dist/tools/browser-fill.d.ts +5 -36
  133. package/dist/tools/browser-fill.d.ts.map +1 -1
  134. package/dist/tools/browser-fill.js +9 -44
  135. package/dist/tools/browser-fill.js.map +1 -1
  136. package/dist/tools/browser-navigate.d.ts +6 -27
  137. package/dist/tools/browser-navigate.d.ts.map +1 -1
  138. package/dist/tools/browser-navigate.js +6 -23
  139. package/dist/tools/browser-navigate.js.map +1 -1
  140. package/dist/tools/browser-run-scenario.d.ts +5 -31
  141. package/dist/tools/browser-run-scenario.d.ts.map +1 -1
  142. package/dist/tools/browser-run-scenario.js +10 -46
  143. package/dist/tools/browser-run-scenario.js.map +1 -1
  144. package/dist/tools/browser-save-scenario.d.ts +3 -28
  145. package/dist/tools/browser-save-scenario.d.ts.map +1 -1
  146. package/dist/tools/browser-save-scenario.js +102 -55
  147. package/dist/tools/browser-save-scenario.js.map +1 -1
  148. package/dist/tools/browser-snapshot.d.ts +6 -39
  149. package/dist/tools/browser-snapshot.d.ts.map +1 -1
  150. package/dist/tools/browser-snapshot.js +4 -31
  151. package/dist/tools/browser-snapshot.js.map +1 -1
  152. package/dist/tools/browser-start-session.d.ts +4 -23
  153. package/dist/tools/browser-start-session.d.ts.map +1 -1
  154. package/dist/tools/browser-start-session.js +38 -51
  155. package/dist/tools/browser-start-session.js.map +1 -1
  156. package/dist/tools/browser-type.d.ts +5 -35
  157. package/dist/tools/browser-type.d.ts.map +1 -1
  158. package/dist/tools/browser-type.js +10 -45
  159. package/dist/tools/browser-type.js.map +1 -1
  160. package/dist/tools/contracts.d.ts +17 -63
  161. package/dist/tools/contracts.d.ts.map +1 -1
  162. package/dist/tools/contracts.js +91 -47
  163. package/dist/tools/contracts.js.map +1 -1
  164. package/dist/tools/cross-pr.d.ts +56 -15
  165. package/dist/tools/cross-pr.d.ts.map +1 -1
  166. package/dist/tools/cross-pr.js +141 -38
  167. package/dist/tools/cross-pr.js.map +1 -1
  168. package/dist/tools/git-diff.d.ts +18 -2
  169. package/dist/tools/git-diff.d.ts.map +1 -1
  170. package/dist/tools/git-diff.js +143 -23
  171. package/dist/tools/git-diff.js.map +1 -1
  172. package/dist/tools/git-history.d.ts +5 -16
  173. package/dist/tools/git-history.d.ts.map +1 -1
  174. package/dist/tools/git-history.js +3 -10
  175. package/dist/tools/git-history.js.map +1 -1
  176. package/dist/tools/history.d.ts +4 -33
  177. package/dist/tools/history.d.ts.map +1 -1
  178. package/dist/tools/history.js +6 -31
  179. package/dist/tools/history.js.map +1 -1
  180. package/dist/tools/impact.d.ts +7 -51
  181. package/dist/tools/impact.d.ts.map +1 -1
  182. package/dist/tools/impact.js +15 -67
  183. package/dist/tools/impact.js.map +1 -1
  184. package/dist/tools/index.d.ts +3 -8
  185. package/dist/tools/index.d.ts.map +1 -1
  186. package/dist/tools/index.js +3 -8
  187. package/dist/tools/index.js.map +1 -1
  188. package/dist/tools/kit.d.ts +66 -113
  189. package/dist/tools/kit.d.ts.map +1 -1
  190. package/dist/tools/kit.js +60 -28
  191. package/dist/tools/kit.js.map +1 -1
  192. package/dist/tools/link-workspace.d.ts +7 -45
  193. package/dist/tools/link-workspace.d.ts.map +1 -1
  194. package/dist/tools/link-workspace.js +10 -48
  195. package/dist/tools/link-workspace.js.map +1 -1
  196. package/dist/tools/lookup.d.ts +4 -14
  197. package/dist/tools/lookup.d.ts.map +1 -1
  198. package/dist/tools/lookup.js +4 -14
  199. package/dist/tools/lookup.js.map +1 -1
  200. package/dist/tools/mark-incident.d.ts +7 -54
  201. package/dist/tools/mark-incident.d.ts.map +1 -1
  202. package/dist/tools/mark-incident.js +15 -68
  203. package/dist/tools/mark-incident.js.map +1 -1
  204. package/dist/tools/observe-runtime.d.ts +27 -210
  205. package/dist/tools/observe-runtime.d.ts.map +1 -1
  206. package/dist/tools/observe-runtime.js +258 -436
  207. package/dist/tools/observe-runtime.js.map +1 -1
  208. package/dist/tools/observe-tests.d.ts +9 -88
  209. package/dist/tools/observe-tests.d.ts.map +1 -1
  210. package/dist/tools/observe-tests.js +34 -108
  211. package/dist/tools/observe-tests.js.map +1 -1
  212. package/dist/tools/pr-analysis.d.ts +18 -2
  213. package/dist/tools/pr-analysis.d.ts.map +1 -1
  214. package/dist/tools/pr-analysis.js +73 -23
  215. package/dist/tools/pr-analysis.js.map +1 -1
  216. package/dist/tools/pre-push.d.ts +94 -9
  217. package/dist/tools/pre-push.d.ts.map +1 -1
  218. package/dist/tools/pre-push.js +139 -34
  219. package/dist/tools/pre-push.js.map +1 -1
  220. package/dist/tools/propagation.d.ts +11 -53
  221. package/dist/tools/propagation.d.ts.map +1 -1
  222. package/dist/tools/propagation.js +14 -57
  223. package/dist/tools/propagation.js.map +1 -1
  224. package/dist/tools/questions.d.ts +13 -63
  225. package/dist/tools/questions.d.ts.map +1 -1
  226. package/dist/tools/questions.js +33 -105
  227. package/dist/tools/questions.js.map +1 -1
  228. package/dist/tools/refusal-fetch.d.ts +4 -40
  229. package/dist/tools/refusal-fetch.d.ts.map +1 -1
  230. package/dist/tools/refusal-fetch.js +4 -40
  231. package/dist/tools/refusal-fetch.js.map +1 -1
  232. package/dist/tools/runtime-incident.d.ts +4 -63
  233. package/dist/tools/runtime-incident.d.ts.map +1 -1
  234. package/dist/tools/runtime-incident.js +10 -87
  235. package/dist/tools/runtime-incident.js.map +1 -1
  236. package/dist/tools/scope.d.ts +7 -25
  237. package/dist/tools/scope.d.ts.map +1 -1
  238. package/dist/tools/scope.js +17 -20
  239. package/dist/tools/scope.js.map +1 -1
  240. package/dist/tools/similar-incidents.d.ts +11 -86
  241. package/dist/tools/similar-incidents.d.ts.map +1 -1
  242. package/dist/tools/similar-incidents.js +7 -71
  243. package/dist/tools/similar-incidents.js.map +1 -1
  244. package/dist/tools/validate.d.ts +31 -47
  245. package/dist/tools/validate.d.ts.map +1 -1
  246. package/dist/tools/validate.js +133 -61
  247. package/dist/tools/validate.js.map +1 -1
  248. package/dist/tools/verification-status.d.ts +9 -64
  249. package/dist/tools/verification-status.d.ts.map +1 -1
  250. package/dist/tools/verification-status.js +9 -62
  251. package/dist/tools/verification-status.js.map +1 -1
  252. package/dist/tools/verify-claim.d.ts +5 -52
  253. package/dist/tools/verify-claim.d.ts.map +1 -1
  254. package/dist/tools/verify-claim.js +6 -56
  255. package/dist/tools/verify-claim.js.map +1 -1
  256. package/dist/transport.d.ts +15 -52
  257. package/dist/transport.d.ts.map +1 -1
  258. package/dist/transport.js +16 -60
  259. package/dist/transport.js.map +1 -1
  260. package/package.json +33 -16
@@ -30,8 +30,8 @@
30
30
  * times in one reply. `indexPrAnalysisNodes` collapses that: the lists name
31
31
  * ids, `nodes` holds each node once. Tool version 2.0.0 for it.
32
32
  */
33
- import { changedFiles, changeRisk, NODE_BUDGETS, nodesInFiles, withProminence } from "@descryy/core";
34
- import { answer, briefNode, optionalEnum, optionalInteger, optionalString, requiredString, } from "./kit.js";
33
+ import { changedFiles, changeRisk, NODE_BUDGETS, nodesInFiles, withProminence, workingTreeChangedFiles, } from "@descryy/core";
34
+ import { answer, briefNode, optionalEnum, optionalInteger, descryOwnState, optionalString, ToolInputError, } from "./kit.js";
35
35
  /**
36
36
  * Collapse three overlapping node lists into one map plus three id lists.
37
37
  *
@@ -64,9 +64,24 @@ const SCHEMA = {
64
64
  base: {
65
65
  type: "string",
66
66
  description: "The branch or commit this change is measured against, e.g. \"main\" or \"origin/main\". " +
67
- "Required — there is no defensible default, and guessing one silently changes the diff.",
67
+ "Required unless \"workingTree\" is given — there is no defensible default, and guessing " +
68
+ "one silently changes the diff.",
68
69
  },
69
70
  head: { type: "string", description: "The tip being reviewed. Default HEAD." },
71
+ workingTree: {
72
+ type: "string",
73
+ enum: ["unstaged", "staged", "all"],
74
+ description: "Review the change as it stands in the working tree rather than between two refs — the " +
75
+ "change about to be committed, including files git has never seen. \"all\" is staged and " +
76
+ "unstaged together. Mutually exclusive with \"base\", and never inferred: the two answer " +
77
+ "different questions, so the caller declares which one they are asking. Which ran is " +
78
+ "stated in the reply.",
79
+ },
80
+ includeUntracked: {
81
+ type: "boolean",
82
+ description: "With \"workingTree\", include files git has never seen. On by default — a new file " +
83
+ "written and not yet added is part of the change about to be committed.",
84
+ },
70
85
  trigger: {
71
86
  type: "string",
72
87
  enum: [...TRIGGERS],
@@ -74,26 +89,60 @@ const SCHEMA = {
74
89
  },
75
90
  limit: { type: "integer", minimum: 1, description: "Cap on nodes per list. Default 50." },
76
91
  },
77
- required: ["base"],
78
92
  additionalProperties: false,
79
93
  };
80
94
  async function run(args, ctx) {
81
- // Required rather than defaulted: there is no defensible default base, and
82
- // guessing one would silently change which diff the whole answer describes.
83
- const base = requiredString(args, "base");
84
- const head = optionalString(args, "head") ?? "HEAD";
95
+ // One of the two questions has to be chosen, and neither has a defensible
96
+ // default: guessing would silently change which change set the whole answer
97
+ // describes. This tool's own reasoning is that the diff is what defines a
98
+ // change to review — a working tree *is* a diff, it is simply not a
99
+ // ref-to-ref one, so accepting it completes that principle rather than
100
+ // bending it. Which one ran is stated in the reply.
101
+ const workingTree = optionalString(args, "workingTree");
102
+ const includeUntracked = args["includeUntracked"] !== false;
103
+ const baseArg = optionalString(args, "base");
104
+ if (workingTree === undefined && baseArg === undefined) {
105
+ throw new ToolInputError('Give either "base" (a ref range) or "workingTree" (the change as it stands, uncommitted). ' +
106
+ "There is no defensible default, and guessing one silently changes which change set the " +
107
+ "answer describes.");
108
+ }
109
+ if (workingTree !== undefined && baseArg !== undefined) {
110
+ throw new ToolInputError('"base" and "workingTree" are mutually exclusive — they are two different questions. Ask one.');
111
+ }
112
+ if (workingTree !== undefined && !["unstaged", "staged", "all"].includes(workingTree)) {
113
+ throw new ToolInputError(`"workingTree" must be "unstaged", "staged" or "all" — got "${workingTree}".`);
114
+ }
115
+ const scope = (workingTree ?? "all");
116
+ const mode = baseArg === undefined ? "working-tree" : "range";
117
+ const base = baseArg ?? null;
118
+ const head = base === null ? null : optionalString(args, "head") ?? "HEAD";
119
+ const subject = base === null ? `the working tree (${scope})` : `${base}...${head}`;
120
+ /** Carried into every one of the four reply shapes, so none can omit it. */
121
+ const identity = {
122
+ mode,
123
+ base,
124
+ head,
125
+ ...(base === null ? { workingTree: { scope, includeUntracked } } : {}),
126
+ };
85
127
  const trigger = optionalEnum(args, "trigger", TRIGGERS) ?? "pr";
86
128
  const limit = optionalInteger(args, "limit", 1) ?? 50;
87
129
  const session = ctx.session;
88
130
  const stamp = session.provider().baseStamp();
89
- ctx.progress(`Diffing ${base}...${head}`);
131
+ ctx.progress(`Diffing ${subject}`);
90
132
  let files;
91
133
  try {
92
- files = await changedFiles(session.repoPath, base, head);
134
+ files =
135
+ base === null
136
+ ? await workingTreeChangedFiles(session.repoPath, {
137
+ scope,
138
+ includeUntracked,
139
+ exclude: descryOwnState(session.config.graph),
140
+ })
141
+ : await changedFiles(session.repoPath, base, head);
93
142
  }
94
143
  catch (error) {
95
144
  return answer({
96
- headline: `Could not diff ${base}...${head}.`,
145
+ headline: `Could not diff ${subject}.`,
97
146
  state: "refused",
98
147
  nameLevel: true,
99
148
  resolutionFloor: 0,
@@ -102,16 +151,18 @@ async function run(args, ctx) {
102
151
  irSchemaVersion: stamp.irSchemaVersion,
103
152
  commitSpread: stamp.commitSpread,
104
153
  notes: [
105
- `git rejected the range: ${error.message.trim()}. Check that "${base}" exists ` +
106
- "locally — a shallow clone or a missing fetch is the usual cause.",
154
+ (base === null
155
+ ? `git rejected the working-tree read: ${error.message.trim()}.`
156
+ : `git rejected the range: ${error.message.trim()}. Check that "${base}" ` +
157
+ "exists locally — a shallow clone or a missing fetch is the usual cause."),
107
158
  ],
108
- data: { base, head, files: [] },
159
+ data: { ...identity, files: [] },
109
160
  });
110
161
  }
111
162
  const notes = [];
112
163
  if (files.length === 0) {
113
164
  return answer({
114
- headline: `${base}...${head} changes no files.`,
165
+ headline: `${subject} changes no files.`,
115
166
  nameLevel: true,
116
167
  // 0, not 4. Every other branch of this tool already stamps 0 for the same
117
168
  // reason `get_git_diff` does — a live git read is not a graph-traversal
@@ -124,7 +175,7 @@ async function run(args, ctx) {
124
175
  irSchemaVersion: stamp.irSchemaVersion,
125
176
  commitSpread: stamp.commitSpread,
126
177
  notes: ["An empty diff is a real answer: there is nothing to assess."],
127
- data: { base, head, files: [], nodes: {}, affected: [], untested: [], tests: [] },
178
+ data: { ...identity, files: [], nodes: {}, affected: [], untested: [], tests: [] },
128
179
  });
129
180
  }
130
181
  ctx.progress(`Resolving ${files.length} changed file(s)`, 1, 3);
@@ -137,7 +188,7 @@ async function run(args, ctx) {
137
188
  }
138
189
  if (nodes.length === 0) {
139
190
  return answer({
140
- headline: `None of the ${files.length} changed file(s) are in the graph.`,
191
+ headline: `None of the ${files.length} file(s) changed in ${subject} are in the graph.`,
141
192
  state: "refused",
142
193
  nameLevel: true,
143
194
  resolutionFloor: 0,
@@ -150,7 +201,7 @@ async function run(args, ctx) {
150
201
  "No blast radius was computed. Run analyze first; if it has already run, its disclosures " +
151
202
  "name the languages and paths it could not read.",
152
203
  ],
153
- data: { base, head, files, missing, nodes: {}, affected: [], untested: [], tests: [] },
204
+ data: { ...identity, files, missing, nodes: {}, affected: [], untested: [], tests: [] },
154
205
  });
155
206
  }
156
207
  ctx.progress(`Assessing ${nodes.length} changed symbol(s)`, 2, 3);
@@ -173,8 +224,7 @@ async function run(args, ctx) {
173
224
  result: {
174
225
  ...risk,
175
226
  data: {
176
- base,
177
- head,
227
+ ...identity,
178
228
  files,
179
229
  missing,
180
230
  changedSymbols: nodes.length,
@@ -187,9 +237,9 @@ async function run(args, ctx) {
187
237
  },
188
238
  ...(affected.length === 0 ? { state: "empty" } : {}),
189
239
  nameLevel: true,
190
- headline: `${nodes.length} changed symbol(s) across ${files.length} file(s) affect ${affected.length} ` +
191
- `other node(s). ${risk.data.tests.length} test(s) cover part of that; ${untested.length} ` +
192
- "affected node(s) have no covering test in the graph.",
240
+ headline: `Across ${subject}: ${nodes.length} changed symbol(s) in ${files.length} file(s) affect ` +
241
+ `${affected.length} other node(s). ${risk.data.tests.length} test(s) cover part of that; ` +
242
+ `${untested.length} affected node(s) have no covering test in the graph.`,
193
243
  };
194
244
  }
195
245
  export const prAnalysisTool = {
@@ -1 +1 @@
1
- {"version":3,"file":"pr-analysis.js","sourceRoot":"","sources":["../../src/tools/pr-analysis.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pr-analysis.js","sourceRoot":"","sources":["../../src/tools/pr-analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,MAAM,EACN,SAAS,EACT,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,GAIf,MAAM,UAAU,CAAC;AAsDlB;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAqG,EACrG,QAAkC,EAClC,KAA+B;IAE/B,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,CAAC,IAAmB,EAAU,EAAE;QAC/C,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,cAAc,CACtB,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACvB,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YACxB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACrC,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC,CACJ;QACD,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,KAAK;KACN,CAAC;AACJ,CAAC;AA2ED,MAAM,QAAQ,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAU,CAAC;AAExD,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,0FAA0F;gBAC1F,0FAA0F;gBAC1F,gCAAgC;SACnC;QACD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAE;QAC9E,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC;YACnC,WAAW,EACT,wFAAwF;gBACxF,0FAA0F;gBAC1F,0FAA0F;gBAC1F,sFAAsF;gBACtF,sBAAsB;SACzB;QACD,gBAAgB,EAAE;YAChB,IAAI,EAAE,SAAS;YACf,WAAW,EACT,qFAAqF;gBACrF,wEAAwE;SAC3E;QACD,OAAO,EAAE;YACP,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,GAAG,QAAQ,CAAC;YACnB,WAAW,EAAE,wCAAwC;SACtD;QACD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,oCAAoC,EAAE;KAC1F;IACD,oBAAoB,EAAE,KAAK;CACnB,CAAC;AAIX,KAAK,UAAU,GAAG,CAChB,IAA6B,EAC7B,GAAgB;IAEhB,0EAA0E;IAC1E,4EAA4E;IAC5E,0EAA0E;IAC1E,oEAAoE;IACpE,uEAAuE;IACvE,oDAAoD;IACpD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACxD,MAAM,gBAAgB,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,KAAK,CAAC;IAC5D,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,IAAI,WAAW,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACvD,MAAM,IAAI,cAAc,CACtB,4FAA4F;YAC1F,yFAAyF;YACzF,mBAAmB,CACtB,CAAC;IACJ,CAAC;IACD,IAAI,WAAW,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACvD,MAAM,IAAI,cAAc,CACtB,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IACD,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,cAAc,CAAC,8DAA8D,WAAW,IAAI,CAAC,CAAC;IAC1G,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,WAAW,IAAI,KAAK,CAAkC,CAAC;IACtE,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAE,cAAwB,CAAC,CAAC,CAAE,OAAiB,CAAC;IACpF,MAAM,IAAI,GAAG,OAAO,IAAI,IAAI,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC;IAC3E,MAAM,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,IAAI,EAAE,CAAC;IACpF,4EAA4E;IAC5E,MAAM,QAAQ,GAAG;QACf,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvE,CAAC;IACF,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC;IAChE,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,CAAC;IAE7C,GAAG,CAAC,QAAQ,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;IACnC,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK;YACH,IAAI,KAAK,IAAI;gBACX,CAAC,CAAC,MAAM,uBAAuB,CAAC,OAAO,CAAC,QAAQ,EAAE;oBAC9C,KAAK;oBACL,gBAAgB;oBAChB,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;iBAC9C,CAAC;gBACJ,CAAC,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAK,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,MAAM,CAAiB;YAC5B,QAAQ,EAAE,kBAAkB,OAAO,GAAG;YACtC,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,IAAI;YACf,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,KAAK,EAAE;gBACL,CAAC,IAAI,KAAK,IAAI;oBACZ,CAAC,CAAC,uCAAwC,KAAe,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG;oBAC3E,CAAC,CAAC,2BAA4B,KAAe,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,IAAI,IAAI;wBACnF,yEAAyE,CAAC;aAC/E;YACD,IAAI,EAAE,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;SACjC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,MAAM,CAAiB;YAC5B,QAAQ,EAAE,GAAG,OAAO,oBAAoB;YACxC,SAAS,EAAE,IAAI;YACf,0EAA0E;YAC1E,wEAAwE;YACxE,wEAAwE;YACxE,0EAA0E;YAC1E,wEAAwE;YACxE,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,KAAK,EAAE,CAAC,6DAA6D,CAAC;YACtE,IAAI,EAAE,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;SACnF,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,QAAQ,CAAC,aAAa,KAAK,CAAC,MAAM,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACvE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CACR,GAAG,OAAO,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,6CAA6C;YAC/E,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,sBAAsB;YAC1F,wFAAwF;YACxF,6DAA6D,CAChE,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,MAAM,CAAiB;YAC5B,QAAQ,EAAE,eAAe,KAAK,CAAC,MAAM,uBAAuB,OAAO,oBAAoB;YACvF,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,IAAI;YACf,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,KAAK,EAAE;gBACL,GAAG,KAAK;gBACR,0FAA0F;oBACxF,iDAAiD;aACpD;YACD,IAAI,EAAE,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;SACxF,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,QAAQ,CAAC,aAAa,KAAK,CAAC,MAAM,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,+EAA+E;IAC/E,2EAA2E;IAC3E,2EAA2E;IAC3E,iCAAiC;IACjC,MAAM,IAAI,GAAG,UAAU,CACrB,OAAO,CAAC,QAAQ,EAAE,EAClB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACtB,EAAE,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,CAClC,CAAC;IAEF,KAAK,CAAC,IAAI,CACR,6FAA6F;QAC3F,4FAA4F;QAC5F,uBAAuB,CAC1B,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IAEvF,0EAA0E;IAC1E,4EAA4E;IAC5E,kBAAkB;IAClB,MAAM,KAAK,GAAG,oBAAoB,CAChC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EACxB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EACxB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAChC,CAAC;IAEF,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO;QACL,MAAM,EAAE;YACN,GAAG,IAAI;YACP,IAAI,EAAE;gBACJ,GAAG,QAAQ;gBACX,KAAK;gBACL,OAAO;gBACP,cAAc,EAAE,KAAK,CAAC,MAAM;gBAC5B,aAAa,EAAE,QAAQ,CAAC,MAAM;gBAC9B,aAAa,EAAE,QAAQ,CAAC,MAAM;gBAC9B,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;gBAClC,GAAG,KAAK;aACT;YACD,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC;SACjC;QACD,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,SAAS,EAAE,IAAI;QACf,QAAQ,EACN,UAAU,OAAO,KAAK,KAAK,CAAC,MAAM,yBAAyB,KAAK,CAAC,MAAM,kBAAkB;YACzF,GAAG,QAAQ,CAAC,MAAM,mBAAmB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,+BAA+B;YAC1F,GAAG,QAAQ,CAAC,MAAM,uDAAuD;KAC5E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,UAAU;IAChB,uEAAuE;IACvE,0EAA0E;IAC1E,2EAA2E;IAC3E,yDAAyD;IACzD,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,mDAAmD;IAC1D,WAAW,EACT,6FAA6F;QAC7F,0FAA0F;QAC1F,6FAA6F;QAC7F,uBAAuB;IACzB,WAAW,EAAE,MAA4C;IACzD,GAAG;CACJ,CAAC"}
@@ -38,12 +38,28 @@
38
38
  *
39
39
  * ## Blocking versus informational
40
40
  *
41
- * `blockingTotal` counts `contracts` and `validate` findings only. Those are
42
- * claims that something is *wrong*. `scope` and `pr_analysis` answer "what does
43
- * this change touch" — real, useful, and not a defect, so counting them would
44
- * make every change with a blast radius look like a failure. `descry check`
45
- * exits non-zero on `blockingTotal`, which is why the line has to be drawn
46
- * here rather than left to the caller.
41
+ * `blockingTotal` counts `contracts` and `validate` findings only, and — since
42
+ * UAT round 3, Suggestion 6 — only the ones each tool's own `claim` field
43
+ * marks a `defect`. `scope` and `pr_analysis` answer "what does this change
44
+ * touch" — real, useful, and not a defect, so counting them would make every
45
+ * change with a blast radius look like a failure. A `lead` (`ROUTE_NOT_CALLED`,
46
+ * `SET_BUT_UNDOCUMENTED`) is worth a look but is not provable from the graph
47
+ * alone, so it is counted separately in `leadTotal` rather than folded into
48
+ * the number a git hook branches on. `descry check` exits non-zero on
49
+ * `blockingTotal`, which is why the line has to be drawn here rather than
50
+ * left to the caller.
51
+ *
52
+ * ## Scoped to what you are pushing
53
+ *
54
+ * UAT round 3, B11. `contracts` did not receive the `files` this tool was
55
+ * called with, so `blockingTotal` counted the repository's entire standing
56
+ * backlog rather than the change being pushed — 15 pre-existing
57
+ * `ROUTE_NOT_CALLED` findings for unrelated paths, on a push touching three
58
+ * unrelated files. `contracts` now takes the same `files` this tool was
59
+ * given (it already accepted `paths`, a different axis — a URL template
60
+ * substring, not a source file), so both blocking sources answer about the
61
+ * files in front of the developer. `validate` already took `files`; only the
62
+ * threading into `contracts` was missing.
47
63
  *
48
64
  * ## Class and tier
49
65
  *
@@ -60,18 +76,87 @@ export interface PrePushSection {
60
76
  readonly total: number;
61
77
  /** The top few, in the order that source reported them. */
62
78
  readonly shown: readonly unknown[];
63
- /** True when this source's findings count toward `blockingTotal`. */
64
- readonly blocking: boolean;
79
+ /**
80
+ * True when this source is **the kind that claims something is wrong** —
81
+ * a property of the source, not of what it found this time.
82
+ *
83
+ * **It was called `blocking`, sitting beside a `blockingTotal` that means the
84
+ * other thing.** `contracts` can be `blocking: true` with `total: 0`, and
85
+ * `validate` `blocking: true` with ten leads and a `blockingTotal` of zero,
86
+ * so the obvious consumer arithmetic — sum `total` over the blocking
87
+ * sections — is wrong in both directions. This tool's own test suite made
88
+ * exactly that mistake and passed, because the fixture happened to produce no
89
+ * leads.
90
+ *
91
+ * The name now says which question it answers. The other question — *did this
92
+ * section find anything that blocks?* — is `defects > 0`, and there is no
93
+ * longer a field whose name suggests it answers both.
94
+ */
95
+ readonly claimsFaults: boolean;
96
+ /** Of `total`, how many assert a fault. Zero for a source that claims none. */
97
+ readonly defects: number;
98
+ /** Of `total`, how many are worth a look without asserting one. */
99
+ readonly leads: number;
65
100
  /** This source's own headline, kept verbatim. */
66
101
  readonly headline: string;
67
102
  }
103
+ /**
104
+ * Which change set the coverage section actually described.
105
+ *
106
+ * `pr_analysis` derives its own file list from `base...head` and takes none,
107
+ * deliberately. Three constituents therefore describe the files passed and one
108
+ * describes the branch's committed diff, and in a real run those were 2 files
109
+ * and 25. Both answers were right; presented side by side under one headline
110
+ * they read as one answer about one change.
111
+ *
112
+ * The disclosure explaining that has always been in the reply. It sat below a
113
+ * headline and a section total that both read as though they described the
114
+ * files passed, which is the wrong order for the most common working moment:
115
+ * before a commit, when the git-derived half can see none of the work.
116
+ */
117
+ export interface PrePushCoverage {
118
+ /** The ref-to-ref diff `pr_analysis` answered about. */
119
+ readonly describes: string;
120
+ /** Files passed that the base diff does not contain — whatever the reason. */
121
+ readonly filesOutsideDiff: readonly string[];
122
+ /**
123
+ * Of those, the ones git reports as modified, staged or untracked.
124
+ *
125
+ * Separated because "not in the diff" has two causes and only one is about
126
+ * timing: uncommitted work the developer can commit, versus a file they named
127
+ * that this branch never touched.
128
+ */
129
+ readonly uncommitted: readonly string[];
130
+ }
68
131
  export interface PrePushData {
69
132
  readonly files: readonly string[];
70
133
  readonly sections: readonly PrePushSection[];
71
- /** Contract and environment findings only — see the module header on why scope is not counted. */
134
+ /**
135
+ * Contract and environment findings that **assert a fault**.
136
+ *
137
+ * The doctrine that keeps `scope` and `pr_analysis` out of this number is the
138
+ * same one that keeps a lead out of it: a change with a large blast radius is
139
+ * not a broken change, and neither is a route no code in this graph calls.
140
+ * Both constituents already knew which of their findings claimed a fault —
141
+ * `validate` in a field, `contracts` in the prose of the finding itself — and
142
+ * this composite flattened them into one count a git hook exits on.
143
+ *
144
+ * "15 blocking findings" and "1 defect, 15 leads" are different sentences and
145
+ * only one is worth acting on. A check that cries wolf is worse than no
146
+ * check, because it also discredits the real findings underneath it.
147
+ */
72
148
  readonly blockingTotal: number;
149
+ /** Findings worth a look that assert nothing. Reported, never exited on. */
150
+ readonly leadTotal: number;
73
151
  /** The node budget actually applied to the traversing constituents. */
74
152
  readonly nodeBudget: number;
153
+ /**
154
+ * What the coverage section was about, when one ran.
155
+ *
156
+ * `null` when no base ref was given: `pr_analysis` is skipped entirely then,
157
+ * and a caveat about a section that did not run is a caveat about nothing.
158
+ */
159
+ readonly coverage: PrePushCoverage | null;
75
160
  }
76
161
  export declare const prePushTool: ToolDefinition;
77
162
  //# sourceMappingURL=pre-push.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pre-push.d.ts","sourceRoot":"","sources":["../../src/tools/pre-push.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAKH,OAAO,EAML,KAAK,cAAc,EACpB,MAAM,UAAU,CAAC;AAuClB,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAE/E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IACnC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,kGAAkG;IAClG,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAgND,eAAO,MAAM,WAAW,EAAE,cAezB,CAAC"}
1
+ {"version":3,"file":"pre-push.d.ts","sourceRoot":"","sources":["../../src/tools/pre-push.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAKH,OAAO,EAML,KAAK,cAAc,EACpB,MAAM,UAAU,CAAC;AAuClB,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAE/E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IACnC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAC3C;AAoTD,eAAO,MAAM,WAAW,EAAE,cAiBzB,CAAC"}
@@ -38,19 +38,35 @@
38
38
  *
39
39
  * ## Blocking versus informational
40
40
  *
41
- * `blockingTotal` counts `contracts` and `validate` findings only. Those are
42
- * claims that something is *wrong*. `scope` and `pr_analysis` answer "what does
43
- * this change touch" — real, useful, and not a defect, so counting them would
44
- * make every change with a blast radius look like a failure. `descry check`
45
- * exits non-zero on `blockingTotal`, which is why the line has to be drawn
46
- * here rather than left to the caller.
41
+ * `blockingTotal` counts `contracts` and `validate` findings only, and — since
42
+ * UAT round 3, Suggestion 6 — only the ones each tool's own `claim` field
43
+ * marks a `defect`. `scope` and `pr_analysis` answer "what does this change
44
+ * touch" — real, useful, and not a defect, so counting them would make every
45
+ * change with a blast radius look like a failure. A `lead` (`ROUTE_NOT_CALLED`,
46
+ * `SET_BUT_UNDOCUMENTED`) is worth a look but is not provable from the graph
47
+ * alone, so it is counted separately in `leadTotal` rather than folded into
48
+ * the number a git hook branches on. `descry check` exits non-zero on
49
+ * `blockingTotal`, which is why the line has to be drawn here rather than
50
+ * left to the caller.
51
+ *
52
+ * ## Scoped to what you are pushing
53
+ *
54
+ * UAT round 3, B11. `contracts` did not receive the `files` this tool was
55
+ * called with, so `blockingTotal` counted the repository's entire standing
56
+ * backlog rather than the change being pushed — 15 pre-existing
57
+ * `ROUTE_NOT_CALLED` findings for unrelated paths, on a push touching three
58
+ * unrelated files. `contracts` now takes the same `files` this tool was
59
+ * given (it already accepted `paths`, a different axis — a URL template
60
+ * substring, not a source file), so both blocking sources answer about the
61
+ * files in front of the developer. `validate` already took `files`; only the
62
+ * threading into `contracts` was missing.
47
63
  *
48
64
  * ## Class and tier
49
65
  *
50
66
  * `read` — it runs four read tools and writes nothing. `evidence` — it reports
51
67
  * what those four found and draws no conclusion of its own.
52
68
  */
53
- import { NODE_BUDGETS } from "@descryy/core";
69
+ import { NODE_BUDGETS, uncommittedAmong } from "@descryy/core";
54
70
  import { contractsTool } from "./contracts.js";
55
71
  import { answer, optionalInteger, optionalString, optionalStringArray, } from "./kit.js";
56
72
  import { prAnalysisTool } from "./pr-analysis.js";
@@ -97,8 +113,44 @@ function listOf(data, key) {
97
113
  const value = data[key];
98
114
  return Array.isArray(value) ? value : [];
99
115
  }
116
+ /**
117
+ * A finding's own claim, defaulting to `defect` when it carries none.
118
+ *
119
+ * The default is deliberate and it is the safe direction: a source that has not
120
+ * yet been taught the distinction has its findings counted as fault claims, so
121
+ * adding a check can never silently stop blocking a push. The opposite default
122
+ * would turn every un-migrated source into a source of leads overnight.
123
+ */
124
+ function claimOf(item) {
125
+ return typeof item === "object" &&
126
+ item !== null &&
127
+ item["claim"] === "lead"
128
+ ? "lead"
129
+ : "defect";
130
+ }
131
+ /**
132
+ * The leading clause, when the coverage section is about a different change set.
133
+ *
134
+ * **First, not in a footnote.** This mismatch has always been disclosed, and
135
+ * the disclosure sat underneath a headline and a section total that both read
136
+ * as if they described the files passed. A reader who stops at the headline —
137
+ * which is what a headline is for — got a confident sentence about the wrong
138
+ * work. Ordering is the whole fix.
139
+ *
140
+ * Empty when it does not apply, because a caveat printed on every run is one a
141
+ * reader learns to skip past on the run where it matters.
142
+ */
143
+ function coverageWarning(files, coverage) {
144
+ if (coverage === null || coverage.uncommitted.length === 0)
145
+ return "";
146
+ const n = coverage.uncommitted.length;
147
+ return (`${n} of ${files.length} file(s) are uncommitted, so the pr_analysis section describes ` +
148
+ `committed work only (${coverage.describes}) and not them. ` +
149
+ "The other three sections describe the files you passed. ");
150
+ }
100
151
  async function run(args, ctx) {
101
152
  const files = optionalStringArray(args, "files") ?? [];
153
+ let coverage = null;
102
154
  const perSource = optionalInteger(args, "perSource", 1) ?? PER_SOURCE;
103
155
  const baseRef = optionalString(args, "base");
104
156
  const base = ctx.session.provider().baseStamp();
@@ -110,9 +162,10 @@ async function run(args, ctx) {
110
162
  "Sources are NOT ranked against each other. Whether a contract mismatch outranks an unset " +
111
163
  "environment variable is a judgement Descry has no model for, so each source contributes its " +
112
164
  "own top few and the totals say what they were selected from.",
113
- "blockingTotal counts contracts and validate findings only. scope and pr_analysis answer what a " +
114
- "change touches, which is not a defect — counting them would make every change with a blast " +
115
- "radius look like a failure.",
165
+ "blockingTotal counts contracts and validate findings claimed as defects only — see claim on " +
166
+ "each finding. scope and pr_analysis answer what a change touches, which is not a defect, and " +
167
+ "a lead (worth a look, not provable from the graph alone) is counted separately in leadTotal " +
168
+ "rather than folded into the number a hook branches on.",
116
169
  ];
117
170
  if (files.length === 0) {
118
171
  return answer({
@@ -125,7 +178,7 @@ async function run(args, ctx) {
125
178
  irSchemaVersion: base.irSchemaVersion,
126
179
  commitSpread: base.commitSpread,
127
180
  notes,
128
- data: { files: [], sections: [], blockingTotal: 0, nodeBudget },
181
+ data: { files: [], sections: [], blockingTotal: 0, leadTotal: 0, nodeBudget, coverage: null },
129
182
  });
130
183
  }
131
184
  // Sequential rather than concurrent, deliberately: these share one SQLite
@@ -138,7 +191,7 @@ async function run(args, ctx) {
138
191
  // three that were not -- the same leaked-default failure this repository's
139
192
  // own UAT caught on a refusal path.
140
193
  const floors = [];
141
- const runOne = async (source, tool, toolArgs, pick, blocking) => {
194
+ const runOne = async (source, tool, toolArgs, pick, claimsFaults, claimOf = () => "defect") => {
142
195
  ctx.progress(`Running ${source}`);
143
196
  let sub;
144
197
  try {
@@ -153,23 +206,32 @@ async function run(args, ctx) {
153
206
  state: "failed",
154
207
  total: 0,
155
208
  shown: [],
156
- blocking,
209
+ claimsFaults,
210
+ defects: 0,
211
+ leads: 0,
157
212
  headline: `${source} failed: ${error instanceof Error ? error.message : String(error)}`,
158
213
  });
159
- return;
214
+ return null;
160
215
  }
161
216
  floors.push(sub.resolutionFloor);
162
217
  const items = pick(sub.data);
218
+ // A source that does not claim anything is wrong contributes to neither
219
+ // count, whatever it found — the split is about fault claims, and `scope`
220
+ // makes none.
221
+ const leads = claimsFaults ? items.filter((item) => claimOf(item) === "lead").length : 0;
163
222
  sections.push({
164
223
  source,
165
224
  state: sub.state,
166
225
  total: items.length,
167
226
  shown: items.slice(0, perSource),
168
- blocking,
227
+ claimsFaults,
228
+ defects: claimsFaults ? items.length - leads : 0,
229
+ leads,
169
230
  headline: sub.headline,
170
231
  });
171
232
  for (const note of sub.notes)
172
233
  collectedNotes.push(`${source}: ${note}`);
234
+ return sub;
173
235
  };
174
236
  await runOne("scope", scopeTool, { files, trigger: "pre-push" }, (data) => listOf(data, "affected"), false);
175
237
  if (baseRef === undefined) {
@@ -182,7 +244,9 @@ async function run(args, ctx) {
182
244
  state: "refused",
183
245
  total: 0,
184
246
  shown: [],
185
- blocking: false,
247
+ claimsFaults: false,
248
+ defects: 0,
249
+ leads: 0,
186
250
  headline: "pr_analysis needs a base ref to diff against and has no default. Pass \"base\" to include it.",
187
251
  });
188
252
  }
@@ -197,16 +261,52 @@ async function run(args, ctx) {
197
261
  `${baseRef}...HEAD), not from the files given here: it takes no file list, deliberately, ` +
198
262
  "because the diff is what defines a change to review. So its section may describe a wider " +
199
263
  "or narrower set of files than the other three, which use the list you passed.");
200
- await runOne("pr_analysis", prAnalysisTool, { base: baseRef, trigger: "pre-push" }, (data) => listOf(data, "untested"), false);
264
+ const pr = await runOne("pr_analysis", prAnalysisTool, { base: baseRef, trigger: "pre-push" }, (data) => listOf(data, "untested"), false);
265
+ if (pr !== null) {
266
+ // The comparison is against the list `pr_analysis` itself reports, not a
267
+ // second diff computed here. Two git calls answering the same question
268
+ // is how they come to disagree.
269
+ const inDiff = new Set(listOf(pr.data, "files").filter((f) => typeof f === "string"));
270
+ const outside = files.filter((file) => !inDiff.has(file));
271
+ // A failure here must not take the other three constituents with it —
272
+ // the rule this file already states for a constituent, applied to the
273
+ // caveat about one. Without the classification the reply still reports
274
+ // which files the coverage section did not describe; it just cannot say
275
+ // that the reason was timing.
276
+ let uncommitted = [];
277
+ try {
278
+ uncommitted = await uncommittedAmong(ctx.session.repoPath, outside);
279
+ }
280
+ catch (error) {
281
+ if (outside.length > 0) {
282
+ notes.push(`${outside.length} file(s) you passed are not in ${baseRef}...HEAD, and git could ` +
283
+ `not be asked whether that is because they are uncommitted: ` +
284
+ `${error.message.trim()}. They are listed in coverage.filesOutsideDiff.`);
285
+ }
286
+ }
287
+ coverage = {
288
+ describes: `${baseRef}...HEAD`,
289
+ filesOutsideDiff: outside,
290
+ uncommitted,
291
+ };
292
+ }
201
293
  }
202
294
  await runOne("contracts", contractsTool,
203
- // pathsOnly is what the pre-push tier means for a tool with no traversal to
204
- // budget — see the module header.
205
- { pathsOnly: true }, (data) => listOf(data, "findings"), true);
206
- await runOne("validate", validateTool, { files, maxFindings: VALIDATE_MAX_FINDINGS }, (data) => listOf(data, "findings"), true);
207
- const blockingTotal = sections
208
- .filter((section) => section.blocking)
209
- .reduce((sum, section) => sum + section.total, 0);
295
+ // budget — see the module header. `files` is UAT round 3, B11: without it,
296
+ // contracts compared the whole graph and this section's total was the
297
+ // repository's standing backlog, not the change being pushed.
298
+ { pathsOnly: true, files },
299
+ // shapeMismatches is always empty under pathsOnly, but folded in anyway
300
+ // rather than assumed empty — a future call that drops pathsOnly should
301
+ // not silently under-count defects here.
302
+ (data) => [...listOf(data, "findings"), ...listOf(data, "shapeMismatches")], true, claimOf);
303
+ await runOne("validate", validateTool, { files, maxFindings: VALIDATE_MAX_FINDINGS }, (data) => listOf(data, "findings"), true, claimOf);
304
+ // Each section already reports 0/0 for both when it does not claim faults
305
+ // (`claimsFaults: false`), so summing `defects`/`leads` across every section
306
+ // needs no separate filter — the split already happened when the section was
307
+ // built.
308
+ const blockingTotal = sections.reduce((sum, section) => sum + section.defects, 0);
309
+ const leadTotal = sections.reduce((sum, section) => sum + section.leads, 0);
210
310
  const failed = sections.filter((section) => section.state === "failed");
211
311
  if (failed.length > 0) {
212
312
  notes.push(`${failed.length} of 4 constituent(s) failed and contributed nothing: ` +
@@ -214,15 +314,18 @@ async function run(args, ctx) {
214
314
  "reply is not.");
215
315
  }
216
316
  return answer({
217
- headline: blockingTotal === 0
218
- ? `No contract or environment findings across ${files.length} changed file(s).`
219
- : `${blockingTotal} blocking finding(s) across ${files.length} changed file(s) — see the ` +
220
- "contracts and validate sections.",
317
+ headline: coverageWarning(files, coverage) +
318
+ (blockingTotal === 0 && leadTotal === 0
319
+ ? `No contract or environment findings across ${files.length} changed file(s).`
320
+ : `${blockingTotal} defect(s) and ${leadTotal} lead(s) across ${files.length} changed ` +
321
+ "file(s) — only the defects assert that something is wrong. See the contracts and " +
322
+ "validate sections."),
221
323
  // `empty` is earned here: all four ran against a real graph and found
222
- // nothing blocking. A constituent that refused makes that untrue, so the
223
- // state follows the weakest link rather than the happy path.
224
- state: failed.length > 0 ? "failed" : blockingTotal > 0 ? "ok" : "empty",
225
- data: { files, sections, blockingTotal, nodeBudget },
324
+ // nothing at all, blocking or not. A constituent that refused makes that
325
+ // untrue, so the state follows the weakest link rather than the happy
326
+ // path — and a lead is still something found, so it is `ok`, not `empty`.
327
+ state: failed.length > 0 ? "failed" : blockingTotal + leadTotal > 0 ? "ok" : "empty",
328
+ data: { files, sections, blockingTotal, leadTotal, nodeBudget, coverage },
226
329
  resolutionFloor: (floors.length === 0 ? 0 : Math.min(...floors)),
227
330
  nameLevel: true,
228
331
  commitSha: base.commitSha,
@@ -242,8 +345,10 @@ export const prePushTool = {
242
345
  "returns one short envelope: what your change touches, what it touches that has no test, which " +
243
346
  "API contracts break, and which environment claims do not hold. Each source contributes its own " +
244
347
  "top few — they are deliberately not ranked against each other, because Descry has no model for " +
245
- "whether a contract mismatch outranks an unset variable. blockingTotal counts only the two " +
246
- "sources that report defects, and is what a git hook should branch on.",
348
+ "whether a contract mismatch outranks an unset variable. Both are scoped to the files you pass, " +
349
+ "not the repository's whole backlog. blockingTotal counts only defects (provable from the graph " +
350
+ "alone) from the two sources that report them, and is what a git hook should branch on; leads " +
351
+ "(worth a look, not provable alone) are counted separately in leadTotal.",
247
352
  inputSchema: SCHEMA,
248
353
  run,
249
354
  };