sonicop 26.8.110-aarch64-linux → 26.8.112-aarch64-linux

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdf523a4b9401b42f8350625f6cb2d2c349438569e7f2d8af72b1479cc942b6e
4
- data.tar.gz: 39b5b2256ed32680df4fbba3bf39dfd95deda8af73d5181febfa85c3fda07779
3
+ metadata.gz: f1cab35205ef1b9545aa27aae10b033f94a6ef4285ad74f0f8439176570517ea
4
+ data.tar.gz: 8fa47739e28ec78bcd4ad740ffa2afdb4069a6fc673c9b11ef56f6a9ee6802fc
5
5
  SHA512:
6
- metadata.gz: 004fbc50f12b266531f74f9856950c875fa1877d107c3133a8cc5009e39bd35090caefe776ece330a36662ce7ffb3952870daa9f654fe065f418a645cd96b63b
7
- data.tar.gz: 057cff757ce5734806b792203a6cdaf067cb2d296bfb04f67f308cfc35d8cd7228c45d988e41dd6f68db06f0502f70f2d4b0657533dd76ec9049a425c33e4b4c
6
+ metadata.gz: ee256fff60b527f0baf546b06a61ee57c0f12f3e4bdc25d109972a2376d8f723f66918de47b2c7c26305347c39be451c09422d37cb4d251e7abb4e9bce1ff7fa
7
+ data.tar.gz: 783be95e866e2ec1eeef816e1bd42500b01ff3d0b200073246d2c5e128fb80bd6722920c18d2591d2eb86eb0deb7928962baa9a3edc7d1c83f47352b59a9cde4
data/CONFORMANCE.md CHANGED
@@ -55,17 +55,18 @@ sonicop --force-default-config --format json
55
55
 
56
56
  ## Results
57
57
 
58
- The two kinds of difference are counted separately because they mean different things. A
59
- `Lint/Syntax` difference says the two disagree about whether a file parses, and everything else in
60
- that file follows from it; a difference in any other cop says the port reads the same tree and
61
- draws a different conclusion. Only the second is a defect in a cop.
58
+ Three kinds of difference are counted separately because they mean different things. The set of
59
+ files with a fatal `Lint/Syntax` offense says whether the parsers disagree about accepting a file.
60
+ `Lint/Syntax` positions inside a file both already rejected measure diagnostic recovery, not file
61
+ acceptance. A difference in any other cop says the port reads the same tree and draws a different
62
+ conclusion. Only the last category is a defect in a cop.
62
63
 
63
64
  | Corpus | Excess | Missing | of which `Lint/Syntax` | Other cops | Field differences | Measured |
64
65
  |---|---:|---:|---|---:|---|---|
65
66
  | rubocop/rubocop | 0 | 0 | — | 0 | correctable ×1 | 2026-08-17 |
66
67
  | rails/rails | 0 | 0 | — | 0 | none | 2026-08-17 |
67
68
  | mastodon/mastodon | 0 | 0 | — | 0 | none | 2026-08-17 |
68
- | Homebrew/brew | 263 | 997 | **all of them** | **0** | none | 2026-08-17 |
69
+ | Homebrew/brew | 263 | 997 | **all of them** | **0** | none | 2026-08-18 |
69
70
  | ruby/ruby | 142 | 585 | 117 missing, 44 excess | 92 | 5 | 2026-08-16 |
70
71
 
71
72
  The last column is per row on purpose. A single date at the top of the file would say the five were
@@ -85,14 +86,19 @@ run starts from, and `TargetRubyVersion` is only inferred from the working direc
85
86
  tools therefore fall back to the default of 2.7 (RuboCop says so itself: `Using Ruby 2.7 parser`) and
86
87
  both call `dry_run:,` — a hash value omission, valid since 3.1 — a syntax error. **Run the same corpus
87
88
  at 3.1 and both report zero `Lint/Syntax`.** What is left is not disagreement about which files parse:
88
- the file sets are identical, 569 on each side, and the first diagnostic in each file lands at the same
89
- position. Only the second and later diagnostics diverge, because the two parsers recover from the
90
- error differently — which is what puts offenses on both sides of the ledger rather than only on
91
- RuboCop's. Those are not chased; see *Known divergences*.
92
-
93
- What is checked here is that every one of the 1,260 is a `Lint/Syntax` offense, in both directions.
94
- What is not checked is which recovery produced which diagnostic: the 263 Sonicop reports and RuboCop
95
- does not have not been read one by one. They are accounted for as a class, not individually.
89
+ the file sets are identical, 569 on each side, with no file unique to either parser. The two parsers
90
+ recover differently after encountering invalid syntax, which puts diagnostic positions on both sides
91
+ of the ledger rather than only on RuboCop's.
92
+
93
+ All 263 Sonicop-only positions were classified mechanically, not inferred from their cop name. They
94
+ occur in 135 of those shared syntax-error files, and every one follows a `Lint/Syntax` position that
95
+ both tools reported in the same file. Their messages are 113 end-of-input (`$end`), 86 right
96
+ parentheses (`tRPAREN`), 53 commas (`tCOMMA`), seven `end` keywords (`kEND`), two equals signs
97
+ (`tEQL`), one `when` (`kWHEN`) and one identifier (`tIDENTIFIER`). Thus the former “excess” is not a
98
+ set of valid files rejected only by Sonicop; it is the other direction of the same diagnostic-recovery
99
+ divergence as the 997 RuboCop-only positions. Suppressing every diagnostic after Sonicop's first one
100
+ would make the excess zero, but would also discard 1,998 positions that already match and increase the
101
+ missing side from 997 to 2,995. That is not a conformance fix. See *Known divergences*.
96
102
 
97
103
  Much of ruby/ruby's difference is the same shape,
98
104
  with 117 of the 585 missing and 44 of the 142 excess being `Lint/Syntax` itself,
@@ -181,10 +187,10 @@ but no longer reproduces fails the test, and so does one that appears without be
181
187
  ### Error recovery after a syntax error
182
188
 
183
189
  RuboCop parses with `parser`, an LALR parser that recovers from an error and keeps going, emitting
184
- further diagnostics from the recovered state. Sonicop parses with tree-sitter, which does not model
185
- that recovery, so the follow-on diagnostics cannot be reproduced. On Homebrew this accounts for the
186
- 997 missing `Lint/Syntax` offenses: `class definition in method body`, `dynamic constant assignment`,
187
- `cannot assign to a keyword`, and repeated `unexpected token` inside one multi-line hash.
190
+ further diagnostics from the recovered state. Sonicop parses with tree-sitter and reaches different
191
+ recovery states. On Homebrew this produces 997 RuboCop-only and 263 Sonicop-only `Lint/Syntax`
192
+ positions: examples on the RuboCop side include `class definition in method body`, `dynamic constant
193
+ assignment`, `cannot assign to a keyword`, and repeated `unexpected token` inside one multi-line hash.
188
194
 
189
195
  What the divergence does not change is **which** files are held to be unparseable, and that is what
190
196
  decides whether a file is inspected at all: RuboCop runs no cop other than `Lint/Syntax` on a file
@@ -198,9 +204,10 @@ programs, one of which is English prose that happens to parse as Ruby — where
198
204
  error and `parser` does not. Those five hold 465 of that corpus's 773 differences.
199
205
 
200
206
  Within Homebrew's 569 files the agreement is partial, as recovery cannot be reproduced: 499 report the
201
- same first diagnostic (position and message), and 222 report an identical list end to end. The 277
202
- files in between are the divergence in its purest form — the two agree on where the file first goes
203
- wrong and part company on what follows. The 70
207
+ same first diagnostic (position and message), and 222 report an identical list end to end. In all 569,
208
+ Sonicop's earliest source-position diagnostic is also present in RuboCop's output. The 277 files in
209
+ between are the divergence in its purest form — the two agree on at least one error position and part
210
+ company as recovery proceeds. The 70
204
211
  files whose first diagnostic differs follow one shape — an endless method definition (`def to_s =
205
212
  to_str`, valid from Ruby 3.0, rejected by the default `TargetRubyVersion: 2.7`) leaves `parser`'s
206
213
  method context open, so the enclosing `class` emits `class definition in method body` when it is
@@ -299,17 +306,43 @@ defect, so the difference stands as it is.
299
306
  ## Limits
300
307
 
301
308
  A clean run is a property of the corpora, not a general claim. `known_divergences.yml` carries the
302
- current list of what these corpora never exercise; the main ones are non-default configuration
303
- values, extension plugins, and Windows line endings. Cops that never fire contribute nothing to a
304
- match count, and their silence is indistinguishable from agreement.
305
-
306
- That limit is not hypothetical, and one instance is now measured. `Style/HashSyntax` defaults
307
- `EnforcedShorthandSyntax` to `either`, under which neither tool reports anything; the port
308
- implements none of the other four values, so half the cop is missing. Both the corpus runs and a
309
- sweep of RuboCop's own specs report agreement for it, because both run at the default. A cop can be
310
- half absent and still match everywhere the default reaches. Where a cop's behaviour is selected by
311
- configuration, this document covers the default branch only — the others are neither measured nor
312
- claimed.
309
+ current list of what these corpora never exercise; the main ones are extension plugins and Windows
310
+ line endings. Cops that never fire contribute nothing to a match count, and their silence is
311
+ indistinguishable from agreement.
312
+
313
+ Non-default configuration values used to be the largest of those gaps, and are now measured. Every
314
+ one of the 111 cops carrying an `Enforced*` setting was switched to a non-default value at once —
315
+ `Layout/SpaceInsideParens` to `space`, `Style/HashSyntax` to `hash_rockets` with
316
+ `EnforcedShorthandSyntax: always`, and so on — and rubocop/rubocop re-run against RuboCop under the
317
+ same file. Of 622,317 reference offenses, **99.99% match**, and 84 of the 96 cops that fired match
318
+ exactly.
319
+
320
+ | Cop | Offenses differing | |
321
+ |---|---:|---|
322
+ | `Layout/HashAlignment` | 35 | **RuboCop's own bug**, see below |
323
+ | `Style/BlockDelimiters` | 17 | |
324
+ | `Style/ConditionalAssignment` | 12 | |
325
+ | `Style/MixinGrouping` | 8 | |
326
+ | `Layout/SpaceInsideStringInterpolation` | 6 | |
327
+ | `Style/NumericPredicate` | 5 | |
328
+ | `Style/PercentQLiterals` | 4 | |
329
+ | `Naming/VariableName` | 3 | |
330
+ | `Lint/SymbolConversion` | 3 | |
331
+ | `Layout/SpaceInsideParens` | 1 | |
332
+
333
+ `Layout/HashAlignment`'s 35 are not a defect here. Under `EnforcedHashRocketStyle: separator`
334
+ RuboCop raises `Parser::ClobberingError` on `spec/rubocop/config_loader_spec.rb` — three times, at
335
+ `1111:35`, `1130:38` and `1217:35` — and reports nothing for the hashes it crashed on. Sonicop
336
+ inspects them and reports. Every one of the 35 sits in that file between lines 1114 and 1234.
337
+ Reproduce with:
338
+
339
+ ```bash
340
+ rubocop -c <variants.yml> --only Layout/HashAlignment -d spec/rubocop/config_loader_spec.rb
341
+ ```
342
+
343
+ One value per cop is not the whole configuration space — a cop with four supported styles is
344
+ measured at two of them — so this is a floor, not a ceiling. It does settle the shape of the old
345
+ limit: a cop is no longer allowed to be half absent and still count as matching.
313
346
 
314
347
  The 215 cops RuboCop ships switched off are a limit of a different kind. They are implemented, but a
315
348
  default run never reaches them, so the corpus numbers above say nothing about them. What stands
data/NOTICE CHANGED
@@ -15,9 +15,9 @@ licence position checkable rather than remembered.
15
15
  not the attribution. An entry that is added late is an entry that was, for a
16
16
  while, undocumented in a public repository.
17
17
 
18
- Known to be coming: tests/fixtures/upstream_spec_cases.jsonl, which will hold
19
- input text from RuboCop's specs. It is deliberately **not** listed yet -- this
20
- file describes what is here now, not what is planned.
18
+ That inventory is now complete for what is here. The entry that used to be
19
+ listed as "coming" -- the spec-derived fixtures -- has landed and is recorded
20
+ below with the rest.
21
21
 
22
22
  ================================================================================
23
23
  WHAT IS TAKEN
@@ -32,6 +32,18 @@ RuboCop -- https://github.com/rubocop/rubocop -- MIT
32
32
  Regenerate: scripts/sync_default_yml.sh 1.89.0
33
33
  Full text also kept at licenses/RUBOCOP.txt
34
34
 
35
+ tests/fixtures/upstream_spec_cases.jsonl
36
+ tests/fixtures/upstream_spec_divergences.jsonl
37
+ Input text taken out of RuboCop's own cop specs, each paired with what
38
+ RuboCop 1.89.0 actually reports for it. The spec text is upstream's; the
39
+ expectation beside it is not -- upstream was run once and its output
40
+ recorded, because upstream does not always behave the way its own specs
41
+ say. The second file holds the cases whose `-A` output does not parse as
42
+ Ruby, kept apart so that nothing demands this port reproduce them.
43
+ Regenerate: make spec-fixtures (runs upstream once per cop; needs the
44
+ rubocop gem, which the test run itself does not)
45
+ Read by tests/spec_fixtures.rs
46
+
35
47
  Ruby on Rails -- https://github.com/rails/rails -- MIT
36
48
  Copyright (c) David Heinemeier Hansson
37
49
 
data/README.ja.md CHANGED
@@ -32,22 +32,80 @@ CI へ最小限の変更で導入できます。
32
32
 
33
33
  ## 主な機能
34
34
 
35
- Bundler、Gemspec、Layout、Lint、Metrics、Migration、Naming、Security、Style の各部門の Cop を実装しています。
36
- 一覧はバイナリ自身が正本です。
35
+ Bundler、Gemspec、Layout、Lint、Metrics、Migration、Naming、Security、Style の各デパートメントの
36
+ Cop を実装しています。一覧はバイナリ自身が正本です。
37
37
 
38
38
  ```bash
39
39
  # 認識済み Cop と実装状況の一覧
40
40
  sonicop --show-cops
41
41
  ```
42
42
 
43
- **RuboCop 1.89 の全 609 Cop を実装しています。** 本家のレジストリと名前まで一致しており、
44
- ただしこれは**レジストリについての主張**であって、すべての設定についての主張ではありません。
45
- `Style/HashSyntax` は存在し既定の届く範囲では一致しますが、`EnforcedShorthandSyntax` の
46
- 既定以外の 4 つの値はいずれも未実装です。**Cop は半分欠けたまま、既定の届く範囲では
47
- 一致し続けられます** — [CONFORMANCE.md](CONFORMANCE.md) の *Limits* を参照してください。
43
+ **RuboCop 1.89 の全 609 Cop を実装しています。** 本家のレジストリと名前まで一致しています。
48
44
  `Enabled: pending` の 159 個と `Enabled: false` の 56 個も含みます。この 215 個は本家でも
49
- 既定の実行では走らないので、`--only` で名指しするか設定で有効にしてください。本家にも
50
- 存在しない Cop 名だけをエラーにし、必要なら `--ignore-unrecognized-cops` で続行できます。
45
+ 既定の実行では走らないので、`--only` で名指しするか設定で有効にしてください。本家に存在しない
46
+ Cop 名を書いた場合だけエラーで止まります(`--ignore-unrecognized-cops` で続行できます)。
47
+
48
+ ### Cop 別の一致状況
49
+
50
+ 全 609 Cop を両者で有効にし、本家の spec が供給する 37,491 ケースを、それぞれの spec が
51
+ 指定した `TargetRubyVersion` で走らせて比較した結果です。**完全一致**とは、その Cop の offense が
52
+ 位置・メッセージ・重大度・修正可否まで 1 件残らず一致し、どちらにも余りがないことを指します。
53
+
54
+ <!-- conformance:start -->
55
+ | デパートメント | Cop 数 | 検証済み | 完全一致 | 相違 |
56
+ |---|---:|---:|---:|---:|
57
+ | Bundler | 7 | 7 | **7 ✓** | 0 |
58
+ | Gemspec | 10 | 10 | **10 ✓** | 0 |
59
+ | Layout | 100 | 100 | 90 | 10 |
60
+ | Lint | 157 | 157 | 147 | 10 |
61
+ | Metrics | 10 | 10 | **10 ✓** | 0 |
62
+ | Migration | 1 | 1 | **1 ✓** | 0 |
63
+ | Naming | 19 | 19 | **19 ✓** | 0 |
64
+ | Security | 7 | 7 | **7 ✓** | 0 |
65
+ | Style | 298 | 298 | 288 | 10 |
66
+ | **合計** | **609** | **609** | **579** | **30** |
67
+ <!-- conformance:end -->
68
+
69
+ **先に読むべきは「検証済み」の列です。** ここで一度も発火しなかった Cop は、沈黙が一致と
70
+ 見分けられないため、訊かれないまま一致に数えられてしまいます。**609 個すべてがここで発火します**。
71
+ それが「完全一致」の列を意味あるものにしています。
72
+
73
+ そのうち 3 個は専用の run を要しました。`Lint/DeprecatedReference`・`Lint/NameTypo`・
74
+ `Lint/UnusedPrivateMethod` は `rubydex` のプロジェクトインデックスが無ければ何も報告せず、
75
+ gem の導入と `AllCops/UseProjectIndex` の有効化が要ります。`Lint/DeprecatedReference` は
76
+ さらに条件があり、`@deprecated` を持つメソッドの定義クラスを**継承したクラスの中**から
77
+ 呼ぶ必要があります。本家の spec は「インデックス無しでは offense を出さない」という
78
+ `expect_no_offenses` で始まるので「到達不能」と読みたくなりますが、そうではありません。
79
+
80
+ 「完全一致」を 609 にし、「相違」をゼロにすることが現在の目標です。実コードを足しても
81
+ 届きません。RuboCop が既定で無効にしている 56 Cop と、pending として出荷している Cop の多くは、
82
+ ツリーがどれだけ大きくても素の実行では発火しないためです。そこに届くのは本家の spec が
83
+ 供給する入力の方で、`tests/fixtures/upstream_spec_capture.jsonl` に記録したケースは
84
+ **609 Cop すべてに到達します**(実測)。走らせ方には間違えやすい点が 2 つあり、
85
+ **どちらも失敗せずに表を縮めます**。
86
+
87
+ - **`TargetRubyVersion` は入力の一部であって、全体の設定ではありません。** 2.7 に固定すると
88
+ `Style/ArrayIntersect`・`Naming/BlockForwarding`・`Style/ItBlockParameter` ほか 11 個が
89
+ そもそも発火できません。各ケースはその spec が指定した版で走らせます。
90
+ - **ファイル名そのものを見る Cop があります。** `Bundler/*` は `Gemfile`、`Gemspec/*` は
91
+ `.gemspec`、`Naming/FileName` は名前自体を読みます。全ケースを `.rb` で書き出すと、
92
+ この 17 Cop が何にも一致しませんでした。
93
+
94
+ これとは別に、2026-08-29 に本家 Cop spec から直接抽出できた 11,506 ケースを oracle で
95
+ 照合しました。本家が入力を読めなかった 226 ケースとクラッシュした 1 ケースを除き、測定できた
96
+ 範囲では Sonicop の**検出差分・訂正差分ともにゼロ**でした。この結果は上の表には加えていません。
97
+ 直接抽出できるケースが無い Cop が 51 個あり、ディレクティブ系 3 Cop は `--only` では測定不能な
98
+ ため、この掃引だけで全 609 Cop の完全一致を証明できないからです。また、この直接掃引は各例の
99
+ `TargetRubyVersion` をすべて再現せず、中立的な既定条件で実行しています。そのため、今回変更した
100
+ Ruby 3.4 依存の 4 Cop は 3.4 で別途比較し、メッセージと位置が本家に完全一致することを確認しました。
101
+
102
+ 設定値については別に測っています。既定値でしか一致しない Cop は半分しか実装していないのと
103
+ 同じだからです。`Enforced*` 系の設定を持つ 111 Cop すべてを**既定以外の値**に倒して同じコーパスを
104
+ 流すと、**622,317 件の offense のうち 99.995% が一致**し、発火した 96 Cop のうち 85 個が完全一致です。
105
+ 残るのは 10 Cop(いずれも 17 件以下)と、本家がクラッシュして sonicop が正常に検出する 1 Cop です。
106
+ 内訳は [CONFORMANCE.md](CONFORMANCE.md) にあります。
107
+
108
+ どちらの表も `scripts/conformance_table.rb` で再現できます。
51
109
 
52
110
  ## インストール
53
111
 
@@ -70,7 +128,7 @@ cargo install --git https://github.com/owayo/sonicop
70
128
  # 現在のプロジェクトを検査
71
129
  sonicop
72
130
 
73
- # Cop/部門を選択
131
+ # Cop/デパートメントを指定
74
132
  sonicop --only Layout,Style/StringLiterals app spec
75
133
 
76
134
  # 安全な自動修正/全自動修正
@@ -106,24 +164,30 @@ Style/StringLiterals:
106
164
  EnforcedStyle: single_quotes
107
165
  ```
108
166
 
109
- 既存コマンドとの互換性を保つため、server/LSP/MCP、plugin、cache 系の引数も受理します。
110
- サーバートランスポート、Ruby プラグイン実行、キャッシュ再利用、カスタム Cop、実装済み以外の
111
- Cop は実行しません。
112
-
113
- そのうち大半は、その旨を出力します。`--server` / `--no-server` / `--lsp` / `--mcp` /
114
- `--plugin` は stderr に 1 行の注記を出します。cache 系は何も出しませんが、
115
- 無言でよいのは片方だけです。
116
-
117
- - `--cache=false` はキャッシュを使わないことを求めるもので、sonicop はそれを満たしているため、
118
- 無言が正しい応答です。
119
- - `--cache=true` はキャッシュ再利用を求めるものですが、sonicop はこれを提供しておらず、
120
- それでも無言です。
121
-
122
- Cop の設定値も後者と同じ挙動です。sonicop が実装していない設定値 — たとえば
123
- `Style/HashSyntax` の `EnforcedShorthandSyntax` — は**警告なしに無視されます**。
124
- 名前を綴り間違えた設定値も同様に無視されます。つまり
167
+ 既存コマンドとの互換性を保つため、server/LSP/MCP、plugin 系の引数も受理します。
168
+ サーバートランスポート、Ruby プラグイン実行、カスタム Cop、実装済み以外の Cop は実行しません。
169
+ これらはその旨を出力します。`--server` / `--no-server` / `--lsp` / `--mcp` / `--plugin` は
170
+ stderr に 1 行の注記を出します。
171
+
172
+ cache 系の引数は、受理するだけでなく実際に効きます。sonicop は独自の結果キャッシュを持ち、
173
+ 検査時からサイズ・更新時刻・パーミッションのいずれも動いていないファイルには、
174
+ 保存済みのレポートをそのまま返します。
175
+
176
+ - キャッシュは既定で有効です。`--cache false` で無効化できます。設定ファイルの
177
+ `AllCops/MaxFilesInCache: 0` でも同じです。
178
+ - 置き場所は `--cache-root DIR` で指定します。省略時は `$XDG_CACHE_HOME/sonicop`、
179
+ macOS では `~/Library/Caches/sonicop`、それ以外は `~/.cache/sonicop` です。
180
+ `--cache-root` は `--cache false` とは併用できません。
181
+ - 保持するレポート数の上限は `AllCops/MaxFilesInCache` で、既定は本家と同じ 20,000 件です。
182
+ - autocorrect 実行、`--stdin`、`--profile`、`--memory` では読み書きしません。
183
+ - 本家のキャッシュとは共有しません。形式が別物であり、書いたときとまったく同じ
184
+ ビルドの sonicop にしかエントリを返さないためです。
185
+
186
+ 無言なのは Cop の設定値のほうです。sonicop が実装していない設定値は**警告なしに無視されます**。
187
+ 名前を綴り間違えた設定値も同様です。つまり
125
188
  **offense が 0 件であることは、その設定が効いた証拠にはなりません**。
126
189
  無視された設定値と、違反の無いファイルが、同じ出力になるためです。
190
+ どの設定値まで検証済みかは上の *Cop 別の一致状況* を参照してください。
127
191
 
128
192
  Cop の*名前*は検査されます。設定ファイルに未知の Cop 名があれば、実行はエラーで止まります。
129
193
  素通りするのは、既知の Cop の中の設定値です。
@@ -139,11 +203,13 @@ Mastodon(15,286 件)で、過剰も不足もメタデータ差もありま
139
203
  **件数だけでなくパスまで**一致します(集合として比較。どの側にも余りはありません)。
140
204
  残る差分は `Lint/Syntax` に集中しています。その大半は、本家の LALR パーサが
141
205
  構文エラーから回復して出す追加診断を tree-sitter では再現できないことによるもので、
142
- **これが説明するのは不足の向きだけ**です。**過剰の向きは別の問題で、未調査です** —
143
- Homebrew の 263 件はすべて `Lint/Syntax` であることまでは確認していますが、
144
- 移植版だけが構文エラーと呼ぶその中身は調べていません。autocorrect は RuboCop 自身のツリーと
145
- Mastodon でバイト単位に一致します。この 2 つは死守ラインとして扱い、バイト一致が崩れた場合は
146
- 既知差分ではなく退行として直します。
206
+ 診断位置の差は不足と過剰の両方に出ます。Homebrew の不足 997 件・過剰 263 件はすべて
207
+ `Lint/Syntax` ですが、**構文エラーと判定したファイル集合は 569 対 569 で完全一致**し、
208
+ 移植版だけが拒否したファイルは 0 件です。過剰 263 件は共有エラーファイル 135 件にあり、
209
+ すべて同じファイル内の共通診断より後ろにあるため、別の受理判定バグではなく回復後の診断位置差です。
210
+ Homebrew を問題の構文をサポートする Ruby 3.1 として測ると、両者とも `Lint/Syntax` は 0 件になります。
211
+ autocorrect は RuboCop 自身のツリーと Mastodon でバイト単位に一致します。この 2 つは死守ラインと
212
+ して扱い、バイト一致が崩れた場合は既知差分ではなく退行として直します。
147
213
 
148
214
  コマンド、この数値を測ったコーパスのコミット、この種の計測が誤った結論を導く 2 つの罠は
149
215
  [CONFORMANCE.md](CONFORMANCE.md) にまとめています。
@@ -165,13 +231,13 @@ Mastodon でバイト単位に一致します。この 2 つは死守ライン
165
231
 
166
232
  | コーパス | ファイル | RuboCop 並列 | Sonicop 並列 | RuboCop 単一 | Sonicop 単一 |
167
233
  |---|---:|---:|---:|---:|---:|
168
- | rubocop/rubocop | 1,765 | 11.49 秒 | **3.45 秒** | 42.49 秒 | **16.39 秒** |
169
- | mastodon/mastodon | 3,290 | 27.26 秒 | **6.03 秒** | 42.07 秒 | **19.53 秒** |
170
- | Homebrew/brew | 2,179 | 20.37 秒 | **5.36 秒** | 45.08 秒 | **16.03 秒** |
171
- | rails/rails | 3,551 | 45.89 秒 | **18.96 秒** | 99.56 秒 | **44.61 秒** |
172
- | ruby/ruby | 7,466 | 117.79 秒 | **54.97 秒** | 215.87 秒 | **100.62 秒** |
234
+ | rubocop/rubocop | 1,765 | 12.71 秒 | **4.59 秒** | 42.74 秒 | **13.75 秒** |
235
+ | mastodon/mastodon | 3,290 | 29.95 秒 | **6.48 秒** | 37.60 秒 | **15.88 秒** |
236
+ | Homebrew/brew | 2,179 | 18.20 秒 | **4.31 秒** | 38.72 秒 | **11.67 秒** |
237
+ | rails/rails | 3,551 | 52.55 秒 | **16.88 秒** | 162.55 秒 | **63.97 秒** |
238
+ | ruby/ruby | 7,466 | 132.17 秒 | **43.10 秒** | 199.78 秒 | **76.07 秒** |
173
239
 
174
- 差は並列で 2.1〜4.5 倍、単一プロセスで 2.1〜2.8 倍と幅があり、1 コーパスでは代表できません。
240
+ 差は並列で 2.8〜4.6 倍、単一プロセスで 2.4〜3.3 倍と幅があり、1 コーパスでは代表できません。
175
241
  **単一プロセスの列を読み、並列は目安として扱ってください。** 同じ 2 つのバイナリを 1 日に
176
242
  3 回測ったところ、単一プロセスの値は毎回 16% 以内に収まったのに対し、RuboCop 自身のツリーでの
177
243
  並列の倍率は、マシンが他に何をしていたかだけで 3.3 倍から 9.2 倍まで動きました。単一プロセスは
@@ -182,23 +248,29 @@ Mastodon でバイト単位に一致します。この 2 つは死守ライン
182
248
  Rails・Mastodon の 3 つで**すべての offense が一致**します(計 188,812 件、どちらの側にも
183
249
  残りません)。autocorrect は前者と後者でバイト単位に一致します。
184
250
 
185
- 再現時に注意が必要な点が 2 つあります。RuboCop は **`--cache false` と併用すると
251
+ 再現時に注意が必要な点が 3 つあります。RuboCop は **`--cache false` と併用すると
186
252
  `--parallel` を黙って無効化します**。そのためここでの並列実行はキャッシュを有効にしたうえで
187
253
  実行ごとにキャッシュディレクトリを消しており、`--cache false --parallel` で計測すると
188
254
  単一プロセスを測ることになり差が過大に出ます。また RuboCop の既定は単一プロセス、
189
- Sonicop は `--no-parallel` を渡さない限り並列です。
255
+ Sonicop は `--no-parallel` を渡さない限り並列です。そして**両方ともキャッシュを空にする**
256
+ 必要があります。Sonicop も既定でキャッシュするため、同じツリーを 2 回目に流すと自分の
257
+ キャッシュが答えてしまい、エンジンについては何も測れません。どちらにも使い捨ての
258
+ キャッシュディレクトリを渡してください。
190
259
 
191
260
  ```bash
192
261
  # RuboCop(並列・キャッシュは毎回空・既定の全 394 Cop)
193
262
  rubocop --force-default-config --cache true --cache-root "$(mktemp -d)" \
194
263
  --no-color --parallel -f quiet
195
264
 
196
- # Sonicop
197
- sonicop --force-default-config --format quiet
265
+ # Sonicop(キャッシュは毎回空)
266
+ sonicop --force-default-config --cache-root "$(mktemp -d)" --format quiet
198
267
  ```
199
268
 
200
269
  測定機は Apple M2(8 コア)、Ruby 4.0.6(YJIT 利用可)、RubyGems 導入の RuboCop 1.89.0。
201
- 1 分平均のロードアベレージは、計測開始時が 3.6、終了時が 9.6 でした。**アイドル状態ではありません**。
270
+ 1 分平均のロードアベレージは、計測開始時が 4.0、終了時が 3.1 でした。**アイドル状態ではありません**。
271
+ RuboCop 自身のツリーだけは後から単独で測り直しています(負荷 3.7 → 4.0)。1 回目はリリース
272
+ ビルドの終わりがけに走ってしまい、値が 60% ほど高く出たためです。**負荷の違う 1 行を同じ表に
273
+ 並べることはできません**。
202
274
  両者を同じ条件で測っているため倍率は保たれますが、秒数そのものは下限ではなく、静かなマシンなら
203
275
  より速く出ます。コアを奪い合うものが動いていると両者とも膨らみ、その度合いは一致しません。それが
204
276
  並列の列があれだけ動く理由です。秒数そのものが重要なときは、他に負荷のない状態で測り、**実行の
@@ -217,8 +289,8 @@ make gem # source gem
217
289
 
218
290
  ### Cop の追加
219
291
 
220
- Cop は `src/rules/<部門>/<cop>.rs` の 1 ファイルで、公開するのは `check(context, offenses)` の
221
- 1 関数だけです。登録は部門の `mod.rs` に 1 行を足します。
292
+ Cop は `src/rules/<デパートメント>/<cop>.rs` の 1 ファイルで、公開するのは
293
+ `check(context, offenses)` の 1 関数だけです。登録はデパートメントの `mod.rs` に 1 行を足します。
222
294
 
223
295
  ```rust
224
296
  department_rules! {
@@ -242,6 +314,12 @@ Cop ごとの全走査はファイル規模ではなく Cop 数に比例して
242
314
  `scripts/sync_default_yml.sh <rubocop-version>` で行い、由来のバージョンがファイル先頭に
243
315
  記録されます。
244
316
 
317
+ `src/display_width_table.rs` も生成物で、コミットします。RuboCop は表示桁を
318
+ `unicode-display_width` gem で数えるため、この表は手書きせず gem から生成しています。
319
+ 手書きの例外表は実際にずれており、NFD 分解された日本語でキャレットの本数が合わなくなっていました。
320
+ 再生成は `ruby scripts/dump_display_width.rb > src/display_width_table.rs` で行い、
321
+ gem と Unicode のバージョンがファイル先頭に記録されます。
322
+
245
323
  依存更新には `depup --install` を使います。Ruby grammar は再現可能性のため `Cargo.toml` で
246
324
  fork のコミットを固定しています。
247
325
 
data/README.md CHANGED
@@ -41,15 +41,76 @@ sonicop --show-cops
41
41
  ```
42
42
 
43
43
  **All 609 RuboCop 1.89 cops are implemented**, matched name for name against the upstream registry.
44
- That is a claim about the registry, not about every configuration: `Style/HashSyntax` is present and
45
- matches everywhere its default reaches, yet none of the four non-default values of its
46
- `EnforcedShorthandSyntax` are implemented. **A cop can be half absent and still match everywhere the
47
- default reaches** — see *Limits* in [CONFORMANCE.md](CONFORMANCE.md).
48
44
  That includes the 159 shipped as `Enabled: pending` and the 56 shipped as `Enabled: false`, which a
49
45
  default run does not reach on either side — name them with `--only` or switch them on in a
50
46
  configuration, exactly as with RuboCop. Unknown cop names still fail validation unless
51
47
  `--ignore-unrecognized-cops` is supplied.
52
48
 
49
+ ### Cop conformance
50
+
51
+ All 609 cops switched on, on both sides, over the 37,491 cases RuboCop's own specs supply, each
52
+ run at the `TargetRubyVersion` its spec asked for. A cop counts as an **exact match** only when its
53
+ offenses agree completely: every position, message, severity and correctable flag, with nothing
54
+ extra on either side.
55
+
56
+ <!-- conformance:start -->
57
+ | Department | Cops | Exercised | Exact match | Diverging |
58
+ |---|---:|---:|---:|---:|
59
+ | Bundler | 7 | 7 | **7 ✓** | 0 |
60
+ | Gemspec | 10 | 10 | **10 ✓** | 0 |
61
+ | Layout | 100 | 100 | 90 | 10 |
62
+ | Lint | 157 | 157 | 147 | 10 |
63
+ | Metrics | 10 | 10 | **10 ✓** | 0 |
64
+ | Migration | 1 | 1 | **1 ✓** | 0 |
65
+ | Naming | 19 | 19 | **19 ✓** | 0 |
66
+ | Security | 7 | 7 | **7 ✓** | 0 |
67
+ | Style | 298 | 298 | 288 | 10 |
68
+ | **Total** | **609** | **609** | **579** | **30** |
69
+ <!-- conformance:end -->
70
+
71
+ **Read the *Exercised* column first.** A cop nothing here made fire contributes neither way — its
72
+ silence is indistinguishable from agreement, so it would be counted as agreement without ever
73
+ being asked. **Every one of the 609 fires here**, which is what makes the *Exact match* column
74
+ mean what it says.
75
+
76
+ Three of them took a run of their own. `Lint/DeprecatedReference`, `Lint/NameTypo` and
77
+ `Lint/UnusedPrivateMethod` report nothing without a `rubydex` project index, which needs the gem
78
+ installed and `AllCops/UseProjectIndex` switched on — and `Lint/DeprecatedReference` needs more
79
+ than that: the call has to sit inside a class inheriting the one whose method carries the
80
+ `@deprecated` tag. Upstream's own specs open with an `expect_no_offenses` saying the cop is silent
81
+ without the index, which is easy to read as "unreachable"; it is not.
82
+
83
+ Getting *Exact match* to 609 while reducing *Diverging* to zero is the current goal. More real Ruby
84
+ does not get there: the 56 cops RuboCop ships disabled, and much of what it ships as pending, never
85
+ fire in a plain run however large the tree. What does reach every one of them is the input its own
86
+ specs supply — the cases recorded in `tests/fixtures/upstream_spec_capture.jsonl` touch **609 of 609
87
+ cops**, measured. Two things about running them are easy to get wrong, and both silently shrink the
88
+ table rather than failing:
89
+
90
+ - **`TargetRubyVersion` is part of the input, not a global.** Pinning everything at 2.7 leaves
91
+ `Style/ArrayIntersect`, `Naming/BlockForwarding`, `Style/ItBlockParameter` and eleven others
92
+ unable to fire at all. Each case is run at the version its spec asked for.
93
+ - **The filename is what several cops inspect.** `Bundler/*` needs a `Gemfile`, `Gemspec/*` a
94
+ `.gemspec`, and `Naming/FileName` reads the name itself. Writing every case as `.rb` had all 17
95
+ of those cops matching nothing.
96
+
97
+ A separate direct oracle sweep on 2026-08-29 examined 11,506 cases extractable from the upstream
98
+ cop specs. RuboCop could not read 226 of those inputs and crashed on one; among the measurable
99
+ cases, Sonicop had **zero detection differences and zero correction differences**. This result is
100
+ not folded into the table above: 51 cops had no directly extractable case, and three directive cops
101
+ cannot be measured under `--only`, so the sweep does not prove that all 609 cops are exact. The
102
+ direct sweep also uses neutral/default conditions rather than preserving every example's
103
+ `TargetRubyVersion`. The four Ruby 3.4-sensitive cops changed in this pass were therefore compared
104
+ separately at 3.4, where their messages and locations matched RuboCop exactly.
105
+
106
+ Configuration is measured separately, because a cop that only matches at its default value is half
107
+ a cop. Every one of the 111 cops carrying an `Enforced*` setting was switched to a **non-default**
108
+ value at once and the corpus re-run: **99.995% of 622,317 offenses match**, with 85 of the 96 cops
109
+ that fired matching exactly. The residue is 10 cops of at most 17 offenses each, plus one where
110
+ RuboCop crashes and sonicop does not; the list is in [CONFORMANCE.md](CONFORMANCE.md).
111
+
112
+ Reproduce either table with `scripts/conformance_table.rb`.
113
+
53
114
  ## Installation
54
115
 
55
116
  ```bash
@@ -114,22 +175,29 @@ Style/StringLiterals:
114
175
  EnforcedStyle: single_quotes
115
176
  ```
116
177
 
117
- The CLI accepts RuboCop's server/LSP/MCP, plugin, and cache flags to keep existing command lines
118
- parse-compatible. Sonicop does not provide server transports, Ruby plugin execution, cache reuse,
119
- custom Ruby cops, or cops outside the implemented set.
120
-
121
- Most of those flags say so. `--server`, `--no-server`, `--lsp`, `--mcp`, and `--plugin` each print
122
- a one-line notice on stderr. The cache flags print nothing, and only one of them is silent for a
123
- good reason:
124
-
125
- - `--cache=false` asks for no caching, which sonicop already satisfies, so silence is the correct
126
- answer.
127
- - `--cache=true` asks for cache reuse, which sonicop does not provide, and it is silent anyway.
128
-
129
- Cop settings behave like the second case. A setting sonicop does not implement — for example
130
- `EnforcedShorthandSyntax` under `Style/HashSyntax` — is ignored without any warning, and so is a
131
- setting whose name is simply misspelled. **A run that reports no offenses is therefore not evidence
132
- that a setting took effect**, because an ignored setting and a clean file produce the same output.
178
+ The CLI accepts RuboCop's server/LSP/MCP and plugin flags to keep existing command lines
179
+ parse-compatible. Sonicop does not provide server transports, Ruby plugin execution, custom Ruby
180
+ cops, or cops outside the implemented set. Each of those flags says so: `--server`, `--no-server`,
181
+ `--lsp`, `--mcp`, and `--plugin` print a one-line notice on stderr.
182
+
183
+ The cache flags are honoured rather than merely parsed. Sonicop keeps a result cache of its own and
184
+ serves a stored report for a file whose size, modification time and permission bits have not moved
185
+ since it was inspected.
186
+
187
+ - Caching is on by default. `--cache false` turns it off, as does `AllCops/MaxFilesInCache: 0` in a
188
+ configuration file.
189
+ - `--cache-root DIR` chooses where it lives. Without it the root is `$XDG_CACHE_HOME/sonicop`, or
190
+ `~/Library/Caches/sonicop` on macOS, or `~/.cache/sonicop`. `--cache-root` cannot be combined
191
+ with `--cache false`.
192
+ - `AllCops/MaxFilesInCache` bounds how many reports are kept, defaulting to RuboCop's 20,000.
193
+ - Autocorrect runs, `--stdin`, `--profile` and `--memory` neither read nor write it.
194
+ - It is not shared with RuboCop's cache: the formats are unrelated, and an entry is only served back
195
+ to a build of Sonicop identical to the one that wrote it.
196
+
197
+ Cop settings are the silent case. A setting sonicop does not implement is ignored without
198
+ any warning, and so is a setting whose name is simply misspelled. **A run that reports no offenses
199
+ is therefore not evidence that a setting took effect**, because an ignored setting and a clean file
200
+ produce the same output. *Cop conformance* above says which values have been measured.
133
201
 
134
202
  Cop *names* are checked: an unrecognised cop in a configuration file stops the run with an error.
135
203
  It is the settings inside a recognised cop that pass unvalidated.
@@ -146,9 +214,12 @@ Mastodon (15,286), with no excess, no shortfall and no metadata differences. The
146
214
  match exactly on all five — paths, not just counts, compared as sets. What remains is concentrated in
147
215
  `Lint/Syntax`. Most of it is RuboCop's
148
216
  LALR parser recovering from an error and emitting diagnostics a tree-sitter parse cannot
149
- reconstruct — that direction accounts for the shortfall. **The excess is a separate question and has
150
- not been investigated**; on Homebrew all 263 of it is `Lint/Syntax` too, but what Sonicop calls a
151
- syntax error there and RuboCop does not is unexamined.
217
+ reconstruct, and the resulting position differences go in both directions. On Homebrew all 997
218
+ missing and 263 excess positions are `Lint/Syntax`, but the **sets of files rejected as syntax
219
+ errors are exactly the same: 569 versus 569**, with no file rejected only by Sonicop. The 263 excess
220
+ positions occur in 135 shared syntax-error files and every one follows a diagnostic at a position
221
+ shared by both tools, so they are recovery-position differences rather than a separate acceptance
222
+ bug. At Ruby 3.1, which supports the syntax used there, both tools report zero `Lint/Syntax` offenses.
152
223
  Autocorrect is byte-identical on RuboCop's own tree and on Mastodon, the two corpora held as a hard
153
224
  line: a change that breaks byte equality there is a regression, not a new known divergence.
154
225
 
@@ -171,13 +242,13 @@ warmed runs.
171
242
 
172
243
  | Corpus | Files | RuboCop parallel | Sonicop parallel | RuboCop single | Sonicop single |
173
244
  |---|---:|---:|---:|---:|---:|
174
- | rubocop/rubocop | 1,765 | 11.49 s | **3.45 s** | 42.49 s | **16.39 s** |
175
- | mastodon/mastodon | 3,290 | 27.26 s | **6.03 s** | 42.07 s | **19.53 s** |
176
- | Homebrew/brew | 2,179 | 20.37 s | **5.36 s** | 45.08 s | **16.03 s** |
177
- | rails/rails | 3,551 | 45.89 s | **18.96 s** | 99.56 s | **44.61 s** |
178
- | ruby/ruby | 7,466 | 117.79 s | **54.97 s** | 215.87 s | **100.62 s** |
245
+ | rubocop/rubocop | 1,765 | 12.71 s | **4.59 s** | 42.74 s | **13.75 s** |
246
+ | mastodon/mastodon | 3,290 | 29.95 s | **6.48 s** | 37.60 s | **15.88 s** |
247
+ | Homebrew/brew | 2,179 | 18.20 s | **4.31 s** | 38.72 s | **11.67 s** |
248
+ | rails/rails | 3,551 | 52.55 s | **16.88 s** | 162.55 s | **63.97 s** |
249
+ | ruby/ruby | 7,466 | 132.17 s | **43.10 s** | 199.78 s | **76.07 s** |
179
250
 
180
- The gap is 2.1x to 4.5x in parallel and 2.1x to 2.8x single-process, so no single corpus summarizes
251
+ The gap is 2.8x to 4.6x in parallel and 2.4x to 3.3x single-process, so no single corpus summarizes
181
252
  it. **Read the single-process column and treat the parallel one as indicative.** Measuring the same
182
253
  two binaries three times over a day put the single-process figures within 16% of each other every
183
254
  time, while the parallel ratio on RuboCop's own tree moved between 3.3x and 9.2x purely with what
@@ -188,24 +259,29 @@ The speed is not bought by skipping work: over those same 394 cops the two agree
188
259
  on RuboCop's own tree, on Rails and on Mastodon — 188,812 offenses with nothing on either side of the
189
260
  ledger — and autocorrect is byte-identical on the first and the last.
190
261
 
191
- Two details matter for reproducing this. RuboCop **silently turns `--parallel` off when combined
262
+ Three details matter for reproducing this. RuboCop **silently turns `--parallel` off when combined
192
263
  with `--cache false`**, so its parallel runs here use a cache directory that is deleted before each
193
264
  run rather than disabled; timing it with `--cache false --parallel` measures a single process and
194
265
  overstates the difference. RuboCop's default is a single process, while Sonicop is parallel unless
195
- `--no-parallel` is passed.
266
+ `--no-parallel` is passed. And both sides need a **cold** cache: Sonicop caches by default too, so a
267
+ second run over the same tree answers from its own cache and measures nothing about the engine.
268
+ Give each tool a throwaway cache root.
196
269
 
197
270
  ```bash
198
271
  # RuboCop, parallel, cold cache, its full default set of 394 cops
199
272
  rubocop --force-default-config --cache true --cache-root "$(mktemp -d)" \
200
273
  --no-color --parallel -f quiet
201
274
 
202
- # Sonicop
203
- sonicop --force-default-config --format quiet
275
+ # Sonicop, cold cache
276
+ sonicop --force-default-config --cache-root "$(mktemp -d)" --format quiet
204
277
  ```
205
278
 
206
279
  Machine: Apple M2 (8 cores), Ruby 4.0.6 with YJIT available, RubyGems-installed RuboCop 1.89.0.
207
- The one-minute load average was 3.6 when the run started and 9.6 when it finished — the machine was
208
- in use, not idle. Both tools ran under the same conditions, so the ratios hold, but the absolute
280
+ The one-minute load average was 4.0 when the run started and 3.1 when it finished — the machine was
281
+ in use, not idle. RuboCop's own tree was re-measured on its own afterwards, at load 3.7 rising to 4.0,
282
+ because the first pass over it ran while a release build was still finishing and its numbers came out
283
+ 60% high; a row measured under a different load cannot sit in the same table as the others. Both tools
284
+ ran under the same conditions, so the ratios hold, but the absolute
209
285
  seconds are not a floor: expect better on a quiet machine. Anything competing for cores inflates
210
286
  both sides, and not by the same factor on each, which is what makes the parallel column move as much
211
287
  as it does. If the absolute numbers matter to you, measure on an idle machine and record the load
@@ -251,6 +327,13 @@ fails when the two disagree.
251
327
  `scripts/sync_default_yml.sh <rubocop-version>`, which records the source version in the file
252
328
  header.
253
329
 
330
+ `src/display_width_table.rs` is generated and committed too. RuboCop measures display columns with
331
+ the `unicode-display_width` gem, so the table is taken from the gem rather than restated by hand —
332
+ an exception table written out by hand had already drifted far enough to draw the wrong number of
333
+ carets under decomposed Japanese. Regenerate it with
334
+ `ruby scripts/dump_display_width.rb > src/display_width_table.rs`, which records the gem and Unicode
335
+ versions in the file header.
336
+
254
337
  Dependencies are updated with `depup --install`. The Ruby grammar dependency is pinned to an exact
255
338
  fork commit in `Cargo.toml` for reproducible builds.
256
339
 
@@ -15,7 +15,13 @@ module Sonicop
15
15
  MESSAGE
16
16
 
17
17
  begin
18
- exec(binary, *arguments)
18
+ # `[binary, binary]` = exec 形式の強制。`exec(binary, *arguments)` は arguments が空、
19
+ # つまり「カレントディレクトリを見る素の `sonicop`」という最も普通の呼び出しのとき
20
+ # `exec(String)` = commandline 形式に落ちる。この形式は空白で単語分割し、メタ文字が
21
+ # あればまるごと /bin/sh に渡すため、binary のパス次第で ENOENT や exit 127 になる。
22
+ # パスの出所は SONICOP_BINARY と gem の install 先で、どちらもメタ文字を含まない保証がない。
23
+ # argv0 は multi-arg 形式が既定で入れるものと同じ値を明示している。
24
+ exec([binary, binary], *arguments)
19
25
  rescue SystemCallError => error
20
26
  # 実行できない典型は「platform gem は入ったが実行環境と ABI が違う」ケース
21
27
  # (musl 環境に glibc ビルドが入るなど)。素の errno だけでは原因が読めない。
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Generated from Cargo.toml by `rake version:sync`. Do not edit by hand.
4
4
  module Sonicop
5
- VERSION = '26.8.110'
5
+ VERSION = '26.8.112'
6
6
  end
data/libexec/sonicop CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sonicop
3
3
  version: !ruby/object:Gem::Version
4
- version: 26.8.110
4
+ version: 26.8.112
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Yohei