PJR-PP0D exec plan生成時にアンダースコア識別子や_TODO_がMarkdown強調記号として誤解釈され破損する
1. 概要
登録簿の説明文などに含まれるregister_date_timezoneのようなアンダースコア入り識別子や_TODO_/_ASSUMPTION_プレースホルダが、exec plan生成パイプラインを通る際にバッククォートでエスケープされず、Markdownの強調記号として誤って解釈され一部が破損する(例: register_date_timezone が register*date_timezone のように壊れる)。結果としてmarkdownlintのMD049エラーでcommitがブロックされる(PJR-0XXZのclose時に実際に発生し手動修正した)。plan生成時に識別子・プレースホルダ相当の文字列を適切にエスケープ(バッククォート化)する。
prj-0001:pjr-0xxz-pjr-index のclose時に実際に発生した不具合。src/exec-register.tsの_PJR_DESCRIPTION_プレースホルダ置換(約291行目)がitem.description(pjr-index.mdの説明列の値)をエスケープせずそのままplan本文へ埋め込むため、説明文にregister_date_timezoneのようなアンダースコア入り識別子や_TODO_/_ASSUMPTION_が含まれると、生成されたplanのMarkdownとして誤って強調記号(_..._/*...*)に解釈され、一部が破損する(例: register_date_timezone が register*date_timezone のように壊れる)。破損したplanはmarkdownlintのMD049(強調スタイル不統一)でcommitがブロックされる。
2. 完了条件
_PJR_DESCRIPTION_(および同様に登録簿の自由記述をplan/result本文へ埋め込む他のプレースホルダ)が、Markdownの強調記号・コードスパン等に誤解釈されない形でエスケープまたはコードスパン化されて埋め込まれる。- アンダースコアを含む識別子(例:
register_date_timezone)や_TODO_/_ASSUMPTION_を含む説明文からplanを生成した場合に、生成物がmarkdownlint(MD049含む)でエラーにならないことが自動テストで確認できる。 - 過去にこの問題で修正した実例(PJR-0XXZの手動修正内容)と同等のケースが再発しないことをテストで担保する。
- 修正が
_PJR_DESCRIPTION_以外の類似プレースホルダ(exec-plans.ts・exec-register.tsの他テンプレート変数)にも同じリスクがないか確認され、必要な範囲に適用されている。
3. 作業内容
| No | 作業 | 担当 | 状態 | メモ |
|---|---|---|---|---|
| 1 | _PJR_DESCRIPTION_置換箇所とexpandTemplateの実装を確認する | ARC | done | src/exec-register.tsのgenerateRegisterPlan、exec-shared.ts |
| 2 | Markdown特殊文字(_・*・`・|等)を安全に埋め込む方式を実装する | ARC | done | code span 化を選定(prettier がバックスラッシュ抑制を除去するため) |
| 3 | 他のテンプレート変数への同種リスクを洗い出し、必要なら同様の対応を行う | ARC | done | title/description のみ自由記述。enum/日付/ID列は制約付きで対象外 |
| 4 | 自動テストを追加する | ARC | done | 生成 plan を markdownlint にかけ MD049/MD050 が出ないことを検証 |
4. 対応結果
src/exec-shared.tsにescapeMarkdownInlineを追加。_/*を含む ASCII トークン(register_date_timezone・_TODO_等)をバッククォートの code span で包み、Markdown 強調記号としての誤解釈を防ぐ。既存の code span は温存し、日本語などマルチバイト文字はトークン境界となり巻き込まない。- バックスラッシュエスケープ(
\_)は不採用。生成パイプライン末尾のformatMarkdownFile(prettier)が「不要」と判定した抑制を除去して生のアンダースコアへ戻すため、code span 化のみが prettier を通しても安定する。 src/exec-register.tsのgenerateRegisterPlanで、自由記述列由来の_PJR_TITLE_・_PJR_DESCRIPTION_にescapeMarkdownInlineを適用。frontmatter のnameは YAML 値(本文レンダリング対象外)のためitem.titleのまま据え置く。- 自由記述はこの2列のみで、
_PJR_TYPE_(enum)・_PJR_PRIORITY_(enum)・_PJR_OWNER_(role/nickname)・_PJR_DUE_(日付)・_PJR_ID_(PJR-XXXX)は制約付きの値のため対象外とした。 - テスト
tests/src/exec-register-plan-escape.test.tsを追加。escapeMarkdownInlineの単体検証に加え、PJR-0XXZ 実例相当(register_date_timezone・_TODO_・_ASSUMPTION_を含む説明)からgenerateRegisterPlanで生成した plan を markdownlint にかけ MD049/MD050 違反が出ないこと、エスケープ前の生の説明文は違反することを対照で確認する。