tewip-ai 0.70.7 → 0.70.8
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/spec/spec.js +35 -20
- package/package.json +1 -1
package/dist/engine/spec/spec.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export const SPEC_PROMPT_VERSION = 'spec-1';
|
|
2
|
-
const SYSTEM = `You are Tewip's specification writer, a senior product engineer who works from the code.
|
|
3
|
-
|
|
4
|
-
Write an epic, its user stories, and acceptance criteria for the feature described. Use only the facts given: the feature description, the change, the pages of the running app, the tests that already exist, the source files read, and this project's failure history.
|
|
5
|
-
|
|
6
|
-
Rules:
|
|
7
|
-
- Every statement about what the system ALREADY does must be backed by a quote: evidence is a file path from the facts, then ": ", then a piece of that file copied character for character (a line of code, a test name, a comment). If you cannot quote it, do not claim it - put the uncertainty in open_questions.
|
|
8
|
-
- Acceptance criteria are Given / When / Then, each one checkable by a person or a test. No criterion may say "works correctly", "is fast" or "is user-friendly": say the observable thing.
|
|
9
|
-
- A story is one user-visible outcome, written as "As a <role>, I want <outcome> so that <benefit>". Split anything larger.
|
|
10
|
-
- Prefer what the failure history and the existing tests show is risky or already broken.
|
|
11
|
-
- Never write estimates, story points, dates, budgets, market claims or business cases. You cannot check those, so they do not belong here.
|
|
2
|
+
const SYSTEM = `You are Tewip's specification writer, a senior product engineer who works from the code.
|
|
3
|
+
|
|
4
|
+
Write an epic, its user stories, and acceptance criteria for the feature described. Use only the facts given: the feature description, the change, the pages of the running app, the tests that already exist, the source files read, and this project's failure history.
|
|
5
|
+
|
|
6
|
+
Rules:
|
|
7
|
+
- Every statement about what the system ALREADY does must be backed by a quote: evidence is a file path from the facts, then ": ", then a piece of that file copied character for character (a line of code, a test name, a comment). If you cannot quote it, do not claim it - put the uncertainty in open_questions.
|
|
8
|
+
- Acceptance criteria are Given / When / Then, each one checkable by a person or a test. No criterion may say "works correctly", "is fast" or "is user-friendly": say the observable thing.
|
|
9
|
+
- A story is one user-visible outcome, written as "As a <role>, I want <outcome> so that <benefit>". Split anything larger.
|
|
10
|
+
- Prefer what the failure history and the existing tests show is risky or already broken.
|
|
11
|
+
- Never write estimates, story points, dates, budgets, market claims or business cases. You cannot check those, so they do not belong here.
|
|
12
12
|
- out_of_scope is what this epic deliberately does not do. open_questions are the decisions a person must make.`;
|
|
13
13
|
const CRITERION = {
|
|
14
14
|
type: 'object',
|
|
@@ -64,9 +64,29 @@ function readable(facts) {
|
|
|
64
64
|
return [...(facts.testSources ?? []), ...(facts.codeSources ?? [])].map((s) => ({ file: s.file, content: s.content }));
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
* A quote is real when the file is one Tewip read and the
|
|
68
|
-
*
|
|
69
|
-
* the
|
|
67
|
+
* A quote is real when the file is one Tewip read and the quote appears in it **as one piece**.
|
|
68
|
+
*
|
|
69
|
+
* This used to collect the quote's "distinctive parts" - runs of `[A-Za-z0-9_$.]{3,}` - and require
|
|
70
|
+
* each to appear somewhere in the file, in any order. Three fabrications got through a real check
|
|
71
|
+
* against a real file, and the worst was this, offered as evidence that a 20% discount cap is
|
|
72
|
+
* enforced:
|
|
73
|
+
*
|
|
74
|
+
* const rate = Math.min(percent, 20) / 100; // the file says 100, not 20
|
|
75
|
+
*
|
|
76
|
+
* Every part of that - `const`, `rate`, `Math.min`, `percent`, `100` - is in the file. **`20` is
|
|
77
|
+
* not a part at all**, because `{3,}` cannot see a two-character number. So the one token that
|
|
78
|
+
* carried the entire meaning was the one token not checked, and a reader of "What the code already
|
|
79
|
+
* does - each line is quoted from a file Tewip read" would have concluded the bug was fixed.
|
|
80
|
+
*
|
|
81
|
+
* The comment that used to sit here saw the risk and named it exactly - *"a quote that is mostly
|
|
82
|
+
* real but wrong where it matters... 'slice(0, 50)' and 'slice(0, 10000)' differ by one word"* -
|
|
83
|
+
* and `50` was never a word it could compare. A line assembled from real words in an order the file
|
|
84
|
+
* has never contained got through for the same reason.
|
|
85
|
+
*
|
|
86
|
+
* So the quote has to be in the file contiguously. Whitespace is squashed and quote characters are
|
|
87
|
+
* normalised, because those are the two differences between a model's copy and the file that carry
|
|
88
|
+
* no meaning; nothing else is forgiven. A claim that fails this becomes an open question, which is
|
|
89
|
+
* the right place for it.
|
|
70
90
|
*/
|
|
71
91
|
export function quoteHolds(evidence, sources) {
|
|
72
92
|
const at = evidence.indexOf(': ');
|
|
@@ -77,13 +97,8 @@ export function quoteHolds(evidence, sources) {
|
|
|
77
97
|
const source = sources.find((s) => s.file === file || s.file.endsWith(`/${file}`) || file.endsWith(s.file));
|
|
78
98
|
if (!source || quote.length < 3)
|
|
79
99
|
return false;
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
return false;
|
|
83
|
-
const body = source.content;
|
|
84
|
-
// Every distinctive part must be in the file. Anything less lets a quote that is mostly real but
|
|
85
|
-
// wrong where it matters through - "slice(0, 50)" and "slice(0, 10000)" differ by one word.
|
|
86
|
-
return parts.every((part) => body.includes(part));
|
|
100
|
+
const squash = (text) => text.replace(/["'`]/g, '"').replace(/\s+/g, ' ').trim();
|
|
101
|
+
return squash(source.content).includes(squash(quote));
|
|
87
102
|
}
|
|
88
103
|
/**
|
|
89
104
|
* Checks every claim about what already exists, and demotes the ones Tewip cannot quote into open
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tewip-ai",
|
|
3
|
-
"version": "0.70.
|
|
3
|
+
"version": "0.70.8",
|
|
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": [
|