Skip to content

feat(.github): add recurring module scorecard workflow#1012

Merged
bpmct merged 9 commits into
mainfrom
bpmct/module-scorecards
Jul 14, 2026
Merged

feat(.github): add recurring module scorecard workflow#1012
bpmct merged 9 commits into
mainfrom
bpmct/module-scorecards

Conversation

@bpmct

@bpmct bpmct commented Jul 14, 2026

Copy link
Copy Markdown
Member

Adds a recurring workflow that scores every module in the coder namespace against a documented rubric and posts the results as GitHub Discussions: one dedicated discussion per module, plus a pinned 📊 Module Scorecards index grouped by module type (Agent / IDE / Utility). A separate PR workflow compares changed modules against their current score and comments with the diff.

Why a scorecard? It gives us a shared definition of quality (and a goalpost) for modules: what we care about for each one, in one place, for any contributor. It is not a strict gate today, though it may become one, and the criteria will evolve over time. It also helps catch regressions, for example a feature or documented capability being removed, since scores are re-evaluated whenever a module changes.

The rubric lives in .github/scorecard/SCORECARD.md and is read directly by the scoring script at runtime, so editing that one file changes the criteria for every future run. No script changes needed.

Suggested review order

  1. .github/scorecard/SCORECARD.md - the contract (80 lines)
  2. .github/scorecard/lib.ts - shared parsing + GraphQL helpers
  3. .github/scorecard/score-modules.ts - scoring + discussion upserts + PR reports
  4. .github/scorecard/scorecard-index.ts - index aggregation
  5. The two workflow files - plumbing

Rather than simulating the prompt, validate against live output: all 48 modules were scored and posted from this code. Example module discussion: Claude Code module; index: #1011.

Changes

  • .github/scorecard/SCORECARD.md - the rubric: universal themes (Presentation & Onboarding, Credential Hygiene, Restricted-Network Readiness, Engineering Quality) plus a track section (Agent / IDE / Utility) out of 100
  • .github/scorecard/lib.ts - shared constants, summary-table parsing, GraphQL client, discussion lookup
  • .github/scorecard/score-modules.ts - scores modules with Claude (claude-sonnet-4-5, temperature 0), recomputes the overall deterministically from theme scores, and upserts each module's discussion. --pr-report mode compares against the current discussion instead of posting
  • .github/scorecard/scorecard-index.ts - rebuilds the pinned index from the module discussions, grouped by track
  • .github/workflows/module-scorecards.yaml - weekly cron, workflow_dispatch, push to main: rubric change triggers a full run, module changes trigger a scoped run of just those modules; index rebuilds either way
  • .github/workflows/module-scorecard-check.yaml - on PRs touching modules (internal only), scores the changed modules and posts a sticky comment flagging regressions, improvements, or unchanged scores. Read-only against discussions

Secrets

Both are already added to this repo's Actions secrets, so the workflows are ready to run on merge:

  • SCORECARD_ANTHROPIC_API_KEY - Anthropic API key for scoring
  • SCORECARD_DISCUSSIONS_TOKEN - GitHub PAT with Discussions read/write
Design notes
  • Scoring: each criterion is 0 / half / full. Full = implemented and documented. Criteria marked if applicable (Restricted-Network Readiness) are excluded from the denominator when the concern doesn't exist by construction (e.g. git-clone downloads nothing), and the score normalizes to 100.
  • Utility modules skip the track section and normalize from the universal themes only.
  • Internal building blocks (READMEs cautioning against direct use, e.g. coder-utils, agentapi, vscode-desktop-core) are excluded from scoring entirely via a deterministic README check.
  • Deterministic math: the model emits per-criterion scores, but the overall is recomputed by the script from the summary row to prevent arithmetic drift. temperature: 0 keeps re-scores stable (verified: identical re-score on an unchanged module).
  • Idempotency: module discussions are found by title (display name + "module") and updated in place via a hidden module-scorecard HTML comment marker; the index and PR comments use module-scorecard-index and module-scorecard-pr markers respectively.
  • Display name renames: the PR check falls back to finding the old discussion by registry URL and warns in its comment so a maintainer can retitle or delete the old one.
  • Index aggregation reads the summary tables back from the module discussions, so scoped single-module runs still produce a complete index.
  • New modules are picked up automatically: the PR check reports a "first scorecard", and the post-merge run creates the module's discussion and adds it to the index.

🤖 Generated with Coder Agents

@bpmct
bpmct marked this pull request as ready for review July 14, 2026 16:44
@bpmct
bpmct requested a review from jdomeracki-coder as a code owner July 14, 2026 16:44
@bpmct
bpmct requested a review from DevelopmentCats July 14, 2026 16:57

@DevelopmentCats DevelopmentCats left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cant say that I have any complaints since we went through most of this together @bpmct but Jakub might :P

@bpmct
bpmct merged commit 53f5e62 into main Jul 14, 2026
6 checks passed
@bpmct
bpmct deleted the bpmct/module-scorecards branch July 14, 2026 18:34

@david-fraley david-fraley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two primary thoughts for ya @bpmct

  1. Adding in a complementary skill for how to interact with all this, that points at scorecard.md. Could help with the inevitable AI use in module creation/maintenance that might occur. I'm thinking of this like school -- you, the prof, just handed out the rubric; can you give students a study sheet (the skill) so that they build what you want
  2. Is it possible to extend this to templates?

bpmct added a commit that referenced this pull request Jul 15, 2026
…overall math (#1013)

Follow-up to #1012, which merged before the last two commits on its
branch landed. This carries the scoring calibration fix and the index
intro restructure.

## Why

An audit of the initial batch found the model systematically
over-crediting Restricted-Network Readiness. 10 modules scored 20/20;
most were wrong. The model's own notes rationalized credit with
reasoning like "the URL **could be proxied/mirrored at network level**"
(any URL can) and endpoints being "**implicit** in API key usage"
(implicit is not documented). claude-code scored 20/20 on
restricted-network with no mirror variable and no air-gap docs.

## Changes

- **`SCORECARD.md`**: tightened criteria definitions. Mirrorable
artifact source requires an actual module variable overriding the tool's
own download URL (auxiliary config URLs, proxies, and DNS rewrites do
not count). Egress transparency requires a dedicated section enumerating
endpoints. New Strictness rule: never credit out-of-module workarounds
or infer undocumented behavior.
- **`score-modules.ts`**: calibration anchors in the scoring prompt.
Highlights: name the exact URL-override variable or score 0;
offline/skip-install modes count only toward bring-your-own binary;
theme-level N/A is for modules that download nothing, 0 is for missing
capability; inline placeholder keys in README examples cap the secrets
criterion at half; perfect theme scores trigger a self-recheck.
- **`score-modules.ts`**: `fixOverall` now catches a utility overall
emitted as `X / 75` and normalizes it to `/ 100` (previously passed
through unrecomputed).
- **`scorecard-index.ts`**: index intro restructured as what / why / how
it's generated.

## Validation

All 48 discussions were re-scored with this code. Only 3 modules retain
20/20 restricted-network, each verified legitimate: Amazon Q
(`q_install_url` + air-gapped section), Portable Desktop (`url` +
checksum), Mux (`registry_url`). claude-code dropped to 67 (matches a
manual hand-score of ~65), code-server 97 → 87. Live results: [📊 Module
Scorecards](#1011).

Known limitation, unchanged by this PR: ±3-5 run-to-run noise on
subjective criteria even at temperature 0. If the PR regression comments
get noisy, a follow-up can add a tolerance band.

🤖 Generated with [Coder Agents](https://coder.com/docs/ai-coder/agents)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants