tewip-ai 0.69.4 → 0.69.6
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/dist/engine/rules.js +13 -0
- package/dist/engine/work/bug-command.js +67 -5
- package/package.json +1 -1
package/dist/engine/rules.js
CHANGED
|
@@ -157,6 +157,19 @@ const envServerError = {
|
|
|
157
157
|
* Declines when the server failed during the test: the wrong value may come from the
|
|
158
158
|
* backend (ENV) or from a test that provokes errors on purpose, which only the LLM layer,
|
|
159
159
|
* seeing the whole trace, can tell apart (rules-3).
|
|
160
|
+
*
|
|
161
|
+
* **Do not remove the history requirement.** Phase 64 found that `tewip bugs` files almost nothing
|
|
162
|
+
* from one CI run - 1 ticket out of 1,964 real failures - because every test in a single run has
|
|
163
|
+
* `runs < 2` and this rule declines. The proposed fix was to let a plain value mismatch stand on its
|
|
164
|
+
* own: "expected 4, received 3 needs no model" is an obvious-sounding argument, and it was measured
|
|
165
|
+
* in Phase 65 over **2,767 hand-labelled real failures from nine projects**:
|
|
166
|
+
*
|
|
167
|
+
* 293 value mismatches -> TIMING 265 (90.4%), REAL_BUG 26 (8.9%), ENV 2 (0.7%)
|
|
168
|
+
*
|
|
169
|
+
* Per project it is 0%, 0%, 0%, 4%, 5%, 6%, 7%, 11%, 39%. **A flaky test fails its assertion too -
|
|
170
|
+
* that is what failing looks like.** The mismatch is not the signal; the history around it is, which
|
|
171
|
+
* is what the streak conditions below are reading and what one CI run cannot supply. Re-derive with
|
|
172
|
+
* `node eval/mismatch-precision.ts` before changing any of this.
|
|
160
173
|
*/
|
|
161
174
|
const realBugAssertion = {
|
|
162
175
|
id: 'real-bug-assertion',
|
|
@@ -19,6 +19,59 @@ import { TEWIP_LABEL } from './jira-command.js';
|
|
|
19
19
|
import { trackerFromEnv, trackerHelp } from './trackers.js';
|
|
20
20
|
/** Bugs Tewip filed carry this as well, so a second run finds them and does not file again. */
|
|
21
21
|
export const BUG_LABEL = 'tewip-bug';
|
|
22
|
+
/**
|
|
23
|
+
* How sure Tewip has to be before it puts a person's name on a ticket.
|
|
24
|
+
*
|
|
25
|
+
* Named and exported because of what it collides with. Phase 55 capped a model-only diagnosis at
|
|
26
|
+
* **0.45** - the model is not reliable enough for its word alone to be acted on - and this bar has
|
|
27
|
+
* been 0.8 since Phase 10. The two numbers were set eight weeks apart and never compared, and
|
|
28
|
+
* together they mean **a bug only the model recognised can never be filed**, whatever it says.
|
|
29
|
+
*
|
|
30
|
+
* Measured over 1,964 real failures from five public projects (gutenberg, supabase, lxdui, penpot,
|
|
31
|
+
* jupyterlab) with the rules alone: **20 REAL_BUG verdicts, of which 1 reaches 0.8.** Four of the
|
|
32
|
+
* five projects produce none at all. On a real jest report of a plain value mismatch - "Expected: 4,
|
|
33
|
+
* Received: 3", which is as clear as a real bug gets - the verdict is REAL_BUG at 0.45 from the
|
|
34
|
+
* model, and `bugs` files nothing.
|
|
35
|
+
*
|
|
36
|
+
* The bar is not lowered here. A ticket opened on a model's unsupported word is the thing this
|
|
37
|
+
* project exists not to do, and 0.45 is the honest reading of how often that word is right. What
|
|
38
|
+
* changes is that the refusal now says which of the two reasons applies, because "none of them is a
|
|
39
|
+
* real bug Tewip is confident about" was being printed for twenty failures Tewip had called real
|
|
40
|
+
* bugs.
|
|
41
|
+
*/
|
|
42
|
+
export const CONFIDENT_ENOUGH = 0.8;
|
|
43
|
+
/**
|
|
44
|
+
* Why nothing was filed - the two cases told apart.
|
|
45
|
+
*
|
|
46
|
+
* The old sentence was one line for both: `${items.length} failure(s), and none of them is a real
|
|
47
|
+
* bug Tewip is confident about (${kinds})`, where `kinds` was every category present. On a real
|
|
48
|
+
* report it printed **"none of them is a real bug Tewip is confident about (REAL_BUG, ENV)"** -
|
|
49
|
+
* listing REAL_BUG inside the sentence denying there was one. A reader cannot tell from that whether
|
|
50
|
+
* Tewip found nothing or found something it would not act on, and those call for opposite next steps.
|
|
51
|
+
*/
|
|
52
|
+
export function whyNothingWasFiled(items, unsure) {
|
|
53
|
+
const kinds = [...new Set(items.filter((i) => i.diagnosis.category !== 'REAL_BUG').map((i) => i.diagnosis.category))];
|
|
54
|
+
if (unsure.length === 0) {
|
|
55
|
+
return (`${items.length} failure(s), and none of them looks like the application being wrong` +
|
|
56
|
+
`${kinds.length > 0 ? ` - they are ${kinds.join(', ')}` : ''}. Nothing was filed, which is the point.`);
|
|
57
|
+
}
|
|
58
|
+
const highest = Math.max(...unsure.map((i) => i.diagnosis.confidence));
|
|
59
|
+
const byModel = unsure.filter((i) => /AI|gpt|claude|model/i.test(i.source)).length;
|
|
60
|
+
return [
|
|
61
|
+
`${items.length} failure(s). ${unsure.length} of them Tewip reads as a real bug, and none of those reaches the ${CONFIDENT_ENOUGH.toFixed(2)} confidence it requires before opening a ticket in somebody's name - the highest is ${highest.toFixed(2)}.`,
|
|
62
|
+
byModel > 0
|
|
63
|
+
? `${byModel === unsure.length ? 'All' : `${byModel}`} of them came from the AI layer, which is capped at 0.45 on purpose: a model's unsupported word is not enough to file on.`
|
|
64
|
+
: '',
|
|
65
|
+
// What a CI user can actually do about it. The rules decline a value mismatch without a stable
|
|
66
|
+
// failing streak, and on one run there is no streak to read - which is not over-caution:
|
|
67
|
+
// measured over 2,767 labelled real failures, a value mismatch is TIMING 90% of the time and a
|
|
68
|
+
// real bug 9% of the time (`node eval/mismatch-precision.ts`). History is what separates them.
|
|
69
|
+
'What would change this: history. The rules will not call a wrong value a bug without a stable failing streak behind it, because a flaky test produces the same wrong value - on real labelled data a value mismatch is a flaky test nine times out of ten. Keep this project\'s runs (`--name <project>`, or let the Action keep them) and the same failure in a second and third run is what the rules read. A person\'s correction on the failure in CI settles it immediately.',
|
|
70
|
+
`Nothing was filed. These are listed in \`tewip explain\` with their evidence${kinds.length > 0 ? `, alongside ${kinds.join(', ')} failures that are deliberately never filed` : ''}.`,
|
|
71
|
+
]
|
|
72
|
+
.filter(Boolean)
|
|
73
|
+
.join('\n');
|
|
74
|
+
}
|
|
22
75
|
const isBlobDir = (path) => statSync(path).isDirectory() && readdirSync(path).some((f) => /^report.*\.zip$/.test(f));
|
|
23
76
|
/** The bug report a developer actually wants: what failed, what it did, and why Tewip believes it. */
|
|
24
77
|
export function bugBody(item, runUrl) {
|
|
@@ -76,15 +129,15 @@ export async function runBugs(cmd) {
|
|
|
76
129
|
const items = await buildItems(imported.records, index, { dataset: `local: ${name}`, llm: llmFromEnv(), corrections: loadCorrections(historyDir) });
|
|
77
130
|
// Only what Tewip itself calls a bug, and only when it is confident enough to put a person's name
|
|
78
131
|
// on it. Everything else is deliberately left out.
|
|
79
|
-
const bugs = items.filter((i) => i.diagnosis.category === 'REAL_BUG' && i.diagnosis.confidence >=
|
|
132
|
+
const bugs = items.filter((i) => i.diagnosis.category === 'REAL_BUG' && i.diagnosis.confidence >= CONFIDENT_ENOUGH);
|
|
133
|
+
const unsure = items.filter((i) => i.diagnosis.category === 'REAL_BUG' && i.diagnosis.confidence < CONFIDENT_ENOUGH);
|
|
80
134
|
const lines = [`Report: ${cmd.report}`, `Project: ${cmd.projectKey}`, ''];
|
|
81
135
|
if (items.length === 0) {
|
|
82
136
|
console.log('Every test in that report passed. Nothing to file.');
|
|
83
137
|
return [];
|
|
84
138
|
}
|
|
85
139
|
if (bugs.length === 0) {
|
|
86
|
-
|
|
87
|
-
console.log(`${items.length} failure(s), and none of them is a real bug Tewip is confident about (${kinds}). Nothing was filed, which is the point.`);
|
|
140
|
+
console.log(whyNothingWasFiled(items, unsure));
|
|
88
141
|
return [];
|
|
89
142
|
}
|
|
90
143
|
const tracker = chosen?.tracker.canWrite() ? chosen.tracker : null;
|
|
@@ -122,8 +175,17 @@ export async function runBugs(cmd) {
|
|
|
122
175
|
lines.push(` filed ${key}: ${summary}`);
|
|
123
176
|
filed++;
|
|
124
177
|
}
|
|
125
|
-
|
|
126
|
-
|
|
178
|
+
// `items.length - bugs.length` was described as "flaky tests, environment or test data", which is
|
|
179
|
+
// untrue of a REAL_BUG sitting below the bar: a bug Tewip is 0.45 sure of was being counted, in
|
|
180
|
+
// print, as a flaky test. And the `max` cap was silent - the same mistake `prove` made in Phase 58,
|
|
181
|
+
// where a sampled answer read as a whole one.
|
|
182
|
+
const notBugs = items.length - bugs.length - unsure.length;
|
|
183
|
+
const beyondCap = Math.max(0, bugs.length - cmd.max);
|
|
184
|
+
lines.push('', `${bugs.length} of ${items.length} failure(s) look like real bugs.` +
|
|
185
|
+
(notBugs > 0 ? ` ${notBugs} were flaky tests, environment or test data and were deliberately not filed.` : '') +
|
|
186
|
+
(unsure.length > 0 ? ` ${unsure.length} more look like real bugs but below the ${CONFIDENT_ENOUGH.toFixed(2)} confidence needed to file one, so they were not.` : ''));
|
|
187
|
+
if (beyondCap > 0)
|
|
188
|
+
lines.push(`${beyondCap} were past the --max ${cmd.max} limit and were not looked at. Raise it with \`--max ${bugs.length}\`.`);
|
|
127
189
|
lines.push(cmd.create ? `${filed} ticket(s) created in ${tracker?.name}. Tewip never moves, assigns or closes one.` : 'Nothing was created. Add --create to file them.');
|
|
128
190
|
console.log(lines.join('\n'));
|
|
129
191
|
return bugs;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tewip-ai",
|
|
3
|
-
"version": "0.69.
|
|
3
|
+
"version": "0.69.6",
|
|
4
4
|
"mcpName": "io.github.hmamut39/tewip",
|
|
5
5
|
"description": "Tewip finds why each failing test failed - real bug, flaky test, environment, test data or changed selector - for any stack, from the command line, CI, or your editor.",
|
|
6
6
|
"keywords": [
|