refactor: unify impl operation gates and correction verification

This commit is contained in:
2026-10-13 16:35:52 +00:00
parent 4e9c46bba2
commit bd73c97a97
24 changed files with 1992 additions and 682 deletions
@@ -3,6 +3,7 @@ import subprocess
import sys
import unittest
from pathlib import Path
from harness.tests.common.impl_contract_docs import read_contract
ROOT = Path(__file__).resolve().parents[3]
SCRIPT = ROOT / "harness/agents/impl/skills/gitea-issue-rework/scripts/evidence_manifest.py"
@@ -29,7 +30,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
self.assertIn("성공 기록을 실패로 덮어쓰지 않는다", text)
for path in SKILLS.values():
with self.subTest(path=path.name):
role = path.read_text(encoding="utf-8")
role = read_contract(path)
gate = role.split("## Managed-lock broker gate", 1)[1].split("\n## ", 1)[0]
self.assertIn("broker-generated", gate)
self.assertIn("ready JSON", gate)
@@ -38,11 +39,11 @@ class VerificationContractDocumentationTests(unittest.TestCase):
def test_role_runtime_startup_precedes_and_does_not_replace_admission(self):
roles = [path for path in (ROOT / 'harness/agents').rglob('SKILL.md')
if 'broker-generated runtime' in path.read_text()]
if 'broker-generated runtime' in read_contract(path)]
self.assertEqual(len(roles), 6)
for path in roles:
with self.subTest(role=path.parent.name):
gate = path.read_text().split('## Managed-lock broker gate', 1)[1].split('\n## ', 1)[0]
gate = read_contract(path).split('## Managed-lock broker gate', 1)[1].split('\n## ', 1)[0]
self.assertIn('ready 이후 각 workflow의 진입 검증·승인 조건을 확인한다', gate)
self.assertIn('Runtime 생성은 approval이나 worktree admission을 대신하지 않는다', gate)
self.assertIn('ready JSON의 `handle`/`socket`', gate)
@@ -55,7 +56,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
self.assertIn("PYTHONDONTWRITEBYTECODE", plan["command_env_allowlist"])
def test_full_suite_tracked_background_reconciles_before_retry(self):
text = SKILLS['rework'].read_text()
text = read_contract(SKILLS['rework'])
heading = '### Tracked bounded background evidence execution'
self.assertIn(heading, text)
section = text.split(heading, 1)[1].split('\n### ', 1)[0]
@@ -78,7 +79,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
self.assertGreater(command["timeout_seconds"], 0)
self.assertLessEqual(command["timeout_seconds"], 3600)
for path in (CACHE, *SKILLS.values()):
text = path.read_text()
text = read_contract(path)
for token in ("evidence-manifest/v3", "timeout_seconds", "process group",
"validate-archived-v2", "TDD RED", "자동 재실행"):
with self.subTest(path=str(path), token=token):
@@ -92,7 +93,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
def test_all_roles_reference_canonical_external_artifacts(self):
for path in (CACHE, *SKILLS.values()):
with self.subTest(path=path.name):
text = path.read_text(encoding="utf-8")
text = read_contract(path)
self.assertIn(CANONICAL, text)
self.assertIn("evidence_gap", text)
self.assertIn("[REDACTED]", text)
@@ -100,7 +101,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
def test_examples_match_real_helper_cli_not_unsupported_options(self):
for path in (SKILLS["implementation"], SKILLS["rework"]):
section = path.read_text().split("## Canonical external verification evidence", 1)[1]
section = read_contract(path).split("## Canonical external verification evidence", 1)[1]
match = re.search(r"```sh\n(.*?)```", section, re.S)
assert match is not None
block = match.group(1).replace("\\\n", " ")
@@ -135,7 +136,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
def test_prepare_contract_binds_root_and_forbids_recursive_parent_creation(self):
for path in (CACHE, SKILLS["implementation"], SKILLS["rework"]):
with self.subTest(path=path.name):
text = path.read_text(encoding="utf-8")
text = read_contract(path)
self.assertIn("exact harness root", text)
self.assertIn("Path.mkdir(parents=True, mode=0o700)", text)
self.assertIn("자동 chmod", text)
@@ -163,7 +164,7 @@ class VerificationContractDocumentationTests(unittest.TestCase):
guard = text.split('### Shared workflow guard gates', 1)[1].split('Issue별 검증 실행 기록의 정본', 1)[0]
self.assertNotIn('or verification root', guard)
for path in (SKILLS['implementation'], SKILLS['rework']):
self.assertNotIn('outside product checkout and verification root', path.read_text())
self.assertNotIn('outside product checkout and verification root', read_contract(path))
self.assertIn('verification/<run-id>', guard)
def test_workflow_guard_readonly_scope_does_not_ban_approved_worker_edits(self):
@@ -173,13 +174,13 @@ class VerificationContractDocumentationTests(unittest.TestCase):
self.assertIn('쓰기 worker는 승인된 변경 allowlist', guard)
def test_workflow_guard_snapshot_protects_scope_before_delegation(self):
implementation = SKILLS["implementation"].read_text()
implementation = read_contract(SKILLS["implementation"])
self.assertIn("workflow_guard.py snapshot", implementation)
self.assertIn("compare-source --repo-root", implementation)
self.assertIn("immutable protected scope", implementation)
def test_workflow_guard_inventory_is_checked_before_adopting_results(self):
rework = SKILLS["rework"].read_text()
rework = read_contract(SKILLS["rework"])
self.assertIn("workflow_guard.py check-tests", rework)
self.assertIn("test inventory", rework)
self.assertIn("RED/GREEN records must be named", rework)
@@ -215,13 +216,13 @@ class VerificationContractDocumentationTests(unittest.TestCase):
masked = 'authorization: ' + '*' * 3 + ' verification'
helper = ROOT / 'harness/lib/workflow_guard.py'
for path in (helper, CACHE):
text = path.read_text()
text = read_contract(path)
with self.subTest(path=path.name):
self.assertEqual(text.count(declaration), 1)
self.assertNotIn(masked, text)
def test_rework_no_longer_excludes_repo_evidence_from_clean_tree(self):
text = SKILLS["rework"].read_text()
text = read_contract(SKILLS["rework"])
self.assertNotIn("plan과 manifest를 제외한 clean tree", text)
self.assertIn("새 evidence는 checkout 밖", text)
self.assertIn("archived v1 read-only", text)