Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions bounty-notes/issue-37-bounty-linkage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# CodeBounty issue #37 linkage note

Issue: https://github.com/CodeBountyOrg/BountyTestRepository/issues/37

## Snapshot

- State: open
- Locked: false
- Assignees: none
- Label: `💰 Bounty Available`
- Visible CodeBounty amount: `$50 USD`
- Required PR syntax from bot announcement: `fixes #37`
- Collision searches run immediately before this branch: `37`, `fixes #37`, `issue 37`, and `issue march 14 315pm`; exact same-scope open PR count was `0`.

## Payout boundary

This is a submitted-visible CodeBounty action only. The bot announcement says a developer must submit an application through CodeBounty to be eligible, so this PR must not be treated as verified-payable or paid until platform/maintainer acceptance is confirmed.

## Local validation

```bash
python3 -m py_compile scripts/validate-codebounty-issue-37.py
python3 scripts/validate-codebounty-issue-37.py test-fixtures/codebounty-issue-37-bounty-linkage.json
git diff --check
```

The PR body should include `fixes #37` to satisfy the CodeBounty linkage rule.
86 changes: 86 additions & 0 deletions scripts/validate-codebounty-issue-37.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Validate the CodeBounty issue #37 bounty-linkage fixture.

The fixture is intentionally local and deterministic: it records the live
GitHub/CodeBounty snapshot used for the PR and checks that the public PR can
carry the required `fixes #37` linkage without overstating payout certainty.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path


def fail(message: str) -> None:
raise SystemExit(f"issue-37 fixture invalid: {message}")


def main() -> None:
if len(sys.argv) != 2:
fail("usage: validate-codebounty-issue-37.py <fixture.json>")

path = Path(sys.argv[1])
if not path.is_file():
fail(f"missing fixture: {path}")

data = json.loads(path.read_text(encoding="utf-8"))
issue = data.get("issue") or {}
bounty = data.get("bounty") or {}
collision = data.get("collision_snapshot") or {}
expected_pr = data.get("expected_pr") or {}

if issue.get("number") != 37:
fail("issue number must be 37")
if issue.get("state") != "open":
fail("issue must be open at snapshot time")
if issue.get("locked") is not False:
fail("locked must be false at snapshot time")
if issue.get("assignees") != []:
fail("issue must be unassigned at snapshot time")
if "💰 Bounty Available" not in issue.get("labels", []):
fail("bounty-available label missing")

if bounty.get("platform") != "CodeBounty":
fail("platform must be CodeBounty")
if bounty.get("visible_amount_usd") != 50:
fail("visible bounty amount must be $50")
if bounty.get("required_pr_linkage", "").lower() != "fixes #37":
fail("required PR linkage must be `fixes #37`")
if bounty.get("developer_application_required") is not True:
fail("developer application requirement must stay explicit")
if bounty.get("verified_payable_at_snapshot") is not False:
fail("fixture must not claim verified-payable payout")

if collision.get("repo_archived") is not False:
fail("repo must be non-archived at snapshot time")
if collision.get("repo_visibility") != "PUBLIC":
fail("repo visibility must be PUBLIC")
if collision.get("same_scope_open_pr_count") != 0:
fail("same-scope open PR count must be zero at snapshot time")
terms = {term.lower() for term in collision.get("open_pr_search_terms", [])}
if {"37", "fixes #37", "issue 37"} - terms:
fail("collision-search terms are incomplete")

required_body = {item.lower() for item in expected_pr.get("body_must_include", [])}
if "fixes #37" not in required_body or "developer_application_required" not in required_body:
fail("expected PR body requirements must preserve issue linkage and payout blocker")

print(
json.dumps(
{
"ok": True,
"issue": issue["number"],
"visible_amount_usd": bounty["visible_amount_usd"],
"required_pr_linkage": bounty["required_pr_linkage"],
"verified_payable_at_snapshot": bounty["verified_payable_at_snapshot"],
"same_scope_open_pr_count": collision["same_scope_open_pr_count"],
},
sort_keys=True,
)
)


if __name__ == "__main__":
main()
37 changes: 37 additions & 0 deletions test-fixtures/codebounty-issue-37-bounty-linkage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"issue": {
"number": 37,
"url": "https://github.com/CodeBountyOrg/BountyTestRepository/issues/37",
"title": "issue march 14 315pm",
"state": "open",
"body": "desc",
"labels": ["💰 Bounty Available"],
"assignees": [],
"locked": false
},
"bounty": {
"platform": "CodeBounty",
"visible_amount_usd": 50,
"status_at_snapshot": "announced",
"required_pr_linkage": "fixes #37",
"developer_application_required": true,
"verified_payable_at_snapshot": false,
"blocker": "The CodeBounty announcement requires a platform application; GitHub-only PR submission is submitted-visible, not verified-payable."
},
"collision_snapshot": {
"checked_at": "2026-05-13T21:59:28Z",
"repo_archived": false,
"repo_visibility": "PUBLIC",
"open_pr_search_terms": ["37", "fixes #37", "issue 37", "issue march 14 315pm"],
"same_scope_open_pr_count": 0
},
"expected_pr": {
"title": "test: add CodeBounty issue 37 linkage fixture",
"body_must_include": [
"fixes #37",
"CodeBounty",
"$50",
"developer_application_required"
]
}
}