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
@@ -0,0 +1,43 @@
"""Canonical impl contracts stay reachable without duplicated skill bodies."""
import re
import unittest
from pathlib import Path
from harness.tests.common.impl_contract_docs import read_contract, REQUIRED
ROOT = Path(__file__).resolve().parents[3]
class ImplArchitectureDocsTests(unittest.TestCase):
def test_skills_require_single_detailed_workflow_source(self):
for name in ("gitea-issue-implementation", "gitea-issue-rework"):
path = ROOT / "harness/agents/impl/skills" / name / "SKILL.md"
text = path.read_text()
reference = path.parent / "references/workflow.md"
with self.subTest(skill=name):
self.assertIn(REQUIRED, text)
self.assertLess(len(text.splitlines()), 100)
self.assertEqual(text.count("name: " + name), 1)
self.assertNotIn("## Managed-lock broker gate", text)
self.assertFalse(reference.read_text().startswith("---"))
contract = read_contract(path)
self.assertEqual(contract.count("## Managed-lock broker gate"), 1)
for gate in ("## Delegation evidence acceptance gate", "## Test inventory source-binding gate", "## Canonical external verification evidence"):
self.assertEqual(contract.count(gate), 1)
def test_all_canonical_impl_markdown_links_resolve(self):
for name in ("gitea-issue-implementation", "gitea-issue-rework"):
directory = ROOT / "harness/agents/impl/skills" / name
for path in [directory / "SKILL.md", directory / "references/workflow.md"]:
for link in re.findall(r"\[[^\]]+\]\(([^)]+)\)", path.read_text()):
if link.startswith(("https://", "http://", "#")):
continue
target = link.split("#", 1)[0]
with self.subTest(path=path.name, link=link):
self.assertTrue((path.parent / target).resolve().exists())
def test_correction_default_and_exception_remain_distinct(self):
text = (ROOT / "harness/agents/impl/skills/gitea-issue-rework/references/readback.md").read_text()
for token in ("strict", "separately", "atomic_client_precondition=false", "residual", "neutered"):
self.assertIn(token.lower(), text.lower())
if __name__ == "__main__":
unittest.main()
+152
View File
@@ -0,0 +1,152 @@
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
sys.path.insert(0, str(ROOT / "harness" / "lib"))
import impl_operation as op
class ImplOperationTests(unittest.TestCase):
def test_reentrant_preflight_cannot_authorize_duplicate_mutation(self):
coordinator = op.Coordinator()
intent = make_intent()
approval = make_approval(intent)
writes = []
entered = []
def preflight(value):
if not entered:
entered.append(True)
coordinator.execute(intent, approval, provider)
return {"fresh": True}
provider = adapter(preflight=preflight, mutate=lambda value: writes.append("write"))
coordinator.execute(intent, approval, provider)
self.assertEqual(writes, ["write"])
def test_preflight_cannot_change_approved_payload_before_mutation(self):
intent = make_intent()
calls = []
def preflight(i):
i.payload["body"] = "unapproved"
return {"fresh": True}
c = op.Coordinator()
result = c.execute(intent, make_approval(intent), adapter(preflight=preflight,
mutate=lambda i: calls.append(i.payload["body"])), calls.append)
self.assertEqual(calls[-1], "ok")
self.assertEqual(result.status, "verified")
def test_attempt_callback_must_be_callable_before_preflight(self):
calls = []
result = op.Coordinator().execute(make_intent(), make_approval(),
adapter(preflight=lambda i: calls.append("preflight") or {"fresh": True}), on_attempt=3)
self.assertEqual(calls, [])
self.assertEqual(result.status, "partial")
def test_attempt_callback_failure_consumes_authority_without_write(self):
calls = []
c = op.Coordinator()
a = adapter(mutate=lambda i: calls.append("write"))
result = c.execute(make_intent(), make_approval(), a,
lambda record: (_ for _ in ()).throw(RuntimeError("secret credential")))
self.assertEqual(calls, [])
self.assertNotIn("secret credential", result.reason)
self.assertEqual(c.execute(make_intent(), make_approval(), a).status, "partial")
def test_malformed_canonical_target_rejected(self):
for target in ("owner/..", "owner/.", "owner/repo\\x", "owner/repo\n"):
with self.subTest(target=target):
i = op.Intent("v1", "push", target, 1, "a"*40, {})
self.assertRaises(ValueError, op.validate, i, op.Approval("v1", "0"*64, "approved"))
def test_unserializable_ack_does_not_lose_verified_result(self):
result = op.Coordinator().execute(make_intent(), make_approval(), adapter(mutate=lambda i: object()))
self.assertEqual(result.status, "verified")
def test_verify_exception_returns_partial_and_no_retry(self):
calls = []
c = op.Coordinator()
a = adapter(mutate=lambda i: calls.append("write"), verify=lambda *args: (_ for _ in ()).throw(RuntimeError("private")))
result = c.execute(make_intent(), make_approval(), a)
self.assertEqual(result.status, "partial")
self.assertNotIn("private", result.reason)
c.execute(make_intent(), make_approval(), a)
self.assertEqual(calls, ["write"])
def test_versioned_intent_and_approval_validate(self):
intent = op.Intent("v1", "comment.patch", "owner/repo", 12, "a" * 40, {"body": "ok"})
approval = op.Approval("v1", intent.digest, "approved")
self.assertEqual(op.validate(intent, approval).digest, intent.digest)
def test_invalid_full_sha_rejected_before_callbacks(self):
calls = []
intent = op.Intent("v1", "push", "owner/repo", 1, "a" * 39, {})
result = op.Coordinator().execute(intent, op.Approval("v1", "0" * 64, "approved"), adapter(), calls.append)
self.assertEqual(result.status, "partial")
self.assertEqual(calls, [])
def test_stale_preflight_fails_without_mutation(self):
calls = []
result = op.Coordinator().execute(make_intent(), make_approval(), adapter(preflight=lambda i: {"fresh": False}), calls.append)
self.assertEqual(result.status, "partial")
self.assertEqual(calls, [])
def test_unsupported_capability_fails_before_write(self):
calls = []
result = op.Coordinator().execute(make_intent(), make_approval(), adapter(capability=False), calls.append)
self.assertEqual(result.status, "partial")
self.assertEqual(calls, [])
def test_uncertain_ack_reconciles_without_second_write(self):
calls = []
a = adapter(mutate=lambda i: (_ for _ in ()).throw(op.UncertainAcknowledgement()), readback=lambda i: {"state": "applied"}, verify=lambda i, p, r: True)
result = op.Coordinator().execute(make_intent(), make_approval(), a, calls.append)
self.assertEqual(len(calls), 1)
self.assertEqual(result.status, "verified")
self.assertEqual(result.assurance["durable_at_most_once"], False)
def test_reuse_cannot_mutate_twice(self):
calls = []
c = op.Coordinator()
a = adapter()
c.execute(make_intent(), make_approval(), a, calls.append)
again = c.execute(make_intent(), make_approval(), a, calls.append)
self.assertEqual(len(calls), 1)
self.assertEqual(again.status, "partial")
def test_verification_requires_trusted_adapter_callback(self):
calls = []
result = op.Coordinator().execute(make_intent(), make_approval(), adapter(verify=lambda *args: False), calls.append)
self.assertEqual(result.status, "partial")
self.assertNotEqual(result.status, "verified")
def test_correction_needs_separate_approval_unless_explicit_patch_exception(self):
calls = []
correction = make_intent(operation="correction")
result = op.Coordinator().execute(correction, make_approval(correction), adapter(capability="ordinary_patch"), calls.append)
self.assertEqual(result.status, "partial")
self.assertEqual(calls, [])
approval = make_approval(correction, correction=True, ordinary_patch=True)
result = op.Coordinator().execute(correction, approval, adapter(capability="ordinary_patch"), calls.append)
self.assertEqual(result.assurance["atomic_client_precondition"], False)
self.assertIn("residual_race", result.assurance)
def make_intent(operation="comment.patch"):
return op.Intent("v1", operation, "owner/repo", 12, "a" * 40, {"body": "ok"})
def make_approval(intent=None, correction=False, ordinary_patch=False):
intent = intent or make_intent()
return op.Approval("v1", intent.digest, "approved", correction=correction, ordinary_patch=ordinary_patch)
def adapter(**kwargs):
defaults = dict(preflight=lambda i: {"fresh": True}, capability=True,
mutate=lambda i: {"written": True}, readback=lambda i: {"state": "applied"},
verify=lambda i, p, r: True)
defaults.update(kwargs)
return op.Adapter(**defaults)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,117 @@
"""Integration regression tests for coordinator-backed initial delivery."""
import importlib.util
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
SCRIPT = ROOT / "harness/agents/impl/skills/gitea-issue-implementation/scripts/implementation_delivery.py"
sys.path.insert(0, str(ROOT))
spec = importlib.util.spec_from_file_location("implementation_delivery", SCRIPT)
delivery = importlib.util.module_from_spec(spec)
spec.loader.exec_module(delivery)
from harness.lib.impl_operation import Approval, Coordinator, Intent
HEAD = "a" * 40
class Adapter:
def __init__(self):
self.events=[]; self.number=7; self.fail_pr=False; self.uncertain=False; self.received=[]
def push_operation(self, intent):
self.received.append(intent)
return self.push(intent.payload['head'])
def create_or_reuse_pr_operation(self, intent):
self.received.append(intent)
return self.create_or_reuse_pr(intent.payload['head'])
def push(self, head): self.events.append("push"); return True
def read_remote_head(self): self.events.append("read-head"); return HEAD
def create_or_reuse_pr(self, head):
self.events.append("create-pr")
if self.fail_pr: raise RuntimeError("failed")
if self.uncertain: raise RuntimeError("uncertain ack")
return self.number
def read_pr(self, number): self.events.append("read-pr"); return {"number":number,"head":HEAD,"state":"open"}
def preflight_operation(self, intent): self.events.append("preflight:"+intent.operation); return {"fresh":True,"scope":intent.target}
def verify_operation(self, intent, before, observed): self.events.append("verify:"+intent.operation); return True
def find_intended_pr(self, head): self.events.append("find-pr"); return None if self.fail_pr else {"number":self.number}
def make_intents():
push=Intent("v1","push","org/repo",42,HEAD,{"head":HEAD})
pr=Intent("v1","pr.create","org/repo",42,HEAD,{"head":HEAD,"body":"approved body","base":"main"})
return push, Approval("v1",push.digest,"approved"), pr, Approval("v1",pr.digest,"approved")
class IntegrationTests(unittest.TestCase):
def invoke(self, adapter, intents=None, approvals=None, recorder=None):
p,pa,r,ra=make_intents(); intents=intents or (p,r); approvals=approvals or (pa,ra)
return delivery.deliver_approved_implementation(adapter,head=HEAD,declaration={"mode":"none"},push_intent=intents[0],push_approval=approvals[0],pr_intent=intents[1],pr_approval=approvals[1],coordinator=Coordinator(),on_attempt=recorder or (lambda entry: None))
def test_full_composed_delivery(self):
a=Adapter(); result=self.invoke(a)
self.assertEqual(result["status"],"verified"); self.assertEqual(result["artifact"]["pr"]["number"],7)
self.assertEqual(a.events.count("push"),1); self.assertEqual(a.events.count("create-pr"),1)
def test_uncertain_pr_acknowledgement_reconciles_without_second_write(self):
a = Adapter()
a.uncertain = True
result = self.invoke(a)
self.assertEqual(result["status"], "verified")
self.assertEqual(a.events.count("create-pr"), 1)
self.assertEqual(a.events.count("find-pr"), 1)
def test_adoption_rejection_never_promotes_existing_remote_state(self):
a = Adapter()
old = delivery._delivery_adoption.require_adoption
delivery._delivery_adoption.require_adoption = lambda *args, **kwargs: (_ for _ in ()).throw(ValueError("rejected"))
try:
result = self.invoke(a)
finally:
delivery._delivery_adoption.require_adoption = old
self.assertEqual(result["status"], "partial")
self.assertNotIn("push", a.events)
self.assertNotIn("create-pr", a.events)
def test_approved_payload_head_mismatch_rejected_before_any_write(self):
a = Adapter()
push, push_approval, pr, pr_approval = make_intents()
for operation in ('push', 'pr.create'):
candidate = Intent('v1', operation, 'org/repo', 42, HEAD, {'head':'f'*40,'body':'approved'})
candidate_approval = Approval('v1',candidate.digest,'approved')
intents = (candidate,pr) if operation == 'push' else (push,candidate)
approvals = (candidate_approval,pr_approval) if operation == 'push' else (push_approval,candidate_approval)
with self.subTest(operation=operation),self.assertRaises(ValueError):
self.invoke(a,intents=intents,approvals=approvals)
self.assertNotIn('push',a.events)
self.assertNotIn('create-pr',a.events)
def test_mutation_callbacks_receive_entire_approved_intent(self):
a = Adapter()
push, push_approval, pr, pr_approval = make_intents()
self.assertEqual(self.invoke(a)['status'],'verified')
self.assertEqual([item.as_dict() for item in a.received],[push.as_dict(),pr.as_dict()])
def test_new_adapter_contract_does_not_require_legacy_mutators(self):
a = Adapter()
a.push = None
a.create_or_reuse_pr = None
a.push_operation = lambda intent: a.events.append('push')
a.create_or_reuse_pr_operation = lambda intent: a.events.append('create-pr') or 7
self.assertEqual(self.invoke(a)['status'],'verified')
self.assertEqual(a.events.count('push'),1)
self.assertEqual(a.events.count('create-pr'),1)
def test_missing_approval_no_writes(self):
a=Adapter(); p,pa,r,ra=make_intents(); ra=Approval("v1","0"*64,"approved")
with self.assertRaises(ValueError): self.invoke(a,approvals=(pa,ra))
self.assertNotIn("push",a.events)
def test_preflight_failure_no_mutation(self):
a=Adapter(); a.preflight_operation=lambda intent:{"fresh":False}
result=self.invoke(a); self.assertEqual(result["status"],"partial"); self.assertNotIn("push",a.events)
def test_pr_failure_preserves_verified_push(self):
a=Adapter(); a.fail_pr=True; result=self.invoke(a)
self.assertEqual(result["status"],"partial"); self.assertEqual(result["push"].status,"verified"); self.assertIsNone(result["artifact"])
def test_mutations_each_require_fresh_adoption(self):
a=Adapter(); calls=[]; old=delivery._delivery_adoption.require_adoption
delivery._delivery_adoption.require_adoption=lambda *args,**kwargs:calls.append(kwargs["expected_stage"])
try: self.invoke(a)
finally: delivery._delivery_adoption.require_adoption=old
self.assertEqual(len(calls),4)
if __name__ == "__main__": unittest.main()
@@ -0,0 +1,135 @@
"""Functional correction verification with provider-shaped synthetic readbacks."""
import copy
import hashlib
import importlib.util
import json
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from harness.tests.impl import test_rework_readback as fixtures
DIRECTORY = Path(__file__).parents[2] / 'agents/impl/skills/gitea-issue-rework/scripts'
spec = importlib.util.spec_from_file_location('correction_verifier', DIRECTORY/'rework_correction.py')
assert spec is not None and spec.loader is not None
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
class CorrectionVerifierTests(unittest.TestCase):
def setUp(self):
fixture = fixtures.ReworkReadbackTests()
fixture.setUp()
fixture.contract["version"] = "1.27.3"
fixture.overrides["/version"] = ({"version":"1.27.3"}, {}, 200)
self.addCleanup(fixture.doCleanups)
self.new = copy.deepcopy(fixture.expected)
self.old = copy.deepcopy(self.new)
free = self.new['marker_free_body']
for label in ('Source Issue', 'Pull Request', 'Source Review'):
free = free.replace('- '+label+': ', '- '+label+': #')
digest = hashlib.sha256(free.encode()).hexdigest()
marker = self.new['marker'].replace(self.new['result_sha256'], digest)
self.old.update(body=free+marker, marker=marker, marker_free_body=free, result_sha256=digest)
self.plan = fixture.legacy.prepare_correction(self.old,self.new,comment_id=501,actor_id=42)
fixture.add_result()
fixture.comments[0]['body'] = self.old['body']
self.before = fixture.adapter().snapshot(self.new)
fixture.comments[0]['body'] = self.new['body']
fixture.comments[0]['updated_at'] = '2026-01-03T00:00:00Z'
self.after = fixture.adapter().snapshot(self.new)
event = {'id':601,'type':'comment_ref','user':{'id':42,'login':'gitea-impl-agent'},
'created_at':fixtures.T1,'updated_at':fixtures.T1,'ref_action':'none',
'issue_url':fixtures.ORIGIN+'/acme/demo/issues/7',
'ref_issue':{'number':9,'html_url':fixtures.ORIGIN+'/acme/demo/pulls/9'},
'ref_comment':copy.deepcopy(self.before['raw']['comments']['rows'][0])}
self.before['source_issue_timeline'] = self.timeline(event)
changed = copy.deepcopy(event)
changed.update(ref_action='neutered',updated_at='2026-01-03T00:00:00Z',
ref_comment=copy.deepcopy(self.after['raw']['comments']['rows'][0]))
self.after['source_issue_timeline'] = self.timeline(changed)
self.approval = {'approved':True,'operation':'same_comment_correction',
'historical_failure_baseline_sha256':'1'*64,'old_expected_document':self.old,
'new_expected_document':self.new,'timeline_profile':'observed-comment-ref-neutralization',
'ordinary_patch':True,'provider_version':self.before['provider']['version']}
def timeline(self,event):
return {'complete':True,'rows':[event], 'pages':[{'page':1,'count':1,'headers':{'X-Total-Count':'1'}}]}
def verify(self,profile='observed-comment-ref-neutralization'):
return mod.verify_correction(self.plan,self.before,self.after,self.old['body'],self.new['body'],
self.approval,approval_sha256=mod.sha(mod.canonical(self.approval)),
historical_failure_sha256='1'*64,profile=profile)
def test_exact_approved_reference_neutralization_passes(self):
result=self.verify()
self.assertEqual(result['status'],'verified')
self.assertEqual(result['changed_timeline_ids'],[601])
self.assertEqual(result['historical_handoff_status'],'partial_unchanged')
def test_strict_unchanged_timeline_passes(self):
self.after['source_issue_timeline']=copy.deepcopy(self.before['source_issue_timeline'])
self.approval['timeline_profile']='strict'
self.assertEqual(self.verify('strict')['status'],'verified')
def test_reference_profile_requires_separate_approval(self):
self.approval['timeline_profile']='strict'
with self.assertRaises(mod.Bad): self.verify()
def test_source_and_cache_deltas_fail(self):
for name,field in [('source_issue','title'),('pr','comments'),('pr_issue','comments')]:
original=copy.deepcopy(self.after)
self.after['raw'][name][field] = 99 if field=='comments' else 'changed'
with self.subTest(name=name),self.assertRaises(mod.Bad): self.verify()
self.after=original
def test_unrelated_timeline_field_change_fails(self):
self.after['source_issue_timeline']['rows'][0]['body']='unexpected'
with self.assertRaises(mod.Bad): self.verify()
def test_unrelated_null_timeline_field_is_still_a_mutation(self):
self.after['source_issue_timeline']['rows'][0]['unexpected_field'] = None
with self.assertRaises(mod.Bad): self.verify()
def test_duplicate_and_missing_timeline_rows_fail(self):
original=copy.deepcopy(self.after)
for rows in [[],self.after['source_issue_timeline']['rows']*2]:
self.after=copy.deepcopy(original)
self.after['source_issue_timeline']['rows']=rows
with self.subTest(rows=len(rows)),self.assertRaises(mod.Bad): self.verify()
def test_wrong_actor_head_and_extra_body_change_fail(self):
for field,value in [('actor_id',99),('head','d'*40),('new_body','arbitrary')]:
original=copy.deepcopy(self.plan)
self.plan[field]=value
with self.subTest(field=field),self.assertRaises(mod.Bad): self.verify()
self.plan=original
def test_reference_timestamp_cannot_move_backwards(self):
self.after['source_issue_timeline']['rows'][0]['updated_at']='2025-01-01T00:00:00Z'
with self.assertRaises(mod.Bad): self.verify()
def test_real_cli_valid_inputs_and_no_overwrite(self):
with tempfile.TemporaryDirectory() as td:
root=Path(td)
args=[sys.executable,'-B',str(DIRECTORY/'rework_correction.py'),'verify']
values={'plan':self.plan,'before':self.before,'after':self.after,
'old-comment':{'body':self.old['body']},'new-comment':{'body':self.new['body']},'approval':self.approval}
for name,value in values.items():
raw=json.dumps(value).encode(); path=root/(name+'.json'); path.write_bytes(raw); path.chmod(0o600)
args.extend(['--'+name,str(path),'--'+name+'-sha256',hashlib.sha256(raw).hexdigest()])
output=root/'receipt.json'
args.extend(['--historical-failure-sha256','1'*64,'--profile','observed-comment-ref-neutralization','--output',str(output)])
result=subprocess.run(args,capture_output=True,text=True,timeout=10)
self.assertEqual(result.returncode,0,result.stderr)
saved=output.read_bytes()
again=subprocess.run(args,capture_output=True,text=True,timeout=10)
self.assertNotEqual(again.returncode,0)
self.assertEqual(output.read_bytes(),saved)
def test_digest_tampering_is_rejected(self):
with tempfile.TemporaryDirectory() as td:
path=Path(td)/'data.json';path.write_text('{}')
with self.assertRaises(mod.Bad):mod.load(path,'0'*64)
if __name__=='__main__':unittest.main()
@@ -0,0 +1,163 @@
"""Regression tests for main-owned rework publication integration."""
import copy
import hashlib
import sys
import unittest
from pathlib import Path
from unittest.mock import Mock
ROOT = Path(__file__).resolve().parents[2]
SCRIPT = ROOT / "agents/impl/skills/gitea-issue-rework/scripts"
sys.path.insert(0, str(SCRIPT))
sys.path.insert(0, str(ROOT))
import rework_publication as pub
from harness.lib import impl_operation as ops
HEAD = "a" * 40
def expected():
# Generate through the canonical renderer to avoid hand-authored bodies.
import rework_comment as rc
d = dict(owner="o", repository="r", issue=4, pr=5, review=6,
reviewed_head="b"*40, final_head=HEAD, contract_sha256="c"*64,
result="partial", findings=[dict(id="F1", status="resolved", classification="valid_fix",
changes="changed safely", verification="checks pass", reason="verified")],
local_checks="pass", runtime_browser="not run", commit_status="없음", actions_runs="없음")
dd, vals, fs, extras, cs, ar = rc.canon(d)
body = rc.render_body(dd, vals, fs, extras, cs, ar)
rh = hashlib.sha256(body.encode()).hexdigest()
corr = hashlib.sha256("\0".join(["o", "r", "4", "5", "6", "b"*40, HEAD, "c"*64]).encode()).hexdigest()
marker = f"<!-- gitea-agent:implementation-rework/v1 owner=o repository=r issue=4 pr=5 review=6 reviewed-head={'b'*40} head={HEAD} contract-sha256={'c'*64} result-sha256={rh} correlation={corr} -->\n"
return dict(body=body+marker, marker=marker, marker_free_body=body, result_sha256=rh, correlation=corr,
target=dict(owner="o", repository="r", issue=4, pr=5), review=6,
reviewed_head="b"*40, head=HEAD, contract_sha256="c"*64)
def setup_case(op="comment.create", payload=None, approval_flags=None):
if payload is None:
e=expected(); payload={"expected":e,"target":e["target"]}
intent=ops.Intent("v1", op, "o/r", 5, HEAD, payload)
approval=ops.Approval("v1", intent.digest, "approved", **(approval_flags or {}))
declaration={"mode":"none"}
calls=[]
adapter=ops.Adapter(preflight=lambda i: {"fresh":True,"scope":"exact"}, capability=True,
mutate=lambda i: calls.append(copy.deepcopy(i)) or {"acknowledgement":"ok"},
readback=lambda i: {"scope":"exact","head":HEAD}, verify=lambda i,p,o: True)
return intent,approval,declaration,calls,adapter
class PublicationTests(unittest.TestCase):
def test_entrypoint_is_present_not_import_error(self):
self.assertTrue(callable(getattr(pub,"execute_rework_operation",None)))
def test_invalid_body_target_head_approval_do_not_write(self):
cases=[]
cases.append(setup_case("pr.patch", {"body":"body", "closing":"#4"}))
cases.append(setup_case("comment.create", {"expected":expected(),"target":{"owner":"evil","repository":"r","issue":4,"pr":5}}))
p={"head":"f"*40}; cases.append(setup_case("push",p))
for intent,approval,decl,calls,adapter in cases:
with self.subTest(intent=intent.operation), self.assertRaises(Exception):
pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration=decl,
coordinator=ops.Coordinator(),on_attempt=lambda x:None)
self.assertEqual(calls,[])
def test_single_mutation_and_fresh_adoption_at_boundary(self):
intent,approval,decl,calls,adapter=setup_case()
old=pub.require_adoption
try:
adopted=Mock(return_value=None); pub.require_adoption=adopted
attempts=[]
result=pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration=decl,
coordinator=ops.Coordinator(),on_attempt=attempts.append)
self.assertEqual(result.status,"verified")
self.assertEqual(len(calls),1); self.assertEqual(len(attempts),1)
adopted.assert_called_once()
finally: pub.require_adoption=old
def test_adoption_and_preflight_failure_have_zero_mutations(self):
intent,approval,decl,calls,adapter=setup_case()
old=pub.require_adoption
try:
pub.require_adoption=Mock(side_effect=ValueError("stale"))
r=pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration=decl,
coordinator=ops.Coordinator(),on_attempt=lambda x:None)
self.assertEqual(r.status,"partial"); self.assertEqual(calls,[])
adapter.preflight=lambda i: {"fresh":False}
r=pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration=decl,
coordinator=ops.Coordinator(),on_attempt=lambda x:None)
self.assertEqual(r.status,"partial"); self.assertEqual(calls,[])
finally: pub.require_adoption=old
def test_uncertain_ack_readback_once_literal_true_required(self):
intent,approval,decl,calls,adapter=setup_case()
old=pub.require_adoption
try:
pub.require_adoption=Mock(return_value=None)
mutations=[]; reads=[]
adapter.mutate=lambda i: mutations.append(i) or (_ for _ in ()).throw(ops.UncertainAcknowledgement())
adapter.readback=lambda i: reads.append(i) or {"head":HEAD}
adapter.verify=lambda i,p,o: 1
result=pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration=decl,
coordinator=ops.Coordinator(),on_attempt=lambda x:None)
self.assertEqual(result.status,"partial")
self.assertEqual((len(mutations),len(reads)),(1,1))
finally: pub.require_adoption=old
def test_reuse_collects_fresh_state_without_any_mutation(self):
intent, approval, declaration, calls, adapter = setup_case()
reads = []
adapter.preflight = lambda value: reads.append("preflight") or {"fresh":True}
adapter.readback = lambda value: reads.append("readback") or {"exact":True}
adapter.verify_reuse = lambda value, before, after: after.get("exact") is True
result = pub.verify_rework_reuse(adapter,intent=intent,approval=approval,declaration=declaration)
self.assertEqual(result['action'],'reuse')
self.assertEqual(reads,['preflight','readback'])
self.assertEqual(calls,[])
def test_reuse_stale_preflight_blocks_even_when_callback_would_accept(self):
intent, approval, declaration, calls, adapter = setup_case()
reads=[]
adapter.preflight=lambda value:{"fresh":False}
adapter.readback=lambda value:reads.append(True)
adapter.verify_reuse=lambda *args:True
with self.assertRaises(ValueError):
pub.verify_rework_reuse(adapter,intent=intent,approval=approval,declaration=declaration)
self.assertEqual(reads,[])
self.assertEqual(calls,[])
def test_canonical_comment_cannot_publish_to_different_intent_scope(self):
intent, approval, declaration, calls, adapter = setup_case()
for target, target_id in [('evil/r', 5), ('o/r', 999)]:
changed = ops.Intent('v1', intent.operation, target, target_id, HEAD, intent.payload)
approved = ops.Approval('v1', changed.digest, 'approved')
with self.subTest(target=target, target_id=target_id), self.assertRaises(ValueError):
pub.execute_rework_operation(adapter,intent=changed,approval=approved,declaration=declaration,
coordinator=ops.Coordinator(),on_attempt=lambda record:None)
self.assertEqual(calls, [])
def test_unimplemented_client_cas_correction_blocks_before_write(self):
import rework_comment as rc
new = expected()
old = copy.deepcopy(new)
body = new['marker_free_body']
for label in ('Source Issue','Pull Request','Source Review'):
body = body.replace('- '+label+': ','- '+label+': #')
digest = hashlib.sha256(body.encode()).hexdigest()
marker = new['marker'].replace(new['result_sha256'],digest)
old.update(body=body+marker,marker=marker,marker_free_body=body,result_sha256=digest)
payload = {'old_expected':old,'new_expected':new,'comment_id':7,'actor_id':42}
intent = ops.Intent('v1','correction','o/r',7,HEAD,payload)
approval = ops.Approval('v1',intent.digest,'approved',correction=True)
calls = []
adapter = ops.Adapter(lambda value:{'fresh':True},True,
lambda value:calls.append('write'),lambda value:{'exact':True},lambda *args:True)
with self.assertRaises(ValueError):
pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration={'mode':'none'},
coordinator=ops.Coordinator(),on_attempt=lambda record:None)
self.assertEqual(calls,[])
def test_generic_comment_patch_rejected_and_correction_requires_explicit_approval(self):
intent,approval,decl,calls,adapter=setup_case("comment.patch",{"body":"arbitrary"})
with self.assertRaises(ValueError): pub.execute_rework_operation(adapter,intent=intent,approval=approval,declaration=decl,coordinator=ops.Coordinator(),on_attempt=lambda x:None)
self.assertEqual(calls,[])
if __name__ == "__main__": unittest.main()
+2 -1
View File
@@ -7,6 +7,7 @@ import unittest
from argparse import Namespace
from pathlib import Path
from urllib.parse import parse_qs, urlsplit
from harness.tests.common.impl_contract_docs import read_contract
DIRECTORY = Path(__file__).parents[2] / 'agents/impl/skills/gitea-issue-rework/scripts'
ORIGIN = 'https://gitea.jsfamily.quest'
@@ -696,7 +697,7 @@ class ReworkReadbackTests(unittest.TestCase):
def test_shared_commit_message_safety_rule_is_linked_and_amend_is_narrow(self):
common = (DIRECTORY.parents[4]/'operations/repository-cache.md').read_text()
skill = (DIRECTORY.parent/'SKILL.md').read_text()
skill = read_contract(DIRECTORY.parent / 'SKILL.md')
self.assertIn('## Commit-message reference safety', common)
for clause in ('complete subject and body', 'cross-repository',
'non-default branch', 'explicit user authorization',