﻿RC_Tests 自然言語仕様

【この文書の目的】
この自然言語仕様に従い、Windowsのデスクトップ版Wordで動くVBAの標準モジュールを作成する。対象モジュール名はこの文書の先頭に示す。関数名、引数の順序、辞書キーを変更しない。変数宣言を必須にし、手動で標準モジュールへ貼り付ける形式で作成する。属性行やThisDocument用のイベントは不要。
他モジュールの公開処理を呼び出す部分は、その処理の存在を前提とする。同じ公開関数を各モジュールへ重複実装しない。不明な会社書式は確認してから記入し、勝手に推測しない。

【ツール全体の契約】
・旧規程と新規程を読み取り専用で解析し、新欄が左、旧欄が右の編集可能なWord表を別ファイルへ保存する。入力を上書きしない。
・外部AI、外部通信、追加ソフト、外部テンプレートを実行時に使わない。Wordの標準オブジェクトと、遅延バインディングによるScripting.Dictionary、Scripting.FileSystemObject、VBScript.RegExpを使う。追加の参照設定を要求しない。
・通常の成功時はdocxだけを出力する。確認レポート、対応表TSV、手動対応を読み込んで再生成する機能は作らない。RC_Reportモジュールも作らない。
・issuesは処理中だけの内部診断。致命的な失敗時の画面表示と実行失敗TXTは残す。RC_Testsを明示実行した場合のテストTXTは別扱い。
・フォントや余白の変更は本文の変更とみなさない。原文の数字、否定語、句読点、空白、タブを言い換えたり削除したりしない。照合専用の正規化を原文や下線位置へ適用しない。
・Office、Wordのマクロ設定、OSのセキュリティ設定は変更しない。自分が開いた入力や作成した文書だけを閉じる。

【共通データ構造】
以下のキーは大文字小文字を含めて統一する。辞書中のオブジェクトはオブジェクトとして格納・差し替えし、文字列化しない。存在しない片側ノードは空文字ではなくNothingとする。Collectionの添字と文字位置は1始まり。

1. 解析文書：sourceは入力パスまたは識別文字列、titleは文書名、articlesは条ノードのCollection、historyは末尾履歴ノードのCollection、extrasは条に属さない保全ノードのCollection。
2. ノード：id、kind、prefix、gap、body、raw、heading、line、children。
  idは解析順ID。条はA001等、項はA001.P001等、号はA001.P001.I001等、履歴はH001等、未知段落はUに元段落番号を続ける。
  kindはarticle、paragraph、item、history、unknownのいずれか。prefixは元の番号文字列、gapは番号と本文の間の元の空白等、bodyは番号を除く本文、rawはprefix・gap・bodyをそのまま連結したもの。headingは条の直前の括弧見出し、lineは元入力の段落位置、childrenは子ノードのCollection。
  条ノード自身のbodyは空文字。その条の先頭本文は第1項ノードP001へ入れる。P001のprefixには元の第n条の番号を入れ、項番号「1」を新たに補わない。条ノードのrawは元番号とgapだけとなる。条にはheadingLineも加え、見出しの元段落位置を記録する。
3. 対応ペア：newとoldは新旧ノードまたはNothing、scoreはDoubleの類似度、statusはauto、review、new、deletedのいずれか、childrenは子対応ペアのCollection。
4. 内部診断：kind、location、reason、rawの4文字列を持つ辞書をissuesのCollectionへ追加する。利用者向けの確認レポートへ書き出さない。
5. 差分結果：newとoldは各側の下線区間Collection、fallbackは長文の代替計算を使ったBoolean。区間はstartという1始まり文字位置とlengthという文字数を持つ辞書。改行や空白を含む原文字列上の位置を使う。
6. 出力行：newTextとoldText、newHeadingとoldHeading、newHeadingBlankとoldHeadingBlank、newPrefixとoldPrefix、newArticleとoldArticle、newNoteとoldNote、historyGap、newSpansとoldSpans。
  TextとNoteは文字列。HeadingとPrefixは文字数のLong。HeadingBlank、Article、historyGapはBoolean。Spansは上記の下線区間Collection。初期値は文字列が空、文字数が0、BooleanがFalse、Collectionは空。

【モジュール間の公開処理】
RC_Configは設定定数、RC_Color、RC_Navy、RC_HeaderFill、RC_Regex、RC_TrimSpace、RC_MatchText、RC_NumberKeyを提供する。
RC_ParseはRC_Dict、RC_Node、RC_ParseText、RC_ReadDocument、RC_ParseLines、RC_NodeText、RC_AddIssueを提供する。
RC_MatchはRC_Similarity、RC_MatchScore、RC_NewPair、RC_Align、RC_PairChangedを提供する。
RC_CharDiffはRC_Diff、RC_AddSpanを提供する。
RC_OutputはRC_OutputDocumentを提供する。
RC_MainはCreateComparisonTable、RC_ShowOutput、RC_RunFiles、RC_UniqueBase、RC_WriteTextを提供する。
RC_Testsは任意の開発用RC_TestAllを提供する。通常の入口からテストを実行しない。
主な呼出し：MainがParseで旧・新を読み、Matchへ新articles・旧articles・issues・locationの順で渡し、Outputへpairs・新解析文書・旧解析文書・issuesの順で渡す。OutputがCharDiffを呼び、各処理がConfigとParseの共通処理を使う。

【他モジュールを呼ぶ際の引数契約】
次の一覧は呼出し互換性のために示す。この文書の対象以外のモジュールの実装を重複して作らない。
RC_Main
・CreateComparisonTable：公開。引数はなし。戻り値なし。
・RC_ShowOutput：公開。引数はoutput（String、値渡し）。戻り値なし。
・RC_RunFiles：公開。引数はoldPath（String、値渡し）、newPath（String、値渡し）、outputFolder（String、値渡し）。戻り値はString。
・RC_UniqueBase：公開。引数はfolder（String、値渡し）、stem（String、値渡し）。戻り値はString。
・RC_WriteText：公開。引数はpath（String、値渡し）、text（String、値渡し）。戻り値なし。
RC_Config
・RC_Color：公開。引数はhexRGB（String、値渡し）。戻り値はLong。
・RC_Navy：公開。引数はなし。戻り値はLong。
・RC_HeaderFill：公開。引数はなし。戻り値はLong。
・RC_Regex：公開。引数はpattern（String、値渡し）。戻り値はObject。
・RC_TrimSpace：公開。引数はtext（String、値渡し）。戻り値はString。
・RC_MatchText：公開。引数はtext（String、値渡し）。戻り値はString。
・RC_NumberKey：公開。引数はprefix（String、値渡し）。戻り値はString。
RC_Parse
・RC_Dict：公開。引数はなし。戻り値はObject。
・RC_Node：公開。引数はnodeId（String、値渡し）、kind（String、値渡し）、prefix（String、値渡し）、gap（String、値渡し）、body（String、値渡し）、line（Long、値渡し）。戻り値はObject。
・RC_ParseText：公開。引数はtext（String、値渡し）、source（String、値渡し）、issues（Collection、値渡し）。戻り値はObject。
・RC_ReadDocument：公開。引数はpath（String、値渡し）、issues（Collection、値渡し）。戻り値はObject。
・RC_ParseLines：公開。引数はlines（Variant、値渡し）、source（String、値渡し）、issues（Collection、値渡し）。戻り値はObject。
・RC_NodeText：公開。引数はn（Object、値渡し）、includePrefix（Boolean、値渡し、省略可能・既定値False）。戻り値はString。
・RC_AddIssue：公開。引数はissues（Collection、値渡し）、kind（String、値渡し）、location（String、値渡し）、reason（String、値渡し）、raw（String、値渡し）。戻り値なし。
RC_Match
・RC_Similarity：公開。引数はleftText（String、値渡し）、rightText（String、値渡し）。戻り値はDouble。
・RC_MatchScore：公開。引数はnn（Object、値渡し）、oo（Object、値渡し）、ni（Long、値渡し）、oi（Long、値渡し）、nc（Long、値渡し）、oc（Long、値渡し）。戻り値はDouble。
・RC_NewPair：公開。引数はnn（Object、値渡し）、oo（Object、値渡し）、score（Double、値渡し）、status（String、値渡し）。戻り値はObject。
・RC_Align：公開。引数はnews（Collection、値渡し）、olds（Collection、値渡し）、issues（Collection、値渡し）、location（String、値渡し）。戻り値はCollection。
・RC_PairChanged：公開。引数はpair（Object、値渡し）。戻り値はBoolean。
RC_CharDiff
・RC_Diff：公開。引数はnews（String、値渡し）、olds（String、値渡し）。戻り値はObject。
・RC_AddSpan：公開。引数はspans（Collection、値渡し）、first（Long、値渡し）、length（Long、値渡し）。戻り値なし。
RC_Output
・RC_OutputDocument：公開。引数はpairs（Collection、値渡し）、newDoc（Object、値渡し）、oldDoc（Object、値渡し）、issues（Collection、値渡し）。戻り値はDocument。
RC_Tests
・RC_TestAll：公開。引数はoutputFolder（String、値渡し）。戻り値はString。

【共通の境界条件】
自動採番、複雑な表、画像、脚注、本文外の図形、変更履歴の解釈は全面対応しない。内部診断と入力原本を保全するが、抽出できないものを架空の条文へ変換しない。
分割・統合の意味を自動で確定しない。残った原文を新設・削除として保全する。一般的な1対多分割の検出を保証しない。条の順序逆転を見やすく示す改善も別課題であり、この再構築で勝手に照合方式を変えない。
この文書は現行処理を再実装するための仕様。AIが生成したVBAのコンパイル・動作・原文保全は、Wordで別途確認する。

【このモジュールの入口・引数・戻り値】
・RC_TestAll：公開。引数はoutputFolder（String、値渡し）。戻り値はString。
・RC_Assert：モジュール内専用。引数はcondition（Boolean、値渡し）、title（String、値渡し）、log（String、参照渡し）。戻り値なし。
・RC_FindPair：モジュール内専用。引数はpairs（Collection、値渡し）、newId（String、値渡し）。戻り値はObject。
・RC_SpanText：モジュール内専用。引数はtext（String、値渡し）、spans（Collection、値渡し）。戻り値はString。
・RC_CheckCoverage：モジュール内専用。引数はpairs（Collection、値渡し）、used（Object、値渡し）。戻り値なし。

【担当範囲】
任意の開発用回帰テスト。通常のCreateComparisonTableからは呼ばない。VBAとして実行できたことと静的なテキスト検査は区別する。生成時の同一条件で28項目に戻すのではなく、手動対応を除いた27項目を作る。

【RC_TestAll】
指定出力フォルダーに対し、開始時刻付きのログ文字列を作る。各ケースでは新しいissuesを作り、RC_ParseTextとRC_Alignへ与える。必要なときだけRC_OutputDocumentで自分の検査用文書を作り、保存せず閉じる。テスト完了後、重複しない「VBA回帰テスト_日時.txt」をRC_UniqueBaseとRC_WriteTextで保存し、同じログを返す。
失敗時は自分の検査用Documentだけを保存せず閉じ、FAILと理由を付けた「VBA回帰テスト失敗_日時.txt」を可能な範囲で保存する。成功と表示せず、テストのエラーを再送出する。

【27項目：入力と期待結果】
1. 文書名「試験規程」、見出し「（目的）」、第１条「利用目的を定める。」、第２項「本人へ通知する。」、その号「書面で通知する。」を両側同一で比較。対応条1件、変更False、issues0。
2. 上記の条のchildrenが2項。
3. 上記の第2項のchildrenが1号。
4. 上記の第１条番号だけ第２条へ変更すると、対応条1件で変更True。
5. 4を出力すると先頭項の新に変更なし注記、旧に省略注記が含まれる。
6. 4の出力の変わった全角条番号数字だけに下線がある。元の検査では先頭項セルの7文字目の下線を確認する。
7. 番号内空白・行頭タブ付き「第 １ 条」、半角「 2」とタブ、半角括弧内空白付き「 ( 1 )」を解析し、1条・2項・第2項内1号となる。
8. 見出しは「（申請）」。旧第1項本文は「申請書は受付へ提出する。」、旧第2項本文は「結果は本人へ通知する。」。新第2項に「緊急の連絡先を事前に登録しなければならない。」を挟み、旧第2項を新第3項へずらす。新A001.P003は旧A001.P002へ対応し、bodyは同一。
9. 旧の号は申請書、審査結果通知書、保存期間台帳。新から中間号を消して保存期間台帳を第2号へ詰める。新I002が旧I003へ対応する。
10. 9の出力で親の「次の各号とする。」の柱書を新旧とも全文掲載する。
11. 部門長対所属長で差分文字列が新「部門」、旧「所属」。
12. 文書管理システム対管理台帳で両語句全体が差分文字列。
13. ５年間対３年間で数字だけが差分。
14. 許可する。対許可しない。で両側に差分が存在し、否定を落とさない。
15. 本文。対本文で新の句点だけが差分。
16. 同一対同一で両区間Collectionは0件。
17. 1500文字のaに新b、旧cを付けた長文でfallback=True、新差分bだけ。
18. 旧は申請条「申請書は総務窓口に提出する。」、次に保管条「原本は鍵付き保管庫に保存する。」。新は見出しと本文を保持し保管・申請へ順序を逆転、番号も振り直す。対応2件で新1→旧A002、新2→旧A001、issues0。これは現行照合の回帰であり、逆転表示の改善を検証済みという意味ではない。
19. 18をRC_CheckCoverageすると新旧各条と先頭項を含め8ノードで、重複なし。
20. 同じ見出しと「担当者は必要な記録を保存する。」を持つ2条のうち第1条番号だけ第3条へ変える。複数の同内容候補があるのでissuesが1件以上。
21. 20の新旧全ノードが重複せず8件保持される。
22. 見出しは各条とも「（手続）」。旧第1条本文は「申請は書面で行い、担当者が申請内容を審査し、審査結果を通知し、保存期限まで申請記録を保管する。」。新第1条本文は「申請は書面で行い、担当者が申請内容を審査し、審査結果を通知する。」、新第2条本文は「担当者が申請内容を審査し、審査結果を通知し、保存期限まで申請記録を保管する。」。分割候補のissuesが1件以上。
23. 22の元ノードが新旧合計6件、重複なしで保全される。
24. 22の新旧を逆に渡した統合ケースでissuesが1件以上。
25. 24の元ノードが新旧合計6件、重複なしで保全される。
26. 条の後に「未認識の続き段落を保全する。」を追加するとissues1件で、その全文が第1項のunknown子ノードrawに残る。
27. 旧の見出しは「（旧）」、新は「（新）」。同じ第1条番号でも、旧本文「工場の温度センサーは月曜日に点検する。」、新本文「国内出張の宿泊費上限を宿泊地別に定める。」という無関係な内容なら、対応ではなく新設・削除の2ペアになる。
ケースの原文はここに挙げた語句を用い、比較の差を変えない。条番号と項番号を通常文字で入れ、入力の段落はCRで区切る。

【補助処理】
RC_Assertは条件がFalseなら項目名を理由にエラー、TrueならPASSと項目名をログ末尾へ追加する。
RC_FindPairはpairsを走査し、新ノードがありidが指定newIdに一致するペアを返す。見つからなければ対応がないエラー。
RC_SpanTextはspansを順に走査し、元文字列のstartからlength文字を取り出して連結する。
RC_CheckCoverageは全ペアを再帰走査し、新側は「new:」とid、旧側は「old:」とidをキーにused辞書へrawを入れる。同じキーが既にあれば原文重複としてエラーにする。片側Nothingは数えない。空のchildrenも正常に扱う。

【テスト範囲】
27項目は現在の処理の回帰。一般的な分割検出、複雑な表・画像、自動採番、実規程の順序逆転を全面保証するテストへ言い換えない。フォント・表罫線・最新履歴・行位置の完全検証は生成されたWordの構造と全ページの描画を別途確認する。
