feat: data bootstrap + health check + Codex P1 regression tests - #9
Conversation
1. scripts/bootstrap_morph_data.sh morphhb (sparse clone, wlc/ only) と morphgnt を data/ 配下に配置する。 データなしでもアプリは正常動作する(unavailable を返すのが正しい挙動)。 2. GET /api/lexicon/health morphhb/morphgnt の配置状態、correspondence_index のエントリ数、 verify_verse のサニティチェック結果を返す。 データ未配置でも 200 — "missing" は故障ではなく状態の記述。 3. biblical_correspondence/tests/test_lexicon_health.py (22 tests) - verify_verse が unavailable 時に contains=None を返すことを固定(Codex P1 回帰防止) - not_found と unavailable が混在しないことを各ケースで確認 - correspondence_lookup の三状態(found/not_found/unavailable)を固定 - /api/lexicon/health エンドポイントの HTTP 応答を固定 全 22 テスト、データ未配置環境でパス。 4. README_DATA.md 「データなし ≠ 故障」「unavailable ≠ not_found」を明記。 三状態の意味・bootstrap 手順・ライセンスを記載。 https://claude.ai/code/session_017WKYFbVsWhWZA3M8Jc1eKs
There was a problem hiding this comment.
Code Review
This pull request introduces a robust data management and health monitoring system for biblical morphological data. Key additions include a /health endpoint for status tracking, a bootstrap script for automated data acquisition, and documentation clarifying the 'three-state' logic for data availability. Feedback suggests optimizing the /health endpoint by moving imports to the top level and improving the efficiency of entry counting in the correspondence index. Additionally, the reviewer recommended safer directory copying in the shell script to prevent nested paths and better error handling to avoid silent failures.
| operational — morphhb が存在し、サニティチェック(Gen.3.5/H3045)が found を返す | ||
| degraded — morphhb 未配置(unavailable を返す正常動作) | ||
| """ | ||
| from pathlib import Path |
| try: | ||
| with open(corr_index_path, encoding="utf-8") as f: | ||
| corr_entry_count = len(json.load(f).get("entries", [])) | ||
| except Exception: | ||
| pass |
| git sparse-checkout set "$MORPHHB_SUBDIR" | ||
| ) | ||
|
|
||
| cp -r "$TMPDIR_HEB/morphhb/$MORPHHB_SUBDIR" "$MORPHHB_DEST" |
There was a problem hiding this comment.
cp -r は、コピー先ディレクトリが既に存在する場合に意図せず階層が深くなる(wlc/wlc になる)可能性があります。mkdir -p でディレクトリを作成した上で、中身のみをコピーする(例: cp -r src/. dest/)方法がより安全です。同様の箇所が 73 行目にもあります。
| cp -r "$TMPDIR_HEB/morphhb/$MORPHHB_SUBDIR" "$MORPHHB_DEST" | |
| mkdir -p "$MORPHHB_DEST" | |
| cp -r "$TMPDIR_HEB/morphhb/$MORPHHB_SUBDIR/." "$MORPHHB_DEST/" |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44bdd8b670
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| trap 'rm -rf "$TMPDIR_GRK"' EXIT | ||
|
|
||
| git clone --depth 1 "$MORPHGNT_REPO" "$TMPDIR_GRK/morphgnt" | ||
| cp -r "$TMPDIR_GRK/morphgnt" "$MORPHGNT_DEST" |
There was a problem hiding this comment.
Copy dataset contents without nesting destination directories
This cp -r call copies the entire cloned morphgnt directory into data/morphgnt when data/morphgnt already exists, producing data/morphgnt/morphgnt/... instead of files at data/morphgnt/*.txt. In that state, MORPHGNT_PATH.glob("*.txt") finds nothing, so Greek data remains effectively unavailable even though bootstrap reports success. This is reproducible whenever a stale/empty destination directory exists from a prior partial setup.
Useful? React with 👍 / 👎.
| os.environ.setdefault("MORPHHB_PATH", str(_BC_DIR / "data" / "__nonexistent_morphhb__")) | ||
| os.environ.setdefault("MORPHGNT_PATH", str(_BC_DIR / "data" / "__nonexistent_morphgnt__")) |
There was a problem hiding this comment.
Force test data paths instead of honoring pre-set environment
Using setdefault here makes these regression tests depend on external environment state: if MORPHHB_PATH/MORPHGNT_PATH are already set (for example by a developer shell or CI job), the tests run against real data and assertions expecting status == "unavailable" will fail. That makes the new safety suite non-deterministic and can hide or spuriously report regressions.
Useful? React with 👍 / 👎.
cp -r src/wlc dest/wlc は dest/wlc が既存の場合 dest/wlc/wlc/ になる。 mkdir -p + cp -r src/wlc/. dest/wlc/ 形式に統一し、 実行回数・dest の存在状態に依らず冪等にする。morphgnt も同様。 https://claude.ai/code/session_017WKYFbVsWhWZA3M8Jc1eKs
setdefault は環境変数が既に設定されていると上書きしない。 実環境に morphhb が配置済みの場合、Codex P1 回帰テストが unavailable ではなく found を返し、バグを見逃す。 os.environ["MORPHHB_PATH"] / ["MORPHGNT_PATH"] の強制代入に変更し、 このテストファイルを外部環境から完全に独立させる。 回帰防止テストは、環境依存をゼロにしないと意味がない。 https://claude.ai/code/session_017WKYFbVsWhWZA3M8Jc1eKs
except Exception: pass はログも状態フラグもなく全エラーを飲む。 JSON パースエラーとファイル読み取りエラーを別々に捕捉し、 ログに記録した上でレスポンスの correspondence_index.error に含める。 entry_count=0 のまま通過するが、原因が response で可視になる。 https://claude.ai/code/session_017WKYFbVsWhWZA3M8Jc1eKs
目的
「データなし=故障」という誤解を潰す。利用者から見て
unavailableが故障に見える危険を除去する。追加内容
1.
scripts/bootstrap_morph_data.shmorphhb(ヘブライ語形態論 XML)と morphgnt(ギリシャ語形態論)を
data/配下に配置する導線。wlc/のみ取得、全履歴不要)2.
GET /api/lexicon/health{ "morphhb": {"status": "missing", "path": "...", "xml_files": 0}, "morphgnt": {"status": "missing", "path": "...", "txt_files": 0}, "correspondence_index": {"entry_count": 18}, "verify_verse_status": "degraded", "verify_verse_detail": "morphhb missing — verify_verse returns unavailable (expected behavior)", "note": "morphhb/morphgnt missing は故障ではない。..." }verify_verse_status:operational(morphhb あり + サニティチェック通過)/degraded(データなし)noteフィールドで「missing ≠ 故障」を明示データ配置後の期待値:
{ "morphhb": {"status": "available", "xml_files": 39}, "morphgnt": {"status": "available", "txt_files": 27}, "verify_verse_status": "operational", "verify_verse_detail": "Gen.3.5/H3045 → found ✓" }3.
tests/test_lexicon_health.py(22 tests)Codex P1 回帰防止が主目的。
TestVerseVerifyUnavailablecontains=None(Falseではない)を固定TestVerseVerifyBadRefunavailableを返すことを固定TestLookupWordTestCorrespondenceLookupfound/not_found/unavailableの三状態を固定TestHealthEndpoint/api/lexicon/healthの HTTP 応答を固定Codex P1 の核心を固定するテスト:
4.
README_DATA.md変更なし
app.pyロジック変更なしbiblical_lexicon.py変更なし実行方法
https://claude.ai/code/session_017WKYFbVsWhWZA3M8Jc1eKs
Generated by Claude Code