patina-cli 3.11.0

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 (180) hide show
  1. package/.patina.default.yaml +211 -0
  2. package/CHANGELOG.md +265 -0
  3. package/LICENSE +21 -0
  4. package/README.md +319 -0
  5. package/README_JA.md +254 -0
  6. package/README_KR.md +253 -0
  7. package/README_ZH.md +254 -0
  8. package/SKILL-MAX.md +455 -0
  9. package/SKILL.md +730 -0
  10. package/assets/brand/patina-icon.svg +9 -0
  11. package/assets/brand/patina-logo.svg +17 -0
  12. package/assets/social/patina-before-after.svg +46 -0
  13. package/assets/social/patina-og.svg +31 -0
  14. package/bin/patina.js +9 -0
  15. package/core/scoring.md +657 -0
  16. package/core/standalone-prompt.md +364 -0
  17. package/core/stylometry.md +754 -0
  18. package/core/voice.md +163 -0
  19. package/docs/AUTHENTICATION.md +105 -0
  20. package/docs/AUTHENTICATION_KR.md +105 -0
  21. package/docs/BRANDING.md +37 -0
  22. package/docs/CLI.md +80 -0
  23. package/docs/COMPARISON.md +38 -0
  24. package/docs/COOKBOOK.md +173 -0
  25. package/docs/DEMO.md +40 -0
  26. package/docs/ETHICS.md +27 -0
  27. package/docs/EXAMPLES.md +130 -0
  28. package/docs/EXAMPLES_KR.md +130 -0
  29. package/docs/EXIT-CODES.md +25 -0
  30. package/docs/FAQ.md +67 -0
  31. package/docs/FAQ_KR.md +65 -0
  32. package/docs/FLAG-PARITY.md +53 -0
  33. package/docs/GLOSSARY.md +123 -0
  34. package/docs/PATTERNS-EN.md +718 -0
  35. package/docs/PATTERNS-JA.md +706 -0
  36. package/docs/PATTERNS-KO.md +707 -0
  37. package/docs/PATTERNS-ZH.md +706 -0
  38. package/docs/PATTERNS.md +22 -0
  39. package/docs/ROADMAP.md +315 -0
  40. package/docs/audits/2026-05-deep-research.md +290 -0
  41. package/docs/benchmarks/detector-comparison.json +442 -0
  42. package/docs/benchmarks/detector-comparison.md +65 -0
  43. package/docs/benchmarks/latest.json +988 -0
  44. package/docs/benchmarks/latest.md +112 -0
  45. package/docs/integrations/docker.md +19 -0
  46. package/docs/integrations/github-action.md +59 -0
  47. package/docs/integrations/pre-commit.md +77 -0
  48. package/docs/integrations/release.md +43 -0
  49. package/docs/internal/HARNESS.md +14 -0
  50. package/docs/internal/README.md +14 -0
  51. package/docs/internal/WARP.md +23 -0
  52. package/docs/research/2025-rebaseline-plan.md +89 -0
  53. package/docs/research/ai-human-metrics.md +380 -0
  54. package/docs/social/gstack-cardnews.html +236 -0
  55. package/docs/social/gstack-cardnews.md +88 -0
  56. package/docs/social/gstack-thread.md +106 -0
  57. package/docs/social/patina-launch-copy.md +227 -0
  58. package/docs/superpowers/specs/2026-04-03-meaning-preservation-design.md +299 -0
  59. package/lexicon/ai-en.md +162 -0
  60. package/lexicon/ai-ko.md +159 -0
  61. package/package.json +100 -0
  62. package/patina-max/SKILL.md +523 -0
  63. package/patina-max/composite.py +457 -0
  64. package/patterns/en-communication.md +89 -0
  65. package/patterns/en-content.md +133 -0
  66. package/patterns/en-filler.md +113 -0
  67. package/patterns/en-language.md +163 -0
  68. package/patterns/en-structure.md +173 -0
  69. package/patterns/en-style.md +139 -0
  70. package/patterns/en-viral-hook.md +211 -0
  71. package/patterns/ja-communication.md +101 -0
  72. package/patterns/ja-content.md +153 -0
  73. package/patterns/ja-filler.md +123 -0
  74. package/patterns/ja-language.md +190 -0
  75. package/patterns/ja-structure.md +142 -0
  76. package/patterns/ja-style.md +147 -0
  77. package/patterns/ja-viral-hook.md +216 -0
  78. package/patterns/ko-communication.md +98 -0
  79. package/patterns/ko-content.md +154 -0
  80. package/patterns/ko-filler.md +105 -0
  81. package/patterns/ko-language.md +182 -0
  82. package/patterns/ko-structure.md +147 -0
  83. package/patterns/ko-style.md +146 -0
  84. package/patterns/ko-viral-hook.md +211 -0
  85. package/patterns/zh-communication.md +101 -0
  86. package/patterns/zh-content.md +153 -0
  87. package/patterns/zh-filler.md +118 -0
  88. package/patterns/zh-language.md +173 -0
  89. package/patterns/zh-structure.md +145 -0
  90. package/patterns/zh-style.md +159 -0
  91. package/patterns/zh-viral-hook.md +216 -0
  92. package/profiles/academic.md +53 -0
  93. package/profiles/blog.md +81 -0
  94. package/profiles/casual-conversation.md +105 -0
  95. package/profiles/code-comment.md +104 -0
  96. package/profiles/commit-message.md +99 -0
  97. package/profiles/default.md +62 -0
  98. package/profiles/email.md +52 -0
  99. package/profiles/formal.md +98 -0
  100. package/profiles/instructional.md +80 -0
  101. package/profiles/legal.md +57 -0
  102. package/profiles/marketing.md +56 -0
  103. package/profiles/medical.md +53 -0
  104. package/profiles/narrative.md +79 -0
  105. package/profiles/release-notes.md +98 -0
  106. package/profiles/social.md +56 -0
  107. package/profiles/technical.md +53 -0
  108. package/scripts/benchmark-report.mjs +252 -0
  109. package/scripts/check-release-metadata.mjs +48 -0
  110. package/scripts/detector-comparison.mjs +267 -0
  111. package/scripts/lint.mjs +40 -0
  112. package/scripts/precommit-score.mjs +31 -0
  113. package/scripts/prose-score.mjs +186 -0
  114. package/scripts/update-benchmark-ranges.mjs +108 -0
  115. package/src/api.js +330 -0
  116. package/src/auth.js +105 -0
  117. package/src/backends/claude-cli.js +112 -0
  118. package/src/backends/codex-cli.js +121 -0
  119. package/src/backends/contract.js +21 -0
  120. package/src/backends/gemini-cli.js +135 -0
  121. package/src/backends/index.js +159 -0
  122. package/src/cache.js +106 -0
  123. package/src/cli.js +1280 -0
  124. package/src/commands/doctor.js +229 -0
  125. package/src/commands/init.js +208 -0
  126. package/src/config.js +126 -0
  127. package/src/errors.js +53 -0
  128. package/src/features/index.js +96 -0
  129. package/src/features/lexicon.js +90 -0
  130. package/src/features/segment.js +49 -0
  131. package/src/features/stylometry.js +50 -0
  132. package/src/loader.js +103 -0
  133. package/src/logger.js +70 -0
  134. package/src/manifest.js +162 -0
  135. package/src/max-mode.js +207 -0
  136. package/src/ouroboros.js +233 -0
  137. package/src/output.js +480 -0
  138. package/src/prompt-builder.js +409 -0
  139. package/src/providers.js +100 -0
  140. package/src/scoring.js +531 -0
  141. package/src/security.js +133 -0
  142. package/tests/fixtures/suspect-zones/en/ai/en-ai-01.md +16 -0
  143. package/tests/fixtures/suspect-zones/en/ai/en-ai-02.md +16 -0
  144. package/tests/fixtures/suspect-zones/en/ai/en-ai-03.md +17 -0
  145. package/tests/fixtures/suspect-zones/en/ai/en-ai-04.md +15 -0
  146. package/tests/fixtures/suspect-zones/en/ai/en-ai-05.md +16 -0
  147. package/tests/fixtures/suspect-zones/en/ai/en-ai-06-chat-register.md +16 -0
  148. package/tests/fixtures/suspect-zones/en/natural/en-nat-01.md +15 -0
  149. package/tests/fixtures/suspect-zones/en/natural/en-nat-02.md +15 -0
  150. package/tests/fixtures/suspect-zones/en/natural/en-nat-03.md +15 -0
  151. package/tests/fixtures/suspect-zones/en/natural/en-nat-04.md +15 -0
  152. package/tests/fixtures/suspect-zones/en/natural/en-nat-05.md +15 -0
  153. package/tests/fixtures/suspect-zones/expected-ranges.json +939 -0
  154. package/tests/fixtures/suspect-zones/ja/ai/ja-ai-01.md +11 -0
  155. package/tests/fixtures/suspect-zones/ja/ai/ja-ai-02.md +11 -0
  156. package/tests/fixtures/suspect-zones/ja/ai/ja-ai-03.md +11 -0
  157. package/tests/fixtures/suspect-zones/ja/natural/ja-nat-01.md +11 -0
  158. package/tests/fixtures/suspect-zones/ja/natural/ja-nat-02.md +11 -0
  159. package/tests/fixtures/suspect-zones/ja/natural/ja-nat-03.md +11 -0
  160. package/tests/fixtures/suspect-zones/ko/ai/ko-ai-01.md +14 -0
  161. package/tests/fixtures/suspect-zones/ko/ai/ko-ai-02.md +16 -0
  162. package/tests/fixtures/suspect-zones/ko/ai/ko-ai-03.md +15 -0
  163. package/tests/fixtures/suspect-zones/ko/ai/ko-ai-04.md +15 -0
  164. package/tests/fixtures/suspect-zones/ko/ai/ko-ai-05.md +16 -0
  165. package/tests/fixtures/suspect-zones/ko/ai/ko-ai-06-chat-register.md +16 -0
  166. package/tests/fixtures/suspect-zones/ko/natural/ko-nat-01.md +15 -0
  167. package/tests/fixtures/suspect-zones/ko/natural/ko-nat-02.md +15 -0
  168. package/tests/fixtures/suspect-zones/ko/natural/ko-nat-03.md +15 -0
  169. package/tests/fixtures/suspect-zones/ko/natural/ko-nat-04.md +14 -0
  170. package/tests/fixtures/suspect-zones/ko/natural/ko-nat-05.md +15 -0
  171. package/tests/fixtures/suspect-zones/zh/ai/zh-ai-01.md +11 -0
  172. package/tests/fixtures/suspect-zones/zh/ai/zh-ai-02.md +11 -0
  173. package/tests/fixtures/suspect-zones/zh/ai/zh-ai-03.md +11 -0
  174. package/tests/fixtures/suspect-zones/zh/natural/zh-nat-01.md +11 -0
  175. package/tests/fixtures/suspect-zones/zh/natural/zh-nat-02.md +11 -0
  176. package/tests/fixtures/suspect-zones/zh/natural/zh-nat-03.md +11 -0
  177. package/tests/quality/README.md +121 -0
  178. package/tests/quality/benchmark.mjs +306 -0
  179. package/tests/quality/detectors.manual.example.json +31 -0
  180. package/tests/quality/dogfood.mjs +44 -0
@@ -0,0 +1,442 @@
1
+ {
2
+ "reportVersion": 1,
3
+ "generatedAt": "2026-05-20T03:54:28.830Z",
4
+ "fixtureCount": 34,
5
+ "benchmarkGeneratedAt": "2026-05-20T03:54:28.820Z",
6
+ "note": "Offline comparison harness. Built-in Patina row uses deterministic suspect-zone analyzer; third-party rows are manual opt-in only.",
7
+ "manualInput": null,
8
+ "detectors": [
9
+ {
10
+ "id": "patina-deterministic",
11
+ "name": "Patina deterministic suspect-zone analyzer",
12
+ "kind": "in-tree",
13
+ "mode": "offline",
14
+ "threshold": "burstiness low OR MATTR low OR lexicon density > threshold"
15
+ }
16
+ ],
17
+ "summaries": {
18
+ "patina-deterministic": {
19
+ "tp": 18,
20
+ "fp": 0,
21
+ "fn": 0,
22
+ "tn": 16,
23
+ "total": 34,
24
+ "fixtureCount": 34,
25
+ "coverage": 1,
26
+ "accuracy": 1,
27
+ "precision": 1,
28
+ "recall": 1,
29
+ "f1": 1
30
+ }
31
+ },
32
+ "rows": [
33
+ {
34
+ "fixture_id": "en-ai-01",
35
+ "lang": "en",
36
+ "class": "ai",
37
+ "detector": "patina-deterministic",
38
+ "expected_hot": true,
39
+ "predicted_hot": true,
40
+ "correct": true,
41
+ "score": 1,
42
+ "source": "tests/quality/benchmark.mjs",
43
+ "notes": null
44
+ },
45
+ {
46
+ "fixture_id": "en-ai-02",
47
+ "lang": "en",
48
+ "class": "ai",
49
+ "detector": "patina-deterministic",
50
+ "expected_hot": true,
51
+ "predicted_hot": true,
52
+ "correct": true,
53
+ "score": 1,
54
+ "source": "tests/quality/benchmark.mjs",
55
+ "notes": null
56
+ },
57
+ {
58
+ "fixture_id": "en-ai-03",
59
+ "lang": "en",
60
+ "class": "ai",
61
+ "detector": "patina-deterministic",
62
+ "expected_hot": true,
63
+ "predicted_hot": true,
64
+ "correct": true,
65
+ "score": 1,
66
+ "source": "tests/quality/benchmark.mjs",
67
+ "notes": null
68
+ },
69
+ {
70
+ "fixture_id": "en-ai-04",
71
+ "lang": "en",
72
+ "class": "ai",
73
+ "detector": "patina-deterministic",
74
+ "expected_hot": true,
75
+ "predicted_hot": true,
76
+ "correct": true,
77
+ "score": 1,
78
+ "source": "tests/quality/benchmark.mjs",
79
+ "notes": null
80
+ },
81
+ {
82
+ "fixture_id": "en-ai-05",
83
+ "lang": "en",
84
+ "class": "ai",
85
+ "detector": "patina-deterministic",
86
+ "expected_hot": true,
87
+ "predicted_hot": true,
88
+ "correct": true,
89
+ "score": 1,
90
+ "source": "tests/quality/benchmark.mjs",
91
+ "notes": null
92
+ },
93
+ {
94
+ "fixture_id": "en-ai-06-chat-register",
95
+ "lang": "en",
96
+ "class": "ai",
97
+ "detector": "patina-deterministic",
98
+ "expected_hot": true,
99
+ "predicted_hot": true,
100
+ "correct": true,
101
+ "score": 1,
102
+ "source": "tests/quality/benchmark.mjs",
103
+ "notes": null
104
+ },
105
+ {
106
+ "fixture_id": "en-nat-01",
107
+ "lang": "en",
108
+ "class": "natural",
109
+ "detector": "patina-deterministic",
110
+ "expected_hot": false,
111
+ "predicted_hot": false,
112
+ "correct": true,
113
+ "score": 0,
114
+ "source": "tests/quality/benchmark.mjs",
115
+ "notes": null
116
+ },
117
+ {
118
+ "fixture_id": "en-nat-02",
119
+ "lang": "en",
120
+ "class": "natural",
121
+ "detector": "patina-deterministic",
122
+ "expected_hot": false,
123
+ "predicted_hot": false,
124
+ "correct": true,
125
+ "score": 0,
126
+ "source": "tests/quality/benchmark.mjs",
127
+ "notes": null
128
+ },
129
+ {
130
+ "fixture_id": "en-nat-03",
131
+ "lang": "en",
132
+ "class": "natural",
133
+ "detector": "patina-deterministic",
134
+ "expected_hot": false,
135
+ "predicted_hot": false,
136
+ "correct": true,
137
+ "score": 0,
138
+ "source": "tests/quality/benchmark.mjs",
139
+ "notes": null
140
+ },
141
+ {
142
+ "fixture_id": "en-nat-04",
143
+ "lang": "en",
144
+ "class": "natural",
145
+ "detector": "patina-deterministic",
146
+ "expected_hot": false,
147
+ "predicted_hot": false,
148
+ "correct": true,
149
+ "score": 0,
150
+ "source": "tests/quality/benchmark.mjs",
151
+ "notes": null
152
+ },
153
+ {
154
+ "fixture_id": "en-nat-05",
155
+ "lang": "en",
156
+ "class": "natural",
157
+ "detector": "patina-deterministic",
158
+ "expected_hot": false,
159
+ "predicted_hot": false,
160
+ "correct": true,
161
+ "score": 0,
162
+ "source": "tests/quality/benchmark.mjs",
163
+ "notes": null
164
+ },
165
+ {
166
+ "fixture_id": "ja-ai-01",
167
+ "lang": "ja",
168
+ "class": "ai",
169
+ "detector": "patina-deterministic",
170
+ "expected_hot": true,
171
+ "predicted_hot": true,
172
+ "correct": true,
173
+ "score": 1,
174
+ "source": "tests/quality/benchmark.mjs",
175
+ "notes": null
176
+ },
177
+ {
178
+ "fixture_id": "ja-ai-02",
179
+ "lang": "ja",
180
+ "class": "ai",
181
+ "detector": "patina-deterministic",
182
+ "expected_hot": true,
183
+ "predicted_hot": true,
184
+ "correct": true,
185
+ "score": 1,
186
+ "source": "tests/quality/benchmark.mjs",
187
+ "notes": null
188
+ },
189
+ {
190
+ "fixture_id": "ja-ai-03",
191
+ "lang": "ja",
192
+ "class": "ai",
193
+ "detector": "patina-deterministic",
194
+ "expected_hot": true,
195
+ "predicted_hot": true,
196
+ "correct": true,
197
+ "score": 1,
198
+ "source": "tests/quality/benchmark.mjs",
199
+ "notes": null
200
+ },
201
+ {
202
+ "fixture_id": "ja-nat-01",
203
+ "lang": "ja",
204
+ "class": "natural",
205
+ "detector": "patina-deterministic",
206
+ "expected_hot": false,
207
+ "predicted_hot": false,
208
+ "correct": true,
209
+ "score": 0,
210
+ "source": "tests/quality/benchmark.mjs",
211
+ "notes": null
212
+ },
213
+ {
214
+ "fixture_id": "ja-nat-02",
215
+ "lang": "ja",
216
+ "class": "natural",
217
+ "detector": "patina-deterministic",
218
+ "expected_hot": false,
219
+ "predicted_hot": false,
220
+ "correct": true,
221
+ "score": 0,
222
+ "source": "tests/quality/benchmark.mjs",
223
+ "notes": null
224
+ },
225
+ {
226
+ "fixture_id": "ja-nat-03",
227
+ "lang": "ja",
228
+ "class": "natural",
229
+ "detector": "patina-deterministic",
230
+ "expected_hot": false,
231
+ "predicted_hot": false,
232
+ "correct": true,
233
+ "score": 0,
234
+ "source": "tests/quality/benchmark.mjs",
235
+ "notes": null
236
+ },
237
+ {
238
+ "fixture_id": "ko-ai-01",
239
+ "lang": "ko",
240
+ "class": "ai",
241
+ "detector": "patina-deterministic",
242
+ "expected_hot": true,
243
+ "predicted_hot": true,
244
+ "correct": true,
245
+ "score": 1,
246
+ "source": "tests/quality/benchmark.mjs",
247
+ "notes": null
248
+ },
249
+ {
250
+ "fixture_id": "ko-ai-02",
251
+ "lang": "ko",
252
+ "class": "ai",
253
+ "detector": "patina-deterministic",
254
+ "expected_hot": true,
255
+ "predicted_hot": true,
256
+ "correct": true,
257
+ "score": 1,
258
+ "source": "tests/quality/benchmark.mjs",
259
+ "notes": null
260
+ },
261
+ {
262
+ "fixture_id": "ko-ai-03",
263
+ "lang": "ko",
264
+ "class": "ai",
265
+ "detector": "patina-deterministic",
266
+ "expected_hot": true,
267
+ "predicted_hot": true,
268
+ "correct": true,
269
+ "score": 1,
270
+ "source": "tests/quality/benchmark.mjs",
271
+ "notes": null
272
+ },
273
+ {
274
+ "fixture_id": "ko-ai-04",
275
+ "lang": "ko",
276
+ "class": "ai",
277
+ "detector": "patina-deterministic",
278
+ "expected_hot": true,
279
+ "predicted_hot": true,
280
+ "correct": true,
281
+ "score": 1,
282
+ "source": "tests/quality/benchmark.mjs",
283
+ "notes": null
284
+ },
285
+ {
286
+ "fixture_id": "ko-ai-05",
287
+ "lang": "ko",
288
+ "class": "ai",
289
+ "detector": "patina-deterministic",
290
+ "expected_hot": true,
291
+ "predicted_hot": true,
292
+ "correct": true,
293
+ "score": 1,
294
+ "source": "tests/quality/benchmark.mjs",
295
+ "notes": null
296
+ },
297
+ {
298
+ "fixture_id": "ko-ai-06-chat-register",
299
+ "lang": "ko",
300
+ "class": "ai",
301
+ "detector": "patina-deterministic",
302
+ "expected_hot": true,
303
+ "predicted_hot": true,
304
+ "correct": true,
305
+ "score": 1,
306
+ "source": "tests/quality/benchmark.mjs",
307
+ "notes": null
308
+ },
309
+ {
310
+ "fixture_id": "ko-nat-01",
311
+ "lang": "ko",
312
+ "class": "natural",
313
+ "detector": "patina-deterministic",
314
+ "expected_hot": false,
315
+ "predicted_hot": false,
316
+ "correct": true,
317
+ "score": 0,
318
+ "source": "tests/quality/benchmark.mjs",
319
+ "notes": null
320
+ },
321
+ {
322
+ "fixture_id": "ko-nat-02",
323
+ "lang": "ko",
324
+ "class": "natural",
325
+ "detector": "patina-deterministic",
326
+ "expected_hot": false,
327
+ "predicted_hot": false,
328
+ "correct": true,
329
+ "score": 0,
330
+ "source": "tests/quality/benchmark.mjs",
331
+ "notes": null
332
+ },
333
+ {
334
+ "fixture_id": "ko-nat-03",
335
+ "lang": "ko",
336
+ "class": "natural",
337
+ "detector": "patina-deterministic",
338
+ "expected_hot": false,
339
+ "predicted_hot": false,
340
+ "correct": true,
341
+ "score": 0,
342
+ "source": "tests/quality/benchmark.mjs",
343
+ "notes": null
344
+ },
345
+ {
346
+ "fixture_id": "ko-nat-04",
347
+ "lang": "ko",
348
+ "class": "natural",
349
+ "detector": "patina-deterministic",
350
+ "expected_hot": false,
351
+ "predicted_hot": false,
352
+ "correct": true,
353
+ "score": 0,
354
+ "source": "tests/quality/benchmark.mjs",
355
+ "notes": null
356
+ },
357
+ {
358
+ "fixture_id": "ko-nat-05",
359
+ "lang": "ko",
360
+ "class": "natural",
361
+ "detector": "patina-deterministic",
362
+ "expected_hot": false,
363
+ "predicted_hot": false,
364
+ "correct": true,
365
+ "score": 0,
366
+ "source": "tests/quality/benchmark.mjs",
367
+ "notes": null
368
+ },
369
+ {
370
+ "fixture_id": "zh-ai-01",
371
+ "lang": "zh",
372
+ "class": "ai",
373
+ "detector": "patina-deterministic",
374
+ "expected_hot": true,
375
+ "predicted_hot": true,
376
+ "correct": true,
377
+ "score": 1,
378
+ "source": "tests/quality/benchmark.mjs",
379
+ "notes": null
380
+ },
381
+ {
382
+ "fixture_id": "zh-ai-02",
383
+ "lang": "zh",
384
+ "class": "ai",
385
+ "detector": "patina-deterministic",
386
+ "expected_hot": true,
387
+ "predicted_hot": true,
388
+ "correct": true,
389
+ "score": 1,
390
+ "source": "tests/quality/benchmark.mjs",
391
+ "notes": null
392
+ },
393
+ {
394
+ "fixture_id": "zh-ai-03",
395
+ "lang": "zh",
396
+ "class": "ai",
397
+ "detector": "patina-deterministic",
398
+ "expected_hot": true,
399
+ "predicted_hot": true,
400
+ "correct": true,
401
+ "score": 1,
402
+ "source": "tests/quality/benchmark.mjs",
403
+ "notes": null
404
+ },
405
+ {
406
+ "fixture_id": "zh-nat-01",
407
+ "lang": "zh",
408
+ "class": "natural",
409
+ "detector": "patina-deterministic",
410
+ "expected_hot": false,
411
+ "predicted_hot": false,
412
+ "correct": true,
413
+ "score": 0,
414
+ "source": "tests/quality/benchmark.mjs",
415
+ "notes": null
416
+ },
417
+ {
418
+ "fixture_id": "zh-nat-02",
419
+ "lang": "zh",
420
+ "class": "natural",
421
+ "detector": "patina-deterministic",
422
+ "expected_hot": false,
423
+ "predicted_hot": false,
424
+ "correct": true,
425
+ "score": 0,
426
+ "source": "tests/quality/benchmark.mjs",
427
+ "notes": null
428
+ },
429
+ {
430
+ "fixture_id": "zh-nat-03",
431
+ "lang": "zh",
432
+ "class": "natural",
433
+ "detector": "patina-deterministic",
434
+ "expected_hot": false,
435
+ "predicted_hot": false,
436
+ "correct": true,
437
+ "score": 0,
438
+ "source": "tests/quality/benchmark.mjs",
439
+ "notes": null
440
+ }
441
+ ]
442
+ }
@@ -0,0 +1,65 @@
1
+ # Detector Comparison Harness
2
+
3
+ This report is generated offline from the checked-in suspect-zone fixtures. It is a comparison harness, not a vendor ranking claim.
4
+
5
+ ## Current run
6
+
7
+ - Generated at: 2026-05-20T03:54:28.830Z
8
+ - Fixture source: `tests/fixtures/suspect-zones/**`
9
+ - Fixture count: 34
10
+ - Manual third-party input: none
11
+ - Reproduce built-in comparison: `npm run benchmark:compare`
12
+ - Merge manual scores: `node scripts/detector-comparison.mjs --input tests/quality/detectors.manual.example.json`
13
+
14
+ ## Summary
15
+
16
+ | detector | name | kind | covered | coverage | accuracy | precision | recall | TP | FP | FN | TN |
17
+ |---|---|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
18
+ | patina-deterministic | Patina deterministic suspect-zone analyzer | in-tree | 34/34 | 100.0% | 100.0% | 100.0% | 100.0% | 18 | 0 | 0 | 16 |
19
+
20
+ ## Fixture-level rows
21
+
22
+ | fixture | lang | class | detector | expected | predicted | ok | score | source |
23
+ |---|---|---|---|---|---|---:|---:|---|
24
+ | en-ai-01 | en | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
25
+ | en-ai-02 | en | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
26
+ | en-ai-03 | en | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
27
+ | en-ai-04 | en | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
28
+ | en-ai-05 | en | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
29
+ | en-ai-06-chat-register | en | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
30
+ | en-nat-01 | en | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
31
+ | en-nat-02 | en | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
32
+ | en-nat-03 | en | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
33
+ | en-nat-04 | en | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
34
+ | en-nat-05 | en | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
35
+ | ja-ai-01 | ja | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
36
+ | ja-ai-02 | ja | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
37
+ | ja-ai-03 | ja | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
38
+ | ja-nat-01 | ja | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
39
+ | ja-nat-02 | ja | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
40
+ | ja-nat-03 | ja | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
41
+ | ko-ai-01 | ko | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
42
+ | ko-ai-02 | ko | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
43
+ | ko-ai-03 | ko | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
44
+ | ko-ai-04 | ko | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
45
+ | ko-ai-05 | ko | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
46
+ | ko-ai-06-chat-register | ko | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
47
+ | ko-nat-01 | ko | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
48
+ | ko-nat-02 | ko | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
49
+ | ko-nat-03 | ko | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
50
+ | ko-nat-04 | ko | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
51
+ | ko-nat-05 | ko | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
52
+ | zh-ai-01 | zh | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
53
+ | zh-ai-02 | zh | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
54
+ | zh-ai-03 | zh | ai | patina-deterministic | hot | hot | ✓ | 1 | tests/quality/benchmark.mjs |
55
+ | zh-nat-01 | zh | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
56
+ | zh-nat-02 | zh | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
57
+ | zh-nat-03 | zh | natural | patina-deterministic | cold | cold | ✓ | 0 | tests/quality/benchmark.mjs |
58
+
59
+ ## Manual third-party protocol
60
+
61
+ 1. Use only redistributable fixture text from `tests/fixtures/suspect-zones/**`.
62
+ 2. Paste text into a third-party detector manually, respecting that service's terms.
63
+ 3. Record only fixture id, detector id, date/version, score, and hot/cold label. Do not check private text into the repo.
64
+ 4. Run this script with `--input <json>`. The script does not scrape sites or call external APIs.
65
+ 5. Treat results as time-stamped evidence, not a universal claim about authorship detection.