dsh-data-quality 0.1.3 → 0.3.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 (103) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.es.md +7 -1
  3. package/README.hi.md +7 -1
  4. package/README.md +22 -9
  5. package/README.pt.md +7 -1
  6. package/README.zh.md +7 -1
  7. package/cordis.patch.yml +11 -0
  8. package/lib/index.js +1609 -145
  9. package/lib/types/config.d.ts +12 -0
  10. package/lib/types/config.d.ts.map +1 -1
  11. package/lib/types/config.js +35 -0
  12. package/lib/types/config.js.map +1 -1
  13. package/lib/types/contract.d.ts +83 -0
  14. package/lib/types/contract.d.ts.map +1 -0
  15. package/lib/types/contract.js +144 -0
  16. package/lib/types/contract.js.map +1 -0
  17. package/lib/types/dataset.d.ts +50 -3
  18. package/lib/types/dataset.d.ts.map +1 -1
  19. package/lib/types/dataset.js +76 -21
  20. package/lib/types/dataset.js.map +1 -1
  21. package/lib/types/events.d.ts +2 -0
  22. package/lib/types/events.d.ts.map +1 -1
  23. package/lib/types/events.js.map +1 -1
  24. package/lib/types/index.d.ts +13 -8
  25. package/lib/types/index.d.ts.map +1 -1
  26. package/lib/types/index.js +17 -6
  27. package/lib/types/index.js.map +1 -1
  28. package/lib/types/presets.d.ts +28 -0
  29. package/lib/types/presets.d.ts.map +1 -0
  30. package/lib/types/presets.js +134 -0
  31. package/lib/types/presets.js.map +1 -0
  32. package/lib/types/profile.d.ts +40 -1
  33. package/lib/types/profile.d.ts.map +1 -1
  34. package/lib/types/profile.js +66 -10
  35. package/lib/types/profile.js.map +1 -1
  36. package/lib/types/provider-local.d.ts +7 -1
  37. package/lib/types/provider-local.d.ts.map +1 -1
  38. package/lib/types/provider-local.js +72 -2
  39. package/lib/types/provider-local.js.map +1 -1
  40. package/lib/types/report-html.d.ts +41 -0
  41. package/lib/types/report-html.d.ts.map +1 -0
  42. package/lib/types/report-html.js +192 -0
  43. package/lib/types/report-html.js.map +1 -0
  44. package/lib/types/scorecard.d.ts +50 -0
  45. package/lib/types/scorecard.d.ts.map +1 -0
  46. package/lib/types/scorecard.js +186 -0
  47. package/lib/types/scorecard.js.map +1 -0
  48. package/lib/types/service.d.ts +32 -2
  49. package/lib/types/service.d.ts.map +1 -1
  50. package/lib/types/service.js.map +1 -1
  51. package/lib/types/store.d.ts +21 -1
  52. package/lib/types/store.d.ts.map +1 -1
  53. package/lib/types/store.js +13 -1
  54. package/lib/types/store.js.map +1 -1
  55. package/lib/types/tools/clean.d.ts.map +1 -1
  56. package/lib/types/tools/clean.js +76 -1
  57. package/lib/types/tools/clean.js.map +1 -1
  58. package/lib/types/tools/profile-report-schema.d.ts +319 -0
  59. package/lib/types/tools/profile-report-schema.d.ts.map +1 -0
  60. package/lib/types/tools/profile-report-schema.js +96 -0
  61. package/lib/types/tools/profile-report-schema.js.map +1 -0
  62. package/lib/types/tools/profile.d.ts.map +1 -1
  63. package/lib/types/tools/profile.js +6 -53
  64. package/lib/types/tools/profile.js.map +1 -1
  65. package/lib/types/tools/report.d.ts +14 -0
  66. package/lib/types/tools/report.d.ts.map +1 -0
  67. package/lib/types/tools/report.js +112 -0
  68. package/lib/types/tools/report.js.map +1 -0
  69. package/lib/types/tools/shared.d.ts.map +1 -1
  70. package/lib/types/tools/shared.js +22 -2
  71. package/lib/types/tools/shared.js.map +1 -1
  72. package/lib/types/tools/verify.d.ts.map +1 -1
  73. package/lib/types/tools/verify.js +36 -1
  74. package/lib/types/tools/verify.js.map +1 -1
  75. package/lib/types/verify.d.ts +49 -3
  76. package/lib/types/verify.d.ts.map +1 -1
  77. package/lib/types/verify.js +111 -4
  78. package/lib/types/verify.js.map +1 -1
  79. package/lib/types/version.d.ts +8 -1
  80. package/lib/types/version.d.ts.map +1 -1
  81. package/lib/types/version.js +8 -1
  82. package/lib/types/version.js.map +1 -1
  83. package/package.json +1 -1
  84. package/src/config.ts +52 -0
  85. package/src/contract.ts +190 -0
  86. package/src/dataset.ts +101 -21
  87. package/src/events.ts +2 -0
  88. package/src/index.ts +27 -8
  89. package/src/presets.ts +146 -0
  90. package/src/profile.ts +105 -11
  91. package/src/provider-local.ts +77 -3
  92. package/src/report-html.ts +208 -0
  93. package/src/scorecard.ts +244 -0
  94. package/src/service.ts +34 -2
  95. package/src/store.ts +28 -2
  96. package/src/tools/clean.ts +76 -1
  97. package/src/tools/profile-report-schema.ts +98 -0
  98. package/src/tools/profile.ts +8 -56
  99. package/src/tools/report.ts +137 -0
  100. package/src/tools/shared.ts +21 -2
  101. package/src/tools/verify.ts +40 -2
  102. package/src/verify.ts +151 -5
  103. package/src/version.ts +9 -1
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Shared JSON-Schema spec for the profile report's canonical value, reused by
3
+ * `data_profile` (its output) and `data_clean` (the `diffPreview` before/after
4
+ * snapshots). One source of truth so the two tools never drift.
5
+ * @module dsh-data-quality/tools-profile-report-schema
6
+ */
7
+ /** One column card's schema. */
8
+ export declare const COLUMN_PROFILE_SCHEMA: {
9
+ readonly type: "object";
10
+ readonly properties: {
11
+ readonly name: {
12
+ readonly type: "string";
13
+ readonly required: true;
14
+ };
15
+ readonly inferredType: {
16
+ readonly type: "string";
17
+ readonly enum: readonly ["number", "date", "boolean", "string", "empty", "mixed"];
18
+ readonly required: true;
19
+ };
20
+ readonly missing: {
21
+ readonly type: "number";
22
+ readonly required: true;
23
+ };
24
+ readonly missingRate: {
25
+ readonly type: "number";
26
+ readonly required: true;
27
+ };
28
+ readonly unique: {
29
+ readonly type: "number";
30
+ readonly required: true;
31
+ };
32
+ readonly numeric: {
33
+ readonly type: "object";
34
+ readonly properties: {
35
+ readonly count: {
36
+ readonly type: "number";
37
+ readonly required: true;
38
+ };
39
+ readonly distinct: {
40
+ readonly type: "number";
41
+ readonly required: true;
42
+ };
43
+ readonly min: {
44
+ readonly type: "number";
45
+ readonly required: true;
46
+ };
47
+ readonly max: {
48
+ readonly type: "number";
49
+ readonly required: true;
50
+ };
51
+ readonly mean: {
52
+ readonly type: "number";
53
+ readonly required: true;
54
+ };
55
+ readonly median: {
56
+ readonly type: "number";
57
+ readonly required: true;
58
+ };
59
+ readonly p25: {
60
+ readonly type: "number";
61
+ readonly required: true;
62
+ };
63
+ readonly p75: {
64
+ readonly type: "number";
65
+ readonly required: true;
66
+ };
67
+ readonly outliers: {
68
+ readonly type: "number";
69
+ readonly required: true;
70
+ };
71
+ };
72
+ readonly additionalProperties: false;
73
+ };
74
+ readonly topValues: {
75
+ readonly type: "array";
76
+ readonly items: {
77
+ readonly type: "object";
78
+ readonly properties: {
79
+ readonly value: {
80
+ readonly type: "string";
81
+ readonly required: true;
82
+ };
83
+ readonly count: {
84
+ readonly type: "number";
85
+ readonly required: true;
86
+ };
87
+ };
88
+ readonly additionalProperties: false;
89
+ };
90
+ };
91
+ readonly notes: {
92
+ readonly type: "array";
93
+ readonly items: {
94
+ readonly type: "string";
95
+ };
96
+ readonly required: true;
97
+ };
98
+ };
99
+ readonly additionalProperties: false;
100
+ };
101
+ /** The full profile report's schema. */
102
+ export declare const PROFILE_REPORT_SCHEMA: {
103
+ readonly type: "object";
104
+ readonly properties: {
105
+ readonly schemaVersion: {
106
+ readonly type: "number";
107
+ readonly required: true;
108
+ };
109
+ readonly dataset: {
110
+ readonly type: "string";
111
+ readonly required: true;
112
+ };
113
+ readonly rowCount: {
114
+ readonly type: "number";
115
+ readonly required: true;
116
+ };
117
+ readonly sampled: {
118
+ readonly type: "boolean";
119
+ readonly required: true;
120
+ };
121
+ readonly profiledRows: {
122
+ readonly type: "number";
123
+ readonly required: true;
124
+ };
125
+ readonly columnCount: {
126
+ readonly type: "number";
127
+ readonly required: true;
128
+ };
129
+ readonly duplicateRows: {
130
+ readonly type: "number";
131
+ readonly required: true;
132
+ };
133
+ readonly duplicateRate: {
134
+ readonly type: "number";
135
+ readonly required: true;
136
+ };
137
+ readonly duplicateSampleRowIndexes: {
138
+ readonly type: "array";
139
+ readonly items: {
140
+ readonly type: "number";
141
+ };
142
+ readonly required: true;
143
+ };
144
+ readonly scorecard: {
145
+ readonly type: "object";
146
+ readonly properties: {
147
+ readonly overall: {
148
+ readonly oneOf: readonly [{
149
+ readonly type: "number";
150
+ }, {
151
+ readonly type: "null";
152
+ }];
153
+ readonly required: true;
154
+ };
155
+ readonly weightedOverall: {
156
+ readonly oneOf: readonly [{
157
+ readonly type: "number";
158
+ }, {
159
+ readonly type: "null";
160
+ }];
161
+ readonly required: true;
162
+ };
163
+ readonly dimensions: {
164
+ readonly type: "array";
165
+ readonly items: {
166
+ readonly type: "object";
167
+ readonly properties: {
168
+ readonly name: {
169
+ readonly type: "string";
170
+ readonly enum: readonly ["completeness", "uniqueness", "validity", "consistency", "timeliness", "accuracy"];
171
+ readonly required: true;
172
+ };
173
+ readonly score: {
174
+ readonly oneOf: readonly [{
175
+ readonly type: "number";
176
+ }, {
177
+ readonly type: "null";
178
+ }];
179
+ readonly required: true;
180
+ };
181
+ readonly note: {
182
+ readonly type: "string";
183
+ readonly required: true;
184
+ };
185
+ };
186
+ readonly additionalProperties: false;
187
+ };
188
+ readonly required: true;
189
+ };
190
+ };
191
+ readonly additionalProperties: false;
192
+ readonly required: true;
193
+ };
194
+ readonly encoding: {
195
+ readonly type: "object";
196
+ readonly properties: {
197
+ readonly bom: {
198
+ readonly oneOf: readonly [{
199
+ readonly type: "string";
200
+ }, {
201
+ readonly type: "null";
202
+ }];
203
+ readonly required: true;
204
+ };
205
+ readonly validUtf8: {
206
+ readonly type: "boolean";
207
+ readonly required: true;
208
+ };
209
+ };
210
+ readonly additionalProperties: false;
211
+ };
212
+ readonly generatedAt: {
213
+ readonly type: "number";
214
+ readonly required: true;
215
+ };
216
+ readonly reportKey: {
217
+ readonly type: "string";
218
+ };
219
+ readonly columns: {
220
+ readonly type: "array";
221
+ readonly items: {
222
+ readonly type: "object";
223
+ readonly properties: {
224
+ readonly name: {
225
+ readonly type: "string";
226
+ readonly required: true;
227
+ };
228
+ readonly inferredType: {
229
+ readonly type: "string";
230
+ readonly enum: readonly ["number", "date", "boolean", "string", "empty", "mixed"];
231
+ readonly required: true;
232
+ };
233
+ readonly missing: {
234
+ readonly type: "number";
235
+ readonly required: true;
236
+ };
237
+ readonly missingRate: {
238
+ readonly type: "number";
239
+ readonly required: true;
240
+ };
241
+ readonly unique: {
242
+ readonly type: "number";
243
+ readonly required: true;
244
+ };
245
+ readonly numeric: {
246
+ readonly type: "object";
247
+ readonly properties: {
248
+ readonly count: {
249
+ readonly type: "number";
250
+ readonly required: true;
251
+ };
252
+ readonly distinct: {
253
+ readonly type: "number";
254
+ readonly required: true;
255
+ };
256
+ readonly min: {
257
+ readonly type: "number";
258
+ readonly required: true;
259
+ };
260
+ readonly max: {
261
+ readonly type: "number";
262
+ readonly required: true;
263
+ };
264
+ readonly mean: {
265
+ readonly type: "number";
266
+ readonly required: true;
267
+ };
268
+ readonly median: {
269
+ readonly type: "number";
270
+ readonly required: true;
271
+ };
272
+ readonly p25: {
273
+ readonly type: "number";
274
+ readonly required: true;
275
+ };
276
+ readonly p75: {
277
+ readonly type: "number";
278
+ readonly required: true;
279
+ };
280
+ readonly outliers: {
281
+ readonly type: "number";
282
+ readonly required: true;
283
+ };
284
+ };
285
+ readonly additionalProperties: false;
286
+ };
287
+ readonly topValues: {
288
+ readonly type: "array";
289
+ readonly items: {
290
+ readonly type: "object";
291
+ readonly properties: {
292
+ readonly value: {
293
+ readonly type: "string";
294
+ readonly required: true;
295
+ };
296
+ readonly count: {
297
+ readonly type: "number";
298
+ readonly required: true;
299
+ };
300
+ };
301
+ readonly additionalProperties: false;
302
+ };
303
+ };
304
+ readonly notes: {
305
+ readonly type: "array";
306
+ readonly items: {
307
+ readonly type: "string";
308
+ };
309
+ readonly required: true;
310
+ };
311
+ };
312
+ readonly additionalProperties: false;
313
+ };
314
+ readonly required: true;
315
+ };
316
+ };
317
+ readonly additionalProperties: false;
318
+ };
319
+ //# sourceMappingURL=profile-report-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-report-schema.d.ts","sourceRoot":"","sources":["../../../src/tools/profile-report-schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,gCAAgC;AAChC,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCxB,CAAA;AAEV,wCAAwC;AACxC,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CxB,CAAA"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Shared JSON-Schema spec for the profile report's canonical value, reused by
3
+ * `data_profile` (its output) and `data_clean` (the `diffPreview` before/after
4
+ * snapshots). One source of truth so the two tools never drift.
5
+ * @module dsh-data-quality/tools-profile-report-schema
6
+ */
7
+ const SCORECARD_DIMENSION_NAMES = ['completeness', 'uniqueness', 'validity', 'consistency', 'timeliness', 'accuracy'];
8
+ /** One column card's schema. */
9
+ export const COLUMN_PROFILE_SCHEMA = {
10
+ type: 'object',
11
+ properties: {
12
+ name: { type: 'string', required: true },
13
+ inferredType: { type: 'string', enum: ['number', 'date', 'boolean', 'string', 'empty', 'mixed'], required: true },
14
+ missing: { type: 'number', required: true },
15
+ missingRate: { type: 'number', required: true },
16
+ unique: { type: 'number', required: true },
17
+ numeric: {
18
+ type: 'object',
19
+ properties: {
20
+ count: { type: 'number', required: true },
21
+ distinct: { type: 'number', required: true },
22
+ min: { type: 'number', required: true },
23
+ max: { type: 'number', required: true },
24
+ mean: { type: 'number', required: true },
25
+ median: { type: 'number', required: true },
26
+ p25: { type: 'number', required: true },
27
+ p75: { type: 'number', required: true },
28
+ outliers: { type: 'number', required: true },
29
+ },
30
+ additionalProperties: false,
31
+ },
32
+ topValues: {
33
+ type: 'array',
34
+ items: {
35
+ type: 'object',
36
+ properties: {
37
+ value: { type: 'string', required: true },
38
+ count: { type: 'number', required: true },
39
+ },
40
+ additionalProperties: false,
41
+ },
42
+ },
43
+ notes: { type: 'array', items: { type: 'string' }, required: true },
44
+ },
45
+ additionalProperties: false,
46
+ };
47
+ /** The full profile report's schema. */
48
+ export const PROFILE_REPORT_SCHEMA = {
49
+ type: 'object',
50
+ properties: {
51
+ schemaVersion: { type: 'number', required: true },
52
+ dataset: { type: 'string', required: true },
53
+ rowCount: { type: 'number', required: true },
54
+ sampled: { type: 'boolean', required: true },
55
+ profiledRows: { type: 'number', required: true },
56
+ columnCount: { type: 'number', required: true },
57
+ duplicateRows: { type: 'number', required: true },
58
+ duplicateRate: { type: 'number', required: true },
59
+ duplicateSampleRowIndexes: { type: 'array', items: { type: 'number' }, required: true },
60
+ scorecard: {
61
+ type: 'object',
62
+ properties: {
63
+ overall: { oneOf: [{ type: 'number' }, { type: 'null' }], required: true },
64
+ weightedOverall: { oneOf: [{ type: 'number' }, { type: 'null' }], required: true },
65
+ dimensions: {
66
+ type: 'array',
67
+ items: {
68
+ type: 'object',
69
+ properties: {
70
+ name: { type: 'string', enum: [...SCORECARD_DIMENSION_NAMES], required: true },
71
+ score: { oneOf: [{ type: 'number' }, { type: 'null' }], required: true },
72
+ note: { type: 'string', required: true },
73
+ },
74
+ additionalProperties: false,
75
+ },
76
+ required: true,
77
+ },
78
+ },
79
+ additionalProperties: false,
80
+ required: true,
81
+ },
82
+ encoding: {
83
+ type: 'object',
84
+ properties: {
85
+ bom: { oneOf: [{ type: 'string' }, { type: 'null' }], required: true },
86
+ validUtf8: { type: 'boolean', required: true },
87
+ },
88
+ additionalProperties: false,
89
+ },
90
+ generatedAt: { type: 'number', required: true },
91
+ reportKey: { type: 'string' },
92
+ columns: { type: 'array', items: COLUMN_PROFILE_SCHEMA, required: true },
93
+ },
94
+ additionalProperties: false,
95
+ };
96
+ //# sourceMappingURL=profile-report-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-report-schema.js","sourceRoot":"","sources":["../../../src/tools/profile-report-schema.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/tools/profile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAyCvD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,mDAwC5D"}
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/tools/profile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAKvD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,mDA4B5D"}
@@ -5,43 +5,8 @@
5
5
  */
6
6
  import { defineTool } from '@deepseek-ai/dsh-tools';
7
7
  import { renderProfileText } from "../profile.js";
8
+ import { PROFILE_REPORT_SCHEMA } from "./profile-report-schema.js";
8
9
  import { workspaceOf } from "./shared.js";
9
- const COLUMN_PROFILE_SCHEMA = {
10
- type: 'object',
11
- properties: {
12
- name: { type: 'string', required: true },
13
- inferredType: { type: 'string', enum: ['number', 'date', 'boolean', 'string', 'empty', 'mixed'], required: true },
14
- missing: { type: 'number', required: true },
15
- missingRate: { type: 'number', required: true },
16
- unique: { type: 'number', required: true },
17
- numeric: {
18
- type: 'object',
19
- properties: {
20
- min: { type: 'number', required: true },
21
- max: { type: 'number', required: true },
22
- mean: { type: 'number', required: true },
23
- median: { type: 'number', required: true },
24
- p25: { type: 'number', required: true },
25
- p75: { type: 'number', required: true },
26
- outliers: { type: 'number', required: true },
27
- },
28
- additionalProperties: false,
29
- },
30
- topValues: {
31
- type: 'array',
32
- items: {
33
- type: 'object',
34
- properties: {
35
- value: { type: 'string', required: true },
36
- count: { type: 'number', required: true },
37
- },
38
- additionalProperties: false,
39
- },
40
- },
41
- notes: { type: 'array', items: { type: 'string' }, required: true },
42
- },
43
- additionalProperties: false,
44
- };
45
10
  /**
46
11
  * Build the `data_profile` tool definition against a mounted service.
47
12
  * @param service - the mounted ctx.dataQuality implementation.
@@ -52,35 +17,23 @@ export function defineProfileTool(service) {
52
17
  name: 'data_profile',
53
18
  description: [
54
19
  'Profile a workspace CSV/TSV/JSON/JSONL dataset with deterministic TypeScript computation (no mental math).',
55
- 'Returns row/column counts, inferred column types, missing rates, unique counts, numeric distributions (min/max/mean/median/p25/p75), IQR outlier counts, mixed-type suspicion notes, and duplicate-row counts.',
56
- 'Column cards cover every row by default; pass sample for a deterministic systematic sample on large files. Datasets above the configured row/size caps are rejected — use sample or raise the caps. The full report persists to the data_quality storage domain (reportKey in the result).',
20
+ 'Returns row/column counts, inferred column types, missing rates, unique counts, numeric distributions (count/distinct/min/max/mean/median/p25/p75), IQR outlier counts, mixed-type suspicion notes, sha256 duplicate-row detection (rate + sample indexes), file encoding (BOM/UTF-8 validity), and a weighted DAMA six-dimension scorecard.',
21
+ 'Pass industryPreset (retail/saas/fund/real-estate/e-commerce/healthcare/logistics/manufacturing/energy) to compare the dataset against that industry\'s expected columns, making the scorecard accuracy dimension determinable. Column cards cover every row by default; pass sample for a deterministic systematic sample on large files. Datasets above the configured row/size caps are rejected — use sample or raise the caps. The full report persists to the data_quality storage domain (reportKey in the result).',
57
22
  ].join('\n'),
58
23
  parameters: {
59
24
  path: { type: 'string', required: true, description: 'Workspace-relative dataset path (.csv/.tsv/.json/.jsonl). JSON datasets must be an array of flat objects.' },
60
25
  sample: { type: 'number', description: 'Optional systematic sample size (every ceil(N/sample)-th row) for the column cards; row counts stay exact.' },
26
+ industryPreset: { type: 'string', enum: ['retail', 'saas', 'fund', 'real-estate', 'e-commerce', 'healthcare', 'logistics', 'manufacturing', 'energy'], description: 'Optional industry preset id; its expected columns feed the scorecard accuracy dimension.' },
61
27
  },
62
28
  output: {
63
- schema: {
64
- type: 'object',
65
- properties: {
66
- dataset: { type: 'string', required: true },
67
- rowCount: { type: 'number', required: true },
68
- sampled: { type: 'boolean', required: true },
69
- profiledRows: { type: 'number', required: true },
70
- columnCount: { type: 'number', required: true },
71
- duplicateRows: { type: 'number', required: true },
72
- generatedAt: { type: 'number', required: true },
73
- reportKey: { type: 'string' },
74
- columns: { type: 'array', items: COLUMN_PROFILE_SCHEMA, required: true },
75
- },
76
- additionalProperties: false,
77
- },
29
+ schema: PROFILE_REPORT_SCHEMA,
78
30
  render: (_args, value) => [{ type: 'text', text: renderProfileText(value) }],
79
31
  },
80
32
  async execute(args, exec) {
81
33
  return service.profileDataset({
82
34
  dataset: args.path,
83
35
  sample: args.sample,
36
+ ...(args.industryPreset !== undefined ? { industryPreset: args.industryPreset } : {}),
84
37
  workspace: workspaceOf(exec),
85
38
  session: exec.agent?.session,
86
39
  signal: exec.signal,
@@ -1 +1 @@
1
- {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/tools/profile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/tools/profile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAEnD,OAAO,EAAE,iBAAiB,EAAsB,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE;YACX,4GAA4G;YAC5G,8UAA8U;YAC9U,4fAA4f;SAC7f,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2GAA2G,EAAE;YAClK,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4GAA4G,EAAE;YACrJ,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,0FAA0F,EAAE;SACjQ;QACD,MAAM,EAAE;YACN,MAAM,EAAE,qBAAqB;YAC7B,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,KAAiC,CAAC,EAAE,CAAC;SACzG;QACD,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI;YACtB,OAAO,OAAO,CAAC,cAAc,CAAC;gBAC5B,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrF,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC;gBAC5B,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO;gBAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The `data_report` model tool: read persisted profile/clean-diff reports
3
+ * back from the `data_quality` storage domain, by exact `reportKey` or by
4
+ * `kind`. Deterministic read-only consumption — no model arithmetic.
5
+ * @module dsh-data-quality/tools/report
6
+ */
7
+ import type { DataQualityService } from '../service.js';
8
+ /**
9
+ * Build the `data_report` tool definition against a mounted service.
10
+ * @param service - the mounted ctx.dataQuality implementation.
11
+ * @returns the tool definition to register.
12
+ */
13
+ export declare function defineReportTool(service: DataQualityService): import("@deepseek-ai/dsh-tools").ToolDefinition;
14
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/tools/report.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAsDvD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,mDAkE3D"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * The `data_report` model tool: read persisted profile/clean-diff reports
3
+ * back from the `data_quality` storage domain, by exact `reportKey` or by
4
+ * `kind`. Deterministic read-only consumption — no model arithmetic.
5
+ * @module dsh-data-quality/tools/report
6
+ */
7
+ import { defineTool } from '@deepseek-ai/dsh-tools';
8
+ import { renderCleanHtml, renderProfileHtml } from "../report-html.js";
9
+ /** The report kinds a caller may query. */
10
+ const REPORT_KINDS = ['profile', 'clean', 'clean-diff', 'verify', 'citations'];
11
+ /** Render one stored report as a self-contained HTML document (profile/clean only). */
12
+ function renderRecordHtml(record) {
13
+ if (record.kind === 'profile') {
14
+ return renderProfileHtml(record.report);
15
+ }
16
+ if (record.kind === 'clean' || record.kind === 'clean-diff') {
17
+ return renderCleanHtml(record.report, record.dataset);
18
+ }
19
+ throw new Error(`data_report html format does not support kind "${record.kind}" (profile/clean only)`);
20
+ }
21
+ /** Project a stored report into the canonical value (the stored report is already lossless JSON). */
22
+ function toView(record) {
23
+ return { key: record.key, kind: record.kind, at: record.at, dataset: record.dataset, report: record.report };
24
+ }
25
+ /** Human-readable report summary for the tool's Native render. */
26
+ function renderReportText(value) {
27
+ const lines = [];
28
+ if (value.key !== undefined) {
29
+ lines.push(value.records.length === 0 ? `No report for ${value.key}` : `Report ${value.key}`);
30
+ }
31
+ else {
32
+ lines.push(`Reports of kind ${value.kind ?? ''} (${value.records.length})`);
33
+ }
34
+ for (const record of value.records) {
35
+ lines.push(`- ${record.key} [${record.kind}] ${record.dataset} @ ${new Date(record.at).toISOString()}`);
36
+ }
37
+ return lines.join('\n');
38
+ }
39
+ /**
40
+ * Build the `data_report` tool definition against a mounted service.
41
+ * @param service - the mounted ctx.dataQuality implementation.
42
+ * @returns the tool definition to register.
43
+ */
44
+ export function defineReportTool(service) {
45
+ return defineTool({
46
+ name: 'data_report',
47
+ description: [
48
+ 'Read persisted data-quality reports back from the data_quality storage domain (deterministic, read-only).',
49
+ 'Pass key (the exact reportKey a prior run returned) to fetch one report, or kind to list every persisted report of that kind, ordered chronologically. Exactly one of key/kind.',
50
+ 'Returns the report envelope(s): kind, dataset, timestamp, and the full stored report (profile/clean/clean-diff/verify/citations). Missing keys and unknown kinds fail loudly.',
51
+ ].join('\n'),
52
+ parameters: {
53
+ key: { type: 'string', description: 'Exact storage reportKey (e.g. 20260819000000000-profile-1a2b3c4d); fetches that one report.' },
54
+ kind: { type: 'string', enum: [...REPORT_KINDS], description: 'Report kind to list (profile/clean/clean-diff/verify/citations).' },
55
+ format: { type: 'string', enum: ['json', 'html'], description: 'Output format. json (default) returns the report envelope(s); html renders one report as a self-contained offline HTML document (requires key; profile/clean only).' },
56
+ },
57
+ output: {
58
+ schema: {
59
+ type: 'object',
60
+ properties: {
61
+ key: { type: 'string' },
62
+ kind: { type: 'string', enum: [...REPORT_KINDS] },
63
+ records: {
64
+ type: 'array',
65
+ items: {
66
+ type: 'object',
67
+ properties: {
68
+ key: { type: 'string', required: true },
69
+ kind: { type: 'string', enum: [...REPORT_KINDS], required: true },
70
+ at: { type: 'number', required: true },
71
+ dataset: { type: 'string', required: true },
72
+ report: { type: 'json', required: true },
73
+ },
74
+ additionalProperties: false,
75
+ },
76
+ required: true,
77
+ },
78
+ html: { type: 'string', description: 'Self-contained offline HTML (present only when format: html).' },
79
+ },
80
+ additionalProperties: false,
81
+ },
82
+ render: (_args, value) => {
83
+ const view = value;
84
+ if (view.html !== undefined)
85
+ return [{ type: 'text', text: view.html }];
86
+ return [{ type: 'text', text: renderReportText(view) }];
87
+ },
88
+ },
89
+ async execute(args, _exec) {
90
+ const hasKey = args.key !== undefined;
91
+ const hasKind = args.kind !== undefined;
92
+ if (hasKey === hasKind) {
93
+ throw new Error('data_report needs exactly one of key/kind');
94
+ }
95
+ const format = (args.format ?? 'json');
96
+ if (hasKey) {
97
+ const record = await service.getReport(args.key);
98
+ return {
99
+ key: args.key,
100
+ records: [toView(record)],
101
+ ...(format === 'html' ? { html: renderRecordHtml(record) } : {}),
102
+ };
103
+ }
104
+ if (format === 'html') {
105
+ throw new Error('data_report html format requires key (exactly one report)');
106
+ }
107
+ const records = await service.listReports(args.kind);
108
+ return { kind: args.kind, records: records.map(toView) };
109
+ },
110
+ });
111
+ }
112
+ //# sourceMappingURL=report.js.map