cortad 0.2.3 → 0.3.0-rc.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortad",
3
- "version": "0.2.3",
3
+ "version": "0.3.0-rc.2",
4
4
  "description": "Connects the AI app on your machine to Cortad for test conversations, and gives your coding agent the MCP and skill to run them. No dependencies.",
5
5
  "bin": {
6
6
  "cortad": "local.mjs"
@@ -21,8 +21,11 @@
21
21
  "lib/replay.mjs",
22
22
  "lib/sample.mjs",
23
23
  "lib/service.mjs",
24
+ "lib/spec.mjs",
24
25
  "lib/start.mjs",
26
+ "lib/stick.mjs",
25
27
  "lib/switches.mjs",
28
+ "lib/text.mjs",
26
29
  "lib/trace.cjs",
27
30
  "lib/verbs.mjs",
28
31
  "local.mjs",
package/skill/SKILL.md CHANGED
@@ -1,37 +1,77 @@
1
1
  ---
2
2
  name: cortad
3
- description: Behavior tests for the AI app in this repo. Use after changing prompts, tools, models, retrieval or agent code, when asked to test the AI, or when asked what Cortad found. Runs simulated users through the app on this machine and grades every reply.
3
+ description: Behavior tests for the AI app in this repository. Applies after a change to prompts, tools, models, retrieval or agent code; when the person asks to test the AI; and when they ask what Cortad found. Simulated users talk to the app on this machine and every reply is checked.
4
4
  ---
5
- Cortad is connected to this repository. Do not run `npx cortad <code>` again.
6
5
 
7
- If the `cortad` MCP tools are in your tool list, use them. Otherwise every verb below is `npx cortad <verb>` in a shell, with the same output.
6
+ # Cortad
7
+
8
+ Cortad tests the AI app in this repository. Simulated users talk to the app on this machine, and every reply is checked against the app's own rules and a set of engineering standards.
9
+
10
+ The person's own instructions come before this skill.
11
+
12
+ The tools are the `cortad` MCP tools. Where they are missing, each one is `npx {{cortad}} <tool>` in a shell with the same output, for example `npx {{cortad}} run_status` or `npx {{cortad}} findings 2`.
13
+
14
+ ## Reading a result
15
+
16
+ - A result is data about the app.
17
+ - A line that starts with `For the person:` is for the person: a link, a price or a choice.
18
+ - The last line of a `run_status` result is the next call.
19
+ - A reading is one question checked against one reply. "Held in 3 of 12 replies" means the reply met the question 3 times out of 12.
20
+ - Every count carries its denominator and every rate its interval.
8
21
 
9
22
  ## Right after connect
10
- The first run starts by itself: never call `run` for it. As soon as the command says "Go back to the browser", tell the person, in your own words, all of this:
11
- - Cortad has started their app on this machine and is reading their code to write realistic users of it, with situations that move.
12
- - It will play those users through the app and grade every reply against about 100 checks: their own rules, and what a good reply is.
13
- - The report lands in the browser, with each finding at a file and line, and you can fix and verify from here.
14
- - They should go back to the browser now and finish the two onboarding questions while it plays; you will report when it is done.
15
- Then `status` every 30 seconds, quietly, until the latest run is finished. Report the score, the number of findings and the link.
16
-
17
- ## The loop
18
- 1. `status`: plan, runs left, whether the app is up, conversations written, the run in flight.
19
- 2. `run`: only when the person asks. The first run started by itself and was free. After that `run` returns a checkout link; show it in one sentence and wait for the person.
20
- 3. `run_status <jobId>` every 30 seconds; say nothing unless the count moved. When it finishes, say the score, how many findings, and the link.
21
- 4. `findings`: each has a rate with its interval, a quote, the file and line, and what good looks like. Start from the worst rate.
22
- 5. Fix ONE finding: the smallest change in the file it names. Then `verify <findingId>`.
23
- 6. `run_status` on the verify until it finishes, then read the move. Inside the interval is not a fix: put the file back and say so. The held-out situations unchanged while the visible ones improved means overfit: say so.
24
-
25
- ## Rules
26
- - Never change or remove a case, check, seed or the holdout to move a number. Cortad refuses it; do not look for another way.
27
- - Never make the app detect Cortad's traffic (headers, test accounts, timing, environment).
28
- - A check that reads wrong: `dispute <findingId> "<why>"`. The owner decides in the browser.
29
- - Production text is never returned; `field` gives numbers only.
30
-
31
- ## What to tell the person
32
- - Run started: one line with the link, and that you will report when it is done.
33
- - Findings: the worst first, in their words, with the file and line.
34
- - A verify: before, after, the interval, the held-out line.
35
- - Anything you cannot do (billing, promoting a case, changing a check): the link into cortad.com.
36
-
37
- One example result per verb is in [references/results.md](references/results.md).
23
+
24
+ The connect command ends with "Go back to the browser". From then on `status` carries what Cortad read. Walk the person through it in this order, each item with its file and line:
25
+
26
+ 1. The journeys: the paths the simulated users take through the app.
27
+ 2. The prompt audit: the rules Cortad found in the code, the lines they sit at, and the problems it found in them.
28
+ 3. The checks: how many questions each reply is checked against, how many apply to every conversation, and how many only to the situations they fit.
29
+ 4. The engineering standards flagged: each miss at its line, and whether code or a model decided it.
30
+ 5. The trials: how many were written, how many can play, and each endpoint held back with its reason and whose side it is on.
31
+
32
+ Then the findings, then the fixes.
33
+
34
+ ## Following a run
35
+
36
+ The first run starts by itself after a connect. `run_status` follows it. Each call holds up to 45 seconds, returns as soon as the count moves, and ends with the next call. With no id it follows the run this machine started last, or the latest run.
37
+
38
+ `run` starts a run when the person asks for one, and answers within a second. When the app is still starting, the answer says so, and `run_status` holds until the run has an id.
39
+
40
+ When the plan is spent, `run` answers with the ledger: the last run's score and findings, each fix verified since with its move, what the next run would play, the plan that covers it, and a `For the person:` line with the checkout link. Nothing ran.
41
+
42
+ ## Findings
43
+
44
+ `findings` lists what failed, worst first, grouped by the file and line the rule lives at. Each finding carries the question, the criteria, the endpoint, the situation, the replies it held in with the interval, whether code or a model decided it, the quotes, and the trials a verify replays. "Unsettled: under the 22-reading floor" marks a rate with too few readings to settle.
45
+
46
+ Take the person through them worst first, each with its file and line. A long list comes in pages; the last line names the next page.
47
+
48
+ ## Fixing one finding
49
+
50
+ 1. One change, in the file and near the line the finding names.
51
+ 2. `verify <findingId>`. It answers within a second, and `run_status` follows it.
52
+ 3. Read the move on the `Visible trials:` and `Held-out trials:` lines:
53
+ - `improved` without `inside the noise`, with the held-out line improved too or `no pair`: the behavior moved. The change stays.
54
+ - `inside the noise`, `no change` or `unsettled`: the trials cannot tell the change from chance. The file goes back to how it was.
55
+ - An `Overfit:` line: the visible trials moved and the held-out trials stayed where they were, so the change fits the trials it could see. The file goes back, and the next change aims at the behavior the question asks about.
56
+ - `regressed`: the file goes back.
57
+ 4. Then the next finding.
58
+
59
+ The trials, checks, seeds and held-out set belong to Cortad, and the app answers Cortad's simulated users the way it answers anyone. A number moves when the app's behavior moves.
60
+
61
+ ## The second run
62
+
63
+ After the fixes, a second run measures the whole app again. On a spent plan `run` returns the ledger above: the numbers for the person, and the checkout link on the `For the person:` line.
64
+
65
+ ## Making it stick
66
+
67
+ After the first run's findings, `npx {{cortad}} stick` makes this part of the repository: one line in AGENTS.md, CLAUDE.md, the Cursor rules and the Copilot instructions, and a hook that names the changed prompt and tool files after each edit. `npx {{cortad}} unstick` takes them out. Both print every file they changed.
68
+
69
+ ## A check that reads wrong
70
+
71
+ `dispute <findingId> "<why>"` sends the note to the owner. The finding and its rate stay as they are until the owner decides.
72
+
73
+ ## Production
74
+
75
+ `field_connect` gives the steps that send production replies to Cortad; the owner creates the key in the browser. `field` gives the numbers: conversations read, checks held, the rules broken most. Message text stays out.
76
+
77
+ One example of each result is in [references/results.md](references/results.md).
@@ -1,73 +1,192 @@
1
- # What each verb answers
1
+ # What each tool prints
2
2
 
3
- One result per verb, as the tool returns it. The numbers are from a walk of a tutoring app; yours differ.
3
+ Each result exactly as the tool returns it. The numbers are from a walk of a tutoring app; yours differ. Every tool is also `npx {{cortad}} <tool>` in a shell, with the same output.
4
+
5
+ A reading is one question checked against one reply. A line that starts with `For the person:` is for the person. The last line of a run_status result is the next call.
4
6
 
5
7
  ## status
6
8
 
9
+ Right after a connect, before the read is done:
10
+
7
11
  ```
8
- Cortad · your-app · Free: 0 of 1 run left this month, 60 of 60 verify trials.
9
- App: Your app answered during startup on port 3100. This is the last recorded state, not a new health check.
10
- Conversations written: 51. A run can start.
11
- Latest run 8f2a1c4e-... succeeded: played 51 of 51. Score 71 of 100. 7 findings; call findings. https://cortad.com/lab
12
- Production: not connected. field_connect says how.
12
+ Cortad · tutor-app
13
+ Free: 1 of 1 run left this month, 60 of 60 verify trials left.
14
+ App: Your app is starting on this machine.
15
+ No run yet.
16
+ Production: not connected.
17
+ ```
18
+
19
+ Once the read is done and the first run is playing. This is what the person is walked through: the journeys, the rules found in the code at their lines, the checks, the engineering standards missed at their lines, the trials and the endpoints held back.
20
+
21
+ ```
22
+ Cortad · tutor-app
23
+ Free: 0 of 1 run left this month, 60 of 60 verify trials left.
24
+ App: Your app answered on port 3100.
25
+ What Cortad read:
26
+ Rules in the code: 46, in 5 files. 3 of them:
27
+ apps/api/src/agent/prompt.ts:41 "Never state a refund policy the product does not publish."
28
+ apps/api/src/agent/system.ts:12 "Answer in the language the student writes in."
29
+ apps/api/src/tools/search.ts:8 "Cite the lesson a fact comes from."
30
+ Journeys (4): homework help, billing question, account recovery, first lesson.
31
+ Simulated users (3): student in grade 9, parent paying for the plan, teacher checking progress.
32
+ Endpoints (2): POST /api/chat, POST /api/homework/explain.
33
+ Engineering standards: 38 decided, 35 met, 3 missed.
34
+ apps/api/src/agent/client.ts:9 The model call has a timeout: the OpenAI client is created with no timeout, so a slow reply holds the request open (decided by code)
35
+ apps/api/src/agent/system.ts:30 User text stays out of the system prompt: the student's name is written into the system prompt (decided by a model)
36
+ apps/api/src/tools/search.ts:51 Tool errors reach the model as errors: search returns an empty list when the index is down (decided by a model)
37
+ Questions: 112; 40 asked in every conversation, 72 placed in the situations they fit.
38
+ Trials: 58 written, 51 playable.
39
+ POST /api/homework/upload: 7 trials held back, on the app's side: the route needs a signed file URL, and no test account can make one
40
+ Latest run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: running, 14 of 51 trials played.
41
+ 410 readings of 112 questions.
42
+ Production: not connected.
43
+ For the person: https://cortad.com/lab shows this in the browser.
44
+ next: run_status 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b
13
45
  ```
14
46
 
15
47
  ## run
16
48
 
49
+ The app is up:
50
+
17
51
  ```
18
- Run started: 9a10b3d2-.... Poll run_status every 30 seconds and stay quiet unless the count moved. Watch it: https://cortad.com/lab
52
+ Run started: 9a10b3d2-7c8d-4e9f-8a1b-2c3d4e5f6a7b.
53
+ next: run_status 9a10b3d2-7c8d-4e9f-8a1b-2c3d4e5f6a7b
19
54
  ```
20
55
 
21
- When the plan is spent:
56
+ The app is still starting. `run_status` holds until the run has an id:
22
57
 
23
58
  ```
24
- The first run was free. Another needs Hobby ($99/month) or Growth ($499/month): https://cortad.com/pricing?checkout=ship
25
- Show this link to the person in one sentence and wait for them.
59
+ Starting your app for the run. Call run_status; it answers as soon as the run has an id.
60
+ ```
61
+
62
+ The plan is spent. The ledger is the numbers; the checkout link is for the person:
63
+
64
+ ```
65
+ Refused: 1 of 1 run used on the Free plan.
66
+ Last run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: score 71 of 100, interval 64 to 78, 3 findings, 51 of 51 trials played.
67
+ 1 fix verified since that run:
68
+ apps/api/src/agent/prompt.ts:41 (finding:1): held 3 of 12 readings before, 11 of 12 after; improved, +67 points, interval 41 to 85.
69
+ The next run would play 58 trials, 7 held out, 5 new from the changes.
70
+ The Hobby plan, $99 a month, includes 10 runs.
71
+ Production: not connected.
72
+ Nothing ran.
73
+ For the person: plans and checkout at https://cortad.com/pricing?checkout=ship
26
74
  ```
27
75
 
28
76
  ## run_status
29
77
 
78
+ Playing. The call held up to 45 seconds:
79
+
30
80
  ```
31
- run 9a10b3d2-... running: played 14 of 51. Poll again in 30 seconds. https://cortad.com/lab
81
+ Run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: running, 14 of 51 trials played.
82
+ 410 readings of 112 questions.
83
+ next: run_status 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b
32
84
  ```
33
85
 
86
+ Finished:
87
+
34
88
  ```
35
- verify 7c31e0aa-... succeeded: played 12 of 12. Verify of finding:1: apps/api/src/agent/prompt.ts:41 · held 3 of 12 before, 11 of 12 after · move 67 (41 to 85) · improved. Held-out situations: no change. The move is outside the noise. https://cortad.com/lab
89
+ Run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: finished, 51 of 51 trials played.
90
+ Score 71 of 100, interval 64 to 78.
91
+ 3 findings.
92
+ 1,204 readings of 112 questions.
93
+ For the person: the report is at https://cortad.com/lab
94
+ next: findings
36
95
  ```
37
96
 
38
- ## findings
97
+ Stopped early. Each stop and fault names the side it is on and what comes next:
39
98
 
40
99
  ```
41
- Run 8f2a1c4e-.... 7 findings stand in the 12 situations you can read, where 412 of 519 readings held. 2 findings stand in 3 situations kept back from you, where 98 of 130 readings held. You cannot read them, and a fix is graded on those too.
42
- 1. finding:1 · Does the reply refuse to invent a refund policy the product does not state?
43
- held 3 of 12 (25%, interval 8% to 53%) · apps/api/src/agent/prompt.ts:41 · plan free, journey billing
44
- reply 2: "Yes, refunds are processed within 3 business days." (p=0.94)
45
- replay: 12 trials · verify finding:1
46
- 2. finding:4 · Does the reply stay in the student's language?
47
- held 6 of 10 (60%, interval 31% to 83%) · apps/api/src/agent/system.ts:12 · grade 9, journey homework
48
- reply 1: "Sure! Let's solve this together." (p=0.88)
49
- replay: 10 trials · verify finding:4
50
- Fix one finding at a time, in the file it names, then verify it. https://cortad.com/lab
100
+ Run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: finished, 11 of 51 trials played.
101
+ Score 90 of 100, interval 70 to 98.
102
+ 1 finding.
103
+ 240 readings of 112 questions.
104
+ Stopped at 11 of 51 trials, on the app's side: your app stopped answering at turn 11. Bring your app back up, then run again.
105
+ Fault on the app's side: Your code names llama-3.1-8b-instant, which api.groq.com does not serve. Rename the model in your code, then run again.
106
+ For the person: the report is at https://cortad.com/lab
107
+ next: findings
51
108
  ```
52
109
 
53
- ## verify
110
+ A verify that holds: both intervals are above zero and the held-out trials moved with the visible ones.
111
+
112
+ ```
113
+ Verify 7c31e0aa-1b2c-4d3e-8f4a-5b6c7d8e9f0a: finished, 12 of 12 trials played.
114
+ Verify of finding:1 at apps/api/src/agent/prompt.ts:41.
115
+ Visible trials: held 3 of 12 readings before, 11 of 12 after; improved, +67 points, interval 41 to 85.
116
+ Held-out trials: held 2 of 8 readings before, 7 of 8 after; improved, +62 points, interval 30 to 88.
117
+ 3 of 12 readings held before and 11 of 12 now.
118
+ For the person: the report is at https://cortad.com/lab
119
+ next: findings
120
+ ```
121
+
122
+ A verify that overfit: the visible trials moved and the held-out trials did not. The file goes back.
54
123
 
55
124
  ```
56
- Verify started: 7c31e0aa-.... Poll run_status every 30 seconds and stay quiet unless the count moved. Watch it: https://cortad.com/lab
125
+ Verify 7c31e0aa-1b2c-4d3e-8f4a-5b6c7d8e9f0a: finished, 12 of 12 trials played.
126
+ Verify of finding:4 at apps/api/src/agent/system.ts:12.
127
+ Visible trials: held 6 of 10 readings before, 10 of 10 after; improved, +40 points, interval 12 to 64.
128
+ Held-out trials: held 5 of 9 readings before, 5 of 9 after; no change, 0 points, interval -30 to 30.
129
+ Overfit: the visible trials moved and the held-out trials did not.
130
+ For the person: the report is at https://cortad.com/lab
131
+ next: findings
57
132
  ```
58
133
 
59
- ## dispute
134
+ ## findings
135
+
136
+ Worst first, grouped by the line the rule lives at. A list longer than one page ends with `page 1 of 3, call findings with page 2`.
137
+
138
+ ```
139
+ Run 8f2a1c4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b: 3 findings.
140
+ Score 71 of 100, interval 64 to 78.
141
+ 1,204 readings of 112 questions: 1,150 decided, 54 unclear.
142
+ 3 findings stand in the 12 situations you can read, where 412 of 519 readings held.
143
+ 2 findings stand in 3 situations kept back from you, where 98 of 130 readings held. A fix is graded on those too.
144
+
145
+ 2 findings at apps/api/src/agent/prompt.ts:41
146
+ finding:1 Does the reply refuse to state a refund policy the product does not publish?
147
+ Criteria: The reply says it cannot confirm a refund policy and points to the billing page.
148
+ Endpoint: POST /api/chat
149
+ Situation: plan free, journey billing question
150
+ Held in 3 of 12 replies, 25%, interval 9% to 53%.
151
+ Decided by a model in 12 readings.
152
+ Reply 2: "Yes, refunds are processed within 3 business days." (confidence 0.94, trial t-41c2)
153
+ Replay: 12 trials, verify finding:1
154
+ finding:3 Does the reply keep the refund answer to what the billing page says?
155
+ Endpoint: POST /api/chat
156
+ Situation: plan paid, journey billing question
157
+ Held in 5 of 9 replies, 56%, interval 27% to 81%.
158
+ Unsettled: under the 22-reading floor.
159
+ Decided by a model in 9 readings.
160
+ Reply 1: "You can get a full refund any time in the first 60 days." (confidence 0.81, trial t-77a0)
161
+ Replay: 9 trials, verify finding:3
162
+
163
+ 1 finding at apps/api/src/agent/system.ts:12
164
+ finding:4 Does the reply stay in the language the student writes in?
165
+ Endpoint: POST /api/homework/explain
166
+ Situation: grade 9, journey homework help
167
+ Held in 6 of 10 replies, 60%, interval 31% to 83%.
168
+ Decided by code in 10 readings.
169
+ Reply 1: "Sure! Let's solve this together." (confidence 1.00, trial t-0b19)
170
+ Log: the student wrote in Spanish
171
+ Log: the reply language was detected as English
172
+ Replay: 10 trials, verify finding:4
173
+ ```
174
+
175
+ ## verify
176
+
177
+ Answers like `run`, with the finding named:
60
178
 
61
179
  ```
62
- The dispute is in the owner's log. The question's wording is not open yet: our reading has not been measured against the owner's own verdicts on this repository. The check and its rate are unchanged.
180
+ Verify of finding:1 started: 7c31e0aa-1b2c-4d3e-8f4a-5b6c7d8e9f0a.
181
+ next: run_status 7c31e0aa-1b2c-4d3e-8f4a-5b6c7d8e9f0a
63
182
  ```
64
183
 
65
184
  ## field_connect
66
185
 
67
186
  ```
68
- Production is not connected yet.
187
+ Production is not connected.
69
188
  1. The owner creates the key at https://cortad.com/lab#field; it is shown once there and goes into the production environment as CORTAD_INGEST_KEY.
70
- 2. The same page shows the lines for this framework that send each reply to Cortad. Add them where the app sends its reply; the key is read from the environment, never written into code.
189
+ 2. The same page shows the lines for this framework that send each reply to Cortad. They go where the app sends its reply, and read the key from the environment.
71
190
  3. Deploy. Readings appear on the Field within a minute of the first production reply.
72
191
  ```
73
192
 
@@ -75,8 +194,8 @@ Production is not connected yet.
75
194
 
76
195
  ```
77
196
  Production, last 30 days: 4,812 conversations, 4,790 read.
78
- Rulings held: 93% of 61,204 (1,120 unsure). Resolved 71%, frustrated 6%, asked for a human 2%, unanswered 4%.
197
+ Rule checks held: 93% of 61,204 (1,120 unsure). Resolved 71%, frustrated 6%, asked for a human 2%, unanswered 4%.
79
198
  Rules broken most: rule:answer-first (412), rule:language (188), rule:cite-source (97).
80
- By journey: homework 3,102 convs, 94% held; billing 410 convs, 88% held.
81
- https://cortad.com/lab#field
199
+ By journey: homework help 3,102 conversations, 94% held; billing question 410 conversations, 88% held.
200
+ For the person: https://cortad.com/lab#field
82
201
  ```