Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ace CODEOWNERS
# Maintainers own merge. Path owners review; they are not a merge bot.
* @kvnloo
2 changes: 2 additions & 0 deletions .github/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ After deployment, your sites will be available at:
- **Production (main)**: `https://<username>.github.io/<repo>/`
- **Development (dev)**: `https://<username>.github.io/<repo>/dev/`

Rolling Verified OSS Loop branches (`preview`, `nightly`) are **not** Pages slots. Do not invent `/preview/<slug>/` without extending `.github/workflows/deploy.yml`.

Replace `<username>` with your GitHub username and `<repo>` with your repository name.

## How It Works
Expand Down
31 changes: 31 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Bug
description: Something is broken. Include a red command if you have one.
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Search open issues and PRs first. Issues are not claims — a claim lease comes after this is triaged `claimable`.
- type: textarea
id: expected
attributes:
label: Expected
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual
validations:
required: true
- type: textarea
id: red
attributes:
label: Red command
description: Exact command that fails, or "manual / no command yet"
placeholder: pytest tests/test_foo.py::test_bar
- type: textarea
id: environment
attributes:
label: Environment
placeholder: OS, language version, commit SHA
25 changes: 25 additions & 0 deletions .github/ISSUE_TEMPLATE/claim.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Claim
description: Bounded claim lease for an already-triaged claimable issue. Prefer a comment on the existing issue.
title: "claim: "
labels: ["claimed"]
body:
- type: markdown
attributes:
value: |
Prefer commenting this YAML on the existing issue. Open this form only if the project asks for a dedicated claim issue.
- type: textarea
id: lease
attributes:
label: Lease
value: |
```yaml
issue:
claimant:
base_revision:
claimed_at:
expires_at:
scope:
work_url:
```
validations:
required: true
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Discussions
url: https://github.com/kvnloo/ace/discussions
about: Ideas, adoption help, or questions that are not a claimable issue
26 changes: 26 additions & 0 deletions .github/ISSUE_TEMPLATE/feature.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Feature
description: A proposed change. Maintainers own whether it is claimable.
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Do not start work until this issue is `claimable` and you hold a claim lease.
- type: textarea
id: problem
attributes:
label: Problem
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposal
validations:
required: true
- type: textarea
id: acceptance
attributes:
label: Acceptance
description: What a reviewer can check on an exact head
placeholder: test name, docs path, or runtime check
37 changes: 37 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Summary

<!-- What this PR does, in one paragraph. -->

## Checklist

- [ ] **Ownership respected**: changes stay inside `AGENTS.md` boundaries
- [ ] **Searched issues/PRs**: no duplicate in-flight work
- [ ] **Claimed issue**: work started after a bounded claim, not from the issue title alone
- [ ] **Fail-then-pass**: bug fixes include the red command and the green command
- [ ] **No secrets**: no tokens, API keys, `.env`, or pairing files
- [ ] **Mode** (select one):
- [ ] **Unattended** — donated compute (cloud agent)
- [ ] **Copilot** — human-supervised
- [ ] **Workers never merge `main`/`dev`**: this PR does not grant worker merge of production

## Evidence

```yaml
issue:
base_revision:
head_revision:
tests:
red:
green:
sabotage:
mutation: n/a
runtime_evidence: []
limitations: []
ai_assistance:
```

Tests from another head are not evidence. If mutation is `n/a`, write `n/a` — do not invent a score. The receipt workflow fails the PR if these keys are empty or `head_revision` is not this PR's SHA.

## Related

<!-- Fixes #123 -->
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Stack-neutral: GitHub Actions only. Do not add npm/pip/cargo ecosystems here;
# oss-onboard must not bake a language lockfile updater into every target.
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- enhancement
- area:verify
25 changes: 25 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
area:docs:
- changed-files:
- any-glob-to-any-file:
- 'docs/**/*'
- '*.md'
- 'AGENTS.md'
- 'README.md'
- 'CONTRIBUTING.md'

area:loop:
- changed-files:
- any-glob-to-any-file: '.github/**/*'

area:verify:
- changed-files:
- any-glob-to-any-file:
- 'tests/**/*'
- 'scripts/**/*'
- '**/*.test.*'
- 'skills/tdd/**'
- 'skills/verify/**'
- 'skills/orient/**'
- 'skills/anti-slop/**'
- 'skills/pstack/**'
- 'skills/dr-eggbot/**'
37 changes: 37 additions & 0 deletions .github/labels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Labels for the Verified OSS Loop

Create these in GitHub Settings → Labels, or copy and run `.github/scripts/create-labels.sh` (`--labels` on init).

## Loop

| Name | Color | Meaning |
|---|---|---|
| claimable | 0E8A16 | Maintainers opened this for a bounded claim |
| claimed | FBCA04 | A live lease exists |
| needs-discussion | D876E3 | Maintainer or worker proposal; not a claim until promoted to claimable |
| needs-review | 5319E7 | Evidence receipt is attached; independent review next |
| blocked | D93F0B | External or policy block |
| keep | 1D76DB | KEEP after merge |
| discard | 6A737D | DISCARD with a lesson, not silence |

## Priority

| Name | Color |
|---|---|
| priority:P0 | D73A4A |
| priority:P1 | E99695 |
| priority:P2 | F9D0C4 |
| priority:P3 | FEF2C0 |

## Kind

| Name | Color |
|---|---|
| bug | D73A4A |
| enhancement | A2EEEF |
| security | B60205 |
| good-first-issue | 7057FF |
| area:docs | 0075CA |
| area:loop | C5DEF5 |
| area:verify | BFDADC |
| stale | FFFFFF |
140 changes: 140 additions & 0 deletions .github/scripts/check-receipt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""Check a Verified OSS Loop evidence receipt. Stdlib only. Does not merge."""
from __future__ import annotations

import argparse
import re
import sys
from typing import Any

SHA_RE = re.compile(r"^[0-9a-f]{7,40}$", re.I)
REQUIRED_TOP = ("issue", "base_revision", "head_revision")


def extract_yaml_blocks(text: str) -> list[str]:
blocks = re.findall(r"```(?:ya?ml)\s*\n(.*?)```", text, re.S | re.I)
if blocks:
return blocks
stripped = text.strip()
if stripped.startswith("---") or re.search(r"^(issue|base_revision|head_revision)\s*:", stripped, re.M):
return [text]
return [text]


def parse_simple_yaml(block: str) -> dict[str, Any]:
"""Tiny YAML subset: top-level keys and one nested mapping (tests)."""
data: dict[str, Any] = {}
current_map: dict[str, str] | None = None
current_key: str | None = None
for raw in block.splitlines():
if not raw.strip() or raw.strip().startswith("#"):
continue
nested = re.match(r"^ ([A-Za-z0-9_]+)\s*:\s*(.*)$", raw)
if nested and current_map is not None:
current_map[nested.group(1)] = nested.group(2).strip()
continue
top = re.match(r"^([A-Za-z0-9_]+)\s*:\s*(.*)$", raw)
if not top:
continue
key, val = top.group(1), top.group(2).strip()
if val == "" or val == "|":
current_map = {}
data[key] = current_map
current_key = key
continue
data[key] = val
current_map = None
current_key = key
_ = current_key
return data


def pick_receipt(text: str) -> dict[str, Any]:
best: dict[str, Any] = {}
score = -1
for block in extract_yaml_blocks(text):
parsed = parse_simple_yaml(block)
hits = sum(1 for k in REQUIRED_TOP if k in parsed)
if hits > score:
best, score = parsed, hits
return best


def nonempty(val: Any) -> bool:
if val is None:
return False
if isinstance(val, dict):
return any(nonempty(v) for v in val.values())
return str(val).strip() not in ("", "null", "~")


def sha_ok(val: Any) -> bool:
s = str(val).strip().lower()
return bool(SHA_RE.match(s))


def heads_match(receipt_head: str, expected: str) -> bool:
a, b = receipt_head.strip().lower(), expected.strip().lower()
return a == b or a.startswith(b) or b.startswith(a)


def check(text: str, expected_head: str | None = None) -> list[str]:
errors: list[str] = []
data = pick_receipt(text)
if not data:
return ["no evidence YAML found (need a ```yaml receipt with issue/base_revision/head_revision)"]

for key in REQUIRED_TOP:
if key not in data:
errors.append(f"missing {key}")
elif not nonempty(data[key]):
errors.append(f"{key} is empty")

if "base_revision" in data and nonempty(data["base_revision"]) and not sha_ok(data["base_revision"]):
errors.append("base_revision is not a git SHA")
if "head_revision" in data and nonempty(data["head_revision"]) and not sha_ok(data["head_revision"]):
errors.append("head_revision is not a git SHA")

tests = data.get("tests")
if not isinstance(tests, dict):
errors.append("missing tests mapping with red/green")
else:
if not nonempty(tests.get("red")):
errors.append("tests.red is empty")
if not nonempty(tests.get("green")):
errors.append("tests.green is empty")

if expected_head:
head = str(data.get("head_revision") or "").strip()
if not head:
errors.append("head_revision missing; cannot bind to exact head")
elif not heads_match(head, expected_head):
errors.append(
f"head_revision {head} does not match PR head {expected_head} "
"(tests from another SHA are not evidence)"
)
return errors


def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description="Validate a Verified OSS Loop evidence receipt")
p.add_argument("--file", help="PR body or receipt markdown/YAML (default: stdin)")
p.add_argument("--head", help="Expected PR head SHA (exact-head check)")
args = p.parse_args(argv)
if args.file:
with open(args.file, encoding="utf-8") as f:
text = f.read()
else:
text = sys.stdin.read()
errors = check(text, args.head)
if errors:
print("receipt check failed:")
for e in errors:
print(f" - {e}")
return 1
print("ok: evidence receipt is complete")
return 0


if __name__ == "__main__":
sys.exit(main())
38 changes: 38 additions & 0 deletions .github/scripts/create-labels.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Create Verified OSS Loop labels on the current GitHub repo.
# Requires: gh auth. Does not overwrite existing label descriptions.
set -euo pipefail

if ! command -v gh >/dev/null 2>&1; then
echo "gh is required" >&2
exit 1
fi

create() {
local name="$1" color="$2" desc="$3"
if gh label list --limit 200 --json name --jq '.[].name' | grep -Fxq "$name"; then
echo "exists: $name"
return 0
fi
gh label create "$name" --color "$color" --description "$desc"
}

create claimable "0E8A16" "Maintainers opened this for a bounded claim"
create claimed "FBCA04" "A live claim lease exists"
create "needs-discussion" "D876E3" "Maintainer or worker proposal; not a claim until promoted to claimable"
create needs-review "5319E7" "Evidence receipt attached; independent review next"
create blocked "D93F0B" "External or policy block"
create keep "1D76DB" "KEEP after merge"
create discard "6A737D" "DISCARD with a recorded lesson"
create "priority:P0" "D73A4A" "Critical"
create "priority:P1" "E99695" "High"
create "priority:P2" "F9D0C4" "Medium"
create "priority:P3" "FEF2C0" "Low"
create bug "D73A4A" "Something is broken"
create enhancement "A2EEEF" "Proposed change"
create security "B60205" "Security-sensitive; do not discuss exploits in public"
create "good-first-issue" "7057FF" "Good first claim after triage"
create "area:docs" "0075CA" "Documentation"
create "area:loop" "C5DEF5" "Claim/lease/receipt process"
create "area:verify" "BFDADC" "Tests, mutation, evidence"
create stale "FFFFFF" "Quiet; not a claim block"
Loading
Loading