scamscript 0.6.0__tar.gz → 0.7.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.
Files changed (84) hide show
  1. {scamscript-0.6.0 → scamscript-0.7.0}/.github/workflows/release.yml +0 -23
  2. {scamscript-0.6.0 → scamscript-0.7.0}/CHANGELOG.md +27 -0
  3. {scamscript-0.6.0 → scamscript-0.7.0}/PKG-INFO +29 -3
  4. {scamscript-0.6.0 → scamscript-0.7.0}/README.md +28 -2
  5. scamscript-0.7.0/corpus/real/real-commonwealth-bank-card-vishing.txt +1459 -0
  6. scamscript-0.7.0/corpus/real/real-credit-union-card-vishing.txt +47 -0
  7. scamscript-0.7.0/corpus/real/real-ftc-apple-support-robocall.txt +7 -0
  8. scamscript-0.7.0/corpus/real/real-ftc-interest-rate-robocall.txt +7 -0
  9. scamscript-0.7.0/corpus/real/real-ftc-irs-settlement-robocall.txt +7 -0
  10. scamscript-0.7.0/corpus/real/real-ftc-ssa-suspension-robocall.txt +7 -0
  11. scamscript-0.7.0/corpus/real/real-ftc-student-loan-robocall.txt +7 -0
  12. scamscript-0.7.0/corpus/real/real-ftc-utility-rebate-robocall.txt +7 -0
  13. scamscript-0.7.0/corpus/real/real-medicare-benefits-vishing.txt +519 -0
  14. scamscript-0.7.0/corpus/real/real-usps-invalid-zip-smishing.txt +6 -0
  15. scamscript-0.7.0/docs/real-corpus.md +37 -0
  16. {scamscript-0.6.0 → scamscript-0.7.0}/pyproject.toml +1 -1
  17. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/__init__.py +1 -1
  18. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/analysis.py +14 -4
  19. scamscript-0.7.0/src/scamscript/brief.py +95 -0
  20. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/cli.py +77 -6
  21. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/client.py +1 -1
  22. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/config.py +2 -1
  23. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/ingest.py +33 -13
  24. scamscript-0.7.0/src/scamscript/language.py +62 -0
  25. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/prompts.py +11 -5
  26. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/taxonomy.py +12 -5
  27. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/verify.py +24 -6
  28. scamscript-0.7.0/tests/test_brief.py +57 -0
  29. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_cli.py +20 -2
  30. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_ingest.py +32 -0
  31. scamscript-0.7.0/tests/test_language.py +28 -0
  32. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_taxonomy.py +5 -0
  33. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_verify.py +32 -0
  34. {scamscript-0.6.0 → scamscript-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  35. {scamscript-0.6.0 → scamscript-0.7.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  36. {scamscript-0.6.0 → scamscript-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  37. {scamscript-0.6.0 → scamscript-0.7.0}/.github/SECURITY.md +0 -0
  38. {scamscript-0.6.0 → scamscript-0.7.0}/.github/pull_request_template.md +0 -0
  39. {scamscript-0.6.0 → scamscript-0.7.0}/.github/workflows/ci.yml +0 -0
  40. {scamscript-0.6.0 → scamscript-0.7.0}/.gitignore +0 -0
  41. {scamscript-0.6.0 → scamscript-0.7.0}/CITATION.cff +0 -0
  42. {scamscript-0.6.0 → scamscript-0.7.0}/CODE_OF_CONDUCT.md +0 -0
  43. {scamscript-0.6.0 → scamscript-0.7.0}/CONTRIBUTING.md +0 -0
  44. {scamscript-0.6.0 → scamscript-0.7.0}/LICENSE +0 -0
  45. {scamscript-0.6.0 → scamscript-0.7.0}/docs/banner.svg +0 -0
  46. {scamscript-0.6.0 → scamscript-0.7.0}/docs/calibration.md +0 -0
  47. {scamscript-0.6.0 → scamscript-0.7.0}/docs/demo.gif +0 -0
  48. {scamscript-0.6.0 → scamscript-0.7.0}/docs/sample-report.md +0 -0
  49. {scamscript-0.6.0 → scamscript-0.7.0}/docs/social-preview.png +0 -0
  50. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/fake_output_json.txt +0 -0
  51. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/fence_escape.txt +0 -0
  52. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/fixed_attack_type.txt +0 -0
  53. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/non_json_demand.txt +0 -0
  54. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/print_system_prompt.txt +0 -0
  55. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/role_switch.txt +0 -0
  56. {scamscript-0.6.0 → scamscript-0.7.0}/examples/adversarial/score_override.txt +0 -0
  57. {scamscript-0.6.0 → scamscript-0.7.0}/examples/crude_robocall.txt +0 -0
  58. {scamscript-0.6.0 → scamscript-0.7.0}/examples/gov_impersonation_vishing.txt +0 -0
  59. {scamscript-0.6.0 → scamscript-0.7.0}/examples/prompt_injection_script.txt +0 -0
  60. {scamscript-0.6.0 → scamscript-0.7.0}/examples/romance_scam_sms.txt +0 -0
  61. {scamscript-0.6.0 → scamscript-0.7.0}/examples/sophisticated_wire_fraud.txt +0 -0
  62. {scamscript-0.6.0 → scamscript-0.7.0}/examples/tech_support_scam.txt +0 -0
  63. {scamscript-0.6.0 → scamscript-0.7.0}/scripts/calibrate.py +0 -0
  64. {scamscript-0.6.0 → scamscript-0.7.0}/scripts/injection_eval.py +0 -0
  65. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/__main__.py +0 -0
  66. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/dedupe.py +0 -0
  67. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/models.py +0 -0
  68. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/redact.py +0 -0
  69. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/render.py +0 -0
  70. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/report.py +0 -0
  71. {scamscript-0.6.0 → scamscript-0.7.0}/src/scamscript/store.py +0 -0
  72. {scamscript-0.6.0 → scamscript-0.7.0}/tests/fixtures/reprints/copy-header.txt +0 -0
  73. {scamscript-0.6.0 → scamscript-0.7.0}/tests/fixtures/reprints/copy-punctuation.txt +0 -0
  74. {scamscript-0.6.0 → scamscript-0.7.0}/tests/fixtures/reprints/near-twin.txt +0 -0
  75. {scamscript-0.6.0 → scamscript-0.7.0}/tests/fixtures/reprints/original.txt +0 -0
  76. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_analysis.py +0 -0
  77. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_client.py +0 -0
  78. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_dedupe.py +0 -0
  79. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_models.py +0 -0
  80. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_prompts.py +0 -0
  81. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_redact.py +0 -0
  82. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_render.py +0 -0
  83. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_report.py +0 -0
  84. {scamscript-0.6.0 → scamscript-0.7.0}/tests/test_store.py +0 -0
@@ -4,12 +4,6 @@ on:
4
4
  push:
5
5
  tags: ["v*"]
6
6
  workflow_dispatch:
7
- inputs:
8
- repository:
9
- description: Target index
10
- type: choice
11
- options: [pypi, testpypi]
12
- default: testpypi
13
7
 
14
8
  permissions:
15
9
  contents: read
@@ -38,25 +32,8 @@ jobs:
38
32
  name: dist
39
33
  path: dist/
40
34
 
41
- testpypi:
42
- needs: build
43
- if: github.event_name == 'workflow_dispatch' && inputs.repository == 'testpypi'
44
- runs-on: ubuntu-latest
45
- environment: testpypi
46
- permissions:
47
- id-token: write
48
- steps:
49
- - uses: actions/download-artifact@v4
50
- with:
51
- name: dist
52
- path: dist/
53
- - uses: pypa/gh-action-pypi-publish@release/v1
54
- with:
55
- repository-url: https://test.pypi.org/legacy/
56
-
57
35
  pypi:
58
36
  needs: build
59
- if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.repository == 'pypi')
60
37
  runs-on: ubuntu-latest
61
38
  environment: pypi
62
39
  permissions:
@@ -5,6 +5,33 @@ schema are the things that count as public API.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.7.0 - 2026-11-02
9
+
10
+ ### Added
11
+
12
+ - `brief` command: a one-page defence handout per type from a finished run.
13
+ - `--language` override and stopword language detection; the prompt asks for the script's own language.
14
+ - `corpus/real/` with ten published transcripts, provenance in every header, and `docs/real-corpus.md`.
15
+ - `--force` before overwriting an output file.
16
+
17
+ ### Fixed
18
+
19
+ - Apostrophes inside words (`target's`) were read as quote delimiters, producing false `missing`
20
+ verdicts. Long quotes are now checked clause by clause.
21
+ - A recursive walk followed a symlink loop; it now terminates.
22
+ - A file changing mid-read is reported instead of being half-analyzed.
23
+ - Utility-rebate robocalls classified as `refund`; utility is matched first.
24
+
25
+ ### Changed
26
+
27
+ - Default `--max-tokens` 4096 → 6144, after two real calls hit the ceiling on the first attempt.
28
+
29
+ ## 0.6.1 - 2026-11-02
30
+
31
+ ### Changed
32
+
33
+ - Removed the unused TestPyPI job and environment. Manual dispatch publishes to PyPI directly.
34
+
8
35
  ## 0.6.0 - 2026-11-02
9
36
 
10
37
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: scamscript
3
- Version: 0.6.0
3
+ Version: 0.7.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
@@ -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`, `--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,12 @@ 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
+ Briefings group the same way. Build one from a finished run:
182
+
183
+ ```bash
184
+ scamscript brief --type tech-support --output briefing.md
185
+ ```
186
+
169
187
  The raw phrase is always kept next to the slug. An unrecognised description lands in `other` and the
170
188
  CLI names any filter token it did not recognise.
171
189
 
@@ -220,6 +238,12 @@ Every request appends to a timestamped JSONL file under `~/.scamscript/logs/` (o
220
238
  a run replays without spending tokens, and `prune --keep 200 --keep-days 30` keeps the store
221
239
  bounded. Directories are `0700` and log files `0600`.
222
240
 
241
+ ## Paths
242
+
243
+ `--file` and `--dir` resolve symlinks, a recursive walk survives a symlink loop, and a file that
244
+ changes while it is read is an error rather than a half-read prompt. Output files are not overwritten
245
+ unless `--force` is passed.
246
+
223
247
  ## Install and configure
224
248
 
225
249
  Python 3.12+. `pip install scamscript` for use, `pip install -e ".[dev]"` from a clone for tests.
@@ -281,6 +305,7 @@ src/scamscript/
281
305
  verify.py quote checking against the source
282
306
  tests/ schema, retry, redaction, verification, client and CLI tests
283
307
  examples/ six fictional transcripts, plus adversarial/ fixtures
308
+ corpus/real/ ten published transcripts with provenance
284
309
  scripts/ calibration and injection harnesses
285
310
  docs/ calibration record, sample report, banner, demo
286
311
  ```
@@ -293,7 +318,8 @@ docs/ calibration record, sample report, banner, demo
293
318
  - Duplicate folding ignores formatting only; a single changed digit keeps a copy separate.
294
319
  - Type slugs are keyword-matched, so an unusual description falls to `other` rather than inventing one.
295
320
  - The cost cap depends on provider-reported usage and can overshoot by the in-flight count.
296
- - Analysis is English-centric: the prompt and schema assume English artifacts.
321
+ - The prompt asks the model to answer in the script's own language and `--language` overrides
322
+ detection, but the type keywords are English: a non-English script often falls to `other`.
297
323
  - Quote checking compares text, not meaning. A legitimate paraphrase left in quotes is flagged;
298
324
  an accurate paraphrase without quotes is skipped rather than judged.
299
325
 
@@ -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`, `--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,12 @@ 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
+ Briefings group the same way. Build one from a finished run:
146
+
147
+ ```bash
148
+ scamscript brief --type tech-support --output briefing.md
149
+ ```
150
+
133
151
  The raw phrase is always kept next to the slug. An unrecognised description lands in `other` and the
134
152
  CLI names any filter token it did not recognise.
135
153
 
@@ -184,6 +202,12 @@ Every request appends to a timestamped JSONL file under `~/.scamscript/logs/` (o
184
202
  a run replays without spending tokens, and `prune --keep 200 --keep-days 30` keeps the store
185
203
  bounded. Directories are `0700` and log files `0600`.
186
204
 
205
+ ## Paths
206
+
207
+ `--file` and `--dir` resolve symlinks, a recursive walk survives a symlink loop, and a file that
208
+ changes while it is read is an error rather than a half-read prompt. Output files are not overwritten
209
+ unless `--force` is passed.
210
+
187
211
  ## Install and configure
188
212
 
189
213
  Python 3.12+. `pip install scamscript` for use, `pip install -e ".[dev]"` from a clone for tests.
@@ -245,6 +269,7 @@ src/scamscript/
245
269
  verify.py quote checking against the source
246
270
  tests/ schema, retry, redaction, verification, client and CLI tests
247
271
  examples/ six fictional transcripts, plus adversarial/ fixtures
272
+ corpus/real/ ten published transcripts with provenance
248
273
  scripts/ calibration and injection harnesses
249
274
  docs/ calibration record, sample report, banner, demo
250
275
  ```
@@ -257,7 +282,8 @@ docs/ calibration record, sample report, banner, demo
257
282
  - Duplicate folding ignores formatting only; a single changed digit keeps a copy separate.
258
283
  - Type slugs are keyword-matched, so an unusual description falls to `other` rather than inventing one.
259
284
  - The cost cap depends on provider-reported usage and can overshoot by the in-flight count.
260
- - Analysis is English-centric: the prompt and schema assume English artifacts.
285
+ - The prompt asks the model to answer in the script's own language and `--language` overrides
286
+ detection, but the type keywords are English: a non-English script often falls to `other`.
261
287
  - Quote checking compares text, not meaning. A legitimate paraphrase left in quotes is flagged;
262
288
  an accurate paraphrase without quotes is skipped rather than judged.
263
289