Skip to content

feat(contributor-growth): name contract operations instead of gh; Jira as a tracker backend - #1549

Merged
potiuk merged 6 commits into
apache:mainfrom
potiuk:feat/contributor-growth-contracts
Oct 6, 2026
Merged

potiuk merged 6 commits into
apache:mainfrom
potiuk:feat/contributor-growth-contracts

Conversation

@potiuk

@potiuk potiuk commented Oct 6, 2026

Copy link
Copy Markdown
Member

What

The contributor-growth family called gh directly in about 30 places, and its counting engine, contributor-metrics, was hard-wired to GitHub.
After this PR the skills name capability-contract operations, GitHub is one adapter for them, and Jira is a second backend for the tracker side.
A project that reviews on GitHub and files issues in Jira now gets correct contributor activity from both.

Follows #1548 (the optimization pass on the same family).

Contract operations added

Contract Operations Spec
contract:change-request list_authored, list_reviews_given (counts and lengths, never bodies), list_authored_commits (with a signed_off_by flag for DCO) tools/change-request/README.md
contract:tracker list_filed, list_triaged, list_commented, list_created, first_reply new minimal spec tools/tracker/README.md
contract:source-control repository_metadata, put_file tools/github/source-control.md
contract:people (new) get_profile, list_collaborators, add_team_member (the one write, confirmation-gated) new tools/people/README.md

The GitHub resolutions of every operation live in tools/github/operations.md.

Adapter coverage

GitHub Jira
change-request activity yes no PR model
tracker activity (all five) yes yes
source-control metadata and write yes n/a
get_profile yes yes (display name, existence)
list_collaborators, add_team_member yes no such concept

GitLab, Forgejo and Bitbucket already implement the base contracts; their adapters for the new operations are follow-ups using the same seam.

contributor-metrics

fetch now has two sides: the code host (PRs, reviews, PR threads) and the tracker (issues filed, triaged and commented on).

  • GitHub on both sides: output is byte-for-byte what it was. There is no new key, the cache keys are the same, and all existing tests pass unchanged.
  • Jira as tracker:
    • The tracker is configured from the same <project-config>/issue-tracker-config.md other skills read; flags and environment variables can override it.
    • --tracker-login covers a Jira username that differs from the GitHub handle.
  • Jira client: a new stdlib-only, GET-only client, jira_bridge.rest in tools/jira. Keeping it there leaves the substrate tool free of network code.

Jira token handling

The token is the user's personal credential, while the Jira URL comes from project configuration, which may be committed.
So the client:

  • requires https://, allowing http:// only for loopback;
  • sends the token only to a host the user confirmed (JIRA_API_HOST, or a host= line in ~/.config/apache-magpie/jira-token), and only on requests to that host. Otherwise it reads anonymously and says why;
  • refuses redirects;
  • never puts the token in an error message.

Each rule has a test, including a loopback redirect that must not reach the second server.
Upgrade note: an existing Jira token without a confirmed host is no longer sent. Add host= or set JIRA_API_HOST.

Still GitHub-only

  • GitHub Discussions, an optional signal outside every contract. It is marked as GitHub-adapter-only.
  • The github-codeowners governance model, which is GitHub by definition; its operation still goes through contract:people.
  • Change-request activity on non-GitHub forges, which is a follow-up.

Testing

  • Evals for every touched skill: 129 before (3 failing, all known flakes) → 145/145 after, including a new activity-sweep case with issues from Jira and PRs from GitHub that keeps the same card shape.
  • tools/contributor-metrics: 77 tests. tools/jira has new client tests. ruff and mypy are clean.
  • Validator exit 0 with the same SOFT warnings as main; capability-sync is clean.
  • prek run --all-files is green.
  • Vendor neutrality:
    • skills capability-pure 19 → 22; this family 3 → 6;
    • contracts green 12/15; contract:people is green on GitHub + Atlassian;
    • no skill is vendor-coupled.

The contract:people label needs creating on the repository.


Gen-AI disclosure: prepared with the assistance of Claude Code (Claude Opus 5); reviewed by the author.

🤖 Generated with Claude Code

potiuk added 6 commits October 6, 2026 23:45
…ople

Add the read-only queries the contributor-growth skills need to the
capability contracts, so those skills can stop calling `gh` directly:

- contract:change-request gains list_authored, list_reviews_given and
  list_authored_commits (links, dates, counts and flags; never bodies).
- contract:tracker gets a minimal interface spec, tools/tracker/, for
  list_filed, list_triaged, list_commented, list_created and first_reply.
- contract:source-control documents two hosted-repository operations,
  repository_metadata and put_file, in tools/github/source-control.md.
- New contract:people (tools/people/): profile lookup, repository
  collaborators, and one confirmed write, add_team_member.

GitHub implements every new operation (operations.md § People and
§ Contributor activity); Jira implements the tracker queries and
profile lookup. GitLab, Forgejo and Bitbucket are listed as follow-ups.
contract:people is registered with the validator, the vendor-neutrality
scorer (vendor-backed: GitHub + Atlassian, green), the capability map,
the labeler and the adapter registry.

Generated-by: Claude Opus 5
Split fetching into a code-host side (PRs authored, reviews, PR threads;
contract:change-request) and a tracker side (issues filed, triaged,
issue threads; contract:tracker), so the two can come from different
systems.

Today's GitHub code moves unchanged into backends/github.py. With both
sides on GitHub — the default and the only configuration so far — it
runs exactly the historical searches and produces the same items and
output; every existing test passes untouched. A `streams` argument lets
it answer one side only, searching `type:pr` threads when another
backend owns the issues.

contributor_metrics.fetch is now the dispatcher and keeps its public
names (fetch_items, GhError, InvalidLogin, InvalidRepo, the substantive
defaults). Shared pieces — the side names, the BackendError base and the
generic pushback phrases — live in backends/common.py.

Generated-by: Claude Opus 5
A project can review on GitHub and file issues in Jira. With
`--tracker-config <project-config>/issue-tracker-config.md` naming
`tracker_type: jira` (or `--tracker jira`), GitHub answers PRs, reviews
and PR threads, and the new `jira` backend answers issues filed, issues
triaged and issue threads, for the contributor's `--tracker-login`.

- Issues filed: JQL on reporter and creation date.
- Triage: someone else's issue on which the user changed status,
  labels, component, priority, assignee, resolution or fix version, or
  commented — read from the issue history, plus a direct
  `CHANGED BY … DURING` search that reaches beyond the scan cap.
- Threads: issues the user commented on, dated by their first comment
  in the window.

Pushback candidates use the tracker roster only, since Jira has no
author association; comment bodies stay inside the backend. The URL and
project key resolve from issue-tracker-config.md as other skills
resolve `<issue-tracker>`, overridable with --jira-url/--jira-project.
Output gains a `backends` key and the cache key includes it, only in
Jira mode; GitHub-only output is unchanged.

The HTTP client is a new stdlib-only, GET-only `jira_bridge.rest` in
tools/jira, following the bridge's auth conventions (JIRA_API_TOKEN /
JIRA_AUTH_SCHEME, or a token under ~/.config/apache-magpie), so the
network surface stays in the tracker adapter. Tests run against
recorded responses; no network.

Generated-by: Claude Opus 5
Replace every direct `gh` call in the contributor-growth family with the
contract operation it performs, with GitHub named as the adapter where
it helps and its command shapes kept in tools/github:

- candidate-screen: repository visibility and report commit through
  contract:source-control (repository_metadata, put_file), readers
  through contract:people (list_collaborators), the merged-change pool
  and pre-filter counts through contract:change-request.
- activity-sweep, contributor-to-committer, nomination, calibrate:
  repository age and reachability through repository_metadata, adapter
  auth checks, and contributor-metrics told about a separate tracker
  (--tracker-config, --tracker-login).
- identity-map, real-names, community-signals: profiles and linked
  accounts through contract:people (get_profile), commit e-mails and
  names through list_authored_commits. GitHub Discussions stays an
  optional, clearly marked GitHub-only signal.
- sentiment: issues, first replies, changes and reviews through
  contract:tracker and contract:change-request.
- committer-onboarding: the team invite is contract:people
  add_team_member (GitHub wording kept for the github-codeowners model);
  the DCO check reads signed_off_by from list_authored_commits.

Every gate, confirmation, privacy and injection rule is unchanged, and
so is behaviour on a GitHub project. Token counts restamped.

Generated-by: Claude Opus 5
The Jira URL comes from project configuration, which anyone with write
access can commit, while the token is the user's personal credential.
jira_bridge.rest now keeps a changed URL from silently receiving it:

- the URL must be https:// (http:// only for localhost, 127.0.0.1, ::1);
- the token is sent only to the host the user confirmed for it
  (JIRA_API_HOST, or a host= line beside token= in
  ~/.config/apache-magpie/jira-token) and only on requests to that host;
  otherwise it is withheld, reads go out anonymously, and auth_note —
  surfaced in contributor-metrics notes — says why;
- redirects are refused, naming the target, so the token never follows
  one;
- the token never appears in an error, a note or the client's repr.

Tests cover each rule, including a live loopback redirect that must not
reach the second server.

Generated-by: Claude Opus 5
Add an activity-sweep render case whose PRs and reviews come from GitHub
and whose issues come from a Jira tracker; the card keeps its shape.
Update the candidate-screen deliver output spec that quoted the old gh
command, and regenerate the generated sections.

Generated-by: Claude Opus 5
@github-actions github-actions Bot added family:tools tools/* family:docs Docs, MISSION.md, READMEs family:ci .github workflows, prek, validators capability:triage Sweep + classify + propose disposition capability:review Deep per-item code review or contributor mentoring capability:intake Import external signal + sync tracker state capability:resolve Close-out: invalidate, dedupe, CVE allocate, announcement capability:stats Read-only dashboards, metrics, governance evidence family:contributor-growth contributor-growth skills contract:tracker Tool capability: issue / board / label backend contract:source-control Tool capability: branch / commit / diff / push (VCS) contract:change-request Tool capability: proposed-change review + merge gate (PR / MR / Gerrit change) substrate:analytics Tool substrate: read-only metrics / dashboards / renderers substrate:framework-dev Tool substrate: build / validate / eval the framework itself labels Oct 6, 2026
@potiuk
potiuk merged commit d1f8f2c into apache:main Oct 6, 2026
58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capability:intake Import external signal + sync tracker state capability:resolve Close-out: invalidate, dedupe, CVE allocate, announcement capability:review Deep per-item code review or contributor mentoring capability:stats Read-only dashboards, metrics, governance evidence capability:triage Sweep + classify + propose disposition contract:change-request Tool capability: proposed-change review + merge gate (PR / MR / Gerrit change) contract:people contract:source-control Tool capability: branch / commit / diff / push (VCS) contract:tracker Tool capability: issue / board / label backend family:ci .github workflows, prek, validators family:contributor-growth contributor-growth skills family:docs Docs, MISSION.md, READMEs family:tools tools/* substrate:analytics Tool substrate: read-only metrics / dashboards / renderers substrate:framework-dev Tool substrate: build / validate / eval the framework itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant