Bind C-25 JSON to the scanned source commit (STATE-WP-0094-T03)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 32s

The checker JSON reports per repository repo_slug, source_revision (full
40-hex HEAD SHA) and source_revision_reason; C-25 findings repeat them so a
findings-only consumer can bind. A dirty workplans/ tree, a non-git path,
a missing HEAD or a tree changing mid-scan yields null plus a reason, never
HEAD or a branch name. plan_owner_returns validates and passes the revision
into every candidate and refuses findings bound elsewhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 692292@bnt-lap001
Assistant-Session: 89c7d8e8-e1b3-47eb-9411-a0ab227fca2f
This commit is contained in:
tegwick 2026-10-04 13:33:24 +02:00
parent a0083ab78c
commit 150cb0b201
6 changed files with 284 additions and 1 deletions

View file

@ -15,6 +15,7 @@ from datetime import date
_REPO = re.compile(r"^[a-z0-9][a-z0-9-]*$")
_TASK = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")
_STATES = {"open", "claimed", "succeeded", "failed", "expired"}
_SHA = re.compile(r"^[0-9a-f]{40}$")
def _uuid(value: object) -> str:
@ -91,6 +92,12 @@ def plan_owner_returns(
raise ValueError("invalid repository identity")
if report.get("result") == "error":
raise ValueError("cannot plan from failed checker collection")
# Passed through unchanged so candidates stay bound to the scanned commit;
# None (unknown/dirty scan) travels as None and the eligibility builder
# refuses it. Never substituted or guessed here.
revision = report.get("source_revision")
if revision is not None and (not isinstance(revision, str) or not _SHA.fullmatch(revision)):
raise ValueError("source_revision must be a full 40-hex commit SHA or null")
issues = report.get("issues")
if not isinstance(issues, list):
raise ValueError("checker issues must be a list")
@ -100,6 +107,8 @@ def plan_owner_returns(
raise ValueError("invalid checker issue")
if issue.get("check_id") != "C-25" or "owner_return" not in issue:
continue
if issue.get("repo_slug", repo) != repo or issue.get("source_revision", revision) != revision:
raise ValueError("C-25 finding is bound to a different repository or revision")
context = issue["owner_return"]
if not isinstance(context, Mapping):
raise ValueError("invalid owner-return context")
@ -118,7 +127,8 @@ def plan_owner_returns(
encoded = json.dumps([repo, task, message], separators=(",", ":")).encode()
event = "owner-return:" + hashlib.sha256(encoded).hexdigest()
candidates[event] = {
"target_repo": repo, "task_record_id": task, "message_id": message,
"target_repo": repo, "source_revision": revision,
"task_record_id": task, "message_id": message,
"activity_definition_id": definition, "triggering_event_id": event,
"disposition": "stopped" if stop else "reviewable",
"stop_reason": stop, "ops_run_id": None,