refactor: 문서 개선 중

This commit is contained in:
donghyeon-ka
2026-09-21 14:30:55 +09:00
parent c93cdea150
commit 805a18f486
1497 changed files with 525837 additions and 59152 deletions
+129
View File
@@ -182,6 +182,49 @@ class ContractTest(unittest.TestCase):
with Fixture(mutate(source=["analysis/05-persistence.md §3.5"])):
self.assertIn("근거가 SSOT 밖에만 있다", verifier.verify("fixture").warns)
def test_numbered_ssot_anchor_is_resolved_against_heading(self):
index = copy.deepcopy(INDEX)
index["candidateScope"]["sections"] = ["§3"]
index["topics"]["session-custody"]["kinds"]["case"][0]["source"] = [
"final/document.md#§3.1"
]
index["topics"]["session-custody"]["kinds"]["concept"][0]["source"] = [
"final/document.md#§3.1"
]
with Fixture(index) as fx:
ssot = os.path.join(fx.base, "final/document.md")
open(ssot, "w", encoding="utf-8").write(
"# fixture\n\n## 3. 세션\n\n### 3.1 교환\n\n내용\n"
)
data = fx.read()
data["ssotSha256"] = hashlib.sha256(open(ssot, "rb").read()).hexdigest()
fx.write(data)
report = verifier.verify("fixture")
self.assertNotIn("앵커가 검사 가능한 절 제목/번호 형식이 아니다", report.warns)
self.assertNotIn("SSOT 에 없는 번호 절을 가리키는 앵커", report.errors)
def test_missing_numbered_ssot_anchor_is_an_error(self):
index = copy.deepcopy(INDEX)
index["candidateScope"]["sections"] = ["§3"]
index["topics"]["session-custody"]["kinds"]["case"][0]["source"] = [
"final/document.md#§3.9"
]
index["topics"]["session-custody"]["kinds"]["concept"][0]["source"] = [
"final/document.md#§3.1"
]
with Fixture(index) as fx:
ssot = os.path.join(fx.base, "final/document.md")
open(ssot, "w", encoding="utf-8").write(
"# fixture\n\n## 3. 세션\n\n### 3.1 교환\n\n내용\n"
)
data = fx.read()
data["ssotSha256"] = hashlib.sha256(open(ssot, "rb").read()).hexdigest()
fx.write(data)
self.assertIn(
"SSOT 에 없는 번호 절을 가리키는 앵커",
verifier.verify("fixture").errors,
)
def test_readiness_is_not_publication(self):
with Fixture(mutate(readiness="NEEDS_EVIDENCE")):
self.assertIn("글을 쓰면 안 되는 readiness 인데 기록이 있다",
@@ -191,6 +234,39 @@ class ContractTest(unittest.TestCase):
with Fixture(mutate(readiness="REJECTED")):
self.assertIn("readiness 값이 계약에 없다", verifier.verify("fixture").errors)
def test_resolved_question_is_a_valid_written_state(self):
index = copy.deepcopy(INDEX)
question = {
"title": "이미 답을 얻은 질문",
"kind": "question",
"slug": "resolved-question",
"readiness": "RESOLVED",
"source": ["final/document.md#fixture"],
"known": "직접 관측으로 답을 얻었다",
"unknown": "후속 조건만 남았다",
"next-verification": "후속 조건을 별도 검증한다",
"decision-criterion": "직접 관측으로 닫혔다",
"relations": ["case:session-split-across-nodes"],
}
index["topics"]["session-custody"]["kinds"]["question"] = [question]
index["candidates"].append({
"id": "F004",
"disposition": "PROMOTE",
"dispositionReview": "CONFIRMED",
"target": "question:resolved-question",
})
with Fixture(index) as fx:
folder = os.path.join(fx.studio, "session-custody/question")
os.makedirs(folder, exist_ok=True)
open(os.path.join(folder, "question-resolved.md"), "w", encoding="utf-8").write(
"---\nkind: QUESTION\nslug: resolved-question\n"
"title: 이미 답을 얻은 질문\ntopic: session-custody\n"
"project: fixture\nquestionStatus: RESOLVED\n---\n"
)
report = verifier.verify("fixture")
self.assertNotIn("QUESTION readiness 는 OPEN 또는 RESOLVED 다", report.errors)
self.assertNotIn("글을 쓰면 안 되는 readiness 인데 기록이 있다", report.errors)
def test_record_outside_the_contract_is_an_error(self):
with Fixture() as fx:
os.makedirs(os.path.join(fx.studio, "orphan-topic/concept"))
@@ -421,6 +497,44 @@ class LayoutTest(unittest.TestCase):
self.assertIn("기록이 가리키는 그림에 techviz 정본이 없다",
layout.verify("fixture").warns)
def test_context_snapshot_detects_ssot_drift_without_techviz_tool(self):
with Fixture() as fx:
fx.diagram("context-map", cited=True)
document = os.path.join(fx.base, "final/document.md")
open(document, "w", encoding="utf-8").write(
"# fixture\n\n## 1. 이전\n\n그대로\n\n"
"## 2. 대상\n\n그림 근거\n\n"
"## 3. 다음\n\n바뀐 내용\n"
)
source = os.path.join(fx.base, "final/.techviz/context-map")
with open(os.path.join(source, "spec.json"), "w", encoding="utf-8") as fh:
json.dump({"source_context": {
"document": "document.md",
"document_sha256": "1" * 64,
}}, fh)
with open(os.path.join(source, "context.json"), "w", encoding="utf-8") as fh:
json.dump({
"previous_section": {
"heading": {"text": "1. 이전"},
"text": "## 1. 이전\n\n그대로\n",
},
"current_section": {
"heading": {"text": "2. 대상"},
"text": "## 2. 대상\n\n그림 근거\n",
},
"next_section": {
"heading": {"text": "3. 다음"},
"text": "## 3. 다음\n\n예전 내용\n",
},
}, fh, ensure_ascii=False)
original = layout._context_sha
layout._context_sha = lambda _: None
try:
report = layout.verify("fixture")
finally:
layout._context_sha = original
self.assertIn("SSOT 문맥이 바뀐 뒤 그림을 다시 보지 않았다", report.warns)
def test_evidence_folder_outside_the_convention_is_an_error(self):
with Fixture() as fx:
os.makedirs(os.path.join(fx.base, "final/evidence/screenshots"))
@@ -453,6 +567,21 @@ class LayoutTest(unittest.TestCase):
encoding="utf-8").write("원본\n")
self.assertIn("반입 원본이 남아 있다", layout.verify("fixture").warns)
def test_durable_import_snapshot_is_not_transient_source_debt(self):
with Fixture() as fx:
os.makedirs(os.path.join(fx.base, "source/docs"))
open(os.path.join(fx.base, "source/docs/lab.md"), "w",
encoding="utf-8").write("원본\n")
data = fx.read()
data["sourcePolicy"] = {
"mode": "DURABLE_IMPORT_SNAPSHOT",
"reason": "exact commit이 없는 반입 당시 working-tree 바이트를 보존한다",
}
fx.write(data)
report = layout.verify("fixture")
self.assertNotIn("반입 원본이 남아 있다", report.warns)
self.assertIn("durable import snapshot", report.facts.get("source", ""))
if __name__ == "__main__":
unittest.main()