Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/v3-coverage-strata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!-- SPDX-License-Identifier: MIT -->
# 固定model coverageの文書平均・入力サイズ別評価

2026-09-21。[会話corpus評価](v3-spoken-corpus.md)のmicro集計に、
文書ごとの等重み平均とbyte長区間を追加した。
native実行・再学習・閾値調整は行わず、未較正の固定tableを使う。

## 指標の意味

microは全出現数の分子・分母を足した比率で、長文の寄与が大きい。
macroは分母が正の各文書の比率を等重みで平均する。
分母0の文書は0点にせず除外し、指標ごとの有効・未定義文書数を記録する。
保存値は厳密な分数。以下の百分率は読みやすさのため小数6桁に丸めた。

| 指標 | micro (%) | 文書macro (%) |
| --- | ---: | ---: |
| 頻出letter coverage | 99.812777 | 99.811233 |
| 未知letter率 | 0.187223 | 0.188767 |
| matrix pair coverage | 99.752397 | 99.756002 |
| matrix内の未観測pair率 | 2.396426 | 2.387837 |

全指標で有効16文書・未定義0文書。旧reportの全document観測とaggregate countsは一致した。
この表はencoding accuracy、native confidence、独立母集団での品質比較ではない。
microとmacroが近くても、corpusの代表性や統計的独立性は証明できない。

## サイズ分布によって分かった不足

全16文書が[1024,4096) bytesに入り、他区間は0文書だった。
したがってこのcorpusだけでは、数十byteの短文や数十〜数百KiB文書への
適合を判断できない。空区間もreportに残し、未評価の範囲を隠さない。
同じ文書を切断したvariantを追加したわけではなく、全文の長さによる分類である。

French Tatoeba pilotでは複数文が同じoriginを持ち、既存の
`duplicate selected evaluation source hash/origin`検証で拒否された。
成功結果として数えず、重複防止を緩めたり文を結合したりしなかった。
集計対象の文書単位と、漏洩防止用のsource groupを分ける場合は別契約として検証する。

## 再現情報

- training artifact: `856a8ba06a4a6d8450ddb3f4afeafdf99223a2c715350ce6e381a8e271c80515`
- model contract: `007efecaae466c6f23066dc8088f6a63167de3f4c39e5624481bf38c575466f3`
- evaluation manifest: `6340aff3b3d424fced87b782d75036c64152b4840eec98a05dc9a5b4f90216aa`
- v2 report content hash: `4b2b75e83a72723edd2c344ede3dc536ae074609e96c0ff9f9c69308a6bdcaf0`
- evaluator依存source hash: `c222fa5971082021a731eb2dcb6a1e0a4ac011f3f86093c1f5845d853471898f`

`sequence-coverage-evaluation-v2`の仕様は
[native側の日本語文書](../src/ext/uchardet/models/experimental/SEQUENCE_EVALUATION.md)を参照。
旧reportを上書きせず、Git管理外の別fileへ保存した。
追加testsはmacro/microの違い、空分母、全サイズ境界、counts保存を検証し、
model関連46 testsが成功した。P01・独立holdout封印・生成modelの権利保留は維持する。
12 changes: 12 additions & 0 deletions docs/v3-foundation-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,15 @@ fresh/reuseと固定randomを含む6 scheduleでも最終候補が一致した

これはfeed後のsnapshotであり、全byteの状態遷移履歴ではない。rejectの根本原因や
ranking理由は未解決のまま。P01保留中の作業や追加の不正入力探索は再開していない。

[固定model coverageの文書平均・サイズ別評価](v3-coverage-strata.md)では、
会話16文書が1〜4 KiBに集中し、短文・大文書の評価が欠けていることを明示した。
microだけでなく文書macroを厳密分数で記録し、未定義分母・空区間を区別する。

[trace ON/OFFの限定測定](v3-trace-cost.md)では同一buildのlibraryとbenchmarkが
byte一致した。native小fixtureの計測値も記録したが、最初の条件に時間ドリフトがあり、
同一実行ファイルの差を高速化やregressionとして扱わない。

[ranking契約のsource調査](v3-ranking-contract.md)では、threshold、既知languageの
重複整理、同点順序、weightを別段階として整理した。入力ごとの原因証明とは分け、
保存値照合の`UNRESOLVED`を根拠なく確定理由へ置き換えない。
66 changes: 66 additions & 0 deletions docs/v3-ranking-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!-- SPDX-License-Identifier: MIT -->
# 現行candidate rankingのsource上の契約

調査revision: uchardet `04f3bc4a927d116da12a8e161273239a804e21c5`。
sourceを読んだ整理であり、新しい入力のnative実行、ranking再実装、
安全性修正、公開API変更は行っていない。

## 一つの「順位問題」にまとめない

候補が返るまでには異なる段階がある。

1. prober内で候補とscoreを作る。
2. UniversalDetectorがshortcutまたはthresholdを通った候補をReportする。
3. C API側が既知languageの重複を整理し、confidence順へ挿入する。
4. language weightが有効なら別候補列を重み付きconfidence順へ並べる。
5. Python wrapperが結果を公開する。

現在のtraceは2のraw Reportを別のobserver subclassで記録する。
最終C API候補列の内部操作をその場で記録しているわけではない。
raw Reportに存在しないencodingが、最初から未実装なのか、prober内部で失われたのか、
threshold以下だったのかは、raw Reportと最終結果だけでは区別できない。

## sourceで確認した規則

| 段階 | 確認した挙動 | 分析時の注意 |
| --- | --- | --- |
| shortcut | shortcutがあるとその候補をReportして終了 | 通常のhigh-byte候補収集と同じ経路ではない |
| threshold | high-byte経路はscoreが0.20より大きい候補だけReport | 0.20と同値は通らない。閾値はこの経路のもの |
| 重複 | encodingが同名かつ双方のlanguageが非null・同名なら重複比較 | null-language同士はこの条件を満たさない |
| 同一候補 | 新scoreが既存より大きければ置換、以下なら新Reportを採用しない | codec aliasの同等性で重複整理しているわけではない |
| 挿入順 | 自分より小さいconfidenceの手前に挿入 | 同scoreでは既存候補の後。alphabetical tie-breakではない |
| weight | raw候補列からweighted列を再構築 | final confidenceはraw confidenceと同一とは限らない |
| weighted同点 | raw候補列の走査順を保つ挿入 | 同点化後も元の順序が影響する |

weightは指定languageならその係数、それ以外はdefault係数をraw confidenceに掛ける。
C APIのgetterがweighted列を選ぶ条件はlanguage weight mapが空でないことである。
default weightだけを設定する場合を、Pythonのlanguage_weightsと同じ契約として説明しない。
Python側はlanguage keyを小文字化し、係数を有限の0〜1へ検証する。
C APIを直接呼ぶ場合まで、そのPython検証が適用されるとは限らない。

ここでの順序説明は通常の有限scoreについてのsource整理。
NaN等の異常score、reset後の全lifecycle契約、allocation failureを検証した記述ではない。
これらの追加native安全性検証はP01の保留を維持する。

## sourceと入力ごとの原因証明を区別する

規則が分かっても、ある入力の正解候補が下位だった理由を自動確定できるわけではない。
model coverage、候補を作ったprober、threshold前score、Report順序、
実際に設定されたweightを同じrevision・入力・feedで対応付ける必要がある。
同score・同labelのReportが複数あれば、保存値の一致だけで採用元を一意に決めない。

したがって[保存値の対応照合tool](v3-report-attribution.md)の
`ranking_reason=UNRESOLVED`は変更しない。Pythonへrankingを複製して
engineと独立に乖離する第二の判定実装を作らない。
将来の診断追加では、まず「threshold前」「Report」「重複整理」「weight後」の
どの段階を観測したかを明示し、最終順位だけから推測した理由をlogへ入れない。

## 固定した根拠

- `src/nsUniversalDetector.cpp`: DataEnd、MINIMUM_THRESHOLD。
Git blob `06c2d9a2306afdb136d99e9020863c576d22c492`。
- `src/uchardet.cpp`: HandleUniversalDetector::Report / WeighCandidates / getters。
Git blob `f5b46ba9b31e7c435523f1b03a8d29f96cb8f20e`。
- cChardet `src/cchardet/__init__.py`: _validate_language_weights。

この調査をcandidate stability、score較正、全入力での正当性の実行証拠に読み替えない。
58 changes: 58 additions & 0 deletions docs/v3-trace-cost.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!-- SPDX-License-Identifier: MIT -->
# trace build optionの無効時影響:限定測定

2026-09-21。native `063ad3e9a62c90db482550e278a8682b98d0198a`で
`BUILD_INTROSPECTION=ON`からOFFへ切り替え、同じbuild directory、GCC16.2.1、
Release/static設定で再buildした。小fixtureだけを使用し、P01の大入力検証は再開していない。

## 生成物の一致

切り替え前後で静的library全体とnative benchmark実行ファイルがbyte一致した。

| 生成物 | 両設定のSHA-256 |
| --- | --- |
| libuchardet.a | `6b9b78d7d7d206081ab278ec319b02a28fc2d557348f3edad253bbf8372effbb` |
| uchardet-benchmark | `4c8a52308a73091006cc442dff926daba00354b4cdd095728e8d1621419390b8` |

optionは別の診断実行ファイルを追加するだけで、engineへ実行時flagやcallbackを注入しない。
OFFへの切り替え時にengineの再compileも発生しなかった。
これは同一build内のON/OFF比較であり、過去の別revisionのarchive比較とは区別する。
古いtrace実行ファイルはbuild directoryに残り得るが、OFFのbuild targetには含まれない。

## native C APIでの測定

空・11-byte ASCII・135-byte日本語UTF-8の既存3fixtureを一巡する時間。
input hashは[候補照合の固定入力](v3-report-attribution.md)と同じ。
I/OとPython処理を計測外とする既存`uchardet-benchmark`を使い、CPU affinityは0へ固定した。
各process内3回warm-up後、1001回を測定。ON→OFF/OFF→ONを交互に10組実行した。
fresh/reuse × whole/7-byteの4条件、各設定・条件に10,010 samples。
checksumは全processで153612だった。checksumを全候補の完全一致検証の代用にはしない。

| mode | chunk | ON median (ms) | OFF median (ms) | ON p95 (ms) | OFF p95 (ms) |
| --- | ---: | ---: | ---: | ---: | ---: |
| fresh | whole | 0.0465665 | 0.0453945 | 0.085760 | 0.074549 |
| fresh | 7 | 0.050424 | 0.050604 | 0.054231 | 0.054541 |
| reuse | whole | 0.039844 | 0.039894 | 0.041567 | 0.041267 |
| reuse | 7 | 0.050975 | 0.051105 | 0.055103 | 0.055132 |

medianは各processの中央値の平均ではなく全sampleを合算した中央値。
p95は昇順sampleのnearest-rankで計算した。native出力の小数精度を超える精度は主張しない。

**両実行ファイルが同一なので、表の差を機能の高速化・低速化と解釈しない。**
とくに最初のfresh/wholeではprocess medianがON 0.072906→0.039122 ms、
OFF 0.074178→0.039223 msへ低下した。3回の短いwarm-upだけでは実行環境の
時間変動を取り除けなかった。CPU周波数が原因と実測確定したわけでもない。
この条件のp95差を機能由来のregression判定に使用しない。
後半3条件のmedian差は約0.13〜0.36%だが、一般的な性能保証や誤差上限ではない。

再現する場合はON buildのbenchmarkとlibraryを保存し、同じdirectoryで
`cmake -DBUILD_INTROSPECTION=OFF`と再buildを実行してhashを先に比較する。
各実行は `taskset -c <CPU> uchardet-benchmark fresh 1001 0 <空> <ASCII> <日本語>`。
modeとchunkを上表に合わせ、10組で実行順を交互にする。入力読込をnative計測内へ移さない。

## 結論と未完了範囲

当該buildのengine/benchmarkにはON/OFFで実行コードの差がない。
診断toolを実際に起動した際のJSON生成・allocationコストは別であり、ここでは測っていない。
他compiler、配布wheel、大入力、一般的な並列性能を検証したとは扱わない。
#120の観測基盤を支える限定的証拠として記録し、reject/ranking原因の網羅まで完了とはしない。
Loading