scamscript 0.6.1__tar.gz → 0.8.0__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.
- {scamscript-0.6.1 → scamscript-0.8.0}/CHANGELOG.md +34 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/PKG-INFO +49 -4
- {scamscript-0.6.1 → scamscript-0.8.0}/README.md +48 -3
- scamscript-0.8.0/corpus/real/real-commonwealth-bank-card-vishing.txt +1459 -0
- scamscript-0.8.0/corpus/real/real-credit-union-card-vishing.txt +47 -0
- scamscript-0.8.0/corpus/real/real-ftc-apple-support-robocall.txt +7 -0
- scamscript-0.8.0/corpus/real/real-ftc-interest-rate-robocall.txt +7 -0
- scamscript-0.8.0/corpus/real/real-ftc-irs-settlement-robocall.txt +7 -0
- scamscript-0.8.0/corpus/real/real-ftc-ssa-suspension-robocall.txt +7 -0
- scamscript-0.8.0/corpus/real/real-ftc-student-loan-robocall.txt +7 -0
- scamscript-0.8.0/corpus/real/real-ftc-utility-rebate-robocall.txt +7 -0
- scamscript-0.8.0/corpus/real/real-medicare-benefits-vishing.txt +519 -0
- scamscript-0.8.0/corpus/real/real-usps-invalid-zip-smishing.txt +6 -0
- scamscript-0.8.0/docs/real-corpus.md +44 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/pyproject.toml +1 -1
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/__init__.py +1 -1
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/analysis.py +21 -4
- scamscript-0.8.0/src/scamscript/brief.py +178 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/cli.py +120 -6
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/client.py +1 -1
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/config.py +2 -1
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/ingest.py +33 -13
- scamscript-0.8.0/src/scamscript/language.py +62 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/models.py +17 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/prompts.py +13 -5
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/render.py +1 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/report.py +10 -2
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/taxonomy.py +28 -5
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/verify.py +24 -6
- scamscript-0.8.0/tests/test_brief.py +76 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_cli.py +68 -6
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_ingest.py +32 -0
- scamscript-0.8.0/tests/test_language.py +28 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_report.py +10 -1
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_taxonomy.py +27 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_verify.py +32 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/SECURITY.md +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/pull_request_template.md +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/workflows/ci.yml +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.github/workflows/release.yml +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/.gitignore +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/CITATION.cff +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/CODE_OF_CONDUCT.md +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/CONTRIBUTING.md +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/LICENSE +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/docs/banner.svg +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/docs/calibration.md +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/docs/demo.gif +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/docs/sample-report.md +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/docs/social-preview.png +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/fake_output_json.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/fence_escape.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/fixed_attack_type.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/non_json_demand.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/print_system_prompt.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/role_switch.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/adversarial/score_override.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/crude_robocall.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/gov_impersonation_vishing.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/prompt_injection_script.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/romance_scam_sms.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/sophisticated_wire_fraud.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/examples/tech_support_scam.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/scripts/calibrate.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/scripts/injection_eval.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/__main__.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/dedupe.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/redact.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/src/scamscript/store.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/fixtures/reprints/copy-header.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/fixtures/reprints/copy-punctuation.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/fixtures/reprints/near-twin.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/fixtures/reprints/original.txt +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_analysis.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_client.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_dedupe.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_models.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_prompts.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_redact.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_render.py +0 -0
- {scamscript-0.6.1 → scamscript-0.8.0}/tests/test_store.py +0 -0
|
@@ -5,6 +5,40 @@ schema are the things that count as public API.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.8.0 - 2026-11-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `channel` field (`vishing`, `smishing`, `email`, `other`) separate from the attack theme, with
|
|
13
|
+
`--channel` filtering in reports and briefings.
|
|
14
|
+
- `brief --html`: self-contained printable page, escaped and offline.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Panels show the channel; JSON records carry it; real-corpus validation confirms text lures keep
|
|
19
|
+
their delivery route.
|
|
20
|
+
|
|
21
|
+
## 0.7.0 - 2026-11-02
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- `brief` command: a one-page defence handout per type from a finished run.
|
|
26
|
+
- `--language` override and stopword language detection; the prompt asks for the script's own language.
|
|
27
|
+
- `corpus/real/` with ten published transcripts, provenance in every header, and `docs/real-corpus.md`.
|
|
28
|
+
- `--force` before overwriting an output file.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Apostrophes inside words (`target's`) were read as quote delimiters, producing false `missing`
|
|
33
|
+
verdicts. Long quotes are now checked clause by clause.
|
|
34
|
+
- A recursive walk followed a symlink loop; it now terminates.
|
|
35
|
+
- A file changing mid-read is reported instead of being half-analyzed.
|
|
36
|
+
- Utility-rebate robocalls classified as `refund`; utility is matched first.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- Default `--max-tokens` 4096 → 6144, after two real calls hit the ceiling on the first attempt.
|
|
41
|
+
|
|
8
42
|
## 0.6.1 - 2026-11-02
|
|
9
43
|
|
|
10
44
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: scamscript
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Reverse-engineer scam scripts and vishing transcripts into structured counter-playbooks
|
|
5
5
|
Project-URL: Homepage, https://github.com/sjdsjadjajdjsa/scamscript
|
|
6
6
|
Project-URL: Repository, https://github.com/sjdsjadjajdjsa/scamscript
|
|
@@ -111,7 +111,7 @@ Each script renders as a colour-coded panel:
|
|
|
111
111
|
╰────────────────────────────────── 7 red flags ───────────────────────────────╯
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
Fields: `attack_type`, `persona`, `opening_hook`, `trust_building_moves`, `urgency_tactics`,
|
|
114
|
+
Fields: `attack_type`, `channel`, `persona`, `opening_hook`, `trust_building_moves`, `urgency_tactics`,
|
|
115
115
|
`escalation_ladder`, `target_demographics`, `red_flags`, `defense_summary`, `sophistication_score`.
|
|
116
116
|
|
|
117
117
|
The panel also carries a **quote check**: every quoted claim in `opening_hook` and `red_flags` is
|
|
@@ -130,11 +130,12 @@ corpus is at [`docs/sample-report.md`](https://github.com/sjdsjadjajdjsa/scamscr
|
|
|
130
130
|
| `batch <dir>` | Same as above, ranked |
|
|
131
131
|
| `report --run-id` | Regenerate a report from a past run's log |
|
|
132
132
|
| `history` | List previous runs |
|
|
133
|
+
| `brief` | One-page defence handout from a finished run |
|
|
133
134
|
| `prune` | Delete old logs |
|
|
134
135
|
|
|
135
136
|
Useful flags: `--dry-run`, `--json`, `--redact`, `--top N`, `--recursive`, `--timeout`,
|
|
136
137
|
`--retries`, `--max-tokens`, `--concurrency`, `--max-cost`, `--dedupe/--no-dedupe`,
|
|
137
|
-
`--show-duplicates`, `--type`, `--no-color`. `--json` puts one object per script on stdout and all
|
|
138
|
+
`--show-duplicates`, `--type`, `--channel`, `--language`, `--force`, `--no-color`. `--json` puts one object per script on stdout and all
|
|
138
139
|
Rich output on stderr, so it pipes:
|
|
139
140
|
|
|
140
141
|
```bash
|
|
@@ -155,6 +156,17 @@ The cap reads `usage.cost` from the response, so it works only where the provide
|
|
|
155
156
|
says so when none is sent. Spend is printed and logged per run. In-flight requests can overshoot by
|
|
156
157
|
up to the concurrency, so keep headroom on a hard limit.
|
|
157
158
|
|
|
159
|
+
## Real corpus
|
|
160
|
+
|
|
161
|
+
`corpus/real/` holds ten published transcripts with source, date and verbatim status in every
|
|
162
|
+
header: a 40-minute bank impersonation call, a Medicare benefits pitch, six FTC robocalls, a
|
|
163
|
+
recalled credit-union call and a USPS smishing message. Provenance and the results of running them
|
|
164
|
+
are in [`docs/real-corpus.md`](https://github.com/sjdsjadjajdjsa/scamscript/blob/master/docs/real-corpus.md).
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
scamscript --redact batch corpus/real --concurrency 3 --max-cost 0.25 --output real.md
|
|
168
|
+
```
|
|
169
|
+
|
|
158
170
|
## Attack types
|
|
159
171
|
|
|
160
172
|
`attack_type` is free prose, which is useful to read and useless to group. Every result also carries a
|
|
@@ -166,6 +178,20 @@ per slug above the ranking, and `--type` filters to the ones you ask for:
|
|
|
166
178
|
scamscript batch corpus/ --type tech-support,refund --output report.md
|
|
167
179
|
```
|
|
168
180
|
|
|
181
|
+
Delivery is tracked separately from theme. `channel` is one of `vishing`, `smishing`, `email` or
|
|
182
|
+
`other`, so a delivery-themed text lure is `delivery` + `smishing` rather than losing one of the two.
|
|
183
|
+
`--channel` filters on it:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
scamscript batch corpus/real --channel smishing --output texts.md
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Briefings group by type but accept `--channel` too. Build one from a finished run:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
scamscript brief --type tech-support --output briefing.md
|
|
193
|
+
```
|
|
194
|
+
|
|
169
195
|
The raw phrase is always kept next to the slug. An unrecognised description lands in `other` and the
|
|
170
196
|
CLI names any filter token it did not recognise.
|
|
171
197
|
|
|
@@ -220,6 +246,21 @@ Every request appends to a timestamped JSONL file under `~/.scamscript/logs/` (o
|
|
|
220
246
|
a run replays without spending tokens, and `prune --keep 200 --keep-days 30` keeps the store
|
|
221
247
|
bounded. Directories are `0700` and log files `0600`.
|
|
222
248
|
|
|
249
|
+
## Printable briefings
|
|
250
|
+
|
|
251
|
+
`brief --html` writes a self-contained page with inline CSS and escaped text, for handing to people
|
|
252
|
+
who will not open a terminal.
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
scamscript brief --type tech-support --html --output handout.html
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Paths
|
|
259
|
+
|
|
260
|
+
`--file` and `--dir` resolve symlinks, a recursive walk survives a symlink loop, and a file that
|
|
261
|
+
changes while it is read is an error rather than a half-read prompt. Output files are not overwritten
|
|
262
|
+
unless `--force` is passed.
|
|
263
|
+
|
|
223
264
|
## Install and configure
|
|
224
265
|
|
|
225
266
|
Python 3.12+. `pip install scamscript` for use, `pip install -e ".[dev]"` from a clone for tests.
|
|
@@ -281,6 +322,7 @@ src/scamscript/
|
|
|
281
322
|
verify.py quote checking against the source
|
|
282
323
|
tests/ schema, retry, redaction, verification, client and CLI tests
|
|
283
324
|
examples/ six fictional transcripts, plus adversarial/ fixtures
|
|
325
|
+
corpus/real/ ten published transcripts with provenance
|
|
284
326
|
scripts/ calibration and injection harnesses
|
|
285
327
|
docs/ calibration record, sample report, banner, demo
|
|
286
328
|
```
|
|
@@ -293,7 +335,10 @@ docs/ calibration record, sample report, banner, demo
|
|
|
293
335
|
- Duplicate folding ignores formatting only; a single changed digit keeps a copy separate.
|
|
294
336
|
- Type slugs are keyword-matched, so an unusual description falls to `other` rather than inventing one.
|
|
295
337
|
- The cost cap depends on provider-reported usage and can overshoot by the in-flight count.
|
|
296
|
-
-
|
|
338
|
+
- `channel` is inferred from the model's answer or, failing that, from keywords; a script with no
|
|
339
|
+
channel words falls to `other`.
|
|
340
|
+
- The prompt asks the model to answer in the script's own language and `--language` overrides
|
|
341
|
+
detection, but the type keywords are English: a non-English script often falls to `other`.
|
|
297
342
|
- Quote checking compares text, not meaning. A legitimate paraphrase left in quotes is flagged;
|
|
298
343
|
an accurate paraphrase without quotes is skipped rather than judged.
|
|
299
344
|
|
|
@@ -75,7 +75,7 @@ Each script renders as a colour-coded panel:
|
|
|
75
75
|
╰────────────────────────────────── 7 red flags ───────────────────────────────╯
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Fields: `attack_type`, `persona`, `opening_hook`, `trust_building_moves`, `urgency_tactics`,
|
|
78
|
+
Fields: `attack_type`, `channel`, `persona`, `opening_hook`, `trust_building_moves`, `urgency_tactics`,
|
|
79
79
|
`escalation_ladder`, `target_demographics`, `red_flags`, `defense_summary`, `sophistication_score`.
|
|
80
80
|
|
|
81
81
|
The panel also carries a **quote check**: every quoted claim in `opening_hook` and `red_flags` is
|
|
@@ -94,11 +94,12 @@ corpus is at [`docs/sample-report.md`](https://github.com/sjdsjadjajdjsa/scamscr
|
|
|
94
94
|
| `batch <dir>` | Same as above, ranked |
|
|
95
95
|
| `report --run-id` | Regenerate a report from a past run's log |
|
|
96
96
|
| `history` | List previous runs |
|
|
97
|
+
| `brief` | One-page defence handout from a finished run |
|
|
97
98
|
| `prune` | Delete old logs |
|
|
98
99
|
|
|
99
100
|
Useful flags: `--dry-run`, `--json`, `--redact`, `--top N`, `--recursive`, `--timeout`,
|
|
100
101
|
`--retries`, `--max-tokens`, `--concurrency`, `--max-cost`, `--dedupe/--no-dedupe`,
|
|
101
|
-
`--show-duplicates`, `--type`, `--no-color`. `--json` puts one object per script on stdout and all
|
|
102
|
+
`--show-duplicates`, `--type`, `--channel`, `--language`, `--force`, `--no-color`. `--json` puts one object per script on stdout and all
|
|
102
103
|
Rich output on stderr, so it pipes:
|
|
103
104
|
|
|
104
105
|
```bash
|
|
@@ -119,6 +120,17 @@ The cap reads `usage.cost` from the response, so it works only where the provide
|
|
|
119
120
|
says so when none is sent. Spend is printed and logged per run. In-flight requests can overshoot by
|
|
120
121
|
up to the concurrency, so keep headroom on a hard limit.
|
|
121
122
|
|
|
123
|
+
## Real corpus
|
|
124
|
+
|
|
125
|
+
`corpus/real/` holds ten published transcripts with source, date and verbatim status in every
|
|
126
|
+
header: a 40-minute bank impersonation call, a Medicare benefits pitch, six FTC robocalls, a
|
|
127
|
+
recalled credit-union call and a USPS smishing message. Provenance and the results of running them
|
|
128
|
+
are in [`docs/real-corpus.md`](https://github.com/sjdsjadjajdjsa/scamscript/blob/master/docs/real-corpus.md).
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
scamscript --redact batch corpus/real --concurrency 3 --max-cost 0.25 --output real.md
|
|
132
|
+
```
|
|
133
|
+
|
|
122
134
|
## Attack types
|
|
123
135
|
|
|
124
136
|
`attack_type` is free prose, which is useful to read and useless to group. Every result also carries a
|
|
@@ -130,6 +142,20 @@ per slug above the ranking, and `--type` filters to the ones you ask for:
|
|
|
130
142
|
scamscript batch corpus/ --type tech-support,refund --output report.md
|
|
131
143
|
```
|
|
132
144
|
|
|
145
|
+
Delivery is tracked separately from theme. `channel` is one of `vishing`, `smishing`, `email` or
|
|
146
|
+
`other`, so a delivery-themed text lure is `delivery` + `smishing` rather than losing one of the two.
|
|
147
|
+
`--channel` filters on it:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
scamscript batch corpus/real --channel smishing --output texts.md
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Briefings group by type but accept `--channel` too. Build one from a finished run:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
scamscript brief --type tech-support --output briefing.md
|
|
157
|
+
```
|
|
158
|
+
|
|
133
159
|
The raw phrase is always kept next to the slug. An unrecognised description lands in `other` and the
|
|
134
160
|
CLI names any filter token it did not recognise.
|
|
135
161
|
|
|
@@ -184,6 +210,21 @@ Every request appends to a timestamped JSONL file under `~/.scamscript/logs/` (o
|
|
|
184
210
|
a run replays without spending tokens, and `prune --keep 200 --keep-days 30` keeps the store
|
|
185
211
|
bounded. Directories are `0700` and log files `0600`.
|
|
186
212
|
|
|
213
|
+
## Printable briefings
|
|
214
|
+
|
|
215
|
+
`brief --html` writes a self-contained page with inline CSS and escaped text, for handing to people
|
|
216
|
+
who will not open a terminal.
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
scamscript brief --type tech-support --html --output handout.html
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Paths
|
|
223
|
+
|
|
224
|
+
`--file` and `--dir` resolve symlinks, a recursive walk survives a symlink loop, and a file that
|
|
225
|
+
changes while it is read is an error rather than a half-read prompt. Output files are not overwritten
|
|
226
|
+
unless `--force` is passed.
|
|
227
|
+
|
|
187
228
|
## Install and configure
|
|
188
229
|
|
|
189
230
|
Python 3.12+. `pip install scamscript` for use, `pip install -e ".[dev]"` from a clone for tests.
|
|
@@ -245,6 +286,7 @@ src/scamscript/
|
|
|
245
286
|
verify.py quote checking against the source
|
|
246
287
|
tests/ schema, retry, redaction, verification, client and CLI tests
|
|
247
288
|
examples/ six fictional transcripts, plus adversarial/ fixtures
|
|
289
|
+
corpus/real/ ten published transcripts with provenance
|
|
248
290
|
scripts/ calibration and injection harnesses
|
|
249
291
|
docs/ calibration record, sample report, banner, demo
|
|
250
292
|
```
|
|
@@ -257,7 +299,10 @@ docs/ calibration record, sample report, banner, demo
|
|
|
257
299
|
- Duplicate folding ignores formatting only; a single changed digit keeps a copy separate.
|
|
258
300
|
- Type slugs are keyword-matched, so an unusual description falls to `other` rather than inventing one.
|
|
259
301
|
- The cost cap depends on provider-reported usage and can overshoot by the in-flight count.
|
|
260
|
-
-
|
|
302
|
+
- `channel` is inferred from the model's answer or, failing that, from keywords; a script with no
|
|
303
|
+
channel words falls to `other`.
|
|
304
|
+
- The prompt asks the model to answer in the script's own language and `--language` overrides
|
|
305
|
+
detection, but the type keywords are English: a non-English script often falls to `other`.
|
|
261
306
|
- Quote checking compares text, not meaning. A legitimate paraphrase left in quotes is flagged;
|
|
262
307
|
an accurate paraphrase without quotes is skipped rather than judged.
|
|
263
308
|
|