Skip to content

Add Better Egg (v2) scoring model#31

Merged
jeffreyksmithjr merged 5 commits into
mainfrom
better-egg
Feb 23, 2026
Merged

Add Better Egg (v2) scoring model#31
jeffreyksmithjr merged 5 commits into
mainfrom
better-egg

Conversation

@jeffreyksmithjr

@jeffreyksmithjr jeffreyksmithjr commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add opt-in v2 scoring model ("Better Egg") based on the validation study (Validation study: GE score predicts merges (AUC 0.671), outperforms all baselines, Better Egg v2 roadmap #27): simplified graph + logistic regression combining graph score, merge rate, and account age
  • Simplify graph builder by removing 3 zero-signal dimensions (self-contribution penalty, language normalization in repo quality, diversity/volume adjustment); language match personalization is retained per validation findings
  • Add closed PR count to GraphQL query at zero API cost for merge rate computation
  • Add scoring_model config (v1 default, v2 opt-in) with --scoring-model CLI option, scoring-model action input/output, MCP parameter, and GOOD_EGG_SCORING_MODEL env var
  • Add "Better Egg" branding and component score breakdown to all output formatters
  • Text dissimilarity intentionally excluded — inverted signal not yet well enough understood
  • 56 new tests (269 total, 93% coverage), full documentation, examples, and CHANGELOG

Test plan

  • uv run pytest --cov=good_egg -v — 269 tests pass, 93% coverage
  • uv run ruff check src/ tests/ scripts/ — all checks pass
  • uv run mypy src/good_egg/ — no issues found
  • Manual smoke test: good-egg score jeffreyksmithjr --repo 2ndSetAI/good-egg --scoring-model v2 --verbose — Better Egg: HIGH (79%)
  • Verify v1 output is unchanged: --scoring-model v1 — Good Egg: HIGH (85%), empty component_scores, scoring_model="v1"
  • Review PR comment rendering with v2 "Better Egg" branding — CI score check passed using @better-egg ref with scoring-model: v2

Review findings addressed

Red team review identified 3 critical, 6 high, 7 medium, 4 low, and 6 informational issues. All were addressed in f6946d6 except text dissimilarity (intentionally excluded). Key fixes:

  • Removed ghost combined_score from all docs (C1)
  • Fixed config field names and weight values in docs to match code (C2, C3)
  • Restored same_language_weight in v2 per issue spec (H2)
  • Explained negative merge_rate_weight in methodology docs (H4)
  • Replaced unsafe Pydantic mutation with model_copy() (H6)
  • Added 3 tests for edge cases: all features disabled, negative weight, opposing signals (M5-M7)
  • Standardized Good Egg (v1) / Better Egg (v2) naming across all docs

Closes #30

Implement the v2 scoring model based on the validation study (5,417 PRs,
49 repos). The v2 model simplifies the graph (removes 3 zero-signal
dimensions) and adds a logistic regression combining graph score with
merge rate and account age.

- Add scoring_model config (v1 default, v2 opt-in) with V2Config block
- Simplify graph builder: no self-contrib penalty, no language
  normalization, no same_language_weight, no diversity/volume adjustment
- Add closed PR count to GraphQL query (zero API cost)
- Add v2 scoring pipeline with sigmoid combined model
- Add "Better Egg" branding and component score breakdown to all
  formatters (markdown, CLI, check-run, JSON)
- Add --scoring-model CLI option, scoring-model action input/output,
  scoring_model MCP parameter, GOOD_EGG_SCORING_MODEL env var
- Add training script for extracting model weights from validation data
- Add 53 new tests (266 total), 93% coverage
- Add documentation across methodology, config, action, library, MCP,
  troubleshooting, README, CHANGELOG, and examples
@github-actions

github-actions Bot commented Feb 23, 2026

Copy link
Copy Markdown

🥚 Better Egg: HIGH Trust

Score: 79%

Score Breakdown

Component Value
Graph Score 80%
Merge Rate 85% (39/46 PRs)
Account Age 4,925 days

Top Contributions

Repository PRs Language Stars
2ndSetAI/good-egg 15 Python 16
jeffreyksmithjr/verskyt 9 Python 2
jeffreyksmithjr/galapagos_nao 7 Elixir 21
aws-samples/aws-big-data-blog 3 Java 895
pytorch/pytorch.github.io 2 HTML 276
nerves-project/nerves_examples 1 Elixir 402
kilimchoi/engineering-blogs 1 Ruby 37160
kdeldycke/plumage 1 CSS 55

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @jeffreyksmithjr, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the scoring capabilities by introducing a new, opt-in 'Better Egg' (v2) model. This model integrates additional signals beyond the contribution graph, such as a user's merge rate and account age, to provide a more robust and comprehensive assessment of trustworthiness. The changes also include extensive updates to configuration, documentation, and output formatting to support the new model, ensuring a seamless experience for users wishing to leverage these advanced scoring features.

Highlights

  • Better Egg (v2) Scoring Model Introduced: An opt-in v2 scoring model, branded 'Better Egg', has been added. This model combines the existing graph score with new features like merge rate and account age using logistic regression, trained on a validation study of 5,129 PRs.
  • Simplified Graph Builder: The graph builder for the v2 model has been simplified by removing three dimensions that provided zero signal: self-contribution penalty, language normalization, and diversity/volume adjustment. This streamlines the graph construction for the combined model.
  • Enhanced Configuration and Control: Users can now select the scoring model (v1 or v2) via a new scoring_model configuration option, a --scoring-model CLI option, a GitHub Action input/output, an MCP server parameter, and a GOOD_EGG_SCORING_MODEL environment variable.
  • Comprehensive Output and Branding: All output formatters (Markdown, CLI table, JSON, GitHub check-run) now include 'Better Egg' branding when using the v2 model, along with a detailed breakdown of component scores (graph score, merge rate, log account age, combined score).
  • Closed PR Count for Merge Rate: The GraphQL query has been updated to fetch the count of closed pull requests at no additional API cost, enabling the calculation of a more accurate merge rate feature for the v2 model.
Changelog
  • CHANGELOG.md
    • Added Better Egg (v2) scoring model, an opt-in combined model extending graph score with merge rate and account age features via logistic regression.
    • Added scoring_model config option (v1 default, v2 for Better Egg).
    • Added v2: config block with graph:, features:, and combined_model: sub-sections.
    • Added --scoring-model CLI option.
    • Added scoring_model GitHub Action input and output.
    • Added scoring_model MCP server parameter on scoring tools.
    • Added GOOD_EGG_SCORING_MODEL environment variable override.
    • Added component score breakdown in v2 output (graph_score, merge_rate, log_account_age, combined_score).
    • Added scoring_model and component_scores fields on TrustScore model.
    • Added 'Better Egg' branding on PR comments when using v2.
    • Added example workflow for v2: examples/better-egg-workflow.yml.
  • README.md
    • Updated to introduce and describe the two scoring models: v1 (Good Egg) and v2 (Better Egg).
  • action.yml
    • Added scoring-model as an input parameter to allow selection of the scoring model.
    • Added scoring-model as an output parameter to indicate which model was used.
  • docs/configuration.md
    • Added a new 'Scoring Model' section detailing how to configure v1 or v2.
    • Introduced the v2 configuration block for Better Egg model parameters.
    • Added GOOD_EGG_SCORING_MODEL to environment variable overrides.
  • docs/github-action.md
    • Updated inputs and outputs tables to include scoring-model.
    • Added a new section 'Using Better Egg (v2)' with an example workflow.
  • docs/library.md
    • Added a new section 'v2 (Better Egg) Configuration' with Python examples for programmatic use.
    • Updated TrustScore model documentation to include scoring_model and component_scores fields.
  • docs/mcp-server.md
    • Updated API endpoints (score_user, check_pr_author, get_trust_details) to accept an optional scoring_model parameter.
    • Modified API responses to include scoring_model and component_scores when v2 is used.
  • docs/methodology.md
    • Added a comprehensive 'Better Egg (v2)' section explaining its motivation, simplified graph, external features, combined model, validation, and component score breakdown.
  • docs/troubleshooting.md
    • Added a 'v2 (Better Egg) Scoring' section to address common questions and differences from v1.
  • examples/.good-egg.yml
    • Added commented-out example configuration for the v2 (Better Egg) scoring model.
  • examples/better-egg-workflow.yml
    • Added a new example GitHub Actions workflow demonstrating how to use the v2 scoring model.
  • scripts/train_v2_weights.py
    • Added a new script to train the v2 (Better Egg) combined model weights from validation study data.
  • src/good_egg/init.py
    • Imported V2Config and added it to the module's __all__ export list.
  • src/good_egg/action.py
    • Modified run_action to read the INPUT_SCORING_MODEL environment variable and apply it to the configuration.
    • Added scoring-model to the GitHub Action outputs.
  • src/good_egg/cli.py
    • Added a --scoring-model option to the score CLI command, allowing users to specify v1 or v2.
  • src/good_egg/config.py
    • Added V2GraphConfig, V2FeaturesConfig, V2CombinedModelConfig, and V2Config Pydantic models to define the structure for v2 model parameters.
    • Introduced a scoring_model field to GoodEggConfig to select between v1 and v2.
    • Updated load_config to support GOOD_EGG_SCORING_MODEL environment variable overrides.
  • src/good_egg/formatter.py
    • Implemented a _brand_name helper function to return 'Better Egg' for v2 scores.
    • Modified format_markdown_comment, format_cli_output, and format_check_run_summary to display 'Better Egg' branding and a component score breakdown for v2 results.
  • src/good_egg/github_client.py
    • Modified the GraphQL query to include closedPullRequests total count for calculating merge rate.
    • Updated get_user_contribution_data to extract and store the closed_pr_count.
  • src/good_egg/graph_builder.py
    • Modified TrustGraphBuilder to accept a simplified flag in its constructor.
    • Adjusted graph building logic to apply simplifications (e.g., no self-contribution penalty, no language normalization) when simplified mode is active for v2.
  • src/good_egg/mcp_server.py
    • Updated _scoring_resources to accept and apply a scoring_model override.
    • Modified score_user, check_pr_author, and get_trust_details functions to pass the scoring_model parameter and include v2-specific fields in their JSON responses.
  • src/good_egg/models.py
    • Added closed_pr_count to the UserContributionData model.
    • Added scoring_model and component_scores fields to the TrustScore model to support v2 results.
  • src/good_egg/scorer.py
    • Refactored the TrustScorer.score method to dispatch to either _score_v1 or _score_v2 based on the configured scoring_model.
    • Implemented _score_v2 to perform scoring using the simplified graph, calculate external features (merge rate, account age), and combine them via logistic regression.
  • tests/conftest.py
    • Added sample_v2_trust_score and sample_v2_contribution_data fixtures for testing the new v2 model.
  • tests/fixtures/user_prs.json
    • Added closedPullRequests field to the mock user data for testing merge rate calculation.
  • tests/test_action.py
    • Added a test to ensure the INPUT_SCORING_MODEL environment variable is correctly read and applied by the GitHub Action.
  • tests/test_cli.py
    • Added a test to verify that the --scoring-model v2 CLI option is correctly processed.
  • tests/test_config.py
    • Added new test classes TestV2Config and TestScoringModelConfig to validate the new v2 configuration models and scoring_model selection mechanisms, including YAML and environment variable overrides.
  • tests/test_formatter.py
    • Added TestBetterEggFormatting to verify that v2 scores are correctly branded as 'Better Egg' and include component score breakdowns in all output formats.
  • tests/test_github_client.py
    • Added a test to confirm that the closed_pr_count is correctly parsed from the GraphQL API response.
  • tests/test_graph_builder.py
    • Added TestSimplifiedMode to verify that the graph builder correctly applies simplifications (e.g., no self-contribution penalty, no language normalization) when in v2 mode.
  • tests/test_mcp_server.py
    • Added tests to ensure the MCP server correctly handles the scoring_model parameter and returns v2-specific fields in its API responses.
  • tests/test_models.py
    • Added tests for the closed_pr_count field in UserContributionData and the scoring_model and component_scores fields in TrustScore.
  • tests/test_scorer.py
    • Added TestV2Scoring to thoroughly test the new v2 scoring logic, including component score population, merge rate calculation, feature toggles, and short-circuiting behavior.
Activity
  • The pull request introduces a new 'Better Egg' (v2) scoring model, which is opt-in and combines graph scores with merge rate and account age.
  • The graph builder has been simplified by removing three dimensions that were found to have zero signal.
  • The GraphQL query was updated to include closed PR counts, enabling the merge rate calculation.
  • Configuration options for the new scoring model have been added across CLI, GitHub Actions, MCP server, and environment variables.
  • Output formatters now display 'Better Egg' branding and a component score breakdown for v2 results.
  • A new script for training v2 model weights was added.
  • Extensive documentation for the v2 model, including methodology, configuration, and troubleshooting, has been provided.
  • Fifty-three new tests were added, bringing test coverage to 93%, ensuring the reliability of the new features.
  • The PR description includes a detailed test plan covering unit tests, linting, type checking, and manual smoke tests for both v1 and v2 outputs.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new 'Better Egg' (v2) scoring model, which extends the existing graph-based scoring (v1) by incorporating merge rate and account age features via logistic regression. The changes involve updating the CHANGELOG.md, README.md, and various documentation files (docs/configuration.md, docs/github-action.md, docs/library.md, docs/mcp-server.md, docs/methodology.md, docs/troubleshooting.md) to reflect the new model, its configuration options, and output details, including a component score breakdown. The core implementation includes adding V2Config to handle v2-specific parameters, modifying the TrustScorer to dispatch between v1 and v2 logic, and updating the GitHubClient to fetch closed PR counts for the new merge rate feature. The GitHub Action, CLI, and MCP server are also updated to support the scoring_model parameter. However, a review comment highlights inconsistencies between the V2Config model's field names (e.g., temporal_merge_rate, graph_score_weight) and the corresponding names used in the documentation and examples (merge_rate, graph_weight), as well as differing default logistic regression weights, which could lead to user confusion and configuration issues.

Comment thread src/good_egg/config.py
@jeffreyksmithjr

Copy link
Copy Markdown
Contributor Author

PR #31 Review: Better Egg (v2) Scoring Model

Critical

C1. Documentation references a combined_score component that does not exist in code

Multiple documentation files reference a combined_score key in component_scores that is never set by the scorer.

Code (src/good_egg/scorer.py:199-204):

component_scores: dict[str, float] = {
    "graph_score": graph_score,
}
if merge_rate is not None:
    component_scores["merge_rate"] = merge_rate
component_scores["log_account_age"] = log_account_age

The keys populated are graph_score, merge_rate, and log_account_age. There is no combined_score key.

But documentation claims it exists:

  • docs/library.md:122: result.component_scores['combined_score'] — will raise KeyError at runtime
  • docs/library.md:162: lists combined_score as a component
  • docs/mcp-server.md:93,131,207: example JSON responses include "combined_score": 0.82
  • docs/methodology.md:256: table lists combined_score as a component
  • CHANGELOG.md:23: changelog claims combined_score is included

This is a user-facing breakage: anyone following the library documentation to access combined_score will get a KeyError.

C2. Config field names in documentation/examples do not match actual code (confirms Gemini finding)

V2FeaturesConfig and V2CombinedModelConfig use field names that differ from what documentation and examples show.

Actual code (src/good_egg/config.py):

  • V2FeaturesConfig.temporal_merge_rate (line 123)
  • V2CombinedModelConfig.graph_score_weight (line 134)

Documentation uses different names:

  • docs/configuration.md:113: merge_rate: true (should be temporal_merge_rate: true)
  • docs/configuration.md:117: graph_weight: 3.0 (should be graph_score_weight)
  • docs/library.md:100-106: "merge_rate": True and "graph_weight": 3.0
  • examples/.good-egg.yml:101: merge_rate: true (should be temporal_merge_rate: true)
  • examples/.good-egg.yml:105: graph_weight: 3.0 (should be graph_score_weight)

Since Pydantic's BaseModel silently ignores unknown fields, users who copy the example config will get default values with no error, making this an insidious silent failure.

C3. Default weight values in documentation differ from trained values in code

Actual trained weights in V2CombinedModelConfig (config.py:133-136):

intercept: float = -0.8094
graph_score_weight: float = 1.9138
merge_rate_weight: float = -0.7783
account_age_weight: float = 0.1493

Documentation and examples show completely different values:

  • docs/configuration.md:116-119: intercept: -1.5, graph_weight: 3.0, merge_rate_weight: 1.2, account_age_weight: 0.4
  • docs/library.md:101-106: same incorrect values
  • examples/.good-egg.yml:109-112: same incorrect values

The merge_rate_weight in code is -0.7783 (negative) but documentation shows 1.2 (positive). This fundamentally reverses the direction of the merge rate effect.


High

H1. Temporal merge rate scoping is NOT implemented as specified

Issue #30 requirement:

Compute the author's merge rate using only PRs merged/closed before the PR being scored.

The actual implementation (scorer.py:173-178) uses total lifetime counts, not temporally-scoped counts. The GraphQL query fetches closedPullRequests(states: CLOSED, first: 0) { totalCount } which returns the total count, not per-PR temporal data.

The feature name temporal_merge_rate in V2FeaturesConfig is therefore misleading. This is a total-count merge rate.

H2. Language match (same_language_weight) is removed in v2 despite issue saying to retain it

Issue #30 explicitly states:

Repo quality (stars, archived, fork) and language match (personalization weighting) are retained — both showed small but significant effects.

However, in graph_builder.py:117-121, when self.simplified is True (v2 mode), the same_language_weight personalization boost is skipped entirely. The methodology doc even acknowledges this removal.

This contradicts the issue requirement. Either the issue needs updating or the code needs to retain same_language_weight in v2.

H3. Text dissimilarity feature is completely absent

Issue #30 requirement #4 specifies adding text dissimilarity as an off-by-default feature with configuration support. There is zero implementation: no config class, no scoring code, no stub. The methodology doc states it "was investigated but not implemented," but the issue explicitly requests it. (Note: the implementation plan said to skip this, so this may be an intentional deviation, but it's not documented on the issue.)

H4. Negative merge_rate_weight (-0.7783) is unexplained and counterintuitive

Higher merge rates decrease the combined score. This is not explained anywhere in the methodology doc, troubleshooting doc, or code comments. Without explanation, this looks like either a training bug or a confusing design choice. Possible explanations (survivorship bias correction, correlation with graph score) should be documented.

H5. Documentation shows alpha, max_iterations, tolerance, context_repo_weight, other_weight under v2.graph — but V2GraphConfig only has 4 fields

The actual V2GraphConfig has half_life_days, max_age_days, archived_penalty, fork_penalty. The v2 scorer uses self.config.graph_scoring.alpha etc. from the v1 config. A user setting v2.graph.alpha: 0.9 would get a Pydantic validation error.

H6. config.scoring_model mutation via direct assignment bypasses Pydantic validation

In action.py:80, cli.py:57, and mcp_server.py:60, the code mutates the Pydantic model directly with # type: ignore[assignment]. Pydantic v2 allows this but bypasses validation, meaning assigning "v3" would succeed silently.


Medium

M1. Missing merge rate handling uses implicit reduced model without documentation

When merge rate is None, the scorer simply skips the term from the logit sum. The intercept and other weights were trained assuming all three features are present. Dropping a feature without adjusting weights may produce biased scores. No documentation explains this choice.

M2. Documentation references V2ScoringConfig which does not exist

docs/configuration.md:230 references V2ScoringConfig. The actual class is V2Config.

M3. Formatter references scoring_metadata.closed_pr_count that is never set

In formatter.py:59-63, the code attempts to read score.scoring_metadata.get("closed_pr_count"), but the v2 scorer never sets this key. Result: the merge rate in PR comments will never show the total PR count context (e.g., "85%" instead of "85% (42/50 PRs)"). Dead code.

M4. Missing test: combined model with all features disabled

No test for temporal_merge_rate: False AND account_age: False simultaneously.

M5. Missing test: negative merge_rate_weight behavior

No test documenting that the negative weight is intentional and produces sensible results.

M6. Missing test: feature interaction (high graph score + low merge rate)

No integration test showing how opposing signals interact in the combined model.

M7. v2 scorer shares v1's graph_scoring config for alpha/max_iterations/tolerance

The split between V2GraphConfig (recency/quality) and GraphScoringConfig (algorithm params) is undocumented. Users cannot configure graph algorithm parameters separately for v2.


Low

L1. closed_pr_count and temporal_merge_rate naming implies temporal scoping that doesn't exist

L2. weights_file config option from issue #30 is not implemented or tracked

L3. Training dataset: issue says "5,417 PRs" but code/docs say "5,129 PRs" — the difference is the merge-rate-null subset filter, but this is not explained

L4. CHANGELOG date 2026-02-20 may be premature — should match actual release date


Informational

  • I1. Pydantic models don't use extra="forbid" — typos in YAML config are silently ignored (exacerbates C2)
  • I2. TrustScore.scoring_model is str not Literal["v1", "v2"]
  • I3. Significant code duplication between _score_v1 and _score_v2 (graph build, personalization, pagerank, normalization, classification, contributions, language match)
  • I4. GraphQL query change (adding closedPullRequests) affects v1 mode API payload (harmless but noted)
  • I5. Cache compatibility is fine — closed_pr_count defaults to 0 for pre-v2 cached data
  • I6. __init__.py exports V2Config but not sub-configs (V2GraphConfig, V2FeaturesConfig, V2CombinedModelConfig)

Summary

Severity Count Key Issues
Critical 3 Ghost combined_score in docs; field name mismatches; weight value mismatches
High 6 No temporal merge rate; language match removed despite spec; text dissimilarity absent; negative weight unexplained; incomplete V2GraphConfig vs docs; unsafe Pydantic mutation
Medium 7 Missing feature handling; wrong class name; dead formatter code; missing tests (x3); undocumented config split
Low 4 Misleading naming; missing weights_file; dataset count discrepancy; premature date
Informational 6 Pydantic extras; typing; duplication; query change; cache compat; export completeness

The three critical issues (C1, C2, C3) will cause incorrect behavior or runtime errors for users following the documentation. These should be resolved before merge. The high-severity issues (particularly H1, H2, H4) represent design decisions that diverge from the issue specification and should at minimum be explicitly acknowledged.

Address all issues from the red team review (except text dissimilarity,
which is intentionally excluded):

Critical fixes:
- Remove ghost `combined_score` key from all docs/examples (C1)
- Fix config field names in docs to match code (C2)
- Fix default weight values in docs to match trained values (C3)

High-severity fixes:
- Retain same_language_weight in v2 simplified mode per issue #30 (H2)
- Explain negative merge_rate_weight in methodology docs (H4)
- Remove incorrect v2.graph fields from docs/examples (H5)
- Use model_copy() instead of direct Pydantic mutation (H6)

Medium fixes:
- Rename temporal_merge_rate to merge_rate (honest naming) (H1/L1)
- Add closed_pr_count to v2 scoring_metadata (M8)
- Fix V2ScoringConfig -> V2Config in docs (M2)
- Document reduced model for missing merge rate (M1)
- Add tests: all features disabled, negative weight, opposing signals

Low fixes:
- Clarify 5,129 vs 5,417 PR count in docs (L4/L5)
- Update CHANGELOG date (L6)
@jeffreyksmithjr

Copy link
Copy Markdown
Contributor Author

Review Fixes (f6946d6)

Addressed all findings from the red team review except text dissimilarity (intentionally excluded — the inverted signal is not yet well enough understood).

Critical fixes

  • C1: Removed ghost combined_score key from all docs, examples, CHANGELOG, and MCP response examples. The actual component keys are graph_score, merge_rate, log_account_age.
  • C2: Fixed config field names in all docs/examples to match code: merge_rate (was temporal_merge_rate in code, now renamed), graph_score_weight (docs had graph_weight).
  • C3: Fixed default weight values in all docs/examples to match trained values: intercept=-0.8094, graph_score_weight=1.9138, merge_rate_weight=-0.7783, account_age_weight=0.1493.

High-severity fixes

  • H2: Restored same_language_weight in v2 simplified mode — issue Implement Good Egg v2 scoring model #30 says language match should be retained since it showed a small but significant effect.
  • H4: Added explanation of the negative merge_rate_weight to methodology docs (survivorship bias correction conditional on graph score).
  • H5: Removed incorrect alpha/max_iterations/tolerance/context_repo_weight/other_weight from v2.graph docs. Added note that v2 shares graph algorithm params with top-level graph_scoring.
  • H6: Replaced direct Pydantic model mutation with model_copy(update=...) in action.py, cli.py, mcp_server.py.

Medium fixes

  • H1/L1: Renamed temporal_merge_ratemerge_rate in V2FeaturesConfig (honest naming since it uses total counts, not temporal scoping).
  • M1: Documented reduced model behavior when merge rate is unavailable.
  • M2: Fixed V2ScoringConfigV2Config in docs.
  • M8: Added closed_pr_count to v2 scoring_metadata, fixing dead code in formatter that tried to show "(X/Y PRs)" format.
  • M5-M7: Added 3 new tests — all features disabled, negative weight behavior, opposing signals.

Low fixes

  • L4/L5: Clarified "5,129 PRs (of 5,417 total, filtered to those with merge rate data)".
  • L6: Updated CHANGELOG date to 2026-02-23.

Verification

  • 269 tests pass, 93% coverage
  • ruff: all checks pass
  • mypy: no issues

Point action ref to @better-egg for self-testing on this branch.
Will be updated to @v1 after release.
@jeffreyksmithjr

Copy link
Copy Markdown
Contributor Author

Note that the CI action has been run on the latest version of the code (as seen in the edit history here).

Ensure all parameter tables, section headers, and comparison tables
consistently pair version numbers with brand names.
Comment thread src/good_egg/config.py
Comment thread src/good_egg/scorer.py
Comment thread docs/methodology.md Outdated
- Remove INPUT_SCORING_MODEL/INPUT_SCORING-MODEL from load_config();
  action.py already handles its own override via model_copy(), so
  load_config() only needs GOOD_EGG_SCORING_MODEL
- Clarify "validation study data" wording in methodology docs
@jeffreyksmithjr
jeffreyksmithjr merged commit cd00138 into main Feb 23, 2026
2 checks passed
@jeffreyksmithjr
jeffreyksmithjr deleted the better-egg branch February 23, 2026 23:17
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.

Implement Good Egg v2 scoring model

2 participants