refactor: unify impl operation gates and correction verification
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user