init: document-haness 설계

This commit is contained in:
DongHyeonka
2026-07-23 17:52:22 +09:00
parent 993788c14e
commit d6f78f92a0
127 changed files with 20099 additions and 1 deletions
+165
View File
@@ -0,0 +1,165 @@
from __future__ import annotations
import json
import shutil
import sys
from pathlib import Path
from helpers import ROOT, run_cli
sys.path.insert(0, str(ROOT / "scripts"))
from check_release_sync import SEMVER_RE # noqa: E402
def test_canonical_quick_rules_are_current() -> None:
result = run_cli("build_quick_rules.py", "--check")
assert result.returncode == 0, result.stderr
def test_quick_rules_check_detects_drift(tmp_path: Path) -> None:
output = tmp_path / "quick-rules.md"
generated = run_cli("build_quick_rules.py", "--output", output)
assert generated.returncode == 0, generated.stderr
current = run_cli("build_quick_rules.py", "--output", output, "--check")
assert current.returncode == 0, current.stderr
output.write_text(output.read_text(encoding="utf-8") + "drift\n", encoding="utf-8")
stale = run_cli("build_quick_rules.py", "--output", output, "--check")
assert stale.returncode == 1
assert "out of date" in stale.stderr
def test_quick_rules_render_every_route_and_threshold_switches(tmp_path: Path) -> None:
rules = json.loads(
(ROOT / "skills/technical-doc-flow/config/quality-rules.json").read_text(encoding="utf-8")
)
rules["thresholds"]["route"]["light"]["requires_existing_draft"] = False
rules["thresholds"]["logic"]["core_claim_max_reader_paragraphs"] = 3
rules["thresholds"]["split"]["default_max_chars"] = 4321
rules["thresholds"]["split"]["minimum_h2_fill_ratio"] = 0.5
custom_rules = tmp_path / "rules.json"
custom_rules.write_text(json.dumps(rules), encoding="utf-8")
output = tmp_path / "quick.md"
result = run_cli(
"build_quick_rules.py", "--rules", custom_rules, "--output", output
)
assert result.returncode == 0, result.stderr
rendered = output.read_text(encoding="utf-8")
assert "기존 초안 불필요" in rendered
assert "독자용 앞 3개 문단" in rendered
assert "`backpressure`" in rendered
assert "`UTF-8`" in rendered
assert "4321자" in rendered
assert "50% (raw `0.5`)" in rendered
first = rendered
rules["thresholds"]["logic"]["core_claim_max_reader_paragraphs"] = 4
rules["thresholds"]["split"]["minimum_h2_fill_ratio"] = 0.501
rules["thresholds"]["finalization"]["max_change_rate"] = 0.151
custom_rules.write_text(json.dumps(rules), encoding="utf-8")
assert run_cli(
"build_quick_rules.py", "--rules", custom_rules, "--output", output
).returncode == 0
second = output.read_text(encoding="utf-8")
assert first != second
assert "독자용 앞 4개 문단" in second
assert "raw `0.501`" in second and "raw `0.151`" in second
def test_quick_rules_validates_custom_runtime_contract(tmp_path: Path) -> None:
contract = json.loads(
(ROOT / "skills/technical-doc-flow/config/runtime-contract.json").read_text(
encoding="utf-8"
)
)
contract["name"] = "wrong-name"
path = tmp_path / "contract.json"
path.write_text(json.dumps(contract), encoding="utf-8")
result = run_cli(
"build_quick_rules.py",
"--contract",
path,
"--output",
tmp_path / "quick.md",
)
assert result.returncode == 2
assert "schema 위반" in result.stderr
def test_release_and_path_contracts_are_current() -> None:
result = run_cli("check_release_sync.py", "--root", ROOT)
assert result.returncode == 0, result.stderr
def test_release_check_rejects_fake_wrapper_and_unmapped_artifact(tmp_path: Path) -> None:
copied = tmp_path / "repository"
shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns("__pycache__", ".pytest_cache"))
wrapper = copied / "scripts" / "split_document.py"
wrapper.write_text(
"from _runtime_entry import execute\nif False:\n execute('split_document.py')\n",
encoding="utf-8",
)
relative_wrapper = copied / "scripts" / "lint_document.py"
relative_wrapper.write_text(
"from ._runtime_entry import execute\nexecute('lint_document.py')\n",
encoding="utf-8",
)
(copied / "scripts" / "_runtime_entry.py").unlink()
contract = copied / "skills" / "technical-doc-flow" / "config" / "runtime-contract.json"
value = json.loads(contract.read_text(encoding="utf-8"))
value["artifacts"]["always"].append("10_unmapped.json")
contract.write_text(json.dumps(value), encoding="utf-8")
verifier = copied / "skills" / "technical-doc-flow" / "scripts" / "verify_run.py"
verifier.write_text(
verifier.read_text(encoding="utf-8").replace(
'"08_lint.json": "lint-report.schema.json"',
'"08_lint.json": "review.schema.json"',
),
encoding="utf-8",
)
result = run_cli("check_release_sync.py", "--root", copied)
assert result.returncode == 1
assert "exact canonical execute template" in result.stderr
assert "root runtime entry helper 누락" in result.stderr
assert "wrapper --help smoke 실패" in result.stderr
assert "매핑이 없는 runtime artifact" in result.stderr
assert "artifact schema mapping 불일치" in result.stderr
def test_release_check_validates_runtime_contract_schema(tmp_path: Path) -> None:
copied = tmp_path / "repository"
shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns("__pycache__", ".pytest_cache"))
contract_path = copied / "skills" / "technical-doc-flow" / "config" / "runtime-contract.json"
contract = json.loads(contract_path.read_text(encoding="utf-8"))
contract["supported_document_kinds"] = ["garbage"]
contract["artifacts"]["unexpected"] = []
contract_path.write_text(json.dumps(contract), encoding="utf-8")
result = run_cli("check_release_sync.py", "--root", copied)
assert result.returncode == 1
assert "runtime-contract.schema.json 검증 실패" in result.stderr
def test_semver_is_strict_and_marketplace_matches_by_name(tmp_path: Path) -> None:
for valid in ("0.1.0", "1.2.3-alpha.1", "1.2.3+build.01", "1.0.0-0"):
assert SEMVER_RE.fullmatch(valid), valid
for invalid in (
"1.0.0-01",
"1.0.0-..",
"1.0.0-alpha..1",
"1.0.0+..",
"1١.0.0",
"1.0.1٢",
"1.0.0-1١",
):
assert not SEMVER_RE.fullmatch(invalid), invalid
copied = tmp_path / "repository"
shutil.copytree(ROOT, copied, ignore=shutil.ignore_patterns("__pycache__", ".pytest_cache"))
marketplace_path = copied / ".claude-plugin" / "marketplace.json"
marketplace = json.loads(marketplace_path.read_text(encoding="utf-8"))
marketplace["plugins"].insert(0, {"name": "unrelated", "version": "0.1.0"})
target = next(item for item in marketplace["plugins"] if item["name"] == "technical-doc-flow")
target["version"] = "9.9.9"
marketplace_path.write_text(json.dumps(marketplace), encoding="utf-8")
result = run_cli("check_release_sync.py", "--root", copied)
assert result.returncode == 1
assert "technical-doc-flow plugin='9.9.9'" in result.stderr