# 付属ツールの詳しい使い方 README の[付属ツール](../README.md#付属ツール)の節を詳しく書いたものです。出力の読み方、オプション、終了コード、任意のフックの入れ方をまとめています。 文章の表現と書式を見る `yomiyasu_lint.py`、推敲の前後を比べる `yomiyasu_diff.py`、2つをまとめて実行して記録を残す `yomiyasu_check.py` の3つのスクリプトと、共有モジュール `markdown_visibility.py`、設定に貼ったときだけ動く任意のフック `yomiyasu_hook.py` を同梱しています。外部ライブラリは要らず、Python の標準ライブラリだけで動きます。Python 3.8 以上の文法で書いており、自動の試験は macOS の Python 3.9.6 と 3.14.5 で動かし、CI では Linux の Python 3.9 と 3.14、Windows の Python 3.12 でも動かしています(Windows を CI に加えたのは 2.1.3 からです。3.8 では確かめていません)。`python3` がない環境では `python` か `py -3` で実行してください。 3つのスクリプトが出すのは、見直し候補と変わった箇所です。意味が保たれたかと、読み手にとって分かりやすいかは判定しません。候補が0件でも、意味が同じだという証明にはなりません。本ツールは特定の構文を対象とする簡易な検査であり、完全なMarkdownレンダラーでもありません。候補をなくすことを目的に機械的に直すのではなく、元の文や文脈と照らし合わせて判断してください。 ## 前後を比べるときは check を使う 推敲の前と後を比べるときは、lint の点数ではなく `yomiyasu_check.py run` の出力の冒頭を見てください。候補があるときは、3行目(実行した検査の要約)のすぐあとに、候補の短い一覧(行番号のある候補は行番号と規則の名前、ない候補は名前)と、下の節を読む案内の2行が出ます(2.1.1 から)。冒頭の数行だけを読んで終えず、出力を最後まで読んでください。記録の行と「硬化の検査:」などの行のあとに、lint の見直し候補の件数を原文と最終稿で並べた行が出て、そのすぐ下に直した箇所の元と後が並びます。 ```text 検査を実行しました(1回目)。下の候補を原文と資料に照らして確かめてください。直すのは1回までです。直したら同じコマンドをもう一度実行し、直さないなら提出の直前に、本文を変えずに verify を1回実行してください。 yomiyasu-check: executed via=run run=20261015T171818Z-53bc8dc2 attempt=1 final=sha256:1154038bb6b0 mode=rewrite checks=lint,diff meaning_risk=0 実行した検査: lint(最終稿)候補0件、diff(原文→最終稿)変更あり 候補2件(うち意味が変わる恐れ0件) diff の候補: つなぎの増減、消えた語 候補の中身は下の節にあります。出力を切らずに読んでください。 この記録は検査を実行したことを示すだけで、意味が保たれたことや読みやすさの合格を示すものではありません。 記録: …/.yomiyasu/runs/20261015T171818Z-53bc8dc2/attempt-1.json 硬化の検査: 候補なし 勢いの検査: 候補なし 慎重表現の検査: 候補なし 値の検査: 候補なし 見直し候補: 原文 0件 → 最終稿 0件(lint の規則に当たった数で、点数ではありません。増えても減っても読みやすさの良し悪しは示しません) ■ 直した箇所(2か所。元と後) @ 元3行目 → 後3行目(本文) 元: 週次の集計バッチを、来月から新しいジョブ基盤に移行します。移行によって、これまで手作業だった再実行の手順が不要になり、運… 後: 週次の集計バッチを、来月から新しいジョブ基盤に移します。移したあとは、これまで手作業だった再実行の手順がいらなくなり、運… @ 元5行目 → 後5行目(本文) 元: **移行の日程**:未定です。 後: 移行の日程はまだ決まっていません。 - 長い所は、変わり始めの少し前からおよそ60字だけを出しています(「…」は省いた所)。省いていない元と後は下の「■ 全文差分」と、記録と同じフォルダの attempt-1.diff.txt にあります。 ■ 差分の見直し候補(diff、2件) ■ 言い回しの種類の増減(意味が変わりやすいところ) - つなぎ: 1 → 0(元: によって/後: なし) ■ 消えた語: 不要、未定、負荷 (このあとに全文差分と、1行目と状態の行がもう一度出ます) ``` この例では、lint の件数は前後とも0件で、1.1.2 の lint でも前後とも100点です。それでも、元と後を並べると2か所を書き直したことが分かります。1か所目は60字で切れているので、2文目で「負荷が大きく下がる」を「作業が減る」に変えたことは、全文差分か、差分の見直し候補の「消えた語: 負荷」で確かめます。 - 「見直し候補」の件数は、lint の規則に当たった数です。読みやすさの点数ではありません。増えても減っても、読みやすくなったかどうかは示しません。同梱のコーパスの推敲48組(古いバージョンの yomiyasu の指示で作った出力)では、件数が減った組が7組、同じ組が36組、増えた組が5組でした。確かめるときは、直した箇所の元と後を読んでください。 - 原文の件数は、最終稿と同じ `--doc-type` と `--reader` で原文に lint をかけて数えます。この lint は必要な検査と記録に入れず、`--fail-on` にも数えません。時間切れなどで数えられなかったときは「原文 数えられず(時間切れ)」と出し、状態は変えません。新規作成では最終稿の件数だけを出し、資料を原文とみなしたときは「資料1(原文とみなした資料) N件 → 最終稿 M件」の形になります。 - 「■ 直した箇所」は、全文差分と同じ組を、文書の初めから10か所まで並べます。長い所は変わり始めの少し前から60字ほどで切るので、1つの段落の中で2つ目の文からあとの変化は見えないことがあります。省いた所と切った所は、下の「■ 全文差分」(記録を残したときは、記録と同じフォルダの `attempt-.diff.txt` にも)で省かずに見られます。短い文書では、同じ元と後が「■ 直した箇所」と「■ 全文差分」に2回出ます。 - 全文差分は空行を手がかりに行を組むので、見出しを足すなどで段落の数が変わると、元と後に別の段落が並ぶことがあります。元と後で行の数が違う組があれば、案内の1行にそのことを書きます。そのときは全文差分で前後の組も読んで、どの段落がどこへ移ったかを確かめてください。 - 1.1.2 までの lint が出していた点数をやめた理由は [点数が出なくなった理由](#点数が出なくなった理由) の節に、JSON に残した `rule_penalty_score` の計算と読み方は [rule_penalty_score の式](#rule_penalty_score-の式) の節に書いています。合否やしきい値には使わず、CI で止めるときは `--fail-on` で候補の中身を見てください。 - verify は、記録と合ったときに4行目に「記録の中身: 見直し候補 最終稿 M件、直した箇所 Kか所(原文の件数と元と後は run の出力にあります)」を出します。原文の件数は記録にないので、verify では出しません。 - スキルは完了報告の確認の記録の「見直し候補」の行に、最後の run のこの行の件数を「(件数は点数ではない。増減は読みやすさの良し悪しを示さない)」と添えて写します。新規作成では最終稿の件数だけです。件数の増減を、読みやすくなった根拠としては書きません。 - `--json` では、run に `candidate_counts`(原文と最終稿の件数)と `changed_places`(直した箇所の数、出した数、省いた数、切ったかどうか)、verify に `final_candidate_count` と `changed_place_count` が付きます。元と後の正確な中身は、今までどおり `diff.full_diff.hunks` にあります。 ## 1. yomiyasu_lint.py(表現と書式の検査) 1つの文章について、AIの文章に多い表現(不自然な比喩動詞、決まり文句、過剰な太字・箇条書き、絵文字、文末コロン、同一文末の連続など)と、日本語の括弧や句読点に隣接して表示先の規則により太字として表示されない可能性がある書き方(`bold_not_rendered`)を検査します。複数行にまたがる太字やブロック境界(引用、見出し、リスト、表)も考慮して判定します。 2.0.0 からは、通常の出力に点数を出しません。出力の1〜3行目は次の3行で、そのあとに見直し候補を行の順に、規則の ID を付けて並べます。 ```text 表現・書式の検査を実行しました。 見直し候補: 3件 この検査では、意味の保持と読者にとっての分かりやすさは判定していません。 内訳: error 0件、warn 3件、info 0件 L3 [WARN] metaphor_verb: 比喩動詞「壊れる」が検出されました。… ``` 点数は JSON の `rule_penalty_score` にだけ残しています。規則に当たった箇所が地の文の量に比べてどれだけ多いかを表した目安で、候補がなければ100、あれば1から99です。文章の品質や読みやすさの点数ではないので、合否には使わないでください。推敲の前後を比べるときは、[前後を比べるときは check を使う](#前後を比べるときは-check-を使う) の節を見てください。 ### 点数が出なくなった理由 1.1.2 の lint は、出力の見出しに「スコア: 90/100」のような点数を出していました。2.0.0 では、この点数を通常の出力から外しました。機能を減らしたのではありません。1.1.2 の規則はすべて残り、`instruction_residue` や `pause_comma` などの規則も足しました。候補は前と同じように1件ずつ出ます(2.0.0 からは行の順に並べ、規則の ID も付けています)。点数は今も `--json` の `rule_penalty_score` で取れます。通常の出力から外した参考値の3行(文字数、太字の頻度、箇条書きの比率)も、JSON の `metrics` にあります。 点数を外したのは、一つの数字が読みやすさの合格点のように見えてしまうからです。点数は決まった規則に当たった箇所を数えただけで、意味が保たれたかも、読み手に伝わるかも見ていません。それでも、95点が100点に上がると文章が良くなったように見えます。逆に、直す前と後で同じ点数だと、読みやすくなったかどうかが分からなくなります(同梱のコーパスでは、4段落を書き直した組が、1.1.2 の点数で前後とも90点でした)。点数が見えていると、点数を上げるための書き換えも起きやすいと考えました。 推敲の前と後を比べるときは、`yomiyasu_check.py run` の出力の「見直し候補: 原文 N件 → 最終稿 M件」の行と「■ 直した箇所」を見て、直した箇所の元と後を読んでください([check で前後を比べる節](#前後を比べるときは-check-を使う))。件数が減ったことは、読みやすくなった証拠にはなりません。道具で点数を使うときの読み方は、下の「rule_penalty_score の式」の節に書いています。 ### rule_penalty_score の式 2.0.0 で、点数を地の文の長さで割る式に変えました。1.1.2 の `score` は件数をそのまま100から引いていたので、同じ文章を2回つなげただけで点数が下がり、長い文書はすぐ0になりました。 候補が0件なら100です。候補があれば、地の文1,000字あたりの重みつきの件数 x を求め、100 × 40 ÷ (40 + x) を四捨五入します。候補があるときは1から99の間に収めるので、0にはなりません。 x の数え方は次のとおりです。地の文は、コードの囲み、表、引用、見出し、前置きの設定(frontmatter)、HTML、URL の字を除き、空白も除いた字数です。地の文が1,000字に満たない文書は、1,000字として割ります。行ごとの候補は、error を3、warn を2、info を1として足し、地の文1,000字あたりに直します。ダッシュの3つの規則(`dash_decoration`、`dash_insertion`、`dash_list_ending`)は、候補を1文書3件までしか出しませんが、点数には当たった行をすべて数えます(1行に何か所あっても1件です)。文書全体で1件だけ出る規則は字数で割らず、1,000字の文書で1件当たったのと同じだけ x に足します(`excess_bold` と `excess_list` は2、`bold_label_list` は1)。`negative_parallelism_density` は、同じ箇所を `negative_parallelism` の候補で数えているので足しません。 地の文が1,000字以下の文書に候補が1件だけなら、warn で95点、info で98点、error で93点です。x が40(1,000字あたり warn が20件)なら50点です。1件で下がる幅は一定ではありません。候補が多いほど1件の幅は小さくなり、長い文書では1件増えても点数が変わらないことがあります(地の文6万字の文書では、error、warn、info のどれが1件でも99点です)。 地の文が1,000字以上の文書は、同じ文章を何回つなげても、点数はほとんど変わりません(tests/corpus の163本を1・2・4・8回つなぎ、地の文が1,000字以上になった回どうしで比べると、種類なしと13の種類のどれでも差は2点以内でした)。地の文が1,000字に満たない文書は1,000字として割るので、短い文書どうしでは点数は候補の件数だけで決まり、長いほうが低く出やすくなります。同じ短い文書をくり返すと、地の文が1,000字を越えるまでは点数が下がります(tests/corpus の `human_oga_01.md` は181字で95点、4回つないだ724字で83点、8回つないだ1,448字からは何回つないでも78点です)。 字数で当てるかを決める規則もあります。`excess_bold` と `excess_list` は地の文が300字を超える文書だけ、`short_summary_heading` は2,000字未満の文書だけに出ます。字数が変わると候補そのものが増えたり減ったりするので、点数も動きます(「## まとめ」の見出しが4つある1,044字の文書は91点で、2回つなぐと見出しの候補が出なくなり100点です)。また、候補の密度は文書全体で見るので、長い文書の一部に候補が固まっていても点数にはあまり出ません(warn が20件ある340字の段落は、それだけなら50点、地の文6万字の文書の中に置くと98点です)。どこに何が当たったかは `findings` で見てください。規則ごとの重みは付けていません。人が書いた文の数が、規則ごとの出やすさを決めるには足りないためです。 `--doc-type` を付けると、その種類で外す規則と、種類を指定したときだけ当てる規則(`pause_comma`、`dialogue_period`、`narrative_density`、`slide_comma`)で候補が変わるので、同じ文書でも点数が変わります。2.2.0 から 2.4.0 で足した規則と型([2.2.0 で足した規則](#220-で足した規則)、[2.3.0 で足した規則](#230-で足した規則)、[2.4.0 で足した直訳語の型](#240-で足した直訳語の型)、[2.4.0 で足したスライドの読点の規則](#240-で足したスライドの読点の規則))の候補は点数を計算する前に除くので、その候補だけの文書は100のままです。種類を変えた結果どうしは比べないでください。バージョンをまたいでも比べないでください。1.1.2 の `score` とは計算が違い、同じ文書でも値が違います。規則を足したバージョンでも値は変わります。`yomiyasu_check.py run --json` の `lint.rule_penalty_score` も同じ値です。JSON の値だけからは点数を計算し直せません。地の文の字数は JSON に出しておらず(`metrics.char_count` は見出しも数えた字数です)、ダッシュの行が4行以上ある文書では `findings` にない行も数えているためです。 CI や道具で使うときは、点数のしきい値で止めず、`--fail-on` の終了コードか、JSON の `counts`(error、warn、info ごとの件数)と `candidate_count`(全部の件数)を使ってください。`rule_penalty_score` は、長さの違う文書の候補の多さを大まかに並べたいときの目安です。 ```bash # Markdownファイルを検査 python3 scripts/yomiyasu_lint.py article.md # warn か error の候補があれば終了コード1を返す(CIやGitフック用。--strict と同じ) python3 scripts/yomiyasu_lint.py article.md --fail-on warn # 文書の種類と読者を指定 python3 scripts/yomiyasu_lint.py slides.md --doc-type slides --reader general # JSON形式(形式2)で結果を出力 python3 scripts/yomiyasu_lint.py article.md --json ``` - `--strict` か `--fail-on` を付けなければ、候補があっても終了コードは0です。CI で使うときは、点数のしきい値で止めず、候補の中身で止めてください(`--fail-on warn`、太字が表示されない書き方だけなら `--fail-on error`)。止めずに警告として表示するだけの使い方も勧めます。 - 終了コードは、0が検査を最後まで実行して条件に当たらなかったとき、1が `--strict` か `--fail-on` に当たったとき、2が使い方か入力の誤り、3が内部の誤りか、出力先が閉じられて結果を最後まで書けなかったときです。 - `--doc-type` を付けると、その種類で普通な書き方を拾う規則の候補を外し、外した件数を出します(外した候補の中身は、付けずに実行すると見られます)。`--reader` は表示と JSON に残すだけで、候補は変えません。 - 行頭から書いた `
` と `
` の組の中にある箇条書きは、箇条書きの比率(`excess_list`)に数えません。根拠を `
` に畳んだ文書で、過剰な箇条書きの候補が出ないようにするためです。中の箇条書きの行の数は、JSON の `metrics` の `details_list_lines` に出ます。 - JSON の `score` と `is_clean` は、`rule_penalty_score` と `no_rule_findings` に名前を変えました。`rule_penalty_score` は計算も変えたので、1.1.2 の `score` に使っていたしきい値はそのまま使えません([rule_penalty_score の式](#rule_penalty_score-の式))。形式は `data.get("format_version", 1)` で見分けられます([CHANGELOG](../CHANGELOG.md) の「互換性のない変更」)。jq での読み替えの例は [JSON を前のキーの名前で読んでいたとき](#json-を前のキーの名前で読んでいたとき) にあります。 このリンターは、推敲で見落としやすい表現を拾うための補助です。文章をAIが書いたかどうかを判定する道具ではありません。同梱の評価用コーパス(`tests/corpus/`)には、モデルに人の文章らしく書かせた例文が8本あり(`tests/corpus/human/human_doc_*.md`。フォルダの名前は human ですが、人が書いた文ではありません)、8本とも見直し候補は0件でした。候補が少ないことは、人が書いた証拠にはなりません。コーパスの中で人が書いた文章は、作者の記事1本を見出しで8つに分けた抜粋(`human_oga_*.md`)だけです。量が少ないので、人の文章とAIの文章をどれだけ見分けられるかの数値は載せていません。1.1.2 の README に載せた human の16本の数値の訂正は、[CHANGELOG](../CHANGELOG.md) の「訂正」に書いています。 ### 2.2.0 で足した規則 - 直訳語は、型で拾うのが主です。語の一覧([プロジェクトの語の一覧](#プロジェクトの語の一覧))の役目は、誤った指摘を外すことと、プロジェクトの事情を足すことです。 - 指摘はどれも info です。`--strict` と `--fail-on` の判定にも、`rule_penalty_score` にも入りません。指摘が出ただけでは直さず、文脈を見て、誰が何をどうするかを書き直します。message に置き換え先の語は出しません。 - コードの囲みとインラインのコード、URL、引用(`>` の行)、カギ括弧と引用符の中、英数字の識別子は見ません(台詞の句点だけはカギ括弧の中を数えます)。 | 規則 | 見る型 | 当てる種類 | |---|---|---| | `calque` | 直訳語。型1は機械やシステムが主語で人や物の動作の動詞(拾う、通る、効く など)、型2は実物の名前の代わりの場所のたとえ(入口、受け口 など)、型3は英語を一語ずつ写した句。1行に1件で、message に型の番号と当たった言い方(置き換え先の語ではありません)が入ります。テストが通る、キャッシュが効く、依存先などの定着した言い方は外します。見出し、表、箇条書きも見ます | すべて | | `metaphor_label` | 見出しか文書の1行目が、記号を除いて8字以下で、「〜の横」「〜のそば」「〜係」「〜番」で終わるか一語だけで、その語が本文に出てこないもの | essay、promo、script を除く | | `say_hedge` | 文末の「と言えるでしょう」。名詞のあとの判断(「契約と言えるでしょう」)、「に当たると言えるでしょう」、カギ括弧の中は外します | すべて | | `thin_evaluation` | 名詞がもともと持つ評価を述語で言い直すだけの文。語の組は `references/lists/thin-evaluation.txt` | すべて | | `katakana_term` | 意味の薄くなりやすいカタカナ語。語は `references/lists/katakana-terms.txt` | すべて | | `dialogue_period` | 台詞(「」『』の中、`名前「…」` と `名前:…` の行)が10個以上あり、最後の字が「。」の台詞が5割以上の文書に1件 | script だけ | | `narrative_density` | 地の文が1,000字以上で、一人称が千字あたり1.0未満、数字と箇条書きの項目が千字あたり8以上の文書に1件 | essay だけ | | `copy_comma_noun` | 20字以下の文で、「な、」「い、」「た、」「の、」のあとに6字以下の名詞(か名詞+を)が来て「。」で終わるもの | すべて(promo は文書の2回目から) | | `bare_verb_chain` | 30字以下の文で、「は」「が」「を」「に」がなく、読点で区切った3つ以上の部分が動詞の終止形か「〜か」で終わり、最後が終止形で「。」になるもの | essay、promo、script、slides を除く | | `project_term` | 語の一覧の flag.txt の語。1行に1件で、message にその行の語が入ります | すべて | 2.2.1 から、技術の文書(直訳語の判定に使う技術の語のうち、画面、通知、フォームのような一般の語を除いた語が5種類以上ある文書)では、同じ文に技術の語がなくても、要求や呼び出しが主題の文の入口と出口(要求は、どれもこの入口を通ります)と、機械やシステムの語がある文の「全〇〇に響く」(全運転手に響きます)にも `calque` の指摘を出します。実物の場所、人が待つ形、文字どおりの音や言葉の響きは外します([CHANGELOG](../CHANGELOG.md) の 2.2.1)。 ### 2.3.0 で足した規則 `renyo_noun`(info)は、他動詞の連用形を1語だけ名詞にした語を「の」で受ける形(「結果の確かめ」「二つの案の比べ」)を指摘する規則です。この形の語は名詞としての自立性が弱く、目的語を「の」で受ける形では使いにくい、という日本語の文法の研究(蔡盛植「日本語動詞連用形への構文論的アプローチ」日本研究 第21集、2014)にもとづいています。漢語を避けて和語で書くと出やすい形です。 - 当てるのは、`references/lists/renyo-nouns.txt` の語(確かめ、直し、比べ、測り、補い、決め、選び、集め など)が「の」のすぐあとに来て、そのあとに助詞(が、を、は、に、で、も、と、から、など、だけ など)か、句読点か、閉じ括弧か、行の終わりが続く所です。指示語の「その」「この」で受ける形(「その確かめは」)にも当てます。1行に1件で、message に当たった言い方(「の確かめ」など。置き換え先の語ではありません)が入ります。見出し、表、箇条書きも見ます。当てる種類はすべてです。 - 当てないもの: 名詞とくっつけた複合語(資金集め、手直し)、複合動詞から来た語(見直し、組み合わせ、洗い出し)、「お」「ご」を付けた形(お選び)、別の意味で名詞として定着した語(住民票の写し、合格の知らせ、詰めが甘い、法律の定め、警察の調べ など。一覧に入れていません)、動詞に続く形(入れやすい、確かめにくい、決めがたい)、「生活の足しになる」「試しに」の「に」、前に「の」がない形(「確かめの道具」)、語のあとに「か」「だ」が続く形(「結果の確かめか」「案の比べだ」)。カギ括弧と引用符の中、引用、コード、HTML の行、英数字の識別子も見ません。 - 推敲では、目的語と動詞の文に戻すか(結果を確かめる)、定着した漢語の名詞にします(結果の確認)。ほかの和語の連用形名詞に替えるだけでは済ませません(SKILL.md「主語と目的語の明確化」)。diff の「文体の硬化」の候補に出ても、この形には戻しません。 - 人のニュース記事(livedoor ニュースコーパス、7,367本、約900万字)、Claude に素で書かせた日本語の48本(約10万字)、同梱の tests/corpus の163本では、指摘は0件でした。指摘は info で、`--strict` と `--fail-on` の判定にも、`rule_penalty_score` にも入りません。 - プロジェクトで定着している語は、語の一覧の `allow.txt` に「の」を付けずに語だけ(確かめ)を書くと外れます。 `references/lists/` の katakana-terms.txt、thin-evaluation.txt、renyo-nouns.txt がないか読めないときは、組み込みの一覧で同じ候補を出します。check は一覧のハッシュ(SHA-256)を記録に残し、一覧を変えると `verify` は `tool_changed` になります。 ### 2.4.0 で足した直訳語の型 `calque` に型4を足しました。英語の短い術語に当てた漢字1字の名詞(「今回の版」の version、「一覧の頭」の head、「lint の印」の mark)に、info の指摘を出します。message には「型4: 英語の短い術語に当てた漢字1字の名詞」と、当たった字(版、印、頭)が入ります。 - 前の語の修飾を受けて名詞として使う「版」(「今回の版」「直した版」「同じ版の」)と、「版ごと」「版の文字列」「版をまたいで」の形に当てます。文に出版物の語(新聞、雑誌、映画、吹き替え など)があれば当てません。同じ行に `translated_term`(warn)の候補があれば、型4の「版」は重ねません。 - 1字で使う「印」には、同じ文に検査や推敲の語(lint、diff、検査、検証、推敲、ログ など)があるときだけ当てます。「×印」「目印」「焼き印」は当てません。同じ文に検査や推敲の語があると、「地図の印」のような文字どおりの使い方にも指摘が出ることがあります。 - 行、一覧、出力、ログ、ファイル、PR などの位置を言う「頭」(「一覧の頭」「出力の頭」)と、「頭の2行」のような形に当てます。「頭が痛い」「曲の頭」のような体や慣用の「頭」は当てません。 - 推敲ではその分野で使う呼び名(バージョン、先頭、指摘)で書きます。何を指すかが原文や資料から決まらなければ、本文を残して書き手に確かめます(`references/calques.md` 4章)。 - 人のニュース記事(約900万字)と、同梱の tests/corpus の163本では、型4の指摘は0件でした。Claude に素で書かせた48本では4件で、どれも文書の別の稿(「短い版」「管理職向けの版」など)を指す、version の意味の「版」でした。ほかの漢字1字の語(段、枠、箱 など)には当てません。型1〜3と同じく info で、`--strict` と `--fail-on` の判定にも、`rule_penalty_score` にも入りません。 ### 2.4.0 で足したスライドの読点の規則 `slide_comma`(info)は、`--doc-type slides` のときだけ、見出しと1行の箇条の、間を作るだけの読点を指摘する規則です。見出しと箇条は一目で読むので、地の文なら残す読点でも外す候補にします。1行に1件で、message に当たった言い方が入ります。 - 見るのは、1行で終わる60字以下の見出し、箇条書き、段落の行です。続きの行がある項目と、複数行の段落の行は見ません。行頭の箇条の印(入れ子も)、「・」「①」「(1)」のような印、【】、「結論:」のようなラベルは外してから文頭を決めます。 - 当てるのは、文頭のつなぎの語(だから、それでも、そこで、結局、まず など)のあと、文頭の決まった「〜ば」(振り返れば、数字で言えば、言われてみれば など)のあと、文頭の6字以上の時や場面の句(その日のうちに、会議が終わるまでに など)のあと、文頭から15字以内の主題(〜では、〜は、〜も)のあと、文頭から10字以内の主語(名詞+が)のあと、目的語の「を」のあとの読点です。 - 当てないもの: 逆接(のに、ても、けれども、ながらも、述語+が)、条件(なら、たら、「〜ときは」「〜場合は」、「上司に言えば」のような「〜ば」)、理由や目的(ので、ために、ためには、するには)、名詞の並び(A、B、C と「Aを、Bを、」)、「その夜、」「翌朝、」のような短い時の句、主題のあとに別の主語が続く所(会議では、担当者が。主語が「〜がある」「〜がない」「〜が多い」のように、あるかないかや数を言う文の主語のときは当てます)と、主題のあとに読点で区切った並びが続く形(〜のは、A、B、C)、長い主語のあとの読点。カギ括弧と引用符の中、引用(`>` の行)、コード、リンクの URL、英数字の識別子は見ません。同じ行に `pause_comma` が出ているときは、主題と主語の読点を重ねて出しません。 - 推敲では、外しても読み違えない読点だけを外します(`references/doc-types/slides.md` 2章)。点数(`rule_penalty_score`)には入りません。ほかの種類では出しません。 ### プロジェクトの語の一覧 git の最上位に `.yomiyasu-words/` フォルダを置き、2つのファイルに1行に1語ずつ書きます。リポジトリに入れてチームで共有する前提のファイルで、状態フォルダ `.yomiyasu/` とは別の場所です(`.yomiyasu/` の中は探しません)。 - `allow.txt`: 直さない語(その分野で定着した言い方)。`calque`、`metaphor_label`、`katakana_term`、`project_term`、`renyo_noun` と、`metaphor_verb`、`translated_term`、`slop_vocabulary` の候補のうち、当たった語が一覧の語と同じものを外します。`calque`、`katakana_term`、`project_term`、`renyo_noun` は1行に1件で行の語を並べるので、許した語だけを除き、ほかの語が残れば候補を残します。外した件数(候補ごと外したもの)は出力と JSON に出ます。 - `flag.txt`: 指摘を出して見直す語(その分野で見直したい言い方)。`project_term`(info)の指摘を出します。扱いはほかの新しい指摘と同じで、文脈を見て書き直すかを決めます。 探す順は次のとおりです。lint、diff、check の3つが同じ順で探します(フックは自分では探さず、受けた `--words` か `--no-words` を check に渡します。下を参照)。 1. `--words フォルダ` を指定したときは、そのフォルダ(ないフォルダを指定すると終了コード2)。 2. 作業ディレクトリから上へたどり、`.git`(フォルダでもファイルでもよい)があるフォルダの `.yomiyasu-words/`。状態フォルダを探すときと同じたどり方で、入れ子のリポジトリでは近いほうの最上位です。 3. git の外では、作業ディレクトリの `.yomiyasu-words/`。 `--no-words` を付けると、一覧を探しも読みもしません(`--words` と一緒には使えません)。フォルダか2つのファイルがないときは、一覧なしとして動きます。一覧がないときの出力は、2.2.0 から 2.4.0 で足した規則と型の候補、2.4.0 で変えた出力の言葉(「太字の印」を「太字の記号」に、「文の種類の印」を「文の種類を表す語」にしたなど)、diff の「原文にない人や担当を足した文」の節のほかは 2.1.3 と同じです。 ファイルは UTF-8 のテキストで、`#` で始まる行と空の行は読み飛ばします。BOM と CRLF の改行も読めます。UTF-8 でないファイルと、1万行を超えるファイルがあると、終了コード2で止め、ファイルの名前と行番号を出します。 一覧を使ったときだけ、JSON の `context` に `words` が入ります。中身は、`path`(フォルダの場所)、`allow_lines` と `flag_lines`(語の数)、`allow_sha256` と `flag_sha256`(ファイルの中身の SHA-256。ファイルがないほうは null で、行数は0)です。lint では、これに `allow_removed`(規則ごとの外した件数)が加わります。人が読む出力には「語の一覧: <場所>(allow N語、flag N語)」の行が出ます。 check の `run` は、自分で一覧を探して読み、lint と diff に同じ場所を渡します。読めない一覧は終了コード2で、何も書きません。記録には一覧を使ったときだけ同じ値(`options.words`)を残し、`verify --replay` は記録の場所で lint と diff をやり直します。フックは lint を動かさないので、`--words フォルダ` か `--no-words` を受けて、続けさせるときや止めるときに案内する `yomiyasu_check.py run` のコマンドに付けます。フックは一覧を読めないときも止めず、状態フォルダの `hook-errors.log` に1行残します。 ### JSON を前のキーの名前で読んでいたとき 1.1.2 までの lint の `--json` の出力を読むスクリプトがあれば、2.0.0 からはキーの名前を読み替えてください。前の名前のキーは残していないので、`jq .score` と `jq .is_clean` は `null` を返します。`jq -e .is_clean` のように jq の終了コードで判定していた CI は、候補があってもなくても失敗します。 | 1.1.2 まで | 2.0.0 から | 中身 | |---|---|---| | `score` | `rule_penalty_score` | 規則に当たった候補の多さの目安です。計算を変えたので、前のしきい値はそのまま使えません([rule_penalty_score の式](#rule_penalty_score-の式)) | | `is_clean` | `no_rule_findings` | 候補が1件もなければ true です。`candidate_count` が0のときと同じです | `format_version` は 2.0.0 からの JSON にあり、値は2です。1.1.2 までの JSON にはこのキーがないので、ないときは1とみなしてください。`yomiyasu_check.py run --json` の `lint` の中のキーも同じ名前と同じ値です(`.lint.rule_penalty_score`)。 ```bash # 2.0.0 からの名前で読む python3 scripts/yomiyasu_lint.py article.md --json | jq '.rule_penalty_score' python3 scripts/yomiyasu_lint.py article.md --json | jq '.no_rule_findings' # 形式を見分ける(2.0.0 からは2、1.1.2 までは1) python3 scripts/yomiyasu_lint.py article.md --json | jq '.format_version // 1' # 1.1.2 と 2.0.0 のどちらの JSON でも読む python3 scripts/yomiyasu_lint.py article.md --json | jq 'if (.format_version // 1) >= 2 then .rule_penalty_score else .score end' python3 scripts/yomiyasu_lint.py article.md --json | jq 'if (.format_version // 1) >= 2 then .no_rule_findings else .is_clean end' ``` 候補の有無を `jq '.no_rule_findings // .is_clean'` と書くと、2.0.0 からの JSON で候補がある文書では `null` になります。jq の `//` は false も値がないものとして扱い、右の `.is_clean` を読むためです。上の例のように `format_version` で分けてください。 CI で止めるときは、点数のしきい値の代わりに `--fail-on` を使ってください。JSON で判定したいときは、`counts` の件数を使えます。 ```bash # warn か error の候補があれば終了コード1(jq は要りません) python3 scripts/yomiyasu_lint.py article.md --fail-on warn # 同じ判定を JSON で行う(warn か error の候補があれば jq の終了コードが1) python3 scripts/yomiyasu_lint.py article.md --json | jq -e '.counts.error + .counts.warn == 0' ``` この節の jq の例は 2.0.1 の lint の出力に jq 1.7.1 をかけて確かめました。どちらの JSON でも読む2つの例と `//` の例は、1.1.2 の lint の出力にもかけて確かめています。 ## 2. yomiyasu_diff.py(推敲の前後の比較) 推敲前と推敲後を比べ、変わった箇所をすべて出します(全文差分)。あわせて、意味が変わる恐れのある変化と、語の増減、文末の種類や立場(勧め/決まり/説明)の変化、太字の表示などの見直し候補を出します。 ```bash # 原文と推敲後の差分を検査(文書の立場を指定。--stance 説明 とも書けます) python3 scripts/yomiyasu_diff.py 元の文.md 書き直した文.md --stance=説明 # 数値・否定・入れ替え・文の種類の変化があれば終了コード1を返す python3 scripts/yomiyasu_diff.py 元の文.md 書き直した文.md --fail-on=meaning-risk # 文末の種類(敬体・常体・立場)の分布のみを確認 python3 scripts/yomiyasu_diff.py --endings 対象文.md ``` 出力の例です(「田中が佐藤を承認した。設定は3日ごとに保存します。」を「佐藤が田中を承認した。設定は30日ごとに保存しません。」にした場合)。 ```text 差分の検査を実行しました。 状態: 変更あり(2か所)。見直し候補 3件、うち意味が変わる恐れ 3件 全文差分は変わった箇所を示すだけで、意味が同じだという証明ではありません。この検査では、意味の保持と読者にとっての分かりやすさは判定していません。 ■ 意味が変わる恐れ(3件。原文と資料に照らして確かめる) - 「が」「を」などが入れ替わった(1行目): 田中 が→を、佐藤 を→が 元: 田中が佐藤を承認した。 後: 佐藤が田中を承認した。 - 数値が変わった(3行目): 3日 → 30日 元: 設定は3日ごとに保存します。 後: 設定は30日ごとに保存しません。 - 否定の有無が変わった(3行目): 保存します → 保存しません 元: 設定は3日ごとに保存します。 後: 設定は30日ごとに保存しません。 ■ 全文差分(変更 2か所。省略していません) @ 元1行目 → 後1行目(本文) 元: 田中が佐藤を承認した。 後: 佐藤が田中を承認した。 @ 元3行目 → 後3行目(本文) 元: 設定は3日ごとに保存します。 後: 設定は30日ごとに保存しません。 差: 設定は3{+0+}日ごとに保存しま[-す-]{+せん+}。 状態: 変更あり(2か所)。見直し候補 3件、うち意味が変わる恐れ 3件 ``` - 状態は「変更なし」「変更はあるが、専用の規則に当たる見直し候補はない」「変更あり」の3つです。全文差分の `[-…-]` は消えた文字、`{+…+}` は足した文字です。 - 意味が変わる恐れとして出すのは、数値、否定、主語と目的語の入れ替え(「が」「を」など)、問いと平叙、文の種類を表す語(伝聞、推量、意見、例え、依頼や決まり)、コード・URL・引用など変えない箇所の変化、引用の書き方(`[1]`、`(山田 2020)` の形)の変化、否定対比の主張の逆転(「Aではなく」で否定していた A が、推敲後に目的や優先の側に出た)、元にない気持ちの語、確度の変化、かぎかっこの中の言葉の変化、原文の状態の語(未定、未確認、調査中など)が消えた書き換え、原文にない約束・保証・再発防止の誓い・因果を足した書き換え、同じ文(分けた・つないだ文を含む)の中での許可と能力の言い方(してよい、構わない、できる、可能だ)の消えと足し、どれか一つを選ぶ言い方(または、どちらか、いずれか など)と全部を含む言い方(両方、どちらも、すべて など)の入れ替え、関連や相関を述べた文に因果の言い方(因果関係、原因、引き起こす など)を足した書き換え、数に付いた概数や範囲を表す語(約、ほど、以上、未満 など)の消えと足しです(最後の3つは 2.1.1 から)。 - `--fail-on=meaning-risk` で終了コード1になるのは、このうち数値、否定、主語と目的語の入れ替え、文の種類(問いと平叙、文の種類を表す語)、引用の書き方の変化、確度を強めた書き換え(かもしれない → 見込み、見込み → 予定、と思われる → 断定など)、原文の状態の語が消えた書き換え(未確認です → 別途確認させていただきます)、原文にない書き手の約束・保証・再発防止の誓いを足したもの(2.1.0 からは常体の「保証する」「保証されている」「担保する」も含む)、許可の言い方が消えたか増えた書き換え(含めてよい → 含められる など)、どれか一つと全部の言い方の入れ替え(AまたはBのどちらか → AとBの両方、またはその逆)、関連や相関を述べた原文の文に因果の言い方を足した書き換え(関連がある → 因果関係がある、相関がある → 引き起こす)、同じ数に付いた概数や範囲を表す語が消えたか増えた書き換え(約120人 → 120人、3日以内 → 3日、以上 ↔ 超)です。`--doc-type` が pr、article、incident、proposal、manual、formal、paper のときは、「場合がある」「ことがある」を消して言い切った書き換えと、断定に「必ず」「確実に」などを足した書き換え(原文の文に義務の語があるときの「必ず」は除く)も数えます。ほかの種類と種類なしでは見直し候補にとどめます。能力の言い方(できる、可能だ)が消えた書き換えは、どの種類でも数えません。コード・URL・引用などの変化、否定対比の主張の逆転、元にない気持ちの語、確度を弱めた書き換え、数えない語だけの確度の変化、予定の言い切り(する予定です → します)、かぎかっこの中の言葉の変化、原文にない因果を足したもの(原文の文が関連や相関を述べていたときは上のとおり数えます)、書き手の行為と読む言い方(いたします、今後・改めて、弊社などの主語)のない「〜します」を足したもの(説明や手順の文かもしれないもの)は、意味が変わる恐れとして出しますが数えません。推量の言い方が同じ強さの別の慎重な言い方に替わっただけの文(かもしれません → 恐れがあります、と思われます → 見込みです。同じ節の同じ事柄についての言い換えに限ります)は、意味が変わる恐れの候補に出さず、数えません。「■ 文の種類を表す語が変わった文」には引き続き出します。台詞の最後の「。」(閉じかぎかっこの前の句点)だけを外したか足した組(「見たのか。」→「見たのか」)は、問いと平叙の変化に数えません(2.2.0 から。種類によりません)。付けなければ、候補があっても終了コードは0です。付けたときは、種類を付けなくても、引用の書き方、統計の値の比較の記号、同じ値の符号が変わった文書で、終了コードが0から1に変わることがあります。依頼や資料に書いてある約束を本文に足したときも、diff は依頼と資料を見られないので、約束を足したものとして数えます(check の資料との照合は、数値だけを資料にある値として扱います)。 - 見出しの数が変わったとき、太字の行や本文の行を見出しにしたとき、見出しを本文の行にしたとき、見出しのレベルを変えたとき(`###` → `####` など)は、「構造」の見直し候補に出します(2.1.1 から)。見出しの数の変化のほかは、元と後の行番号と行の中身を添えます。見直し候補の件数には入りますが、意味が変わる恐れと `--fail-on` には数えません。 - 2.4.0 から、原文にない人や担当を、主語か、知らせる・頼む相手に足した文を、「■ 原文にない人や担当を足した文」の節に出します。「容量が一割を切ったら知らせる。」「障害が起きたら、担当者が再起動する。」を書き直した例を下に示します。原文にある役割の語の前に語を足した形(担当者 → 運用担当者)には、「原文の「担当者」を狭めたかもしれない」と添えます。 ```text ■ 原文にない人や担当を足した文(2件。原文、資料、依頼のどれにもない人や担当なら、原文の書き方に戻す) - 知らせる・頼む相手に「管理者」を足しました(1行目) 元: 容量が一割を切ったら知らせる。 後: 容量が一割を切ったら、管理者に知らせる。 - 主語に「運用担当者」(原文の「担当者」を狭めたかもしれない)を足しました(3行目) 元: 障害が起きたら、担当者が再起動する。 後: 障害が起きたら、運用担当者が再起動する。 ``` - 見るのは全文差分の中の書き直した文だけで、コード、先頭の設定(frontmatter)、HTML は読まず、インラインのコードと URL は伏せます。人や担当の語は、役割の語(担当者、管理者、責任者 など)、部署やチームの語、「〜さん」「〜様」の形の名前、人称の語(私たち、皆さん など)です。同じ人を指す言い換え(アドミン → 管理者、レビュアー → レビュー担当者 など)と、語が原文のどこかにあるものは出しません。`--material 資料` を付けると(何度でも指定できます。`--endings` とは一緒に使えません)、資料にある人や担当も出しません。diff は依頼の文を見られないので、依頼に書いてある人でも出ます。原文、資料、依頼のどれにもいない人や担当なら、原文の書き方に戻してください。 - この節は見直し候補の件数、意味が変わる恐れ、状態の行、`--fail-on` に入れません。`--json` では `added_actors`(いつもあり、候補がなければ空の並び)に、文ごとに `old_line`、`new_line`、`old`、`new`、`actors`(`word`、`frame`、`tier`、`narrowed_from`)が入ります。`frame` は主語なら `subject`、知らせる・頼む相手なら `recipient` です。check の run は資料をすべて diff に渡し、同じ節と、冒頭の候補の一覧の「原文にない人や担当: 後1行目 管理者、…」を出します。 - 推敲で文体が硬くなった箇所(漢字の割合、文の長さ、名詞化の言い回し、漢語の「の」の連続が増えた)と、勢いが落ちた箇所(「!」「?」、絵文字、強める語が減った、見出しが短くなった)は、「■ 文体の硬化」「■ 勢い」の節に見直し候補として出します。この2つは件数と `--fail-on` に入れません。文書の種類によっては参考としてだけ出します(硬化は incident、formal、paper、勢いは pr、article、incident、manual、formal、paper)。検査に使う語の一覧は `references/lists/` にあり、足し引きできます。 - 慎重な言い方(と考えられる、可能性がある、示唆する など)が減った文は「■ 慎重な言い方」に、宛名(〇〇様、〇〇さん)とリンクでないメールアドレスの変化は「■ 動かしてはいけない値」に出します。`--doc-type mail` のときは、敬語の数と「です・ます」の割合が大きく動いた文書を「■ 敬語の度合い」に出します。常体と敬体の切り替えが3文以上かつ原文のその文体の5割以上なら「■ 文体の切り替え」に出します。原文の多い文体にそろえた場合と、主な文体を変えた場合を分けて示します。この4つは見直し候補で、件数と `--fail-on` に入れません。同じ文で推量の言い方が消えたときや確度の強まりの候補が出たときは、慎重な言い方には重ねて出しません。 - 推敲の前後で文を1文ずつ対応させて、文の種類を表す語が消えたり増えたりした文も示します。文の対応は字面の重なりでたどるため、大きく言い換えた文や順番を大きく入れ替えた文では、変化を取りこぼしたり、対応しない文どうしを比べた候補が出たりすることがあります。候補に出なかった文も、元の文と読み比べてください。 - 終了コードは、0が比べ終わって `--fail-on` に当たらなかったとき、1が `--fail-on=meaning-risk` に当たったとき、2が使い方か入力の誤り、3が内部の誤りです。 ## 3. yomiyasu_check.py(検査をまとめて実行して記録を残す) 最終稿に lint を、原文と最終稿に diff をまとめて実行し、記録を残します。スキルは、書き直しのあとに `run` を、提出の直前に `verify` を実行します。 ```bash # 推敲: 原文と最終稿を渡す(資料があれば --material 資料 を足す) python3 scripts/yomiyasu_check.py run --source 原文.md --final 最終稿.md --doc-type article # 新規作成: 資料と最終稿を渡す(資料との照合と lint) python3 scripts/yomiyasu_check.py run --material メモ.md --final 最終稿.md # 推敲で補った値の根拠(抜き書き)を渡し、事実の穴の候補も出す python3 scripts/yomiyasu_check.py run --source 原文.md --final 最終稿.md --material 最終稿.material.txt --fact-gaps # 提出の直前に、最終稿が検査したものと同じかを記録と照らす python3 scripts/yomiyasu_check.py verify --final 最終稿.md ``` run の出力では、記録の行と「硬化の検査:」などの行のあとに、見直し候補の件数(原文 → 最終稿)と直した箇所の元と後が出ます([前後を比べるときは check を使う](#前後を比べるときは-check-を使う) の節)。 出力の2行目は、次のような状態の行です。完了報告の確認の記録には、この行を写します。 ```text yomiyasu-check: executed via=verify run=20261014T124830Z-6b5d53f8 attempt=1 final=sha256:6aa6ecba24a9 mode=rewrite doc_type=article checks=lint,diff meaning_risk=0 replay=ok ``` - 返す状態は「検査を実行した」(`executed`)で、合格ではありません。run は、検査の一部を実行できなければ `partial`、使い方の誤りなら `not_run` を返します。verify は、記録がない(`no_record`)、検査のあとに最終稿を書き換えた(`final_changed`)、記録のあとに検査スクリプトや語の一覧が変わった(`tool_changed`)ときなどに、完了と扱いません。diff を実行していない記録と、別の原稿の記録も、完了と扱いません。書き直す前の文章を資料として渡しても、資料が最終稿とよく似ていれば、run はそれを原文とみなして diff も実行します。 - 記録は、git の最上位(なければ作業ディレクトリ)の `.yomiyasu/` に置きます。自分を無視する `.gitignore` を作るので、git には出ません。先にできていた `.yomiyasu/` でも、`.gitignore` と `state.json` がどちらもなければ作ります。場所は `--state-dir` か環境変数 `YOMIYASU_STATE_DIR` で変えられます。こうして指定したフォルダがすでにあるときは `.gitignore` を足さないので、git に入れたくなければ利用者が無視の設定をしてください。記録には原稿の写しが入りますが、外へは送りません。要らなくなれば消してかまいません。原稿の写しが入るので、状態フォルダとその下のフォルダは、作った OS ユーザーだけが読み書きできるようにします(POSIX では 0o700。Windows でも、Python のバージョンによっては作ったユーザーと管理者だけのフォルダになります)。同じリポジトリをほかの OS ユーザー(Codex のサンドボックスなど)も使うときは、`YOMIYASU_STATE_DIR` か `--state-dir` で、ユーザーごとに別の状態フォルダを指定してください。ほかのユーザーが作った状態フォルダに書き込みを拒まれると、run は記録を残さずに `reason=not_writable` で終わり、start は終了コード3で終わります。どちらも、この指定の仕方を案内します(2.1.2 から)。 - `--state-dir` と `YOMIYASU_STATE_DIR` の値が `~` だけか `~/` で始まるときは、`~` をホームフォルダに置き換えます(Windows では `~\` も)。引用符の中の `~` や、エージェントの設定ファイルに書いた `~` は、シェルが展開しないまま届くためです。`~user/...` のような値や途中に `~` がある値は置き換えず、ほかの相対パスと同じく作業ディレクトリから数えます。ホームフォルダが分からない環境では値をそのまま使います。`HOME` がなく利用者の情報からも決まらないときと、`HOME` が空か `/` だけのときがこれに当たります(状態フォルダをファイルシステムのルートに置かないためです)。`~` だけを指定すると、ホームフォルダそのものが状態フォルダになり、`index/` や `runs/` などのフォルダがホームフォルダの直下にできます。ホームフォルダはすでにあるフォルダなので、`.gitignore` と `state.json` は作りません。ふつうは `~/.yomiyasu` のように、ホームフォルダの下のフォルダを指定してください。 - 記録は実行漏れを見つけるためのもので、改ざんの防止や人の承認の証明にはなりません。同じ権限で原稿と記録の両方を書き換えられる環境では、記録を作り込むこともできます。`verify --replay` は記録の写しで lint と diff を動かし直し、結果が記録と同じかを確かめますが、写しと結果を同じように作り込んだ記録は見分けられません。 - 環境変数: `YOMIYASU_STATE_DIR` は、`--state-dir` を省いたときの状態フォルダです(空白だけの値と、展開されずに `${` が残った値は使いません)。`YOMIYASU_SESSION` は、`run` と `start` で `--session` を省いたときのセッションの識別子です(run では記録に入れるだけで、start では登録をそのセッションに結び付けます)。Codex が渡す `CODEX_THREAD_ID` があれば、run は記録の `host.codex_thread_id` に入れます。記録に入れる値は、空の値と `${` が残った値を null にします。 - `--json` の結果では、出力の「硬化の検査:」「勢いの検査:」「慎重表現の検査:」「値の検査:」「敬語の検査:」の行と同じ文字列が、`stiffness_check`、`tone_check`、`hedges_check`、`immutable_check`、`politeness_check` に入ります(diff を実行しなかったときと、mail でないときの `politeness_check` は null)。候補があるときだけ出る「文体の検査:」の行には文字列のキーがなく、結果は `diff.register` にあります。 - ファイルを作らない対話では、`run --stdin` で原文と最終稿を標準入力から渡します。行全体が `<<>>`、`<<>>`、`<<>>` の行で区切ります。資料の区切りには、`<<>>` の形で出典を書けます([資料の出典と事実の穴の候補](#資料の出典と事実の穴の候補))。この使い方にはシェルが要ります。ファイルを作らない対話や本文だけを返すときも、スキルは返す直前に最終稿だけを `verify --final -` に渡して照合します。 - `--fail-on meaning-risk` は diff と同じ種類に、資料から書いたときの資料にない数値を加えて数えます。`--fail-on warn` と `--fail-on error` は lint の候補で止めます。どれも、記録を残したうえで終了コード1を返します。 - 終了コードは、0が run で条件に当たらなかったとき・verify で記録と合ったとき、1が run で `--fail-on` に当たったとき・verify で記録がないか合わないとき、2が使い方か入力の誤り(何も書きません)、3が検査の一部を実行できなかったときか内部の誤りです。 ### 残した指摘の語 2.2.1 から、最終稿に直訳語(`calque`)と語の一覧(`project_term`)の指摘が残っていると、run は冒頭の一覧のあとに「残した指摘の語: 要求(語の一覧。L9、L25)、に響く(直訳語。L28)。…」の行を出し、「■ 意味が変わる恐れ」のあとに「■ 残した指摘の語」の節を出します。節には、残すなら「書き手に確かめたい点」で尋ねるか、残す理由を「残したAIっぽいところ」に書くかの見分け方と、問いの3点の上限、本文だけを返す指定のときの扱いを書きます。verify も、記録と合ったときに同じ語を「残した指摘の語:」の行で出します。 - 語は lint の候補の message から取り、語ごとに1つにまとめます。同じ語に直訳語と語の一覧の両方の指摘があれば、語の一覧として出します(定着していても残さない決まりが先です)。直訳語の型3の句は「に響く」のように句の名前で出ます。語の一覧の語に「、」があると、2つの語に分かれて出ます。 - lint を流し直さず、run の中では1回だけ数えます。行は集合で持つので、手間は候補の数に比例して増えるだけです。`--replay` なしの verify は、記録の lint の要約(`kept_marks`)を読むだけで、lint と diff を読み込みません。`--replay` のときは、動かし直した lint の結果からも数え、記録の要約と同じかを確かめます。 - `--json` では、run と verify に `kept_marks`(`rule`、`word`、`lines` の並び。指摘がなければ空の並び)が付きます。verify で照合が合わなかったときと、2.2.1 より前の記録では null です。形式のバージョンは上げていません。 - この行と節は検査を実行したことの一部で、尋ねたかどうかを check が確かめるものではありません。状態、終了コード、`--fail-on` の判定は変わりません。 ### 資料の出典と事実の穴の候補 資料のファイル(`--material`)と `--stdin` の資料の部分は、`<<>>` の行で区切ると、区切りごとに別の資料になります。出典は省いてもよく、200字まで書けます(`>>>` は含めません)。区切るのは、空白でない最初の行が区切りの行のときだけです。そうでなければ、今までどおりファイル全体が1つの資料です。 ```text <<>> -RETRY_INTERVAL_SECONDS = 1.0 +RETRY_INTERVAL_SECONDS = 0.5 <<>> 保存は30日、削除は毎日3時に走ります ``` - 出典は記録に残りますが、照合しません。出典の中の数は資料の値として照らされません。 - `<<>>` のような書き損じ)、何も記録せずに終了コード2で止まり、正しい書き方を出します。書き損じた行が黙って資料の中身になり、出典の数が資料の値として照らされないようにするためです。 - 区切りで分けた資料の1つが最終稿と同じ本文のとき、新規作成では今までの資料と同じく終了コード2で止まります。推敲(`--source` あり)では止まりません。短い原稿を根拠の文どおりに直すと、根拠の文と最終稿が同じになるためです。 次の原稿と最終稿を、上の資料と `--fact-gaps` を付けて run に通した出力です(途中を省いています)。 ```text (原稿) ## 変更点 再試行の間隔を短くしました。 保存期間を延ばし、古い記録は毎日消します。 今回の変更で、復元の失敗が大幅に減ります。 (最終稿) ## 変更点 再試行の間隔を1秒から0.5秒に短くしました。 保存期間を30日に延ばし、古い記録は毎日3時に消します。 今回の変更で、復元の失敗が大幅に減ります。 ``` ```text 検査を実行しました(1回目)。下の候補を原文と資料に照らして確かめてください。直すのは1回までです。直したら同じコマンドをもう一度実行し、直さないなら提出の直前に、本文を変えずに verify を1回実行してください。 yomiyasu-check: executed via=run run=20261015T194529Z-0cf033b8 attempt=1 final=sha256:68ec5305c050 mode=rewrite checks=lint,diff,materials meaning_risk=2 実行した検査: lint(最終稿)候補0件、diff(原文→最終稿)変更あり 候補3件(うち意味が変わる恐れ2件)、資料との照合(資料2件)資料にない数値・名前2件、事実の穴の候補1件 (中略) ■ 意味が変わる恐れ(2件。原文と資料に照らして確かめる) - 元にない数値(後3行目): 1秒、0.5秒 元: 再試行の間隔を短くしました。 後: 再試行の間隔を1秒から0.5秒に短くしました。 - 元にない数値(後4行目): 30日、3時(資料にある値) 元: 保存期間を延ばし、古い記録は毎日消します。 後: 保存期間を30日に延ばし、古い記録は毎日3時に消します。 ■ 資料との照合(資料2件) - 資料に基づく補足の候補: 30日、3時 - 資料に基づく補足の候補(該当行): 30日(資料2の1行目「保存は30日、削除は毎日3時に走ります」)、3時(資料2の1行目「保存は30日、削除は毎日3時に走ります」) - 単位のない数とだけ一致(資料にない数値に数えています。根拠の行か読み比べてください): 1秒(資料1の1行目「-RETRY_INTERVAL_SECONDS = 1.0」)、0.5秒(資料1の2行目「+RETRY_INTERVAL_SECONDS = 0.5」) - 照らしたのは数値、名前、語、確度の語だけです。主張、条件、担当が資料どおりかは判定していません。資料と読み比べてください。 ■ 事実の穴の候補(1件。比喩や程度の語だけで、中身や値が書かれていないかもしれない所です。根拠に中身が書かれているときだけ補い、なければ残すか、書き手への問いにしてください。候補は一部だけです) - 後5行目(程度の値(何がどれだけ)がない「大幅に」): 今回の変更で、復元の失敗が大幅に減ります。 ``` - 「資料に基づく補足の候補(該当行)」は、最終稿の値が資料の何行目にあったかです(1つの値に3行まで、行の文は40字まで、値は5つまで)。 - 「単位のない数とだけ一致」は、最終稿の値(0.5秒)と同じ数が、資料の `名前 = 数` か `名前: 数` の形の行にだけあるものです。件数は「資料にない数値」のままで、行を見せるだけです。日付、時刻、パス、バージョンの中の数は見ません。 - 資料の行に「予定」「たぶん」「と思います」などの確度の語があり、最終稿のその値の文にないときは、値を添えて出します(資料「保存期間を30日に延ばす件は、来月からの予定です」、最終稿「保存期間を30日に延ばします。」のとき、`- 資料にあった確度の語が最終稿にない: 予定(30日の文)`)。 - どの行も、資料のその行に同じ値があることを示すだけです。根拠であることも正しいことも示しません。設定の `retry_wait = 3` を回数の「3回」に使うような取り違えも同じ行に出るので、行の名前と最終稿の文を読み比べてください。 - 照合の節に行が足されるだけで、件数、1〜3行目、状態の行、終了コードは変わりません。 - 正しく補った値も原文にない数値なので diff の「意味が変わる恐れ」に出ます(上の2件)。`--fail-on=meaning-risk` を付けた run は正しく補った値でも終了コード1になります。 - `--fact-gaps` を付けると、最終稿のうち、程度の語だけの文(大幅に、劇的に)、変わる前と後の値がない変化(短くしました、高速化しました)、効果だけの文(信頼性が向上します、改善しました)、中身の見えない比喩(土台づくり、連鎖を断ち切る)を「■ 事実の穴の候補」に10件まで出し、3行目の最後に「、事実の穴の候補N件」を足します。候補があれば、ほかの候補がなくても1行目は「下の候補を原文と資料に照らして確かめてください」になります。`--fail-on`、状態の行、必要な検査には入れません。候補は一部だけです([限界](./limitations.md#事実を補う手順と資料の照合))。 - `--doc-type essay` と `promo` では節を出さず、3行目に「事実の穴の候補(種類 essay では出していません)」のように書きます。formal と paper では、節の見出しの文が「この種類では補わず、必要なら書き手への問いにしてください」になります。 - 拾う語の一覧は `references/lists/fact-gaps.txt`(「種類正規表現」の行)にあり、足し引きできます。ないときや読めないときは内蔵の一覧で動き、読めなかったときは節の最後にそのことを1行出します。記録のあとで一覧を変えると、`--fact-gaps` を付けた記録は、ほかの一覧と同じく verify で `tool_changed` になります。付けなかった記録は、この一覧で結果が変わらないので、変えても `tool_changed` になりません。 - `--json` と記録には `fact_gaps`(件数、種類ごとの件数、20件までの候補)が付きます。付けなかった run では null です。照合の JSON の項目には `found_in`(どの資料にあったか)、`evidence`(資料の何行目か)、`bare_in`(単位のない数とだけ一致した行)、`values`(確度の語に添えた値)が、`sources` には `label`(出典)が足されます。形式のバージョンは上げていません。 ## 4. yomiyasu_hook.py(任意のフック) フックは、ホストが決まった時点で動かすコマンドです。yomiyasu_hook.py は、登録した原稿について、検査を実行したか、最終稿が検査記録と同じかを、返答の終わりと投稿の前に確かめます。入れなくても yomiyasu はこれまでどおり使えます。利用者が自分の設定ファイルに貼ったときだけ動き、スキルやプラグインを入れただけでは動きません。 フックは、読みやすさの合格や、意味が保たれたかを判定しません。会話の中の日本語を書き換えたり、登録していない原稿の保存や投稿を止めたりもしません。 ### 登録のしかた 対象になるのは、登録した原稿だけです。 - 端末で `python3 -B /path/to/yomiyasu/scripts/yomiyasu_check.py start --source docs/draft.md` を実行します。最終稿を別のファイルに書くときは `--final docs/final.md` を足します。 - Claude Code では、プロジェクトに置いたスキルを `/yomiyasu docs/draft.md を読みやすくして` のように呼び、原稿のファイルを書くと、フックが登録します。登録するのは、依頼の文で最初に出てくるファイル1つだけです。2つ以上の原稿は、端末で1つずつ `start` してください。 - Codex では、`$yomiyasu:yomiyasu docs/draft.md を読みやすくして` のように依頼の文にスキルの名前を書くと、フックが登録します。`$yomiyasu` と書いても登録します。登録するのは、Claude Code と同じく最初に出てくるファイル1つだけです。試した置き方では Codex がスキルを `yomiyasu:yomiyasu` という名前で一覧に載せたので、`$yomiyasu` と書いた回ではスキルの指示が読み込まれませんでした。 ### 入れ方 1. `python3 /path/to/yomiyasu/scripts/yomiyasu_hook.py --print-config claude-code` で、このスクリプトの絶対パスを入れた設定の例を出します。設定ファイルには書き込みません。 2. 出た JSON を、管理したいプロジェクトの `.claude/settings.json` か `.claude/settings.local.json` に貼ります。ファイルがすでにあるときは、ファイルを置き換えずに、`hooks` のイベントごとの並びに足してください。`~/.claude/settings.json` に貼るとすべてのプロジェクトで動き、Bash と MCP のツールを呼ぶたびに python が起動します。 3. プラグインを更新するとスクリプトのパスが変わります。更新したら、設定の例を出し直して貼り直してください。 Codex では次のように入れます。 1. `python3 /path/to/yomiyasu/scripts/yomiyasu_hook.py --print-config codex` で設定の例を出します。 2. 出た JSON を、管理したいプロジェクトの `.codex/hooks.json` に置きます。ファイルがすでにあるときは、ファイルを置き換えずに、`hooks` のイベントごとの並びに足してください。 3. Codex は、信頼していない hooks.json を、何も知らせずに飛ばします。試したのは、`codex exec` に `--dangerously-bypass-hook-trust` を付けて信頼の確認を飛ばした形だけです。`/hooks` で信頼する手順は試していません。 4. `codex exec` に `--ignore-user-config` を付けると、プロジェクトの `.codex/hooks.json` も読まれず、フックは1つも動きません(1回確かめました)。 ### 動き - 返答を終えるたびに、登録した原稿の最終稿が検査記録と合うかを確かめます。合わなければ、理由を渡して作業を続けさせます。続けさせるのは2回まで、登録から30分まで、run は3回までです。超えたら「未確認」として1回知らせ、それ以上は続けさせません。自動で書き直したり投稿したりはしません。上限は `start` の `--max-stop-blocks`、`--max-runs`、`--deadline-min` で変えられます。 - Claude Code は、フックが作業を続けさせたときに「Stop hook error occurred」と表示し、投稿を止めたときに「PreToolUse:Bash hook error:」に続けて理由を表示します。どちらも、フックの判断を知らせる表示です。 - Codex の `codex exec` では、続けさせる理由が利用者の入力としてエージェントに届きます。投稿を止めたときは「Command blocked by PreToolUse hook:」に続けて理由が出ます。 - 投稿には、`yomiyasu_check.py export --final 最終稿` で書き出した写しを使ってください(例 `gh pr create --body-file <写し>`)。写しは `.yomiyasu/exports/` にでき、検査した最終稿と同じバイト列です。照合が合わないときは写しを作りません。写しができても、合格の判定ではありません。 - 補助として、登録した原稿に関係する `gh` の投稿(pr、issue、release の本文と、api の本文の欄)と MCP の投稿で、本文が検査記録と照合できないときは止めます。`--body "$(cat 最終稿)"` のように本文を取り出せない投稿は、利用者に確かめます(Claude Code の `-p` では実行されません)。Codex には利用者に確かめる仕組みがないので、止めます。登録と関係ない投稿は止めません。 - `yomiyasu_check.py end --source docs/draft.md` で登録を終えられます。セッションが終わったときも終わります。Claude Code の `-p` では1回ごとにセッションが終わるので、端末で登録した原稿が効くのは `-p` の1回分です。`--resume` で続けても、前の回の登録は引き継がれません。 - 登録のある原稿の run は、上限を超えると検査せずに `unverified` と終了コード1を返します。登録の無い原稿の run と verify は、フックを入れる前と同じです。 - フックが登録を探す状態フォルダは、`--state-dir`、環境変数 `YOMIYASU_STATE_DIR`、ホストが渡す作業ディレクトリの git の最上位(なければ作業ディレクトリ)の `.yomiyasu/` の順です。Claude Code では、環境変数 `CLAUDE_PROJECT_DIR` のプロジェクトの `.yomiyasu/` も探します。`--state-dir` と `YOMIYASU_STATE_DIR` の先頭の `~` は check と同じ決まりでホームフォルダに置き換えるので、フックと check は同じフォルダを見つけます。この決まりは 2.0.2 からなので、2.0.1 のフックと 2.0.2 の check を組み合わせると、`~` で始まる値のときにフックと check が別のフォルダを見ます。yomiyasu を 2.0.2 に更新したら、`--print-config` で設定の例を出し直し、フックのパスが 2.0.2 のスクリプトを指すようにしてください。 - フックとして呼ばれたとき(`--host`)は、入力や引数が違っても、登録がなくても、内部の誤りでも、何も出さずに終了コード0で終わります。知らない引数も無視します。ホストの作業を止めないためで、作業を続けさせることと投稿を止めることは、標準出力の JSON で伝えます。`--print-config` の値がないときと、`claude-code` と `codex` のほかの値のときだけ、終了コード2で使える値を出します。引数と終了コードは `yomiyasu_hook.py --help` にあります。 ### フックの限界 - フックは補助で、確かめていない原稿の公開を完全には止められません。フックの時間切れや失敗、一覧にないコマンド(`gh` 以外)、本文を取り出せずパスも書いていない投稿、本文を少し変えた投稿、利用者が自分で行う投稿は止まりません。 - 返答の中だけで推敲し、ファイルに書かなかったときは、フックでは見つけられません。 - Codex の `codex exec` では、「未確認」の知らせが利用者に表示されません(JSON の出力で2回、人向けの出力で1回確かめました)。フックは知らせを出していますが、Codex が表示しません。上限で止まったときは、エージェントの完了報告の「実行しなかった検査」を見て、投稿の前に `yomiyasu_check.py verify` で確かめてください。 - 試した Codex では、エージェントのコマンドはコード実行のツール(`exec_command`)を通り、`Bash` としてフックに届きました。ほかの経路でコマンドを実行したときにフックが見るかは、確かめていません。 - 同じプロジェクトで2つのセッションを同時に動かすと、端末で登録した原稿は、先に動いたセッションのものになります。取り違えを避けたいときは、`start --session` でセッションを指定します。 - 登録、記録、写しは `.yomiyasu/` にあり、エージェントと同じ権限で書き換えられます。改ざんの防止や人の承認の証明にはなりません。フックはネットワークを使わず、本文を外へ送りません。フックの出力と登録のファイルにも、本文は入れません。 ### 試したホスト | ホスト | バージョン | 入れ方 | 試したこと | |---|---|---|---| | Claude Code | 2.1.296(macOS) | プロジェクトの `.claude/settings.json`、`claude -p`、プロジェクトに置いたスキルの `/yomiyasu` | 端末の start と `/yomiyasu` での登録、検査のあとの書き換えで続けさせること、上限での未確認、関係ない作業を止めないこと、export の写しでの投稿、照合の合わない投稿を止めること、本文がフックの出力に出ないこと | | Codex | codex-cli 0.162.1(macOS) | プロジェクトの `.codex/hooks.json`(`--print-config codex` の出力そのまま)、`codex exec`、`--dangerously-bypass-hook-trust`、サンドボックスは workspace-write、承認は never、作業場所の `.agents/skills/` に置いたスキル | 端末の start と `$yomiyasu`・`$yomiyasu:yomiyasu` での登録、上限まで続けさせて止まること(「未確認」の知らせは表示されない)、export の写しでの投稿、照合の合わない投稿と本文を取り出せない投稿を止めること、登録と関係ない投稿を止めないこと、セッションの終わりで登録を終えること、空白を含むパスでフックが動くこと、本文がフックの出力に出ないこと | Codex は、プラグイン、アプリ、メモリ、複数のエージェント、ログインシェル、利用者のルールとスキルを切って試しました。ふだんの設定では、コマンドの形やツールの名前が変わるおそれがあります。 ここにない形は確かめていません。Claude Code の対話モード、Claude Code にプラグインで入れたときの `/yomiyasu:yomiyasu`、`.claude/settings.local.json` と `~/.claude/settings.json` に置く形、Codex の対話の画面、`/hooks` での信頼、`~/.codex/hooks.json` に置く形、会話の途中でエージェントが start したときの結び付け、MCP の投稿(どちらのホストでも)、Windows、Cursor、Claude.ai では試していません。