transcripto 0.1.2__tar.gz → 0.1.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: transcripto
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Search everything your coding agents ever did, grade your own prompts, and price your decisions. Local, stdlib-only, your data never leaves the machine.
5
5
  Author: Oscar Morke
6
6
  License: MIT
@@ -29,19 +29,11 @@ your disk and never opens a socket.
29
29
  uvx transcripto coach
30
30
  ```
31
31
 
32
- > **check which build you got.** `trace`, `--harness cursor`, and the "run `index`
33
- > first" errors below all arrive in **0.1.2**. On anything older, `trace` is not a
34
- > command, cursor is rejected, and the index-gated commands fail with a raw sqlite
35
- > traceback instead of an instruction. One line settles which one you are holding:
32
+ > **which build you got.** `uvx transcripto --version` should print **0.1.3**. If `--version`
33
+ > is not a recognised flag at all you are on 0.1.1, which predates `trace`, Cursor support and
34
+ > this README. `uvx --refresh transcripto` forces a fresh resolve past uv's cache.
36
35
  >
37
- > ```
38
- > uvx transcripto --version # 0.1.2 or newer = this README is accurate
39
- > ```
40
- >
41
- > *Read 2026-08-31: PyPI was serving 0.1.1 while this README described 0.1.2, so
42
- > `uvx transcripto` gave the older build. If `--version` is not even a recognised
43
- > flag, you have 0.1.1 — it was added in 0.1.2 precisely because there was no way
44
- > to tell.* The repo always matches this README and needs nothing installed:
36
+ > The repo always matches this README and needs nothing installed:
45
37
  >
46
38
  > ```
47
39
  > git clone https://github.com/Morkeeth/transcripto && cd transcripto
@@ -81,41 +73,48 @@ the same way.
81
73
 
82
74
  ## what you get back
83
75
 
84
- this is a real run on one machine, pasted unedited, 2026-08-28:
76
+ this is a real run on one machine, 2026-08-31. The numbers are unedited; the two quoted prompts are synthetic stand-ins of the same shape, because your prompts never leave your machine and neither do mine:
85
77
 
86
78
  ```
87
79
 
88
80
  YOUR PROMPT HABITS, GRADED (offline, your machine only)
89
81
 
90
- harness: claude
91
- corpus : 2720 transcript(s), 381,804 records
92
- kept : 3678 prompts you actually typed (0.96% of records)
93
- episodes: 1946 ranked, 910 survived (47%)
94
- tiers : commit 373 | write/edit 537 | reverted 2 | nothing durable 1034
82
+ - your worst looped prompt, with its witness:
83
+ "hmm ok lets just try again and see if it works this time, same thing as before but…"
84
+ NO-DURABLE-RECORD: read-only Bash only, no file change · corrections: 15 · assistant turns: 221
85
+
86
+ + your best landed prompt, with its witness:
87
+ "TERMINAL 3 — parser · ~/CODE/demo Read hack.md. Fix the counter, run the suite, commit if green…"
88
+ COMMIT-WITNESSED: git commit · corrections: 0
95
89
 
96
90
  SURVIVAL IS A PROXY: survival = a durable Write/Edit or an un-reverted git commit in-episode. A PROXY, not proof the work was correct or shipped.
97
91
 
98
92
  SURVIVES MOST do more of these:
99
- 64% (167/260) detailed (>40 words)
100
- 63% (66/104) states-a-check-or-done-condition
101
- 58% (414/708) intent:CHANGE
102
- 58% (21/36) no-object (pronoun/vague)
103
- 57% (99/175) cites-a-file-or-path
93
+ 65% (71/110) states-a-check-or-done-condition
94
+ 64% (178/276) detailed (>40 words)
95
+ 59% (22/37) no-object (pronoun/vague)
96
+ 59% (451/763) intent:CHANGE
97
+ 57% (106/187) cites-a-file-or-path
104
98
 
105
99
  SURVIVES LEAST these tend to loop:
106
- 33% (4/12) intent:REVERT
107
- 39% (411/1043) intent:none
108
- 40% (4/10) intent:TEST
109
- 42% (298/715) terse (<8 words)
110
- 45% (77/173) intent:DESCRIBE
111
-
112
- + your best landed prompt, with its witness:
113
- "mTERMINAL 8 — Mountain of Helicon · ~/CODE/mountain-of-helicon Read ~/CODE/mountain-of-helicon. Two…"
114
- COMMIT-WITNESSED: git commit · corrections: 0
115
-
116
- - your worst looped prompt, with its witness:
117
- "ok, and lets see they might solve it in the future so i can go back to my beloeved routine :) Befor…"
118
- NO-DURABLE-RECORD: read-only Bash only, no file change · corrections: 15 · assistant turns: 221
100
+ 31% (4/13) intent:REVERT
101
+ 40% (451/1129) intent:none
102
+ 42% (320/765) terse (<8 words)
103
+ 42% (81/192) intent:DESCRIBE
104
+ 45% (5/11) intent:TEST
105
+
106
+ harness claude · 2957 transcript(s), 431,085 records · 3969 typed by you (0.92%)
107
+ episodes: 2108 ranked, 992 survived (47%)
108
+ commit 454 · write/edit 538 · reverted 2 · nothing durable 1114
109
+
110
+ ─────────────────────────────────────────────────────────
111
+ compare yours. numbers only, nothing from your prompts:
112
+
113
+ transcripto coach · claude · 2108 episodes · 47% survived
114
+ states-a-check-or-done-condition 65% (71/110)
115
+ intent:none 40% (451/1129)
116
+ gap 1.6x
117
+ ─────────────────────────────────────────────────────────
119
118
  ```
120
119
 
121
120
  those are my numbers on that date, and they move every session i run, so treat
@@ -143,6 +142,74 @@ signal, not a verdict. if it ever prints something that flatters you, distrust i
143
142
 
144
143
  the caveat is printed in the output itself, every run, on purpose.
145
144
 
145
+ ## correction rate
146
+
147
+ > in the repo since 2026-09-02, not yet on PyPI. `python3 transcripto.py coach` prints it.
148
+
149
+ one more line under the coach footer:
150
+
151
+ ```
152
+ correction rate: 6% measured (227 of 4061 typed turns) · v1 catches ~1 in 6, so the real rate is ~26-37%
153
+ ```
154
+
155
+ **correction rate = typed turns that correct the agent ÷ typed turns.** the denominator
156
+ is the same authorship gate as every other number here (`typed` or `queued`, never
157
+ `isMeta`, `isSidechain` or a tool result), so a tool result that happens to say "wrong"
158
+ cannot move it. a typed turn counts as a correction when a **marker** fires in its head:
159
+ the first 80 words after URLs and file paths are stripped, case-insensitive, whole-word:
160
+ a leading or bare `no`, `again`, `wrong`, `not that`, `I meant`, `revert`, `undo`, `stop`,
161
+ `instead`, plus a few measured additions. whole-word, so "against" is not "again" and
162
+ "now" is not "no". the v0 "nudge" rule (a short turn naming the agent's last file) is gone:
163
+ measured over 100 flagged rows it fired alone five times and was wrong five times.
164
+ `TRANSCRIPTO_CORRECTION=v0` brings the old classifier back for comparison.
165
+
166
+ it is one pure function, `is_correction(text)`, and it is a **floor**, now measured rather
167
+ than asserted: on a 200-row labelled sample the v1 classifier has precision 0.81 and recall
168
+ 0.16 (`docs/CORRECTION-PRECISION-2026-09-03.md`), which is why the printed line carries the
169
+ "~1 in 6" correction and a range. read it as a trend on your own history.
170
+ `test_correction.sh` pins the rule and the gate on `fixtures-correction/`.
171
+
172
+ ## export-run
173
+
174
+ > in the repo since 2026-09-02, not yet on PyPI.
175
+
176
+ ```
177
+ transcripto export-run latest # the newest session on this machine
178
+ transcripto export-run 3f9c1a2b # a session id, or a prefix of one
179
+ transcripto export-run path/to/session.jsonl # a transcript file
180
+ transcripto export-run latest --harness codex # --root / --harness as for coach
181
+ ```
182
+
183
+ one run's numbers as JSON, read straight from the transcript file (no index needed).
184
+ this is the contract other tools read (Agent Grinder's card, ZUP's board); the keys are
185
+ frozen under `schema`, and a new key is an addition, never a rename.
186
+
187
+ | key | meaning |
188
+ |---|---|
189
+ | `schema` | `transcripto.export-run/1` |
190
+ | `session_id` | the harness's session id (Claude Code: the file name; Codex: `session_meta.id`; Cursor: the file name) |
191
+ | `project` | the run's `cwd` |
192
+ | `harness` | `claude` · `codex` · `cursor` |
193
+ | `transcript` | absolute path of the file read |
194
+ | `started` · `ended` | first and last record timestamp, UTC, `…Z`; `null` if the file carries none |
195
+ | `duration_s` | `ended − started`, whole seconds |
196
+ | `records` | every record in the file, before any gate |
197
+ | `typed_turns` | records that pass the authorship gate: `promptSource` typed or queued, never meta, sidechain or tool result. the same count coach prints as "typed by you" |
198
+ | `corrections` | typed turns `is_correction()` flags (see above) |
199
+ | `correction_rate` | `corrections / typed_turns`, 3 decimals; `null` when nothing was typed |
200
+ | `tool_calls` | every `tool_use` block the agent emitted |
201
+ | `files_touched` | sorted set of `file_path` (or `notebook_path`) from Edit / Write / Read / MultiEdit / NotebookEdit calls |
202
+ | `commits_in_window` | commits stamped inside `[started, ended]` in the project's git reflog; `null` when `project` is not inside a git repo |
203
+ | `commits` | those commits as `{sha, ts, subject}`, oldest first; `null` when not a repo |
204
+ | `proxy` | the caveat, in the JSON so it travels with the numbers |
205
+
206
+ `commits_in_window` reads `.git/logs/HEAD` directly, not `git log`, because this file
207
+ does not shell out (see privacy). the reflog is the record of what **that working tree**
208
+ did: a commit made there in the window is in it, a commit pulled in from elsewhere is not.
209
+ git expires the reflog after 90 days by default, so a run older than that can read 0 here
210
+ while `git log` would still show its commits. `commit (amend)` counts; a rebase's `pick`
211
+ lines do not. a `.git` file (a worktree) is followed to its gitdir.
212
+
146
213
  ## why your own gate matters here
147
214
 
148
215
  at fleet scale roughly 95% of the `type: user` records in a transcript are not
@@ -200,15 +267,15 @@ claim, so here is the grep that settles it against the single file it ships as:
200
267
  $ grep -nE '^[[:space:]]*(import|from) ' transcripto.py
201
268
  8:import sys, os, json, glob, re, sqlite3, argparse
202
269
  9:from datetime import datetime, timezone
203
- 260: import time
204
- 1051: import datetime
205
- 1061: from the separator), so the result is checked on disk and dropped if it is
270
+ 261: import time
271
+ 1160: import datetime
272
+ 1170: from the separator), so the result is checked on disk and dropped if it is
206
273
  ```
207
274
 
208
275
  five lines, four of which are imports and all four are stdlib. `time` and
209
276
  `datetime` sit inside functions, which is why the pattern allows for indentation —
210
277
  anchor it at `^import` and you would miss two, so do not take my word for the
211
- anchor either. line 1061 is the pattern catching a docstring that happens to begin
278
+ anchor either. line 1170 is the pattern catching a docstring that happens to begin
212
279
  with the word `from`; it is prose, not an import, and it is left in rather than
213
280
  tuned out, because a grep you tuned until it agreed with you proves nothing.
214
281
 
@@ -247,6 +314,7 @@ transcripto sessions recent sessions + the first prompt YOU typed in each
247
314
  transcripto stats what you actually work on
248
315
  transcripto cost what ONE of your decisions costs
249
316
  transcripto coach which of YOUR prompt habits survive (a proxy)
317
+ transcripto export-run one run's numbers as JSON (typed turns, correction rate, commits)
250
318
  ```
251
319
 
252
320
  `ask` is the one that kills "wait, did i lose something?". it answers "what was i
@@ -307,9 +375,12 @@ just gives the file a name on your PATH.
307
375
  ./test_cost.sh 12 assertions
308
376
  ./test_small_n.sh 7 assertions
309
377
  ./test_label_bands.sh 13 assertions
378
+ ./test_correction.sh 32 assertions (correction rate + export-run, 2026-09-02)
379
+ ./test_cursor_partial.sh 7 assertions
380
+ ./test_version.sh 1 assertion (VERSION matches in transcripto.py and pyproject.toml)
310
381
  ```
311
382
 
312
- 61 assertions, all green, re-run 2026-08-31.
383
+ 91 assertions, all green, re-run 2026-09-02.
313
384
 
314
385
  offline, no keys, on fixtures that inherit the real transcript shape including
315
386
  all four ways a non-human record disguises itself as `type: user`.
@@ -11,19 +11,11 @@ your disk and never opens a socket.
11
11
  uvx transcripto coach
12
12
  ```
13
13
 
14
- > **check which build you got.** `trace`, `--harness cursor`, and the "run `index`
15
- > first" errors below all arrive in **0.1.2**. On anything older, `trace` is not a
16
- > command, cursor is rejected, and the index-gated commands fail with a raw sqlite
17
- > traceback instead of an instruction. One line settles which one you are holding:
14
+ > **which build you got.** `uvx transcripto --version` should print **0.1.3**. If `--version`
15
+ > is not a recognised flag at all you are on 0.1.1, which predates `trace`, Cursor support and
16
+ > this README. `uvx --refresh transcripto` forces a fresh resolve past uv's cache.
18
17
  >
19
- > ```
20
- > uvx transcripto --version # 0.1.2 or newer = this README is accurate
21
- > ```
22
- >
23
- > *Read 2026-08-31: PyPI was serving 0.1.1 while this README described 0.1.2, so
24
- > `uvx transcripto` gave the older build. If `--version` is not even a recognised
25
- > flag, you have 0.1.1 — it was added in 0.1.2 precisely because there was no way
26
- > to tell.* The repo always matches this README and needs nothing installed:
18
+ > The repo always matches this README and needs nothing installed:
27
19
  >
28
20
  > ```
29
21
  > git clone https://github.com/Morkeeth/transcripto && cd transcripto
@@ -63,41 +55,48 @@ the same way.
63
55
 
64
56
  ## what you get back
65
57
 
66
- this is a real run on one machine, pasted unedited, 2026-08-28:
58
+ this is a real run on one machine, 2026-08-31. The numbers are unedited; the two quoted prompts are synthetic stand-ins of the same shape, because your prompts never leave your machine and neither do mine:
67
59
 
68
60
  ```
69
61
 
70
62
  YOUR PROMPT HABITS, GRADED (offline, your machine only)
71
63
 
72
- harness: claude
73
- corpus : 2720 transcript(s), 381,804 records
74
- kept : 3678 prompts you actually typed (0.96% of records)
75
- episodes: 1946 ranked, 910 survived (47%)
76
- tiers : commit 373 | write/edit 537 | reverted 2 | nothing durable 1034
64
+ - your worst looped prompt, with its witness:
65
+ "hmm ok lets just try again and see if it works this time, same thing as before but…"
66
+ NO-DURABLE-RECORD: read-only Bash only, no file change · corrections: 15 · assistant turns: 221
67
+
68
+ + your best landed prompt, with its witness:
69
+ "TERMINAL 3 — parser · ~/CODE/demo Read hack.md. Fix the counter, run the suite, commit if green…"
70
+ COMMIT-WITNESSED: git commit · corrections: 0
77
71
 
78
72
  SURVIVAL IS A PROXY: survival = a durable Write/Edit or an un-reverted git commit in-episode. A PROXY, not proof the work was correct or shipped.
79
73
 
80
74
  SURVIVES MOST do more of these:
81
- 64% (167/260) detailed (>40 words)
82
- 63% (66/104) states-a-check-or-done-condition
83
- 58% (414/708) intent:CHANGE
84
- 58% (21/36) no-object (pronoun/vague)
85
- 57% (99/175) cites-a-file-or-path
75
+ 65% (71/110) states-a-check-or-done-condition
76
+ 64% (178/276) detailed (>40 words)
77
+ 59% (22/37) no-object (pronoun/vague)
78
+ 59% (451/763) intent:CHANGE
79
+ 57% (106/187) cites-a-file-or-path
86
80
 
87
81
  SURVIVES LEAST these tend to loop:
88
- 33% (4/12) intent:REVERT
89
- 39% (411/1043) intent:none
90
- 40% (4/10) intent:TEST
91
- 42% (298/715) terse (<8 words)
92
- 45% (77/173) intent:DESCRIBE
93
-
94
- + your best landed prompt, with its witness:
95
- "mTERMINAL 8 — Mountain of Helicon · ~/CODE/mountain-of-helicon Read ~/CODE/mountain-of-helicon. Two…"
96
- COMMIT-WITNESSED: git commit · corrections: 0
97
-
98
- - your worst looped prompt, with its witness:
99
- "ok, and lets see they might solve it in the future so i can go back to my beloeved routine :) Befor…"
100
- NO-DURABLE-RECORD: read-only Bash only, no file change · corrections: 15 · assistant turns: 221
82
+ 31% (4/13) intent:REVERT
83
+ 40% (451/1129) intent:none
84
+ 42% (320/765) terse (<8 words)
85
+ 42% (81/192) intent:DESCRIBE
86
+ 45% (5/11) intent:TEST
87
+
88
+ harness claude · 2957 transcript(s), 431,085 records · 3969 typed by you (0.92%)
89
+ episodes: 2108 ranked, 992 survived (47%)
90
+ commit 454 · write/edit 538 · reverted 2 · nothing durable 1114
91
+
92
+ ─────────────────────────────────────────────────────────
93
+ compare yours. numbers only, nothing from your prompts:
94
+
95
+ transcripto coach · claude · 2108 episodes · 47% survived
96
+ states-a-check-or-done-condition 65% (71/110)
97
+ intent:none 40% (451/1129)
98
+ gap 1.6x
99
+ ─────────────────────────────────────────────────────────
101
100
  ```
102
101
 
103
102
  those are my numbers on that date, and they move every session i run, so treat
@@ -125,6 +124,74 @@ signal, not a verdict. if it ever prints something that flatters you, distrust i
125
124
 
126
125
  the caveat is printed in the output itself, every run, on purpose.
127
126
 
127
+ ## correction rate
128
+
129
+ > in the repo since 2026-09-02, not yet on PyPI. `python3 transcripto.py coach` prints it.
130
+
131
+ one more line under the coach footer:
132
+
133
+ ```
134
+ correction rate: 6% measured (227 of 4061 typed turns) · v1 catches ~1 in 6, so the real rate is ~26-37%
135
+ ```
136
+
137
+ **correction rate = typed turns that correct the agent ÷ typed turns.** the denominator
138
+ is the same authorship gate as every other number here (`typed` or `queued`, never
139
+ `isMeta`, `isSidechain` or a tool result), so a tool result that happens to say "wrong"
140
+ cannot move it. a typed turn counts as a correction when a **marker** fires in its head:
141
+ the first 80 words after URLs and file paths are stripped, case-insensitive, whole-word:
142
+ a leading or bare `no`, `again`, `wrong`, `not that`, `I meant`, `revert`, `undo`, `stop`,
143
+ `instead`, plus a few measured additions. whole-word, so "against" is not "again" and
144
+ "now" is not "no". the v0 "nudge" rule (a short turn naming the agent's last file) is gone:
145
+ measured over 100 flagged rows it fired alone five times and was wrong five times.
146
+ `TRANSCRIPTO_CORRECTION=v0` brings the old classifier back for comparison.
147
+
148
+ it is one pure function, `is_correction(text)`, and it is a **floor**, now measured rather
149
+ than asserted: on a 200-row labelled sample the v1 classifier has precision 0.81 and recall
150
+ 0.16 (`docs/CORRECTION-PRECISION-2026-09-03.md`), which is why the printed line carries the
151
+ "~1 in 6" correction and a range. read it as a trend on your own history.
152
+ `test_correction.sh` pins the rule and the gate on `fixtures-correction/`.
153
+
154
+ ## export-run
155
+
156
+ > in the repo since 2026-09-02, not yet on PyPI.
157
+
158
+ ```
159
+ transcripto export-run latest # the newest session on this machine
160
+ transcripto export-run 3f9c1a2b # a session id, or a prefix of one
161
+ transcripto export-run path/to/session.jsonl # a transcript file
162
+ transcripto export-run latest --harness codex # --root / --harness as for coach
163
+ ```
164
+
165
+ one run's numbers as JSON, read straight from the transcript file (no index needed).
166
+ this is the contract other tools read (Agent Grinder's card, ZUP's board); the keys are
167
+ frozen under `schema`, and a new key is an addition, never a rename.
168
+
169
+ | key | meaning |
170
+ |---|---|
171
+ | `schema` | `transcripto.export-run/1` |
172
+ | `session_id` | the harness's session id (Claude Code: the file name; Codex: `session_meta.id`; Cursor: the file name) |
173
+ | `project` | the run's `cwd` |
174
+ | `harness` | `claude` · `codex` · `cursor` |
175
+ | `transcript` | absolute path of the file read |
176
+ | `started` · `ended` | first and last record timestamp, UTC, `…Z`; `null` if the file carries none |
177
+ | `duration_s` | `ended − started`, whole seconds |
178
+ | `records` | every record in the file, before any gate |
179
+ | `typed_turns` | records that pass the authorship gate: `promptSource` typed or queued, never meta, sidechain or tool result. the same count coach prints as "typed by you" |
180
+ | `corrections` | typed turns `is_correction()` flags (see above) |
181
+ | `correction_rate` | `corrections / typed_turns`, 3 decimals; `null` when nothing was typed |
182
+ | `tool_calls` | every `tool_use` block the agent emitted |
183
+ | `files_touched` | sorted set of `file_path` (or `notebook_path`) from Edit / Write / Read / MultiEdit / NotebookEdit calls |
184
+ | `commits_in_window` | commits stamped inside `[started, ended]` in the project's git reflog; `null` when `project` is not inside a git repo |
185
+ | `commits` | those commits as `{sha, ts, subject}`, oldest first; `null` when not a repo |
186
+ | `proxy` | the caveat, in the JSON so it travels with the numbers |
187
+
188
+ `commits_in_window` reads `.git/logs/HEAD` directly, not `git log`, because this file
189
+ does not shell out (see privacy). the reflog is the record of what **that working tree**
190
+ did: a commit made there in the window is in it, a commit pulled in from elsewhere is not.
191
+ git expires the reflog after 90 days by default, so a run older than that can read 0 here
192
+ while `git log` would still show its commits. `commit (amend)` counts; a rebase's `pick`
193
+ lines do not. a `.git` file (a worktree) is followed to its gitdir.
194
+
128
195
  ## why your own gate matters here
129
196
 
130
197
  at fleet scale roughly 95% of the `type: user` records in a transcript are not
@@ -182,15 +249,15 @@ claim, so here is the grep that settles it against the single file it ships as:
182
249
  $ grep -nE '^[[:space:]]*(import|from) ' transcripto.py
183
250
  8:import sys, os, json, glob, re, sqlite3, argparse
184
251
  9:from datetime import datetime, timezone
185
- 260: import time
186
- 1051: import datetime
187
- 1061: from the separator), so the result is checked on disk and dropped if it is
252
+ 261: import time
253
+ 1160: import datetime
254
+ 1170: from the separator), so the result is checked on disk and dropped if it is
188
255
  ```
189
256
 
190
257
  five lines, four of which are imports and all four are stdlib. `time` and
191
258
  `datetime` sit inside functions, which is why the pattern allows for indentation —
192
259
  anchor it at `^import` and you would miss two, so do not take my word for the
193
- anchor either. line 1061 is the pattern catching a docstring that happens to begin
260
+ anchor either. line 1170 is the pattern catching a docstring that happens to begin
194
261
  with the word `from`; it is prose, not an import, and it is left in rather than
195
262
  tuned out, because a grep you tuned until it agreed with you proves nothing.
196
263
 
@@ -229,6 +296,7 @@ transcripto sessions recent sessions + the first prompt YOU typed in each
229
296
  transcripto stats what you actually work on
230
297
  transcripto cost what ONE of your decisions costs
231
298
  transcripto coach which of YOUR prompt habits survive (a proxy)
299
+ transcripto export-run one run's numbers as JSON (typed turns, correction rate, commits)
232
300
  ```
233
301
 
234
302
  `ask` is the one that kills "wait, did i lose something?". it answers "what was i
@@ -289,9 +357,12 @@ just gives the file a name on your PATH.
289
357
  ./test_cost.sh 12 assertions
290
358
  ./test_small_n.sh 7 assertions
291
359
  ./test_label_bands.sh 13 assertions
360
+ ./test_correction.sh 32 assertions (correction rate + export-run, 2026-09-02)
361
+ ./test_cursor_partial.sh 7 assertions
362
+ ./test_version.sh 1 assertion (VERSION matches in transcripto.py and pyproject.toml)
292
363
  ```
293
364
 
294
- 61 assertions, all green, re-run 2026-08-31.
365
+ 91 assertions, all green, re-run 2026-09-02.
295
366
 
296
367
  offline, no keys, on fixtures that inherit the real transcript shape including
297
368
  all four ways a non-human record disguises itself as `type: user`.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "transcripto"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  description = "Search everything your coding agents ever did, grade your own prompts, and price your decisions. Local, stdlib-only, your data never leaves the machine."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"