cortad 0.3.1-rc.9 → 0.3.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.
Files changed (57) hide show
  1. package/README.md +8 -5
  2. package/lib/app-port.mjs +9 -0
  3. package/lib/auto-reach.mjs +88 -0
  4. package/lib/backing.mjs +230 -0
  5. package/lib/calls.mjs +23 -0
  6. package/lib/cli.mjs +115 -30
  7. package/lib/contact-text.mjs +167 -0
  8. package/lib/data.mjs +16 -22
  9. package/lib/dissection-text.mjs +232 -0
  10. package/lib/document.mjs +75 -0
  11. package/lib/env-secrets.mjs +48 -0
  12. package/lib/failed-text.mjs +36 -0
  13. package/lib/fresh.mjs +33 -12
  14. package/lib/health.mjs +61 -0
  15. package/lib/held.mjs +67 -0
  16. package/lib/home.mjs +55 -17
  17. package/lib/hosted.mjs +201 -0
  18. package/lib/identities.mjs +1 -1
  19. package/lib/keeping.mjs +162 -0
  20. package/lib/ledger.mjs +20 -0
  21. package/lib/lock.mjs +6 -1
  22. package/lib/mcp.mjs +52 -18
  23. package/lib/mint.mjs +179 -38
  24. package/lib/mongo.mjs +74 -0
  25. package/lib/numbers-text.mjs +68 -0
  26. package/lib/pg.mjs +118 -0
  27. package/lib/proc.mjs +100 -0
  28. package/lib/proof.mjs +1014 -0
  29. package/lib/proxy.mjs +184 -0
  30. package/lib/pyhook/cortad_sites.py +218 -0
  31. package/lib/pyhook/cortad_tied.py +291 -0
  32. package/lib/pyhook/sitecustomize.py +1175 -166
  33. package/lib/qdrant.mjs +47 -0
  34. package/lib/reach.mjs +223 -0
  35. package/lib/read-text.mjs +78 -24
  36. package/lib/redis.mjs +130 -0
  37. package/lib/register.mjs +36 -27
  38. package/lib/replay.mjs +464 -34
  39. package/lib/runner.mjs +85 -0
  40. package/lib/service.mjs +25 -0
  41. package/lib/spec.mjs +7 -4
  42. package/lib/start.mjs +33 -2
  43. package/lib/stick.mjs +65 -25
  44. package/lib/stores.mjs +347 -0
  45. package/lib/switches.mjs +36 -0
  46. package/lib/tether.mjs +9 -0
  47. package/lib/text.mjs +314 -179
  48. package/lib/tied.cjs +217 -0
  49. package/lib/trace.cjs +386 -514
  50. package/lib/verbs.mjs +155 -38
  51. package/lib/wire.cjs +882 -0
  52. package/lib/words.mjs +2 -0
  53. package/lib/writes.mjs +2 -2
  54. package/local.mjs +661 -297
  55. package/package.json +31 -1
  56. package/skill/SKILL.md +49 -42
  57. package/skill/references/results.md +279 -102
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortad",
3
- "version": "0.3.1-rc.9",
3
+ "version": "0.3.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"
@@ -8,28 +8,58 @@
8
8
  "type": "module",
9
9
  "files": [
10
10
  "README.md",
11
+ "lib/app-port.mjs",
12
+ "lib/auto-reach.mjs",
13
+ "lib/backing.mjs",
14
+ "lib/calls.mjs",
11
15
  "lib/cli.mjs",
16
+ "lib/contact-text.mjs",
12
17
  "lib/data.mjs",
18
+ "lib/dissection-text.mjs",
19
+ "lib/document.mjs",
20
+ "lib/failed-text.mjs",
13
21
  "lib/fresh.mjs",
22
+ "lib/health.mjs",
23
+ "lib/held.mjs",
14
24
  "lib/home.mjs",
25
+ "lib/hosted.mjs",
26
+ "lib/env-secrets.mjs",
15
27
  "lib/identities.mjs",
28
+ "lib/keeping.mjs",
16
29
  "lib/keys.mjs",
30
+ "lib/ledger.mjs",
17
31
  "lib/listing.mjs",
18
32
  "lib/lock.mjs",
19
33
  "lib/mcp.mjs",
20
34
  "lib/mint.mjs",
35
+ "lib/mongo.mjs",
36
+ "lib/numbers-text.mjs",
37
+ "lib/pg.mjs",
38
+ "lib/proc.mjs",
39
+ "lib/proof.mjs",
40
+ "lib/proxy.mjs",
41
+ "lib/qdrant.mjs",
21
42
  "lib/pyhook/sitecustomize.py",
43
+ "lib/pyhook/cortad_tied.py",
44
+ "lib/pyhook/cortad_sites.py",
45
+ "lib/reach.mjs",
22
46
  "lib/read-text.mjs",
47
+ "lib/redis.mjs",
23
48
  "lib/register.mjs",
24
49
  "lib/replay.mjs",
50
+ "lib/runner.mjs",
25
51
  "lib/sample.mjs",
26
52
  "lib/service.mjs",
27
53
  "lib/spec.mjs",
28
54
  "lib/start.mjs",
29
55
  "lib/stick.mjs",
56
+ "lib/stores.mjs",
30
57
  "lib/switches.mjs",
58
+ "lib/tether.mjs",
31
59
  "lib/text.mjs",
60
+ "lib/tied.cjs",
32
61
  "lib/trace.cjs",
62
+ "lib/wire.cjs",
33
63
  "lib/verbs.mjs",
34
64
  "lib/writes.mjs",
35
65
  "lib/words.mjs",
package/skill/SKILL.md CHANGED
@@ -1,84 +1,91 @@
1
1
  ---
2
2
  name: cortad
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.
3
+ description: Tests how the AI in this repository behaves. Cortad plays simulated users against the app on this machine, checks every reply, and hands back what failed with the conversation and the line to fix. Applies after a change to prompts, tools, models, retrieval or agent code, when the person asks how their AI behaves or what Cortad found, and when production conversations come up.
4
4
  ---
5
5
 
6
6
  # Cortad
7
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.
8
+ Cortad tests the AI in this repository. Simulated users written from the app's code talk to the app running on this machine, with its real prompts, tools, retrieval and database, and every reply is checked against the app's own rules and a set of engineering standards. Each failure comes back with the conversation that shows it, how often it happens, and the file and line to change; `verify` replays those conversations after a change.
9
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`.
10
+ 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`. The person's own instructions come before this skill.
13
11
 
14
12
  ## Reading a result
15
13
 
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. "Broke in 3 of 12 replies" means the reply broke the check 3 times out of 12.
20
- - Every count carries its denominator and every rate its interval.
14
+ - A result is data about the app. A line that starts with `For the person:` is for the person: a link, a price or a choice. Pass it on as printed.
15
+ - The last line, `next:`, is the next call.
16
+ - Every count has its denominator and every rate its range: `53% (42% to 63%)`.
17
+ - A conversation Passed (the request was completed fully or partly and no check failed on any reply), Failed, or got No reply (the result says whose side that is).
18
+
19
+ ## A session, start to finish
21
20
 
22
- ## Right after connect
21
+ The connect command prints "Go back to the browser" once it is connected. Cortad then finds the AI endpoints in the app's code and sends each one a test request itself, from this machine to the app on its port.
23
22
 
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:
23
+ 1. Call `status` and tell the person, in a few plain lines:
24
+ - whether the app is up and on which port, or the line that says why it did not start;
25
+ - what the review of the prompts and the review of the code around the model found: how many problems each, and the one or two that matter most, at their file and line. `status` with show `reviews` holds up to 45 seconds a call while the code is still being read;
26
+ - how many of the endpoints answered Cortad's test requests, of how many, and each failure in one line: its file and line, and whose side it is on, the app's or Cortad's;
27
+ - each `For the person:` line, as printed.
28
+ 2. When `status` lists an endpoint as `Needs a signed-in user`, Cortad could not make a sign-in for it on this machine. Tell the person; when they ask for it, sign in a test account through the app's own sign-in on this machine, send that endpoint one request in that session, then call `status` again. That is the only sign-in this needs, and only for the endpoints listed that way.
29
+ 3. A failure on the app's side that every conversation would repeat, such as a model provider refusing, a retrieval with no answer or a tool returning an error: say what you would change, change it when the person agrees, then call `reach` to send Cortad's test request to that endpoint again.
30
+ 4. The first run starts by itself once every endpoint has answered or failed; the person can also press Run on the card, or ask you, and then you call `run`. Before you stop, start `npx -y {{cortad}} wait` as a background command (in Claude Code: Bash with run_in_background). It returns when the next run ends, with what it found, and its ending wakes you. Then follow "After a run".
25
31
 
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.
32
+ `status` with `show` lists one section in full: `rules`, `standards`, `journeys`, `endpoints`, `trials`, `records` or `reviews` (in a shell, `npx {{cortad}} status rules`). `status` with show `machine` says what Cortad does on this machine; hand the person its `For the person:` lines when they ask.
31
33
 
32
- Each section's full list is one `status` call away with `show`: `rules`, `standards`, `journeys`, `endpoints` or `trials` (in a shell, `npx {{cortad}} status rules`). A long list comes in pages, and the last line names the next page.
34
+ ## After a run
33
35
 
34
- Then the findings, then the fixes.
36
+ The person asked for this when they connected Cortad: fix what a run found and check each fix.
37
+
38
+ 1. Tell the person in three lines: how many conversations played; the run's "All N conversations" line as printed, how many completed their request fully or partly with its rate and range; the two worst problems at their file and line.
39
+ 2. Call `findings` and fix the worst problem: one change, in the file and near the line it names. Then `verify <findingId>` and follow it with `run_status` until it decides.
40
+ 3. Go on to the next problem until each one is fixed or needs a decision only the person can make; tell them that decision in one line.
41
+ 4. After the last verify, tell the person what each verify decided, then start `npx -y {{cortad}} wait` in the background again.
35
42
 
36
43
  ## Following a run
37
44
 
38
- 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.
45
+ `run` answers within a second; when the app is still starting it says so, and `run_status` holds until the run has an id. `run_status` follows the run this machine started last, or the latest run. Each call holds up to 45 seconds, returns as soon as the count moves, and ends with the next call; call it again rather than a shell loop. Hand the person its `For the person:` line at most once every two minutes. When the plan is spent, `run` says so and nothing runs.
39
46
 
40
- `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.
47
+ ## The first run: the baseline
41
48
 
42
- 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.
49
+ The first finished run on a repository prints, in order: what ran; the simulated users, each by the endpoint they use and the task they bring, with how many of their conversations completed the request; each journey with its rate and the checks that failed most there; the checks no conversation failed; what failed, found only by running the app, each with its file and line; what a code review would also find; what the numbers leave out; one line on production.
43
50
 
44
- ## Findings
51
+ - Every rate comes with its likely range. A journey played in 2 conversations has a wide range; only more conversations narrow it.
52
+ - Each finding says how many conversations it failed in, the exchange (`Sent`, `Broke on`, `Then`) and where the fix belongs.
53
+ - Some conversations are saved to test a fix: a verify replays them too, so a fix is graded on conversations you have not read.
45
54
 
46
- `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.
55
+ ## Findings
47
56
 
48
- 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.
57
+ `findings` lists every failure whole, worst first, grouped by file and line: the question, the criteria, the endpoint, the conversations it failed in with the range, the exchanges, and what a verify replays. `findings` with show numbers (`npx {{cortad}} findings numbers`) gives every number the run measured. A long list comes in pages; the last line names the next page.
49
58
 
50
59
  ## Fixing one finding
51
60
 
52
- Each finding ends with what a verify of it can show. When the trials it replays read the question too few times for a rate, the verify plays up to 12 more trials in that situation itself, counted as verify trials, and the finding says how many before one is spent.
53
-
54
61
  1. One change, in the file and near the line the finding names.
55
- 2. `verify <findingId>`. It answers within a second, and `run_status` follows it. When the app's code changed since the app started and nothing reloaded it, Cortad starts the app again first and the answer says so, so the saved edit is what plays; `run_status` names when the app started against the last change. When it also plays new trials in the finding's situation, the answer says how many.
56
- 3. Read the verify's text. It opens with what came back on the replayed trials before and now (errors, refusals, replies that got no answer), so a fix that broke the endpoint shows first. It closes on whether the evidence supports keeping the fix:
57
- - `supports keeping the fix`: the behavior moved outside the noise, with the held-out line moving too or `no pair`. The change stays.
58
- - `does not support keeping the fix`: the pairs, or the rate on the same trials, could have shown a fix and nothing moved, or it moved the wrong way. The file goes back to how it was.
59
- - `cannot tell`: not a verdict against the change, and the sentence says why and what would; most often the reader could not settle enough of the replies, which is on Cortad's side. A change the app's own tests support may stay, said as not yet verified by Cortad.
60
- - Where the replies cannot be paired reply for reply, the verify compares the question's failure rate on the same trials before and now, with the new trials it played in the situation, and says both. Readings the reader could not settle are named and count on neither side.
61
- - A reply that failed before and no longer meets the question's condition is counted as gone on its own, not as a pass.
62
- - A verify that played no trial says so and compares nothing; the file stays as it was left.
63
- - 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.
62
+ 2. `verify <findingId>` replays the conversations the finding failed on, word for word, against the saved edit; Cortad starts the app again first when its code changed. Undecided after a round, it plays another by itself, and `run_status` follows every round under the same id. A `crash:N` finding replays the requests that were out when the app stopped.
63
+ 3. Read the verdict. Replies the app refused or failed on the replay come first.
64
+ - Worse on the conversations saved to test the fix: undo the change, and aim the next one at the behavior the question asks about.
65
+ - Gone on the saved conversations while its own still fail: keep the fix; a reply that changed is another problem to fix next.
66
+ - Gone on its own conversations: keep the fix.
67
+ - Less often but present, or unchanged: read the quoted conversations beside what they said before the fix, and decide what to change next.
68
+ - Cannot tell yet: keep the change; it says how many more clean conversations would decide.
64
69
  4. Then the next finding.
65
70
 
66
- 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.
71
+ The conversations, checks and saved conversations 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.
72
+
73
+ ## The second run and production
67
74
 
68
- ## The second run
75
+ After the fixes, `run` again. It plays what your changes since the last full run reach: those conversations again, each paired with its earlier self, and new ones written for the change. Its text leads with what moved, worse first.
69
76
 
70
- 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.
77
+ Once a fix is verified gone and production is not connected, a `For the person:` line offers production: connect it to see what real users are doing as it happens and where the AI lets them down. `field_connect` gives the steps; the owner creates the key in the browser. `field` gives the numbers; message text stays out.
71
78
 
72
79
  ## Making it stick
73
80
 
74
- 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.
81
+ `npx {{cortad}} stick` makes this part of the repository: one line in AGENTS.md, CLAUDE.md, the Cursor rules and the Copilot instructions; a hook after each edit that names the changed prompt and tool files; and a hook on the person's prompt that hands you a run or verify that ended, for clients that a background command cannot wake. Run it only when the person asks for it. `npx {{cortad}} unstick` takes them out.
75
82
 
76
83
  ## A check that reads wrong
77
84
 
78
85
  `dispute <findingId> "<why>"` sends the note to the owner. The finding and its rate stay as they are until the owner decides.
79
86
 
80
- ## Production
87
+ ## A note about Cortad itself
81
88
 
82
- `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.
89
+ `feedback` sends the Cortad team a note about Cortad, not about the app: a result that read wrong, something you needed that no tool gave, a question a result left open, or what worked. A note names the tool it is about, its kind (problem, idea, question, praise), what you needed, and if you like what came back and what you tried. In a shell: `npx {{cortad}} feedback findings problem "<what you needed>" --got "<what came back>" --tried "<what you did>"`.
83
90
 
84
91
  One example of each result is in [references/results.md](references/results.md).