refactor: 문서 개선 중
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user