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,211 @@
1
+ version: "3.11.0"
2
+ language: ko # Korean (default) -- auto-loads all ko-*.md patterns
3
+ # language: en -- English -- auto-loads all en-*.md patterns
4
+ # language: zh -- Chinese -- auto-loads all zh-*.md patterns
5
+ # language: ja -- Japanese -- auto-loads all ja-*.md patterns
6
+ # Override with CLI: --lang en / --lang zh / --lang ja
7
+ profile: default
8
+ output: rewrite # rewrite | diff | audit | score
9
+
10
+ # Tone categorization (v3.10): named voice axis. Six v1 tones for ko/en.
11
+ # Resolution: explicit --tone > config tone > config profile.
12
+ # auto = heuristic single-tone detection at SKILL.md Phase 4.5b.
13
+ # Unset = profile-only legacy behavior (regression-safe default).
14
+ tone: # one of: casual, professional, academic, narrative, marketing, instructional, auto
15
+ # Override with CLI: --tone <name>
16
+ # zh/ja with explicit tone: warns and falls back to profile.
17
+
18
+ # Optional path to 1-3 user-written paragraphs. CLI --voice-sample wins.
19
+ # Used as a style/register anchor only; facts stay sourced from the input text.
20
+ voice-sample:
21
+
22
+ # Supported languages: ko, en, zh, ja
23
+
24
+ # patterns 목록은 기본 언어(ko)의 팩을 문서화합니다.
25
+ # 실제 로딩은 Glob patterns/{lang}-*.md로 자동 탐색합니다.
26
+ # 특정 팩을 제외하려면 skip-patterns를 사용하세요.
27
+ patterns:
28
+ - ko-structure
29
+ - ko-content
30
+ - ko-language
31
+ - ko-style
32
+ - ko-communication
33
+ - ko-filler
34
+ - ko-viral-hook # score-only — detection without rewrite
35
+
36
+ # English packs (auto-discovered when language: en):
37
+ # - en-structure (5 patterns: #25-28, #30)
38
+ # - en-content
39
+ # - en-language
40
+ # - en-style
41
+ # - en-communication
42
+ # - en-filler (4 patterns: #22-24, #31)
43
+
44
+ # Chinese packs (auto-discovered when language: zh):
45
+ # - zh-structure (5 patterns: #25-28, #30)
46
+ # - zh-content
47
+ # - zh-language
48
+ # - zh-style
49
+ # - zh-communication
50
+ # - zh-filler (4 patterns: #22-24, #31)
51
+
52
+ # Japanese packs (auto-discovered when language: ja):
53
+ # - ja-structure (5 patterns: #25-28, #30)
54
+ # - ja-content
55
+ # - ja-language
56
+ # - ja-style
57
+ # - ja-communication
58
+ # - ja-filler (4 patterns: #22-24, #31)
59
+
60
+ skip-patterns: [] # additive merge across default/global/project configs
61
+ blocklist: [] # additive merge: 추가로 감지할 어휘
62
+ allowlist: [] # additive merge: 감지에서 제외할 어휘
63
+ # Other arrays (for example max-models) are replaced by the higher-precedence
64
+ # config so users can intentionally choose an exact provider list.
65
+
66
+ # MAX mode: multi-model humanization
67
+ # claude uses `claude -p`, gemini uses `gemini -p '' --output-format text`,
68
+ # codex uses `codex exec --skip-git-repo-check --output-last-message <file>`
69
+ # Supported models: claude, codex, gemini
70
+ # Override with CLI: --models claude,gemini,codex
71
+ max-models:
72
+ - claude
73
+ - gemini
74
+
75
+ # Dispatch mode for MAX mode CLI execution
76
+ # omc: tmux pane parallel dispatch (recommended, requires oh-my-claudecode + tmux)
77
+ # - Uses a unique temp dir per run
78
+ # - Waits only for selected models and marks timed-out runs as failed
79
+ # - All providers receive the prompt via stdin
80
+ # direct: sequential stdin dispatch (fallback; apply the same per-model timeout)
81
+ # api: HTTP API dispatch (no local CLI needed; requires PATINA_API_KEY env var)
82
+ # - Uses OpenAI-compatible chat completions endpoint
83
+ # - Works with Anthropic, OpenAI, Google AI Studio, OpenRouter, etc.
84
+ # - Requires curl and jq
85
+ # - Model IDs configurable via PATINA_MODEL_* env vars
86
+ dispatch: omc
87
+
88
+ # Scoring: LLM score remains canonical, with a deterministic shadow score
89
+ # from src/features/* for reproducible drift checks.
90
+ scoring:
91
+ deterministic:
92
+ enabled: true
93
+ divergence-threshold: 20 # warn and prefer the more pessimistic score above this delta
94
+ combined-weight: 0 # default off for combinedScore; users may opt in (e.g. 0.2)
95
+
96
+ # Ouroboros: iterative self-improvement loop
97
+ # Runs the full humanization pipeline repeatedly until the AI score converges.
98
+ # Enable via config or CLI flag: --ouroboros
99
+ ouroboros:
100
+ enabled: false # opt-in; --ouroboros CLI flag overrides to true
101
+ target-score: 30 # stop when overall score <= this value (0-100)
102
+ max-iterations: 3 # hard limit on loop iterations
103
+ plateau-threshold: 10 # stop if score improves by less than this between iterations
104
+ category-weights:
105
+ ko:
106
+ content: 0.18
107
+ language: 0.18
108
+ style: 0.18
109
+ communication: 0.13
110
+ filler: 0.08
111
+ structure: 0.15
112
+ viral-hook: 0.10 # score-only pack (excluded from rewrite)
113
+ en:
114
+ content: 0.20
115
+ language: 0.20
116
+ style: 0.20
117
+ communication: 0.12
118
+ filler: 0.08
119
+ structure: 0.10
120
+ viral-hook: 0.10 # score-only pack (excluded from rewrite)
121
+ zh:
122
+ content: 0.18
123
+ language: 0.18
124
+ style: 0.18
125
+ communication: 0.13
126
+ filler: 0.08
127
+ structure: 0.15
128
+ viral-hook: 0.10 # score-only pack (excluded from rewrite)
129
+ ja:
130
+ content: 0.18
131
+ language: 0.18
132
+ style: 0.18
133
+ communication: 0.13
134
+ filler: 0.08
135
+ structure: 0.15
136
+ viral-hook: 0.10 # score-only pack (excluded from rewrite)
137
+ fidelity-floor: 70 # stop ouroboros if fidelity drops below this
138
+ mps-floor: 70 # stop ouroboros if MPS (meaning preservation) drops below this
139
+ combined-weights:
140
+ default:
141
+ ai-likeness: 0.60
142
+ fidelity: 0.40
143
+ academic:
144
+ ai-likeness: 0.40
145
+ fidelity: 0.60
146
+ blog:
147
+ ai-likeness: 0.70
148
+ fidelity: 0.30
149
+ technical:
150
+ ai-likeness: 0.35
151
+ fidelity: 0.65
152
+ social:
153
+ ai-likeness: 0.75
154
+ fidelity: 0.25
155
+ email:
156
+ ai-likeness: 0.50
157
+ fidelity: 0.50
158
+ legal:
159
+ ai-likeness: 0.35
160
+ fidelity: 0.65
161
+ medical:
162
+ ai-likeness: 0.35
163
+ fidelity: 0.65
164
+ marketing:
165
+ ai-likeness: 0.65
166
+ fidelity: 0.35
167
+ severity-points:
168
+ high: 3
169
+ medium: 2
170
+ low: 1
171
+
172
+ # Stylometry: deterministic statistical preprocessing (SKILL.md Step 4.6)
173
+ # Calculates burstiness (sentence-length CV) and MATTR (lexical diversity) per
174
+ # paragraph, marks suspect zones, and feeds them into 5a/5b as internal memory.
175
+ # See core/stylometry.md for the full algorithm reference.
176
+ stylometry:
177
+ enabled: true # set false to bypass 4.6단계 entirely
178
+ languages: [ko, en, zh, ja] # zh/ja use deterministic character-token fallback
179
+ burstiness:
180
+ bands:
181
+ low: 0.30 # CV < 0.30 → low (suspect). Calibrated v3.5.1 from
182
+ # 0.25 against 300 external paragraphs (HC3 + Wikipedia).
183
+ high: 0.50 # CV > 0.50 → high
184
+ ttr:
185
+ window: 50 # MATTR window in tokens
186
+ bands:
187
+ low: 0.55 # MATTR < 0.55 → low (suspect)
188
+ high: 0.70 # MATTR > 0.70 → high
189
+ sentence_zoom:
190
+ similarity_threshold: 0.20 # adjacent sentences within ±20% token count → grouped as sub-flag
191
+ skip:
192
+ min_paragraphs: 2
193
+ min_sentences: 2
194
+
195
+ # AI-Lexicon Overlap (SKILL.md Step 4.7)
196
+ # Matches paragraphs against an AI-favored phrase dictionary not covered
197
+ # by the 28-pattern catalog. Computes density per 1000 tokens; high
198
+ # density paragraphs are flagged SUSPECT under the 3-signal OR rule
199
+ # (burstiness OR MATTR OR lexicon_density).
200
+ # See core/stylometry.md §16 for the full algorithm.
201
+ lexicon:
202
+ enabled: true
203
+ languages: [en, ko] # zh/ja deferred (no curated lexicon yet)
204
+ density_threshold: 2.0 # matches per 1000 tokens; > threshold → SUSPECT
205
+ # Lexicon files auto-discovered via Glob lexicon/ai-{lang}.md
206
+ # See lexicon/ai-en.md (108 entries) and lexicon/ai-ko.md (90 entries).
207
+ # Calibrated against 400 paragraphs (HC3 + Wikipedia + NamuWiki):
208
+ # AI catch 66% → 76% with Wikipedia FP staying at 25% boundary.
209
+ skip:
210
+ min_paragraphs: 2
211
+ min_sentences: 2
package/CHANGELOG.md ADDED
@@ -0,0 +1,265 @@
1
+ # Changelog
2
+
3
+ All notable changes to patina. Dates are release dates (YYYY-MM-DD).
4
+
5
+ ## Release entry template
6
+
7
+ ```md
8
+ ## X.Y.Z — YYYY-MM-DD
9
+
10
+ **Short release title.**
11
+
12
+ Semver rationale: patch | minor | major — explain whether this changes patterns, schemas, CLI behavior, or docs only.
13
+ ```
14
+
15
+ ## 3.11.0 — 2026-05-20
16
+
17
+ **Launch-readiness polish for trust, benchmarks, and distribution.**
18
+
19
+ Semver rationale: minor — adds CI/release/distribution surfaces and documentation, while preserving the core rewrite pipeline and existing CLI behavior.
20
+
21
+ ### New
22
+
23
+ - Prepared npm release metadata for `patina-cli` plus the `patina-humanizer` alias package.
24
+ - Added a release workflow for npm provenance publishing and GHCR image publishing.
25
+ - Added deterministic GitHub Action and pre-commit scoring surfaces for Markdown review.
26
+ - Added Dockerfile-based container runtime for API-backed CLI use.
27
+
28
+ ### Quality
29
+
30
+ - Added release metadata checks so package/config/skill/changelog versions stay synchronized.
31
+ - Added deterministic prose-score tests and pre-commit E2E coverage.
32
+ - Expanded the deterministic suspect-zone benchmark to ko/en/zh/ja with checked-in per-fixture metric ranges.
33
+ - Added an offline detector-comparison harness and 2025+ re-baseline plan for future benchmark evidence.
34
+
35
+ ## 3.10.0 — 2026-05-06
36
+
37
+ **Tone categorization v1 (6 tones + `auto`).**
38
+
39
+ A first-class `tone` axis sits on top of profiles, giving users an explicit
40
+ voice category without having to memorize the profile catalog. Tone resolution
41
+ is `--tone` CLI > `tone:` config > `profile:` config; absence of any tone keeps
42
+ v3.9.0 behavior intact (regression-safe profile-only path).
43
+
44
+ ### New
45
+
46
+ - **`--tone <name>` flag and `tone:` config field.** Six v1 tones plus `auto`:
47
+ `casual`, `professional`, `academic`, `narrative`, `marketing`,
48
+ `instructional`. Unknown values fail fast with the valid list.
49
+ - **Two new profile backbones:** `profiles/narrative.md` and
50
+ `profiles/instructional.md` (ko + en sections each). zh/ja sections are
51
+ intentionally omitted for v1.
52
+ - **Phase 4.5b heuristic auto-detection.** When `--tone auto`, deterministic
53
+ lexical and structural signals select a single tone with `tone_evidence`
54
+ (1–3 strings) and `tone_confidence` (`low`/`medium`/`high`). No fallback on
55
+ low confidence — always commits to a single tone (A5).
56
+ - **Phase 5b tone override layer.** Resolved tone applies a per-tone override
57
+ pack on top of profile overrides. **Tone overrides replace profile overrides
58
+ on conflict; they do not stack** (idempotent application).
59
+ - **Phase 6 YAML footer.** Every output mode (`rewrite`, `diff`, `audit`,
60
+ `score`) emits a trailing footer block:
61
+ ```
62
+ ---
63
+ tone: <resolved | null>
64
+ tone_source: user | auto | unsupported_language_fallback | profile_only | skipped_short_input
65
+ tone_evidence: [...]
66
+ tone_confidence: low | medium | high | null
67
+ ---
68
+ ```
69
+ Body text in `rewrite` mode contains zero tone metadata leakage.
70
+ - **12 fixture pairs** under `examples/tones/` (6 tones × ko/en) showing the
71
+ documented behavioral direction per tone.
72
+
73
+ ### Behavior
74
+
75
+ - **zh/ja with any `--tone` (including `auto`)** emits a warning to stderr
76
+ and the YAML footer (`tone_source: unsupported_language_fallback`), then
77
+ continues in profile-only mode. Phase 4.5b heuristics only cover ko/en
78
+ signals, so `auto` on zh/ja would silently degrade to residual
79
+ `professional` without useful evidence — the fallback is intentional.
80
+ - **legal/medical fidelity preserved within `professional` tone.** When the
81
+ active profile is `legal` or `medical`, `combined-weights.{legal|medical}`
82
+ (fidelity 0.65) is forced regardless of tone resolution. Tone overrides
83
+ cannot lower the fidelity floor (R2).
84
+ - **Short-input bypass.** Texts with `<2 paragraphs OR <2 sentences` skip
85
+ Phase 4.5b detection entirely and emit `tone_source: skipped_short_input`
86
+ with `tone_evidence: ["input too short"]`. This is distinct from the
87
+ residual-default path (auto detection ran but no signal cluster reached
88
+ threshold), which keeps `tone_source: auto`.
89
+
90
+ ### Quality
91
+
92
+ - **`hasToneFooter()` validates all 4 keys.** Detection now requires `tone`,
93
+ `tone_source`, `tone_evidence`, and `tone_confidence` to be present in the
94
+ fenced block. Partial model-emitted footers no longer suppress the CLI
95
+ authoritative footer.
96
+ - **`resolveTone()` validates `cliTone` input.** Both CLI and config tone
97
+ values are now validated against the allowed tone list, ensuring fail-fast
98
+ behavior regardless of caller.
99
+ - **17 tone unit tests** covering `resolveTone()` priority chain, edge cases
100
+ (empty config, zh/ja fallback, invalid values), backbone profile mapping,
101
+ and `formatOutput` footer emission/deduplication.
102
+
103
+ ### CLI wiring (standalone Node CLI)
104
+
105
+ The standalone `src/cli.js` CLI threads `--tone` through `src/config.js`
106
+ (`resolveTone()`), `src/loader.js` (`toneToBackboneProfile()`),
107
+ `src/prompt-builder.js` (tone context block), and `src/output.js`
108
+ (YAML footer emission for all 4 modes). `--tone bogus` fails fast with the
109
+ valid list. CLI > config > unset priority is preserved. Profile-only
110
+ invocations (`patina --profile blog input.md`, no `--tone` and no `tone:`
111
+ config) behave identically to v3.9.0 except for the appended YAML footer.
112
+
113
+ ## 3.9.0 — 2026-05-05
114
+
115
+ **Standalone CLI security hardening (issues #88, #89, #90).**
116
+
117
+ Three boundary-validation fixes for the standalone `patina` CLI. None of them
118
+ affect the `/patina` skill flow inside Claude Code / Codex CLI / Cursor /
119
+ OpenCode (the skill runs prompts, not the Node CLI), but anyone running
120
+ `patina` from a shell — especially against untrusted input text — should
121
+ upgrade.
122
+
123
+ ### Breaking change
124
+
125
+ - **codex-cli auto-fallback removed.** Previously, when no API key was set
126
+ and `codex` was installed and authenticated, patina silently used the
127
+ codex-cli backend. This sent the user's input to a coding agent, where
128
+ prompt injection in the document body could ask the agent to inspect or
129
+ modify files. The auto-fallback is now removed; codex-cli requires
130
+ explicit `--backend codex-cli` (or `--model codex…`). The error message
131
+ when no API key is found suggests this opt-in.
132
+
133
+ ### Hardening
134
+
135
+ - **Profile name validation** (`src/security.js`, `src/loader.js`). `--profile`
136
+ values and the `profile:` field in `.patina.yaml` must now match
137
+ `/^[A-Za-z0-9_][A-Za-z0-9_-]*$/`. This blocks `../../README` and similar
138
+ path-traversal reads that would have leaked unrelated `.md` files into the
139
+ LLM prompt.
140
+ - **Base URL validation** (`src/api.js`, `src/security.js`). Plaintext
141
+ `http://` is rejected for non-loopback hosts by default. Loopback (`127.*`,
142
+ `localhost`, `::1`) is still allowed for tests and local mocks. Override
143
+ with `--allow-insecure-base-url` or `PATINA_ALLOW_INSECURE_BASE_URL=1` for
144
+ trusted private endpoints. `https://` works as before.
145
+ - **Codex sandbox** (`src/backends/codex-cli.js`). When `--backend codex-cli`
146
+ is used, codex now runs with `--sandbox read-only` from a fresh tempdir
147
+ cwd (`-C <tmpdir>`), so a prompt-injected agent cannot reach the caller's
148
+ repo or write outside the temp dir.
149
+
150
+ ### Migration
151
+
152
+ If you depended on the silent codex-cli auto-fallback, add `--backend
153
+ codex-cli` to your invocation, or set `PATINA_API_KEY` / `--provider`. Run
154
+ `patina auth status` to see backend availability and how to authenticate.
155
+
156
+ ## 3.8.0 — 2026-05-04
157
+
158
+ **Korean lexicon re-curation via differential-frequency mining.**
159
+
160
+ v3.7.0's Korean lexicon was author-curated and contributed only +1pp on AI catch in our paired ko/AI corpus (vs +10pp on English). v3.8.0 mines the corpus for high-signal Korean phrases via differential frequency against NamuWiki human prose, surfacing 12 register markers AI text uses heavily but humans rarely.
161
+
162
+ Mining rule (`.omc/research/v3_8_ko_lexicon_mine.py`):
163
+ - 어절 doc-frequency: AI count ≥ 4 AND ratio AI / (human + 1) ≥ 4.0
164
+ - Reject domain artifacts (proper nouns, year-tokens)
165
+ - Keep only register markers (passive evaluation, encyclopedic verbs, quantifier scaffolding)
166
+
167
+ Added entries (`lexicon/ai-ko.md`, 90 → 102 entries):
168
+ - Strict (8): `평가된다`, `꼽힌다`, `가리킨다`, `사례로`, `다수의`, `알려져`, `일컬어진다`, `평가받다`
169
+ - Phrases (4): `가운데 하나로`, `자리 잡았다`, `알려져 있다`, `~의 사례로`
170
+
171
+ 500-paragraph cross-source result:
172
+
173
+ | Source | v3.7.0 | v3.8.0 | Δ |
174
+ |--------|--------|--------|---|
175
+ | HC3 ChatGPT (en) | 76% | 76% | 0pp |
176
+ | HC3 human (en) | 19% | 19% | 0pp |
177
+ | Wikipedia (en) | 25% | 25% | 0pp |
178
+ | NamuWiki (ko) | 13% | 13% | 0pp |
179
+ | ko/AI corpus | 83% | **91%** | **+8pp** |
180
+
181
+ Clean Pareto improvement: AI catch +8pp on Korean with zero false-positive regression. Korean catch rate is now stronger than English (91% vs 76%).
182
+
183
+ Acceptance gates met: AI recall 91% ≥ 75% · max FP 25% ≤ 25% · ko regression 0pp ≤ +5pp.
184
+
185
+ ## 3.7.0 — 2026-05-04
186
+
187
+ **AI-lexicon overlap signal (new step 4.7).**
188
+
189
+ A flat dictionary (`lexicon/ai-en.md` 108 entries, `lexicon/ai-ko.md` 90 entries) flags AI-favored phrases the 28-pattern catalog does not enumerate. Densities are computed per 1000 tokens; the 4.6 hot rule extends to a 3-signal OR (burstiness OR MATTR OR lexicon_density > 2.0).
190
+
191
+ Calibration (`.omc/research/v3_7_lexicon_eval.py` vs 400 paragraphs):
192
+
193
+ | Source | v3.5.1 | v3.7.0 | Δ |
194
+ |--------|--------|--------|---|
195
+ | HC3 ChatGPT (en) | 66% | **76%** | +10pp |
196
+ | HC3 human (en) | 12% | 19% | +7pp |
197
+ | Wikipedia (en) | 23% | 25% | +2pp |
198
+ | NamuWiki (ko) | 11% | 13% | +2pp |
199
+
200
+ All acceptance gates met (AI ≥ 75%, max FP ≤ 25%, NamuWiki regression ≤ +5pp) — first Pareto improvement over the v3.5.1 wall.
201
+
202
+ Drop list (post-eval, see `core/stylometry.md` §16): `intersection`, `principles`, `mindset`, `iterative`, `responsible`, `methodologies`, `redefine`, `accessible`, `equitable`, `one of the most`, `in conjunction with`, `the power of` — fired more on academic prose than on AI text.
203
+
204
+ Skipped v3.6 (n-gram dropped, §15 negative finding).
205
+
206
+ ## 3.5.1 — 2026
207
+
208
+ **Stylometric calibration patch.**
209
+
210
+ Raised `stylometry.burstiness.bands.low` from 0.25 to 0.30 after external validation against 300 paragraphs (HC3 ChatGPT 100 + HC3 human 100 + Wikipedia 100). v3.5.0 caught 57% of real AI text; v3.5.1 catches 66% with HC3 human FP 12% and Wikipedia FP 23%.
211
+
212
+ Sweep showed no threshold combo satisfies both AI ≥ 70% and max FP ≤ 20% — Wikipedia's encyclopedic register naturally has uniform sentence length. MATTR threshold unchanged (0.55). v3.5.x is an advisory marker for the LLM, not a sole-decision gate. Calibration evidence in `core/stylometry.md` §13.
213
+
214
+ ## 3.5.0 — 2026
215
+
216
+ **Stylometric Suspect Zone Detection.**
217
+
218
+ New step 4.6 inserted between anchor extraction and the pattern phases. Deterministic burstiness (sentence-length CV) and MATTR (window=50) signals flag suspect paragraphs the 28-pattern catalog misses. Languages: ko + en in v1; zh + ja deferred to v2 roadmap. LLM receives a `<suspect-zones>` meta block plus `«P{n} SUSPECT»` paragraph prefixes as internal working memory. New file: `core/stylometry.md`.
219
+
220
+ ## 3.4.0 — 2026
221
+
222
+ **Free-tier ergonomics + 4 new patterns.**
223
+
224
+ - New `codex-cli` backend (no API key — uses local `codex` CLI's ChatGPT OAuth)
225
+ - `patina auth status` / `patina auth login` subcommands with auto-fallback when no API key is set
226
+ - `--provider` shortcuts for Gemini / Groq / Together AI free tiers
227
+ - Pattern additions: #30 (rhetorical question openers) and #31 (conclusion signal words) across all 4 languages, plus #32 (comparative adverb overuse) for KO `보다` and JA `より`
228
+ - Default profile expanded to match other profiles' structure
229
+ - GitHub Actions CI workflow added
230
+
231
+ ## 3.3.0
232
+
233
+ **Meaning Preservation System (MPS).** Ensures humanized text maintains original intent and claims. Semantic anchors (claims, polarity, causation, numbers) are extracted before rewriting and verified after each phase.
234
+
235
+ ## 3.2.0
236
+
237
+ **Ouroboros scoring system.** Pattern-based AI-likeness scoring (0-100), `--score` mode with category breakdown, `--ouroboros` iterative self-improvement loop with configurable termination (target/plateau/regression/max-iterations).
238
+
239
+ ## 3.1.1
240
+
241
+ **MAX mode reliability fixes.** Per-run temp directory, model-scoped wait loop + timeout handling, Gemini stdin dispatch, Codex CLI compatibility (`--output-last-message`, no `-q`).
242
+
243
+ ## 3.1.0
244
+
245
+ **MAX mode.** Installable `/patina-max` skill entrypoint + provider-aware dispatch (`claude -p` / `gemini -p` for Claude/Gemini, `codex exec` for Codex).
246
+
247
+ ## 3.0.0
248
+
249
+ **Multi-language framework.** `--lang` flag, English patterns (24) from blader/humanizer, skill renamed to `patina`.
250
+
251
+ ## 2.2.0
252
+
253
+ Loanword overuse pattern (#28), badges, repo rename.
254
+
255
+ ## 2.1.0
256
+
257
+ 2-Phase pipeline, structure patterns, blog profile, examples.
258
+
259
+ ## 2.0.0
260
+
261
+ Plugin architecture: pattern packs, profiles, config.
262
+
263
+ ## 1.0.0
264
+
265
+ Initial Korean adaptation (24 patterns).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 devswha
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.