Skip to content
Merged
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
109 changes: 109 additions & 0 deletions .github/skills/statistics-infographic/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: statistics-infographic
description: Generate a readable six-panel repository statistics infographic from validated JSON, with exact arithmetic and independent raw GitHub/Git reconciliation.
---

# Repository statistics infographic

Use when asked to consolidate repository-statistics slides into one image, regenerate
the infographic with updated data, or verify its calculations. This is a reusable
six-panel statistical template, not an arbitrary PowerPoint screenshot collage.

The panels cover inferred PR initiation, merge/closed outcomes, start-to-merge
durations, community issue outcomes, Go/JavaScript code composition, and weekly
first-parent code changes. Repository names, dates, counts, proportions, and weeks
come from the input, never from this skill's original dataset.

## Generate

Prefer already collected source evidence. Do not fetch repository data, trigger
workflows, or invent missing statistics. Keep raw data and generated images out of
the repository. Use a temporary or session artifact directory.

Create a Python 3.9+ virtual environment and install the runtime manifest:

```bash
python3 -m venv /tmp/statistics-infographic-venv
/tmp/statistics-infographic-venv/bin/python -m pip install \
-r .github/skills/statistics-infographic/requirements.txt
```

Supply either one JSON object following
[examples/example.json](examples/example.json), or a directory of existing summaries:

```bash
/tmp/statistics-infographic-venv/bin/python \
.github/skills/statistics-infographic/scripts/render_infographic.py \
--input .github/skills/statistics-infographic/examples/example.json \
--output /tmp/statistics-infographic.png
```

For real data, replace `--input` with `--data-dir /path/to/summaries`.
See [references/data-contract.md](references/data-contract.md) for schemas and
statistical definitions. The example is explicitly synthetic, not a gh-aw report.

Optional arguments: `--title`, `--font-regular`, and `--font-bold`. Supply both font
paths together. Automatic discovery supports Arial on macOS/Windows and Liberation
Sans or DejaVu Sans on Linux. Missing fonts fail explicitly; no bitmap fallback is
used.

The output is a static, RGB, 2560 x 3200 PNG with 300-DPI metadata. A successful
render atomically replaces the explicit output path. Invalid data, unreadable
layout, or invalid fonts leave an existing output intact. Counts too large for
their slots, more than 10 duration bands, or more than 260 weeks require a different
layout; do not silently truncate, rescale text to illegibility, or aggregate data.

## Verify accuracy

Input validation proves internal reconciliation, not correctness of the evidence.
When cached raw API records are available, independently recompute the displayed
statistics before delivery:

```bash
/tmp/statistics-infographic-venv/bin/python \
.github/skills/statistics-infographic/scripts/audit_sources.py \
--data-dir /path/to/summaries \
--raw-dir /path/to/raw-records \
--repo /path/to/local-checkout
```

The auditor also accepts `--input` instead of `--data-dir`. Omit `--repo` only if
local Git evidence is unavailable, and disclose that code/history were not audited.
For a repository migration, explicitly supply a repeatable
`--repository-alias previous-owner/previous-name` only when issue numbering is
known to be shared.

The Git audit reads immutable objects at the full input commit, not the worktree.
It requires complete local history, disables lazy object fetching, and never
requests credentials or performs network operations. Missing objects or shallow
history fail explicitly. Large repositories may require substantial memory for
the batched blob inventory.

Open the resulting image and inspect all six panels at normal viewing size:
titles, axes, labels, footnotes, chart proportions, and snapshot metadata. Automated
text-bound and overlap checks complement but do not replace visual inspection.

Deliver the image with its path and disclose missing independent checks or evidence
limitations. In particular, inferred source issues do not prove who initiated an
agent session or which device they used. The no-issue human assumption must be
explicitly authorized for the dataset.

## Maintain

Install the development manifest only for validation work:

```bash
/tmp/statistics-infographic-venv/bin/python -m pip install \
-r .github/skills/statistics-infographic/requirements-dev.txt
HYPOTHESIS_STORAGE_DIRECTORY=/tmp/statistics-infographic-hypothesis \
/tmp/statistics-infographic-venv/bin/python -m unittest discover \
-s .github/skills/statistics-infographic/tests -v
/tmp/statistics-infographic-venv/bin/python -m mypy --strict \
.github/skills/statistics-infographic/scripts
```

The implementation uses immutable typed records, explicit invariants, exact
rational count ratios with half-up rounding, Decimal-oracle property tests,
source-mutation regressions, deterministic rendering, safe CLI output tests, and
pinned-object Git fixtures. These are rigorous software checks, not a mathematical
proof of the whole program or of causal attribution.
78 changes: 78 additions & 0 deletions .github/skills/statistics-infographic/examples/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"origins": {
"repository": "example/metrics",
"snapshot_date": "2026-10-08",
"assumption": "For this synthetic example, all CCA PRs without an identified issue are assumed human-started.",
"total_prs": 100,
"breakdown": [
{ "origin": "AW-started", "prs": 45 },
{ "origin": "Human-started, including assumed direct sessions", "prs": 50 },
{ "origin": "Other / unattributed", "prs": 5 }
],
"components": {
"direct_aw_prs": 15,
"cca_aw_issue_prs": 30,
"cca_human_issue_prs": 10,
"cca_no_issue_assumed_human_prs": 40,
"other_account_prs": 3,
"dependabot_prs": 1,
"mix_prs": 1
},
"outcomes": [
{ "origin": "AW-started", "merged": 30, "closed_without_merging": 15, "open": 0 },
{ "origin": "Human-started, including assumed direct sessions", "merged": 40, "closed_without_merging": 8, "open": 2 },
{ "origin": "Other / unattributed", "merged": 3, "closed_without_merging": 1, "open": 1 }
]
},
"histogram": {
"repository": "example/metrics",
"snapshot_date": "2026-10-08",
"merged_pr_count": 73,
"summary_hours": { "median": 2, "p90": 40.4 },
"histogram": [
{ "bin": "<15 min", "lower_hours_inclusive": 0, "upper_hours_exclusive": 0.25, "count": 10 },
{ "bin": "15-60 min", "lower_hours_inclusive": 0.25, "upper_hours_exclusive": 1, "count": 20 },
{ "bin": "1-6 hours", "lower_hours_inclusive": 1, "upper_hours_exclusive": 6, "count": 25 },
{ "bin": "6-24 hours", "lower_hours_inclusive": 6, "upper_hours_exclusive": 24, "count": 10 },
{ "bin": "1-3 days", "lower_hours_inclusive": 24, "upper_hours_exclusive": 72, "count": 4 },
{ "bin": "3-7 days", "lower_hours_inclusive": 72, "upper_hours_exclusive": 168, "count": 2 },
{ "bin": "7-30 days", "lower_hours_inclusive": 168, "upper_hours_exclusive": 720, "count": 2 },
{ "bin": "30+ days", "lower_hours_inclusive": 720, "upper_hours_exclusive": null, "count": 0 }
]
},
"community": {
"repository": "example/metrics",
"collected_at": "2026-10-08T21:19:30Z",
"all_labelled_issues": 40,
"third_party_issues": 30,
"third_party_author_accounts": 12,
"third_party_issues_landed_main": 20,
"closed_without_merged_main_link": 9,
"third_party_open_issues": 1,
"unique_merged_main_delivery_prs": 18,
"copilot_authored_delivery_prs": 16
},
"structure": {
"repository": "example/metrics",
"commit": "1111111111111111111111111111111111111111",
"included_files": 75,
"nonblank_lines": 20000,
"groups": [
{ "language": "Go", "role": "Implementation", "files": 20, "nonblank_lines": 6000 },
{ "language": "Go", "role": "Tests", "files": 30, "nonblank_lines": 8000 },
{ "language": "JavaScript", "role": "Implementation", "files": 10, "nonblank_lines": 2000 },
{ "language": "JavaScript", "role": "Tests", "files": 15, "nonblank_lines": 4000 }
]
},
"history": {
"repository": "example/metrics",
"commit": "1111111111111111111111111111111111111111",
"week_count": 2,
"total_added": 34000,
"total_deleted": 14000,
"weeks": [
{ "week_start": "2026-09-28", "added": 30000, "deleted": 12000 },
{ "week_start": "2026-10-05", "added": 4000, "deleted": 2000 }
]
}
}
127 changes: 127 additions & 0 deletions .github/skills/statistics-infographic/references/data-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Data contract and interpretation

Use [the synthetic example](../examples/example.json) as the complete minimal input
template. One JSON object has five sections. Alternatively, `--data-dir` maps them
to these filenames:

| Section | Filename | Required evidence |
|---|---|---|
| `origins` | `pr-initiation-assumption-summary.json` | Repository, census date, authorized assumption, three disjoint origin buckets, seven components, outcome counts |
| `histogram` | `pr-time-to-merge-histogram.json` | Same repository/date, merged population, contiguous duration bands, median and P90 in hours |
| `community` | `community-statistics-summary.json` | Repository, timezone-aware collection timestamp, labelled/eligible issues, accounts, issue outcomes, deduplicated delivery PRs |
| `structure` | `repo-structure-statistics.json` | Repository, full commit ID, file/nonblank-line totals, four Go/JavaScript implementation/test groups |
| `history` | `weekly-code-history.json` | Same repository/commit, contiguous Monday-start weeks, additions/deletions and totals |

Counts must be nonnegative integers, not booleans, strings, or floats. All
repositories must match. PR and histogram census dates must match; community has
its own collection time because collection is not atomic. Code and history share
one full 40- or 64-character hexadecimal Git object ID. Optional precomputed
percentages and ratios consumed by the model must agree with the derived rounded
values. Unused metadata is not independently validated.

## PR populations

Use these exact origin names:

- `AW-started`
- `Human-started, including assumed direct sessions`
- `Other / unattributed`

Each has merged, closed-without-merging, and open counts. Their sum must equal the
census. Origin breakdowns and component sums must reconcile. An optional `All PRs`
outcome record must also match.

The source auditor follows this documented **inference policy**, not observed
session-initiation telemetry:

- Direct AW PR: `github-actions` author and recognized workflow provenance marker.
- CCA: `copilot-swe-agent` author. Explicit issue references in the CCA suffix take
precedence; otherwise combine closing-issue links and supported closing-keyword
references from the body, restricted to the repository and authorized aliases.
- AW issue: Bot author plus recognized workflow provenance marker.
- Human-account issue: User author without recognized bot/machine-user naming.
- No identified source issue: assume human initiation **only with user
authorization**, recorded in `assumption`.
- Missing/deleted authors, other automation, and mixed sources remain unattributed.

Account type is not proof of a person, and issue provenance is not proof of the
session initiator. Do not infer phone use or causality. The seven component fields
are shown in the example; the auditor verifies the four named AW/human components
and aggregate outcomes, not a finer subdivision of the residual other bucket.

Origin shares divide by all PRs. Completed merge rate divides merged by
merged + closed-unmerged, excluding open PRs. The displayed ratio divides merged
by closed-unmerged, not by all closed states including merged PRs.

## Time to merge

Measure `mergedAt - createdAt` in UTC for merged PRs only. Boundaries are
lower-inclusive and upper-exclusive; `null` is the final unbounded upper limit.
Bands must cover `[0, infinity)` without gaps/overlap and include boundaries at
1, 6, and 24 hours. Counts sum to the merged population.

Median and P90 use sorted elapsed times with linear interpolation at
`(n - 1) * q`. The model checks ordering and histogram-implied feasible ranges;
only raw-record auditing independently verifies the exact quantiles. Empty
merged populations require `null` quantiles. Percentages under each threshold use
merged PRs as denominator, never all PRs.

Count-derived percentages use exact fractions rounded half up to one decimal;
merge ratios use two decimals. Undefined zero denominators show `n/a`, not 0%.
Histogram/time geometry uses floating-point coordinates, not displayed count
arithmetic.

## Community outcomes

The labelled-issue population must be collected explicitly and completely.
Eligible third-party issues have a User author and association `NONE`,
`CONTRIBUTOR`, `FIRST_TIMER`, or `FIRST_TIME_CONTRIBUTOR`. Distinct author logins are
accounts, not verified people. This differs from CCA source classification and
does not independently exclude every machine-user account.

A landed issue is closed and has a linked merged PR targeting `main` in the same
repository. Landed, closed-without-such-a-link, and open issues form a disjoint
partition. Delivery PRs are deduplicated by number, independently of the issue
count; one PR can link multiple issues. CCA delivery share divides by distinct
delivery PRs. Links do not prove released impact, work causality, or sole credit.

## Code and history

The code scope is Go and JavaScript (`.go`, `.js`, `.cjs`, `.mjs`, `.jsx`), not all
repository languages. Inventory excludes dependency/build/fixture paths,
generated filenames/headers, and the auditor's explicit bundle exclusions.
Classification follows the auditor's `excluded`, `group_key`, and generated-header
rules. The four groups contain distinct language/role pairs; file and nonblank
line totals must reconcile. Test-line share is code volume, **not test coverage**.

History uses complete first-parent traversal at the pinned commit, UTC committer
weeks, root diffs, and merge diffs against the first parent. Renames count as
deletions/additions. Weekly diff totals include blank lines, unlike the code map.
Empty weeks between the first and last selected-code changes are retained.
Historical files whose generated status cannot be identified by the known
path/current-header filters may remain in churn. The auditor verifies each weekly
pair and that net additions minus deletions equals the current physical-line
inventory. It does not equate physical lines with nonblank lines.

## Cached raw records

`--raw-dir` contains flat UTF-8 JSONL records, not GraphQL response envelopes:

- `pr-statistics-data.jsonl`: every census PR's number, state, author login, body,
createdAt, and mergedAt.
- `cca-issue-links.jsonl`: each CCA PR number and `closingIssuesReferences` with
`totalCount` and `nodes`; issue nodes include number, body, repository
`nameWithOwner`, and author login/`__typename`.
- Optional `cca-extra-issues.json`: issue-number keys mapped to cached issue
metadata or `null` for unavailable issues. `not_an_issue: true` identifies a
reference that is actually a PR and is excluded from source issues.
- `community-issues-data.jsonl`: every labelled issue's number, state,
author login/`__typename`, authorAssociation, and
`closedByPullRequestsReferences`. PR nodes include number, mergedAt,
baseRefName, repository `nameWithOwner`, and author login.

Every consumed connection's `totalCount` must equal its node count; paginate
before saving. Duplicate PR/issues, missing CCA inventories/issue metadata,
unknown states, negative durations, and conflicting delivery metadata fail.
The auditor reconciles saved evidence; it does not establish that an upstream
collection was exhaustive or independently recollect the live repository.
3 changes: 3 additions & 0 deletions .github/skills/statistics-infographic/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-r requirements.txt
hypothesis>=6.100,<7
mypy>=1.15,<2
1 change: 1 addition & 0 deletions .github/skills/statistics-infographic/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pillow>=11.0,<13
Loading
Loading