chore: 문서 수정

This commit is contained in:
DongHyeonka
2026-07-29 18:29:25 +09:00
parent 3ac0a367dc
commit 4b7f1a90d2
29 changed files with 1594 additions and 747 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+159
View File
@@ -13,6 +13,50 @@ from tests.helpers import brief_dict, make_brief, make_sources
class LintTests(unittest.TestCase):
@staticmethod
def _korean_experience_brief(document_type: str = "technical_blog") -> Brief:
data = brief_dict(document_type)
data["title"] = "기술적 선택을 설명하는 글"
data["language"] = "ko-KR"
data["reader_goal"] = "안전한 구현 방식을 선택합니다"
data["core_message"] = "기술 선택은 문제와 비용을 함께 설명해야 합니다."
data["constraints"]["style_profile"] = "auto"
return Brief.from_dict(data)
@staticmethod
def _experience_document(
brief: Brief,
*,
marked_sections: set[int] | None = None,
body_by_section: dict[int, str] | None = None,
extra_by_section: dict[int, str] | None = None,
) -> tuple[str, object]:
sources = make_sources()
outline = create_outline(brief, sources)
marked_sections = (
set(range(len(outline.sections)))
if marked_sections is None
else marked_sections
)
body_by_section = body_by_section or {}
extra_by_section = extra_by_section or {}
lines = [f"# {brief.title}", ""]
for index, section in enumerate(outline.sections):
lines.extend([f"## {section.title}", ""])
if index in body_by_section:
lines.append(body_by_section[index])
else:
subject = "저는 " if index in marked_sections else ""
lines.append(
f"{subject}이 절의 입력과 실제 동작을 확인했습니다. "
"현재 구현은 명시된 경계를 사용합니다. "
"대안과 비용, 검증 범위도 함께 설명합니다."
)
if index in extra_by_section:
lines.extend(["", extra_by_section[index]])
lines.append("")
return "\n".join(lines), outline
def test_mock_document_meets_structural_gate(self) -> None:
brief = make_brief()
sources = make_sources()
@@ -142,6 +186,121 @@ class LintTests(unittest.TestCase):
self.assertIn("STYLE001", {issue.code for issue in report.issues})
self.assertEqual(report.metrics["formulaic_ordinal_opening_count"], 3)
def test_korean_experience_contract_blocks_plain_form_endings(self) -> None:
brief = self._korean_experience_brief()
sources = make_sources()
text, outline = self._experience_document(
brief,
extra_by_section={0: "현재 구현은 이 값을 사용한다."},
)
report = lint_document(text, brief, outline, sources)
issues = [issue for issue in report.issues if issue.code == "STYLE002"]
self.assertEqual(len(issues), 1)
self.assertEqual(issues[0].severity, Severity.BLOCKER)
self.assertEqual(report.metrics["plain_form_ending_count"], 1)
def test_korean_style_lint_exempts_non_reader_prose(self) -> None:
brief = self._korean_experience_brief()
sources = make_sources()
text, outline = self._experience_document(
brief,
extra_by_section={
0: (
"### 현재 구현은 사용한다.\n\n"
"> 원문 인용은 현재 구현을 사용한다.\n\n"
"항목 | 설명\n"
"--- | ---\n"
"현재 값 | 현재 구현은 사용한다.\n\n"
"![현재 구현은 사용한다.](diagram.svg)\n\n"
" 명령 출력은 현재 구현을 사용한다.\n\n"
"`현재 구현은 사용한다.`\n\n"
"직접 기록에는 “현재 구현은 사용한다.”라고 적혀 있습니다.\n\n"
"```text\n"
"현재 구현은 사용한다.\n"
"```"
)
},
)
report = lint_document(text, brief, outline, sources)
self.assertNotIn("STYLE002", {issue.code for issue in report.issues})
self.assertEqual(report.metrics["plain_form_ending_count"], 0)
def test_korean_style_lint_requires_first_person_opening(self) -> None:
brief = self._korean_experience_brief()
sources = make_sources()
text, outline = self._experience_document(
brief,
marked_sections=set(range(1, 8)),
)
report = lint_document(text, brief, outline, sources)
issues = [issue for issue in report.issues if issue.code == "STYLE003"]
self.assertEqual(len(issues), 1)
self.assertEqual(issues[0].severity, Severity.BLOCKER)
self.assertFalse(report.metrics["opening_has_first_person"])
def test_korean_style_lint_requires_major_section_coverage(self) -> None:
brief = self._korean_experience_brief()
sources = make_sources()
text, outline = self._experience_document(
brief,
marked_sections={0},
)
report = lint_document(text, brief, outline, sources)
self.assertIn("STYLE003", {issue.code for issue in report.issues})
self.assertEqual(report.metrics["experience_section_count"], 8)
self.assertEqual(report.metrics["marked_experience_section_count"], 1)
self.assertEqual(report.metrics["experience_section_coverage"], 0.125)
def test_korean_style_lint_ignores_non_prose_sections(self) -> None:
brief = self._korean_experience_brief()
sources = make_sources()
text, outline = self._experience_document(
brief,
marked_sections={0, 1},
body_by_section={
4: "```text\n현재 구현은 사용한다.\n```",
5: "항목 | 값\n--- | ---\n구현 | 현재 값",
6: "![구조 그림](diagram.svg)",
7: "> 원문 인용만 남아 있습니다.",
},
)
report = lint_document(text, brief, outline, sources)
self.assertNotIn("STYLE003", {issue.code for issue in report.issues})
self.assertEqual(report.metrics["experience_section_count"], 4)
self.assertEqual(report.metrics["marked_experience_section_count"], 2)
self.assertEqual(report.metrics["experience_section_coverage"], 0.5)
def test_korean_style_lint_accepts_compliant_experience_prose(self) -> None:
brief = self._korean_experience_brief("readme")
sources = make_sources()
text, outline = self._experience_document(
brief,
marked_sections={0, 2, 4, 6},
)
report = lint_document(text, brief, outline, sources)
codes = {issue.code for issue in report.issues}
self.assertNotIn("STYLE002", codes)
self.assertNotIn("STYLE003", codes)
self.assertEqual(
report.metrics["style_contract"],
"korean_first_person_experience_v1",
)
self.assertTrue(report.metrics["opening_has_first_person"])
self.assertEqual(report.metrics["first_person_marker_count"], 4)
self.assertEqual(report.metrics["experience_section_coverage"], 0.5)
def test_numbered_procedure_is_not_formulaic_ordinal_prose(self) -> None:
data = brief_dict()
data["title"] = "기술적 선택을 설명하는 글"