diff --git a/docs/guide/concepts.en.md b/docs/guide/concepts.en.md index a5c28577..d090db4c 100644 --- a/docs/guide/concepts.en.md +++ b/docs/guide/concepts.en.md @@ -129,7 +129,7 @@ To summarize: That `runs/*.json` is where a fact's value lives matters. merge rebuilds `candidates.csv` from it every time, so hand-edits to `candidates.csv` are overwritten and lost on the next `/factlog sync`. That is why correcting a value -goes through [`factlog amend`](../reference/review.en.md#reviewing-facts-factlog-review--accept--reject), +goes through [`factlog amend`](../reference/review.en.md), which updates both sides together. ## candidate vs accepted — the trust boundary diff --git a/docs/guide/concepts.md b/docs/guide/concepts.md index 89176e49..12071f76 100644 --- a/docs/guide/concepts.md +++ b/docs/guide/concepts.md @@ -123,7 +123,7 @@ Windows `C:\Users\<이름>`), `--target <경로>` 로 원하는 위치를 고를 `runs/*.json` 이 “사실의 원본”이라는 점이 중요합니다. merge가 매번 그로부터 `candidates.csv` 를 다시 만들기 때문에, `candidates.csv` 를 손으로 고치면 다음 `/factlog sync` 에 덮여 사라집니다. 그래서 값 교정은 양쪽을 함께 갱신하는 -[`factlog amend`](../reference/review.md#사실-검토-factlog-review--accept--reject) 를 +[`factlog amend`](../reference/review.md) 를 씁니다. ## candidate vs accepted — 신뢰 경계 diff --git a/docs/guide/use-cases.en.md b/docs/guide/use-cases.en.md index 005b0314..28a10ed6 100644 --- a/docs/guide/use-cases.en.md +++ b/docs/guide/use-cases.en.md @@ -59,4 +59,4 @@ walks the whole flow through once without your own data. - `/factlog sync` to produce candidate facts - `factlog review` to review the candidates - retire badly extracted candidates with `factlog reject`; for candidates that only need their wording tidied, fix the value with `factlog amend` and then approve with `factlog accept` (or `factlog amend --accept`) -- For details, see [Reviewing facts](../reference/review.en.md#reviewing-facts-factlog-review--accept--reject) +- For details, see [Reviewing facts](../reference/review.en.md) diff --git a/docs/guide/use-cases.md b/docs/guide/use-cases.md index 441530e1..7468b9f4 100644 --- a/docs/guide/use-cases.md +++ b/docs/guide/use-cases.md @@ -55,4 +55,4 @@ - `/factlog sync` 로 후보 사실을 만든다 - `factlog review` 로 후보를 검토한다 - 잘못 추출된 후보는 `factlog reject` 로 폐기하고, 표현만 다듬을 후보는 `factlog amend` 로 값을 고친 뒤 `factlog accept`(또는 `factlog amend --accept`)로 승인한다 -- 자세한 사용법은 [사실 검토](../reference/review.md#사실-검토-factlog-review--accept--reject) 참고 +- 자세한 사용법은 [사실 검토](../reference/review.md) 참고 diff --git a/docs/reference/review.en.md b/docs/reference/review.en.md index ab581663..eccc636e 100644 --- a/docs/reference/review.en.md +++ b/docs/reference/review.en.md @@ -1,9 +1,7 @@ -# Reviewing facts +# Reviewing facts (`factlog review` / `accept` / `reject`) > 🌐 **English** | [한국어](review.md) -## Reviewing facts (`factlog review` / `accept` / `reject`) - Extraction marks facts `candidate` or `needs_review`; only `confirmed`/`accepted` facts become engine input. Promote or retire them without hand-editing `facts/candidates.csv`: diff --git a/docs/reference/review.md b/docs/reference/review.md index cdbbb14c..d4cc53be 100644 --- a/docs/reference/review.md +++ b/docs/reference/review.md @@ -1,9 +1,7 @@ -# 사실 검토 +# 사실 검토 (`factlog review` / `accept` / `reject`) > 🌐 [English](review.en.md) | **한국어** -## 사실 검토 (`factlog review` / `accept` / `reject`) - 추출은 사실을 `candidate` 또는 `needs_review` 로 표시하며, `confirmed`/`accepted` 사실만 엔진 입력이 됩니다. `facts/candidates.csv` 를 직접 손대지 않고 승격하거나 폐기할 수 있습니다. diff --git a/tests/unit/test_review_doc_links.py b/tests/unit/test_review_doc_links.py new file mode 100644 index 00000000..91b8d7a8 --- /dev/null +++ b/tests/unit/test_review_doc_links.py @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: Apache-2.0 +"""Regression checks for the review-reference title and its inbound links (#283).""" +from __future__ import annotations + +import re +from pathlib import Path + +import pytest + + +ROOT = Path(__file__).resolve().parents[2] + + +def github_heading_slug(title: str) -> str: + """Model GitHub's anchor rule: removed punctuation leaves its spaces intact.""" + return re.sub(r"\s", "-", re.sub(r"[^\w\s-]", "", title.strip().lower())).strip("-") + + +@pytest.mark.parametrize( + ("review_path", "title", "legacy_anchor", "inbound_paths"), + [ + ( + "docs/reference/review.md", + "사실 검토 (`factlog review` / `accept` / `reject`)", + "사실-검토-factlog-review--accept--reject", + ("docs/guide/concepts.md", "docs/guide/use-cases.md"), + ), + ( + "docs/reference/review.en.md", + "Reviewing facts (`factlog review` / `accept` / `reject`)", + "reviewing-facts-factlog-review--accept--reject", + ("docs/guide/concepts.en.md", "docs/guide/use-cases.en.md"), + ), + ], +) +def test_review_title_has_no_duplicate_heading_and_preserves_old_anchor( + review_path: str, title: str, legacy_anchor: str, inbound_paths: tuple[str, str] +): + review = ROOT / review_path + text = review.read_text(encoding="utf-8") + + assert text.startswith(f"# {title}\n") + assert text.count(title) == 1 + assert github_heading_slug(title) == legacy_anchor + + relative_review = "../reference/" + review.name + for inbound_path in inbound_paths: + inbound = (ROOT / inbound_path).read_text(encoding="utf-8") + assert f"]({relative_review})" in inbound