From ba9ccdccc6d5af4bb6b4987ab1b1f24de6b336fb Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 10 Mar 2026 16:28:47 +0000 Subject: [PATCH 1/4] Add v3 scoring model (Diet Egg) and Fresh Egg advisory v3 uses alltime merge rate as the sole scoring input, dropping graph score and log account age from the v2 logistic regression. Fresh accounts (under 365 days) get an advisory surfaced in all output formats without affecting the score. Bots are excluded from the advisory since their synthetic profiles have unreliable age data. - Add FreshAccountAdvisory model and TrustScore.fresh_account field - Add _score_v3() using merge_rate as raw and normalized score - Add _build_fresh_account_advisory() called in all scoring paths - Change default scoring_model from v1 to v3 - Add "Diet Egg" brand name for v3 in all formatters - Widen v2 component breakdown checks to include v3 - Add v3 to CLI, action, and MCP server validation - Update tests: 332 passing, 94% coverage --- src/good_egg/action.py | 2 +- src/good_egg/cli.py | 4 +- src/good_egg/config.py | 2 +- src/good_egg/formatter.py | 37 +++++- src/good_egg/mcp_server.py | 8 +- src/good_egg/models.py | 9 ++ src/good_egg/scorer.py | 78 ++++++++++++- tests/test_config.py | 4 +- tests/test_formatter.py | 156 ++++++++++++++++++++++++- tests/test_models.py | 53 +++++++++ tests/test_scorer.py | 226 ++++++++++++++++++++++++++++++++++++- 11 files changed, 559 insertions(+), 20 deletions(-) diff --git a/src/good_egg/action.py b/src/good_egg/action.py index eb21107..cb47dc0 100644 --- a/src/good_egg/action.py +++ b/src/good_egg/action.py @@ -80,7 +80,7 @@ async def run_action() -> None: os.environ.get("INPUT_SCORING_MODEL") or os.environ.get("INPUT_SCORING-MODEL") ) - if scoring_model_input and scoring_model_input in ("v1", "v2"): + if scoring_model_input and scoring_model_input in ("v1", "v2", "v3"): config = config.model_copy(update={"scoring_model": scoring_model_input}) if skip_known_input is not None: config = config.model_copy( diff --git a/src/good_egg/cli.py b/src/good_egg/cli.py index 618d13b..ea0e07b 100644 --- a/src/good_egg/cli.py +++ b/src/good_egg/cli.py @@ -28,9 +28,9 @@ def main() -> None: @click.option("--json", "output_json", is_flag=True, help="Output as JSON") @click.option( "--scoring-model", - type=click.Choice(["v1", "v2"]), + type=click.Choice(["v1", "v2", "v3"]), default=None, - help="Scoring model (v1 or v2)", + help="Scoring model (v1, v2, or v3)", ) @click.option( "--force-score", diff --git a/src/good_egg/config.py b/src/good_egg/config.py index 576902b..0d44f8b 100644 --- a/src/good_egg/config.py +++ b/src/good_egg/config.py @@ -147,7 +147,7 @@ class V2Config(BaseModel): class GoodEggConfig(BaseModel): """Top-level configuration composing all sub-configs.""" - scoring_model: Literal["v1", "v2"] = "v1" + scoring_model: Literal["v1", "v2", "v3"] = "v3" skip_known_contributors: bool = True graph_scoring: GraphScoringConfig = Field(default_factory=GraphScoringConfig) edge_weights: EdgeWeightConfig = Field(default_factory=EdgeWeightConfig) diff --git a/src/good_egg/formatter.py b/src/good_egg/formatter.py index ca72c83..4015e45 100644 --- a/src/good_egg/formatter.py +++ b/src/good_egg/formatter.py @@ -36,7 +36,11 @@ def _existing_contributor_context(score: TrustScore) -> tuple[int, str]: def _brand_name(score: TrustScore) -> str: """Return 'Better Egg' for v2, 'Good Egg' for v1.""" - return "Better Egg" if score.scoring_model == "v2" else "Good Egg" + if score.scoring_model == "v3": + return "Diet Egg" + if score.scoring_model == "v2": + return "Better Egg" + return "Good Egg" def format_markdown_comment(score: TrustScore) -> str: @@ -67,7 +71,7 @@ def format_markdown_comment(score: TrustScore) -> str: ] # v2 component score breakdown - if score.scoring_model == "v2" and score.component_scores: + if score.scoring_model in ("v2", "v3") and score.component_scores: lines.append("### Score Breakdown") lines.append("") lines.append("| Component | Value |") @@ -122,6 +126,17 @@ def format_markdown_comment(score: TrustScore) -> str: lines.append(f"- {flag}") lines.append("") + # Fresh account advisory + if score.fresh_account and score.fresh_account.is_fresh: + lines.append("### Fresh Account") + lines.append("") + lines.append( + f"\U0001f423 Account is {score.fresh_account.account_age_days} days old" + f" (< {score.fresh_account.threshold_days} days)." + " Fresh accounts correlate with lower merge rates." + ) + lines.append("") + # Low trust note if score.trust_level == TrustLevel.LOW: lines.append("> **First-time contributor -- review manually**") @@ -163,7 +178,7 @@ def format_cli_output(score: TrustScore, verbose: bool = False) -> str: f"Repos: {score.unique_repos_contributed}" ) - if score.scoring_model == "v2" and score.component_scores: + if score.scoring_model in ("v2", "v3") and score.component_scores: lines.append("") lines.append("Component scores:") if "graph_score" in score.component_scores: @@ -191,6 +206,13 @@ def format_cli_output(score: TrustScore, verbose: bool = False) -> str: if value: lines.append(f" - {flag}") + if score.fresh_account and score.fresh_account.is_fresh: + lines.append("") + lines.append( + f"Fresh account: {score.fresh_account.account_age_days} days old" + f" (< {score.fresh_account.threshold_days} days)" + ) + if score.scoring_metadata: lines.append("") lines.append("Metadata:") @@ -234,7 +256,7 @@ def format_check_run_summary(score: TrustScore) -> tuple[str, str]: f"Repos contributed to: {score.unique_repos_contributed}", ] - if score.scoring_model == "v2" and score.component_scores: + if score.scoring_model in ("v2", "v3") and score.component_scores: summary_lines.append("") summary_lines.append("**Score Breakdown:**") if "graph_score" in score.component_scores: @@ -261,5 +283,12 @@ def format_check_run_summary(score: TrustScore) -> tuple[str, str]: summary_lines.append("") summary_lines.append(f"**Flags:** {', '.join(active_flags)}") + if score.fresh_account and score.fresh_account.is_fresh: + summary_lines.append("") + summary_lines.append( + f"**Fresh Account:** {score.fresh_account.account_age_days} days old" + f" (< {score.fresh_account.threshold_days} days)" + ) + summary = "\n".join(summary_lines) return title, summary diff --git a/src/good_egg/mcp_server.py b/src/good_egg/mcp_server.py index 95db190..7764aff 100644 --- a/src/good_egg/mcp_server.py +++ b/src/good_egg/mcp_server.py @@ -57,7 +57,7 @@ async def _scoring_resources( is closed on exit. """ config = _get_config() - if scoring_model is not None and scoring_model in ("v1", "v2"): + if scoring_model is not None and scoring_model in ("v1", "v2", "v3"): config = config.model_copy(update={"scoring_model": scoring_model}) if force_score: config = config.model_copy(update={"skip_known_contributors": False}) @@ -96,7 +96,7 @@ async def score_user( Args: username: GitHub username to score. repo: Target repository in owner/repo format. - scoring_model: Optional scoring model override (v1 or v2). + scoring_model: Optional scoring model override (v1, v2, or v3). force_score: Force full scoring even for known contributors. """ try: @@ -128,7 +128,7 @@ async def check_pr_author( Args: username: GitHub username to check. repo: Target repository in owner/repo format. - scoring_model: Optional scoring model override (v1 or v2). + scoring_model: Optional scoring model override (v1, v2, or v3). force_score: Force full scoring even for known contributors. """ try: @@ -169,7 +169,7 @@ async def get_trust_details( Args: username: GitHub username to analyse. repo: Target repository in owner/repo format. - scoring_model: Optional scoring model override (v1 or v2). + scoring_model: Optional scoring model override (v1, v2, or v3). force_score: Force full scoring even for known contributors. """ try: diff --git a/src/good_egg/models.py b/src/good_egg/models.py index a569872..f4175a1 100644 --- a/src/good_egg/models.py +++ b/src/good_egg/models.py @@ -77,6 +77,14 @@ class ContributionSummary(BaseModel): stars: int = 0 +class FreshAccountAdvisory(BaseModel): + """Advisory for accounts less than one year old.""" + is_fresh: bool + account_age_days: int + created_at: datetime | None = None + threshold_days: int = 365 + + class TrustScore(BaseModel): """Complete trust score result.""" user_login: str @@ -94,3 +102,4 @@ class TrustScore(BaseModel): scoring_metadata: dict[str, Any] = {} scoring_model: str = "v1" component_scores: dict[str, float] = {} + fresh_account: FreshAccountAdvisory | None = None diff --git a/src/good_egg/scorer.py b/src/good_egg/scorer.py index 194d40c..8e7c4f5 100644 --- a/src/good_egg/scorer.py +++ b/src/good_egg/scorer.py @@ -12,6 +12,7 @@ from good_egg.graph_builder import TrustGraphBuilder from good_egg.models import ( ContributionSummary, + FreshAccountAdvisory, TrustLevel, TrustScore, UserContributionData, @@ -40,6 +41,8 @@ def score( } model_name = self.config.scoring_model + fresh_account = self._build_fresh_account_advisory(user_data) + # ---- Bot short-circuit ---- if user_data.profile.is_bot: return TrustScore( @@ -65,15 +68,18 @@ def score( account_age_days=user_data.profile.account_age_days, flags=flags, scoring_model=model_name, + fresh_account=fresh_account, ) # ---- Suspected bot flag ---- if user_data.profile.is_suspected_bot: flags["is_suspected_bot"] = True + if model_name == "v3": + return self._score_v3(user_data, context_repo, flags, fresh_account) if model_name == "v2": - return self._score_v2(user_data, context_repo, flags) - return self._score_v1(user_data, context_repo, flags) + return self._score_v2(user_data, context_repo, flags, fresh_account) + return self._score_v1(user_data, context_repo, flags, fresh_account) # ------------------------------------------------------------------ # v1 scoring path @@ -84,6 +90,7 @@ def _score_v1( user_data: UserContributionData, context_repo: str, flags: dict[str, bool], + fresh_account: FreshAccountAdvisory | None = None, ) -> TrustScore: """Original graph-based scoring pipeline.""" login = user_data.profile.login @@ -130,6 +137,7 @@ def _score_v1( "graph_nodes": graph.number_of_nodes(), "graph_edges": graph.number_of_edges(), }, + fresh_account=fresh_account, ) # ------------------------------------------------------------------ @@ -141,6 +149,7 @@ def _score_v2( user_data: UserContributionData, context_repo: str, flags: dict[str, bool], + fresh_account: FreshAccountAdvisory | None = None, ) -> TrustScore: """v2 scoring: simplified graph + logistic regression combined model.""" login = user_data.profile.login @@ -222,6 +231,71 @@ def _score_v2( }, scoring_model="v2", component_scores=component_scores, + fresh_account=fresh_account, + ) + + # ------------------------------------------------------------------ + # v3 scoring path (Diet Egg) + # ------------------------------------------------------------------ + + def _score_v3( + self, + user_data: UserContributionData, + context_repo: str, + flags: dict[str, bool], + fresh_account: FreshAccountAdvisory | None = None, + ) -> TrustScore: + """v3 scoring: merge rate as sole signal.""" + login = user_data.profile.login + total_prs = len(user_data.merged_prs) + unique_repos = len({pr.repo_name_with_owner for pr in user_data.merged_prs}) + + merged_count = len(user_data.merged_prs) + closed_count = user_data.closed_pr_count + total_author_prs = merged_count + closed_count + merge_rate = ( + merged_count / total_author_prs if total_author_prs > 0 else 0.0 + ) + + trust_level = self._classify(merge_rate, flags) + context_language = self._resolve_context_language(user_data, context_repo) + top_contributions = self._build_top_contributions(user_data) + language_match = self._check_language_match(user_data, context_language) + + return TrustScore( + user_login=login, + context_repo=context_repo, + raw_score=merge_rate, + normalized_score=merge_rate, + trust_level=trust_level, + account_age_days=user_data.profile.account_age_days, + total_merged_prs=total_prs, + unique_repos_contributed=unique_repos, + top_contributions=top_contributions, + language_match=language_match, + flags=flags, + scoring_metadata={ + "closed_pr_count": closed_count, + }, + scoring_model="v3", + component_scores={"merge_rate": merge_rate}, + fresh_account=fresh_account, + ) + + # ------------------------------------------------------------------ + # Fresh account advisory + # ------------------------------------------------------------------ + + @staticmethod + def _build_fresh_account_advisory( + user_data: UserContributionData, + ) -> FreshAccountAdvisory: + """Build a fresh account advisory from user profile data.""" + age_days = user_data.profile.account_age_days + return FreshAccountAdvisory( + is_fresh=age_days < 365, + account_age_days=age_days, + created_at=user_data.profile.created_at, ) # ------------------------------------------------------------------ diff --git a/tests/test_config.py b/tests/test_config.py index 5711e97..ec4c36d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -157,9 +157,9 @@ def test_custom_values(self) -> None: class TestScoringModelConfig: - def test_default_is_v1(self) -> None: + def test_default_is_v3(self) -> None: config = GoodEggConfig() - assert config.scoring_model == "v1" + assert config.scoring_model == "v3" def test_set_to_v2(self) -> None: config = GoodEggConfig(scoring_model="v2") diff --git a/tests/test_formatter.py b/tests/test_formatter.py index 8f52f15..c8c0b8e 100644 --- a/tests/test_formatter.py +++ b/tests/test_formatter.py @@ -11,7 +11,12 @@ format_json, format_markdown_comment, ) -from good_egg.models import ContributionSummary, TrustLevel, TrustScore +from good_egg.models import ( + ContributionSummary, + FreshAccountAdvisory, + TrustLevel, + TrustScore, +) def _make_score(**kwargs) -> TrustScore: @@ -332,3 +337,152 @@ def test_json_existing_contributor(self) -> None: parsed = json.loads(result) assert parsed["trust_level"] == "EXISTING_CONTRIBUTOR" assert parsed["flags"]["is_existing_contributor"] is True + + +class TestDietEggFormatting: + def _make_v3_score(self, **kwargs) -> TrustScore: + defaults = { + "user_login": "testuser", + "context_repo": "owner/repo", + "raw_score": 0.75, + "normalized_score": 0.75, + "trust_level": TrustLevel.HIGH, + "account_age_days": 500, + "total_merged_prs": 30, + "unique_repos_contributed": 8, + "top_contributions": [ + ContributionSummary( + repo_name="cool/project", + pr_count=15, + language="Python", + stars=1200, + ), + ], + "language_match": True, + "flags": {}, + "scoring_metadata": {"closed_pr_count": 10}, + "scoring_model": "v3", + "component_scores": {"merge_rate": 0.75}, + } + defaults.update(kwargs) + return TrustScore(**defaults) + + def test_markdown_diet_egg_header(self) -> None: + score = self._make_v3_score() + md = format_markdown_comment(score) + assert "Diet Egg" in md + assert "Better Egg" not in md + assert "Good Egg" not in md + + def test_markdown_component_breakdown(self) -> None: + score = self._make_v3_score() + md = format_markdown_comment(score) + assert "Score Breakdown" in md + assert "Merge Rate" in md + # graph_score and log_account_age should not appear + assert "Graph Score" not in md + assert "Account Age" not in md + + def test_cli_diet_egg_header(self) -> None: + score = self._make_v3_score() + out = format_cli_output(score) + assert "Diet Egg" in out + + def test_cli_verbose_component_scores(self) -> None: + score = self._make_v3_score() + out = format_cli_output(score, verbose=True) + assert "Component scores" in out + assert "Merge Rate" in out + assert "Graph Score" not in out + + def test_check_run_diet_egg_title(self) -> None: + score = self._make_v3_score() + title, summary = format_check_run_summary(score) + assert "Diet Egg" in title + assert "Score Breakdown" in summary + assert "Merge Rate" in summary + + def test_json_includes_v3_fields(self) -> None: + score = self._make_v3_score() + result = format_json(score) + parsed = json.loads(result) + assert parsed["scoring_model"] == "v3" + assert "merge_rate" in parsed["component_scores"] + assert "graph_score" not in parsed["component_scores"] + + +class TestFreshAccountFormatting: + def _make_fresh_score(self, is_fresh: bool = True, **kwargs) -> TrustScore: + fresh = FreshAccountAdvisory( + is_fresh=is_fresh, + account_age_days=200 if is_fresh else 500, + ) + defaults = { + "user_login": "newbie", + "context_repo": "owner/repo", + "raw_score": 0.6, + "normalized_score": 0.6, + "trust_level": TrustLevel.MEDIUM, + "account_age_days": 200 if is_fresh else 500, + "total_merged_prs": 5, + "unique_repos_contributed": 2, + "flags": {}, + "scoring_model": "v3", + "component_scores": {"merge_rate": 0.6}, + "fresh_account": fresh, + } + defaults.update(kwargs) + return TrustScore(**defaults) + + def test_markdown_fresh_account_shown(self) -> None: + score = self._make_fresh_score(is_fresh=True) + md = format_markdown_comment(score) + assert "Fresh Account" in md + assert "200 days old" in md + + def test_markdown_fresh_account_hidden(self) -> None: + score = self._make_fresh_score(is_fresh=False) + md = format_markdown_comment(score) + assert "Fresh Account" not in md + + def test_cli_fresh_account_shown(self) -> None: + score = self._make_fresh_score(is_fresh=True) + out = format_cli_output(score, verbose=True) + assert "Fresh account" in out + assert "200 days old" in out + + def test_cli_fresh_account_hidden_non_verbose(self) -> None: + score = self._make_fresh_score(is_fresh=True) + out = format_cli_output(score, verbose=False) + assert "Fresh account" not in out + + def test_cli_fresh_account_hidden_not_fresh(self) -> None: + score = self._make_fresh_score(is_fresh=False) + out = format_cli_output(score, verbose=True) + assert "Fresh account" not in out + + def test_check_run_fresh_account_shown(self) -> None: + score = self._make_fresh_score(is_fresh=True) + _, summary = format_check_run_summary(score) + assert "Fresh Account" in summary + assert "200 days old" in summary + + def test_check_run_fresh_account_hidden(self) -> None: + score = self._make_fresh_score(is_fresh=False) + _, summary = format_check_run_summary(score) + assert "Fresh Account" not in summary + + def test_json_fresh_account_serialized(self) -> None: + score = self._make_fresh_score(is_fresh=True) + result = format_json(score) + parsed = json.loads(result) + assert parsed["fresh_account"]["is_fresh"] is True + assert parsed["fresh_account"]["account_age_days"] == 200 + + def test_json_fresh_account_none(self) -> None: + score = TrustScore( + user_login="u", context_repo="o/r", fresh_account=None + ) + result = format_json(score) + parsed = json.loads(result) + assert parsed["fresh_account"] is None diff --git a/tests/test_models.py b/tests/test_models.py index 4dac06c..98611fe 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -5,6 +5,7 @@ from datetime import UTC, datetime, timedelta from good_egg.models import ( + FreshAccountAdvisory, MergedPR, RepoMetadata, TrustLevel, @@ -156,6 +157,58 @@ def test_backward_compat_no_new_fields(self) -> None: assert score.scoring_model == "v1" assert score.component_scores == {} + def test_fresh_account_field_default_none(self) -> None: + score = TrustScore(user_login="u", context_repo="o/r") + assert score.fresh_account is None + + def test_fresh_account_field_set(self) -> None: + advisory = FreshAccountAdvisory( + is_fresh=True, + account_age_days=100, + created_at=datetime(2025, 12, 1, tzinfo=UTC), + ) + score = TrustScore( + user_login="u", + context_repo="o/r", + fresh_account=advisory, + ) + assert score.fresh_account is not None + assert score.fresh_account.is_fresh is True + assert score.fresh_account.account_age_days == 100 + assert score.fresh_account.threshold_days == 365 + def test_top_contributions(self, sample_trust_score: TrustScore) -> None: assert len(sample_trust_score.top_contributions) == 2 assert sample_trust_score.top_contributions[0].repo_name == "elixir-lang/elixir" + + +class TestFreshAccountAdvisory: + def test_construction_fresh(self) -> None: + advisory = FreshAccountAdvisory(is_fresh=True, account_age_days=100) + assert advisory.is_fresh is True + assert advisory.account_age_days == 100 + assert advisory.created_at is None + assert advisory.threshold_days == 365 + + def test_construction_not_fresh(self) -> None: + advisory = FreshAccountAdvisory(is_fresh=False, account_age_days=500) + assert advisory.is_fresh is False + + def test_construction_with_created_at(self) -> None: + dt = datetime(2025, 6, 1, tzinfo=UTC) + advisory = FreshAccountAdvisory( + is_fresh=True, account_age_days=100, created_at=dt + ) + assert advisory.created_at == dt + + def test_serialization_roundtrip(self) -> None: + import json + advisory = FreshAccountAdvisory( + is_fresh=True, + account_age_days=200, + created_at=datetime(2025, 9, 1, tzinfo=UTC), + ) + data = json.loads(advisory.model_dump_json()) + restored = FreshAccountAdvisory(**data) + assert restored.is_fresh is True + assert restored.account_age_days == 200 diff --git a/tests/test_scorer.py b/tests/test_scorer.py index accbe6c..dc252f4 100644 --- a/tests/test_scorer.py +++ b/tests/test_scorer.py @@ -20,6 +20,8 @@ def _make_config(**overrides: object) -> GoodEggConfig: + if "scoring_model" not in overrides: + overrides["scoring_model"] = "v1" return GoodEggConfig(**overrides) # type: ignore[arg-type] @@ -659,7 +661,7 @@ async def test_skip_when_contributor_exists( mock_client.__aexit__ = AsyncMock(return_value=False) mock_client_cls.return_value = mock_client - config = GoodEggConfig(skip_known_contributors=True) + config = GoodEggConfig(skip_known_contributors=True, scoring_model="v1") result = await score_pr_author( login="testuser", repo_owner="my-org", @@ -690,7 +692,7 @@ async def test_no_skip_when_count_is_zero( mock_client.__aexit__ = AsyncMock(return_value=False) mock_client_cls.return_value = mock_client - config = GoodEggConfig(skip_known_contributors=True) + config = GoodEggConfig(skip_known_contributors=True, scoring_model="v1") result = await score_pr_author( login="testuser", repo_owner="my-org", @@ -716,7 +718,7 @@ async def test_force_score_bypasses_check( mock_client.__aexit__ = AsyncMock(return_value=False) mock_client_cls.return_value = mock_client - config = GoodEggConfig(skip_known_contributors=False) + config = GoodEggConfig(skip_known_contributors=False, scoring_model="v1") result = await score_pr_author( login="testuser", repo_owner="my-org", @@ -728,3 +730,221 @@ async def test_force_score_bypasses_check( assert result.trust_level != TrustLevel.EXISTING_CONTRIBUTOR mock_client.check_existing_contributor.assert_not_called() mock_client.get_user_contribution_data.assert_called_once() + + @pytest.mark.asyncio + @patch("good_egg.github_client.GitHubClient") + async def test_existing_contributor_has_no_fresh_account( + self, mock_client_cls: AsyncMock + ) -> None: + """Existing contributor early return should have fresh_account=None.""" + mock_client = AsyncMock() + mock_client.check_existing_contributor = AsyncMock(return_value=3) + mock_client.__aenter__ = AsyncMock(return_value=mock_client) + mock_client.__aexit__ = AsyncMock(return_value=False) + mock_client_cls.return_value = mock_client + + config = GoodEggConfig(skip_known_contributors=True, scoring_model="v1") + result = await score_pr_author( + login="testuser", + repo_owner="my-org", + repo_name="my-repo", + config=config, + token="fake-token", + ) + + assert result.trust_level == TrustLevel.EXISTING_CONTRIBUTOR + assert result.fresh_account is None + + +class TestV3Scoring: + def test_v3_merge_rate_as_score(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + # 3 merged + 2 closed = 3/5 = 0.6 + data = _make_contribution_data(merged_prs=prs, repos=repos, closed_pr_count=2) + result = scorer.score(data, "my-org/my-app") + + assert abs(result.raw_score - 0.6) < 1e-9 + assert abs(result.normalized_score - 0.6) < 1e-9 + assert result.scoring_model == "v3" + + def test_v3_component_scores_shape(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data(merged_prs=prs, repos=repos, closed_pr_count=5) + result = scorer.score(data, "my-org/my-app") + + assert list(result.component_scores.keys()) == ["merge_rate"] + assert 0.0 <= result.component_scores["merge_rate"] <= 1.0 + + def test_v3_no_graph_metadata(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data(merged_prs=prs, repos=repos, closed_pr_count=5) + result = scorer.score(data, "my-org/my-app") + + assert "graph_nodes" not in result.scoring_metadata + assert "graph_edges" not in result.scoring_metadata + assert "closed_pr_count" in result.scoring_metadata + + def test_v3_trust_level_classification(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + # 3 merged + 0 closed = 100% merge rate -> HIGH + data = _make_contribution_data(merged_prs=prs, repos=repos, closed_pr_count=0) + result = scorer.score(data, "my-org/my-app") + + assert result.trust_level == TrustLevel.HIGH + + def test_v3_low_merge_rate(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs = [ + MergedPR( + repo_name_with_owner="org/repo", + title="PR", + merged_at=datetime.now(UTC) - timedelta(days=1), + ), + ] + repos = { + "org/repo": RepoMetadata( + name_with_owner="org/repo", + stargazer_count=100, + ), + } + # 1 merged + 10 closed = 1/11 ~ 0.09 -> LOW + data = _make_contribution_data(merged_prs=prs, repos=repos, closed_pr_count=10) + result = scorer.score(data, "org/repo") + + assert result.trust_level == TrustLevel.LOW + + def test_v3_is_default_model(self) -> None: + config = GoodEggConfig() + assert config.scoring_model == "v3" + + def test_v3_bot_short_circuit(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + data = _make_contribution_data(is_bot=True) + result = scorer.score(data, "org/repo") + + assert result.trust_level == TrustLevel.BOT + assert result.scoring_model == "v3" + + def test_v3_insufficient_data_short_circuit(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + data = _make_contribution_data(merged_prs=[]) + result = scorer.score(data, "org/repo") + + assert result.trust_level == TrustLevel.UNKNOWN + assert result.scoring_model == "v3" + + def test_v3_zero_total_prs(self) -> None: + """Edge case: merged_prs present but closed_pr_count causes 0 denominator.""" + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs = [ + MergedPR( + repo_name_with_owner="org/repo", + title="PR", + merged_at=datetime.now(UTC) - timedelta(days=1), + ), + ] + repos = { + "org/repo": RepoMetadata( + name_with_owner="org/repo", + stargazer_count=100, + ), + } + data = _make_contribution_data(merged_prs=prs, repos=repos, closed_pr_count=0) + result = scorer.score(data, "org/repo") + + assert result.raw_score == 1.0 + assert result.normalized_score == 1.0 + + +class TestFreshAccountAdvisory: + def test_fresh_account_flagged_under_365(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data( + days_old=200, merged_prs=prs, repos=repos + ) + result = scorer.score(data, "org/repo") + + assert result.fresh_account is not None + assert result.fresh_account.is_fresh is True + assert result.fresh_account.account_age_days == 200 + assert result.fresh_account.threshold_days == 365 + + def test_fresh_account_not_flagged_over_365(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data( + days_old=500, merged_prs=prs, repos=repos + ) + result = scorer.score(data, "org/repo") + + assert result.fresh_account is not None + assert result.fresh_account.is_fresh is False + + def test_fresh_account_boundary_exactly_365(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data( + days_old=365, merged_prs=prs, repos=repos + ) + result = scorer.score(data, "org/repo") + + assert result.fresh_account is not None + assert result.fresh_account.is_fresh is False + + def test_fresh_account_none_on_bot_short_circuit(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + data = _make_contribution_data(is_bot=True, days_old=100) + result = scorer.score(data, "org/repo") + + assert result.trust_level == TrustLevel.BOT + assert result.fresh_account is None + + def test_fresh_account_on_insufficient_data(self) -> None: + config = GoodEggConfig(scoring_model="v3") + scorer = TrustScorer(config) + data = _make_contribution_data(merged_prs=[], days_old=100) + result = scorer.score(data, "org/repo") + + assert result.trust_level == TrustLevel.UNKNOWN + assert result.fresh_account is not None + assert result.fresh_account.is_fresh is True + + def test_fresh_account_populated_in_v1(self) -> None: + scorer = TrustScorer(_make_config()) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data( + days_old=200, merged_prs=prs, repos=repos + ) + result = scorer.score(data, "org/repo") + + assert result.fresh_account is not None + assert result.fresh_account.is_fresh is True + + def test_fresh_account_populated_in_v2(self) -> None: + config = GoodEggConfig(scoring_model="v2") + scorer = TrustScorer(config) + prs, repos = _sample_prs_and_repos() + data = _make_contribution_data( + days_old=200, merged_prs=prs, repos=repos + ) + result = scorer.score(data, "org/repo") + + assert result.fresh_account is not None + assert result.fresh_account.is_fresh is True From c785100e44ee14fff36fdcf9586fd966981616f7 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 10 Mar 2026 16:31:29 +0000 Subject: [PATCH 2/4] Run action from local checkout with v3 scoring model Point the Good Egg workflow at ./ instead of the published @v1 tag so the PR runs the branch code. Set scoring-model to v3. --- .github/workflows/good-egg.yml | 5 +++-- action.yml | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/good-egg.yml b/.github/workflows/good-egg.yml index dc56c38..187f0e3 100644 --- a/.github/workflows/good-egg.yml +++ b/.github/workflows/good-egg.yml @@ -11,8 +11,9 @@ jobs: score: runs-on: ubuntu-latest steps: - - uses: 2ndSetAI/good-egg@v1 + - uses: actions/checkout@v4 + - uses: ./ with: github-token: ${{ secrets.GITHUB_TOKEN }} - scoring-model: v2 + scoring-model: v3 skip-known-contributors: 'false' diff --git a/action.yml b/action.yml index 6b94554..90d120f 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: required: false default: 'false' scoring-model: - description: 'Scoring model to use (v1 or v2)' + description: 'Scoring model to use (v1, v2, or v3)' required: false skip-known-contributors: description: 'Skip scoring for authors with merged PRs in the repo (true/false)' @@ -40,7 +40,7 @@ outputs: description: 'GitHub username that was scored' value: ${{ steps.score.outputs.user }} scoring-model: - description: 'Scoring model that was used (v1 or v2)' + description: 'Scoring model that was used (v1, v2, or v3)' value: ${{ steps.score.outputs.scoring-model }} skipped: description: 'Whether scoring was skipped for an existing contributor (true/false)' From f5405856f512bb9fcc6ea57164595249bc0b93cd Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 10 Mar 2026 16:34:47 +0000 Subject: [PATCH 3/4] Restore action workflow to use published @v1 tag Remove the local checkout used for testing. Drop the explicit scoring-model since v3 is now the default. --- .github/workflows/good-egg.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/good-egg.yml b/.github/workflows/good-egg.yml index 187f0e3..cb49c1c 100644 --- a/.github/workflows/good-egg.yml +++ b/.github/workflows/good-egg.yml @@ -11,9 +11,7 @@ jobs: score: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: ./ + - uses: 2ndSetAI/good-egg@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} - scoring-model: v3 skip-known-contributors: 'false' From bed361e685782c26e0b89c3ba01806c45f56a6ba Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 10 Mar 2026 16:47:55 +0000 Subject: [PATCH 4/4] Update docs and examples for v3 (Diet Egg) default - README: update scoring models table, add Fresh Egg section, update description to reflect v3 as default - docs/configuration.md: add v3 to scoring model section, YAML schema, env var table, and scoring_model description - docs/github-action.md: update inputs/outputs tables, replace "Using Better Egg" with general "Selecting a Scoring Model" section, add diet-egg-workflow to example list - docs/library.md: replace v2-only config section with general scoring model selection, add fresh_account to TrustScore field table, update raw_score description - docs/mcp-server.md: update all parameter tables and return examples to show v3 as default - docs/methodology.md: add Diet Egg (v3) section with motivation, Fresh Egg advisory, and component scores; update scoring section to lead with v3 - docs/troubleshooting.md: add v3 and Fresh Egg troubleshooting sections - examples: add diet-egg-workflow.yml, update .good-egg.yml with v3 comments, update library_usage.py with v3 and fresh_account usage - assets: replace PR comment screenshot with Diet Egg version --- README.md | 29 ++++++++++------ assets/pr-comment-screenshot.png | Bin 59352 -> 67045 bytes docs/configuration.md | 36 +++++++++++-------- docs/github-action.md | 19 ++++++----- docs/library.md | 44 ++++++++++++------------ docs/mcp-server.md | 43 +++++++++++++---------- docs/methodology.md | 57 +++++++++++++++++++++++++++++-- docs/troubleshooting.md | 25 ++++++++++++-- examples/.good-egg.yml | 7 +++- examples/diet-egg-workflow.yml | 27 +++++++++++++++ examples/library_usage.py | 16 ++++++++- 11 files changed, 221 insertions(+), 82 deletions(-) create mode 100644 examples/diet-egg-workflow.yml diff --git a/README.md b/README.md index 84e4782..7f465b8 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ Good Egg -Trust scoring for GitHub PR authors using graph-based analysis of -contribution history. +Trust scoring for GitHub PR authors based on contribution history. ## Why @@ -122,23 +121,31 @@ See [docs/mcp-server.md](https://github.com/2ndSetAI/good-egg/blob/main/docs/mcp ## Scoring Models -Good Egg supports two scoring models: +Good Egg supports three scoring models: | Model | Name | Description | |-------|------|-------------| -| `v1` | Good Egg (default) | Graph-based scoring from contribution history | +| `v3` | Diet Egg (default) | Alltime merge rate as sole signal | | `v2` | Better Egg | Graph score + merge rate + account age via logistic regression | +| `v1` | Good Egg | Graph-based scoring from contribution history | -To use v2, set `scoring_model: v2` in your `.good-egg.yml`, pass -`--scoring-model v2` on the CLI, or set `scoring-model: v2` in the action -input. See [Methodology](https://github.com/2ndSetAI/good-egg/blob/main/docs/methodology.md#better-egg-v2) for how the -v2 model works. +v3 is the default. To use an older model, set `scoring_model: v1` or +`scoring_model: v2` in your `.good-egg.yml`, pass `--scoring-model v1` on +the CLI, or set `scoring-model: v1` in the action input. See +[Methodology](https://github.com/2ndSetAI/good-egg/blob/main/docs/methodology.md) for how each model works. + +### Fresh Egg Advisory + +Accounts less than 365 days old receive a "Fresh Egg" advisory in the +output. This is informational only and does not affect the score. Fresh +accounts correlate with lower merge rates in the validation data. ## How It Works -Good Egg builds a weighted contribution graph from a user's merged PRs and -runs personalized graph scoring to produce a trust score relative to your -project. See [Methodology](https://github.com/2ndSetAI/good-egg/blob/main/docs/methodology.md) for details. +The default v3 model (Diet Egg) scores contributors by their alltime merge +rate: merged PRs divided by total PRs (merged + closed). Older models (v1, +v2) build a weighted contribution graph and run personalized graph scoring. +See [Methodology](https://github.com/2ndSetAI/good-egg/blob/main/docs/methodology.md) for details. ## Trust Levels diff --git a/assets/pr-comment-screenshot.png b/assets/pr-comment-screenshot.png index c20df9feca2c3a28e2496b36f9d278f01ddd4d3d..06da3b8c0bfc7622e8b39f0c47df60a9ae270364 100644 GIT binary patch literal 67045 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 HVioXjEkK*1 literal 59352 zcmeFZWl)t}_&2&0u_zU#!yrVu8&o7D6_Jqc?rs$YX%PWw5fG8??(XicO?PhcT;TIR zpWYAW%$YOuo|(gp53nEh9qV4}x_-5`_bX{pteZqP5eNj^{eoT zkd0U?e7mCkQs~tsEX1WKLtYm6{gSn;=yODRJINvfaUb#W#WOjFsFg8$#SmSzhRtaNapfMxUF@Pld(+8=#_`t$D4CC4QJSu+nZICrpJ{n@0;Czv013}5tDHK zM2O4s%H2=#p%oprjygZ*PJm4#0zu>G^=0K&tWnoCVc(z zLrhN(DOFbS<>E^vvZ}3RKyLK;+S=N|!S@-zO$zTDSqVu=nk@H9BJMB~U~=*BOieBN zt0y)`3A%sq#b*p%;%`2Zugoz~ii(PYKOn&53Fvif*=)n6iAS1{j{gei4qi)l-kk-?w%eWTQqZXbCE!@HV+&DvA(}=GaOAP%3U3|+c>=g0+9O??(@Mi0uLA%(i`{1 zWn^l`tI8EuOCoY|e32$T=Z~k6l%ACqS6@Hu&cK`02YFX9h1LA~>+3!3#~r=mMFY2% zQZm#yO_29)-KzZaIv(CI*~U3hoByTEpDH+6E?=LSAeTS+;yI5NVP1`t9ZIZu($qXL z5u2u5uyuO09%dk&7#4<4?so8in8W0!c*v8);reQWBixH+Qq&V7PxWNCl8}U?71)s~tdho)cVw5wR^zFWzY$H1GMnb8)o+gnk(gNsX_PAffN z;^M-G&!EC|rc&4;->LUXD93Ky{U#p+y=1%u7g?H*XWh=XA{HJ zez~8W3g3*%(eFUEFji2ov3~tgsHDdsl|$vO&R4NX3@lr9SZst$LT+jdPx^8LSm zzpJ8hs`hQ)n>t2gsW;hVtT>M?Lj8U)jdDug_$59*KAQO%A*Xjl_`wWTYb)F=tgJqz zMAm9oJudO`I!CES!HP_Z3dF&0k5$+>FJwWy^2t})_s5-ah>3}P-4oOo7qdoltaq3C z&_iWjzMNVa%2^pLVx8a)Zh9duezU#3{j0v%+R=K2%s{%TL_A8*&Q4)GU}eQ5P0sn+ z#_o2_(9q|eB)^1&gztp{@E(zRU6wnH*38Ve@$vDSj}E71S89h?^~Dq0E*{?*1?5_G zih6~>>Tq65L1$oD8UI{M7^5W`6pziVt!4%HBJ@I@%N@G<`l7oL&uZ({D(ipS z>_ruY60sX)+AiyjJI=2ftL^u`k-2l*@`ot7Yr>2DNETg|+qb=L+`LKmnxC>SLtWi& z4Kq3j*X86mvmj^QVJA!WMkM-6xJ!o}=9Sfz&E4&sX8wx_Vx~`t9aZCn(@>9G zH?r~=UhGL~YHw#S+#MVlvHtyj{DDW+(+ssTaTP(wYCWTOL{RkTLwJ0v>*~;{sj0U+ zU?NQ>C&iQ+?ib{LjA_uwtb!Ywwnyr1Z*0^K4WY+xCJ1M^%rmGu>~uAV@2XJ+--zF& zfHOb|4>cOIf1~&UFR_SIvF?!7M zM1?zy4lzeZEU$f!XSaxmNOz{D_PEpXI$8VeN1iJyhUDuTE_qYu1!(s%devkq4C zalXrF#?0=gA0r38rhMPtoEjZsP27w5)`P1Kw{^KAT#~9inqR1hkCtm9*=cu4%0C4U z|9nLUxo6x#Kd-?{{b`Zw2jQ&xin#`_U;fQ!GVZ6-($d-@H6JZxHZwEhR55?XA4w%n z{YftEU5H`N?>l5<^%3kT1OmsF9HzsKfr6)qr!}5f-e0&{2h?RQYYg|sE_TMD^`$6K zKb&T|hP{&Wr=w#aETcR^>>!4zKV7vZQ&XsIUa#ZS|I3#exm3k27ZZ37yk8QkBK?x# zSn)mM{#3p7aem3@!(id?l%e6_t$N}N+&f$NQ&S3SyiUEwcxA!m<>f9LRqjgVE`-i| zE64_N_n&5C#h(Rao(X;8wOOeAP7{0sYpi~2uH|6ey)x@aRX-BXymj zY|54Kvf!7&RI=$R+}rGrL@@PFj~!P=@Y~@n1e|7cF)=9TyU<-;%1F@K5Ul#U!RqDw zX}8MrIR;kL1Ah9|fVH{YoSb+kf1-k7!t-@tg&Shf^)rIqczR*sM@EtX+>nlr&i7nX zJt!!dnM_X<(*3G5m?kz1>@%P+#G}SRP_~#ls&J>vniUDw0FIYQd(~)?6+@o55H4rX%f0dgX<|EHv}7U8+b< z^Qncd_&TG3FSl!kN*yu!{-Spl+ZscqYv_!txmn6VOY1wFXN-%N@3lH2WZ3uj-lG_T zs-o?A6ly-Xu&|KH8fo)aF1h-*R3x{>Btj~J4GGnah|G4W zH|}-3Ck4f1>&jr3 z$C2|yU`8ytrKM%6O4i3ee;WB>6|9Lkj6M|wfK92``%jwU1|)X~$CEl}f+ zijL;C*|-n&@ew=^>R2ZtPEO9NSVWkWf8Wv$WjnIk+1c4FbOu%ayiYdtmyebavpJ&-z@0u5U2CBG?R{JF2S(kO%4wbtfX{3t)1Z zj@VtfdUYDP*1kE@Wip-{{wB#U*K{NRror~f{u=~9tHEo$ev**v#U4rlk2wqg2 zo}hMuHxpTGpPoaSiN7yCuyP`hx-8*bwo7s^M?z#&RHEvBJuBMU`*g3bk3TYz-!EUp zpNP$L_!IQLt&JK5r-!^Y2Ii;NOrF&To_%^CL`Eeb5ECds6uEv3lgnW#Ss&qWcEXHF z#`mS(pZFfHh1=nxKAp+|HKO8VkJf&y?;8LRO*SHo($gSOGWH6y@lx)JW0v5nSm|{A zy(tPZmoH!bA!sfTuU@0OSh%p7<<6h$_hC;Wc@iNLow@)HL?}i z@!7qz%o*n@ro-2!;4?4iYJq%*1YKQSE}STLHiOQum(a+j2h{blIr*Y~R^CSd2vRl} zOQuOaIJjH-RldM%>;~pdt)AchwQ67L#>V_5!WcA-jaxEB$>zRyHSQR`v9z^~w+>^# zBxLzc^QN5D9o1bVf#091)aG-q#c=F5J-^cq#e)Y`B=1W07hWc{M~818ts|YUa+=nk zq8*`7N#x10i8o!3c9YD;oKjVaJ}ziC81xmh@9!_xgsDqb>ae`7aC3cEU??Qk_)xmO z_SR@BVW7Ys*V)k?v2~!Og$3(#p#oOZrH=26>M?8lPTi%#7#!xqwFMI{ZN%o~b?X%! zR4g6qrUU8wuiKMI-02jb%61E{E%*C-UB%X_-!UA7(!5b4#O1t4r|!;wgOk&~c-&q+ zZrzeWu;ONKntiyi@9D!4onOWS>7xT_#1*Go7>F{b{rZL^KHt+r-|ycga?K|`#MO9i zj?JFkzIRW!WRKLs!eSC8`xSI_U?N6cyvytB9p1PN_c#DxC&;lI^?u1;9mXXq_u5_V zSBi38L*XNSaBCL}H#Fxpk7A3nCG>Z7F;6giRB4P?C$QbKVcas&l_k0N$qq^^!qt9bCIIxwO=rohSihL~9!isVQ(QbtvnsI&5_-&Uk`6!V4(ff)3|SDwnnE$^8ESp%hWRUO!n>T01)EdI=9EkNBA=>bIgz`=hIg_{jnAm2b9Q=C+t7gP zxbygEZ;g_hI~;3y;LUGI!qU=Ggh4mk4^rOe+(fsZy?aL#$zfJoUtfRhjQAQ6(Y*9F zrO;;aPD23c%;X0&xi*v^hL*9h#K~1G#Ud@rB$?QUa4ace&Z+hFz?2kPcBB4Ufd6$5 ze8r@tkvofTOd4}!%r#e5Ru!`ynCClUsrRbU^Ua2!EGV3+@o;m$E->ToPgQG6ej{?{ z&KOdxj%i6V!e(v761ny=dLMCkxLV|vDvX5c>s-CmZZ#S zA}}e58d_L3*Z7~;kNEicH+ObwCnhSybj|Q7m!>3NzNE333L%pJku_!?*YY0v*hq3tfoB&CTuL=%^=ah97UY zu<$!`MLVh5(Y|X>1`1scwN(yydV6ptaGrO5X-QluBb$PP!eVoJqUL8ubjhiHL`X>V zx)L-q=$mmSL)iqFSEXa~NxUsts64Ianl+)ZSWa_Yx^(FU3HNhJt_)4=Vu%J*?OE5pWqBPT1;5L0}!Kv5{6Y$#SOt7&WiXxx?2GAl&uynJaYY*5N#b z({H`$sw1Q6zr2+2a(i{j*fjPv!K)nXHqRF7;SGa?<`8an|&v%N~2Ov>}Nq&b%^z;;vtOi>Q#lz|AA3l5lH7RCi$EJPu2I?I6CTgA( z+oEIpN{NYS)bA|TJ+Ur%Y&j_@F3y6p+N#>w05lkYY$mXNSwo%m@v_a$%_P1Vjr$pQ7P>qvX9TDy zbeMHpLKC50zYr10){{E@Y=5)6#GVnT)JvP4kcrRr{u!9mOhhus5)OL$d;0kLEO#)l zDL{_PEnQ~V^Yj8mVE-FbLm*g81ej1`yW+G(L+Mq;pFU*=z}x&cBn5F^CV?q5R8?J4 z;N+Z6Us^=7u(PD1r+1ezRZ*b>>hS(O0-JJxFP~t-e=^ii)Nd7wb?M z^S(Q$-$M%r6@g#4v{gFtLq{1TI6b}dkbxl-I6a(5R%6mH(6^yxtY#V`HCxwL(402| z1E1k*bhLj(h2S-uQ~s4Q*}3KyFGxN_ofX&u`XpjEjyQ7z{AU5TptZwkHC^j};x2j) z2&Lcr;*NsLIaeh&)pFsHz0$Mej+3r(m`q zDI*at()Lp}x`W%O*8rG{NEk!(;y?x?tA6{(<&`9Ew_}I)XkJkOp9}q~hZym*hsWDD zQs3o8P)S8>R9!oxeDEL!KvIYOm^Uu<52h&$GN+Aaf92DfyAvfG1@yNppHaE)-V>Rj zQG;(Wjz~i)nbUTykgo(w^}l85firn zDJ@zrPd6FN44SHmeZ2KbHNHzM?Oh%ad(rcM7WVe@+a1)I=IWU zxsNlM7^Ys;)fD7tJ+H+Q-q_x**S?;Utdh)PUa`#p=uF#E>WDq!KFikQWW!{e<^E_E-R4(u&xO}kZOpyPNkDqkhmLQv=tTbE!!tn2 z-AAVa=YZLGAjGj+za#3wqemWxyTrFFXT`7k`}$KdGY0|kkDM1g*N_|YLjHK+YQS>J zHSDQBwl*^WN=P{2e#ZYu#IF#^RBa4$hbFQ$oXtpXWCy-pQ z{p$mFbI$HKA?HTc26{fesLINBc)Idw@7h2rqz`c2AG=$A)NW-v0xD$?{OdZlHZpo5 zBX}ZN&fx+C0y!WffXYSfjur_!PxPlL%fPVE2h3faSLy0%a9quMjULLlv`wd0`l-%0 z?Cx*?9{pOgJ;=Tl&VKf5qrxS2r0Lsi3KUdSui6`~;p2z7I9sMGmLEsxGO846jEn9X z0Zwu`=}UOtQe0R#xiDMX6pY#rM!$YT=|yC|Y0>_;^ufWwEpqY>8Nt)1pbJ*CM!YOo z8zU5$zR^hNdE7vbk&c@C%)SC0!X(%m=Cy@+k~B0EZ8jpH>u-XV70aCNfoQ7NyD*?s zWQDF=V4~UdtuEJW%yVybcxGAQ()-M)G@0z|>>u3LS7G^0LwA{dzJi`_GX5z{VdxIO zMB}fD!u4{qo#hE~XJ^28{4D_D^B2Mcyt$vXMLc^Uf>br2^_iU1yBT#}xP^5rwzufF zD&86Q|9LjpPLJ0B08mU$?t2lZH7J8uu3UMQzY^kp%WR@NnseO2BM*H=!hv43*hUkI zC7WS)Lgh9Tf~CF`>*?AXzBB$F>qrA;=~_&G(d-z1&BX!R!O z?(W&#&k!HUHwC3t`(WcXbo00uwh~Psm`%UUr)!809Q)p>$3(D!^GC!*MdgFD#fADk z8elY#EHT)=O8GZlC;2Au(7O*FJV0uu<5Ei}2>aqm#_$n>mIorNQkfIG7Y?}|wAJHz z!84lNbbK|359)5H&y9^@p>#^mdwxr`?W&#V*ZUEos`XyZ?%50v4QXaFe|K;%gQIn3 zxC@fG?%d|FTM@I`qNI{Mc&@q40nW=)Bcq!kPv#~>^K%I?uYzPCX=LP6{rg-}AGH)G z;kq>LFoU(-91X{hH=ihX0cGE0*hcqHbd%06y|xJ8coY-)Hyjfa6E{1BaFkXU4Oqfk z%U%_owY9eDz-T6R*o@Lx<#Pq3#)+5eEj3tiMdsB?i=y7 zm2g%a9lc5NS80mYw|r|rtUP;f1g}`^wGyU`3Y{yTvv%^++))V80Fo(?zIC9VA^eCr z143vOwsr^9h1xl2X6aaRY!!RaaG2X?^&qQk2o)M|ge=LpIel4OsCY zjtAeoM;jCqT3?sooA5i~TX?vokdP_XRWv)hJ+2b2nKfhpJn3^Sx&tZI3xql1>a~g7 zqqYccp>6JSTO>VB?lN^H?|P}wa(^0Vh*+R-@a>OUmu@xFl5kldz!_N@$dJ*|q44(h z{@f3|Pef%j1Ph6gV>Kr(aI}*1yuZAVc*ezoFh9kIE=N zd?FGb1k@oDE-&AlarmYvI{lryL`331-CCXbE@teP#?>@AH0nx_oDB!kNnuvh=&(%9 z%?YQ-r-5Mi2(+*wGt_9DpCkUw!znNFh2CUb{f-#=Rph_7e+juuYZ1Y8&(KWS%8DhB ze~$px`z!z?q?)+0^2l;%TZv+4oRAkV0$!+k6irP{!cUB=509SwclzCX#@PDc81sIIZ|uxm$?klNr0VGJ%XFOA8EaQodJzSMOZB z1C^Aln#7>V>zj`)qv^w*zyYQ~g?Nail@&vmR9aP26CwPTQMCHsZI1HQ-HZwk4?p)O z-xKATrF1UN&PqP@e+MtbiPhL$*lI6o4}HpT=Iea%Fa3F&aa-Sy`laL-N`C&d&N9}t zIt`}Dg@sRENt|vWPpnUm(XB_s|Jp?tC&~t%FU~KG(W!$Uf}=XazkU1Y<#labpnQ;b zP!L6Exxgqa&U0uzrfhJ zINX=U3WY4>zq0h@%iWO6N&j9}{QSSuPh)9jmC@<1-*QI0-KJpesg3#J`zgB6AtjRH z-=uzWm&-ipoty4~og$i%f<+z|neE!0j*j7sNt%m4ICCJ9b;iiWc+wKf$dRP>lbnGa z%`)u`zVZNVRgM#iGk%E4z@&-#4WCCay9i$H%v^K zb#)X~_IEoEcTD8U<<^vn#P5kzobvD-)lvRW7T|$IXeKS4pLRoFj{dq@XogBtK`?dC zZuyb;oIv6tsFM%s4Jhgj5<~;Z2Fl##mfj+lF%EMyrm7>m*S;+bR8$m|$?%`pd>8

>-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 diff --git a/docs/configuration.md b/docs/configuration.md index 935eff3..29b240c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -27,23 +27,24 @@ Configuration values are resolved in this order (highest priority first): ## Scoring Model -Good Egg supports two scoring models. Set the model at the top level of the -config file: +Good Egg supports three scoring models. Set the model at the top level of +the config file: ```yaml -scoring_model: v1 # default -- graph-based scoring only +scoring_model: v3 # default -- Diet Egg -- alltime merge rate as sole signal scoring_model: v2 # Better Egg -- graph + external features via logistic regression +scoring_model: v1 # Good Egg -- graph-based scoring only ``` -When using v2, PR comments are branded "Better Egg" instead of "Good Egg". -See [methodology.md](methodology.md#better-egg-v2) for how the v2 model +PR comments are branded "Diet Egg", "Better Egg", or "Good Egg" depending +on the model. See [methodology.md](methodology.md) for how each model works. ## Full YAML Schema ```yaml -# Scoring model selection: v1 (default) or v2 -scoring_model: v1 +# Scoring model selection: v3 (default), v2, or v1 +scoring_model: v3 # Skip scoring for authors who already have merged PRs in the target repo. # When true (the default), existing contributors get an EXISTING_CONTRIBUTOR @@ -127,12 +128,19 @@ v2: ### scoring_model -Selects the scoring model. Set to `v1` (default) for graph-only scoring or -`v2` for the Better Egg combined model. When set to `v2`, the parameters -under the `v2:` block are used and the graph construction is simplified -(no self-contribution penalty, no language normalization in repo quality, no -diversity/volume adjustment). Language match personalization weighting -(`same_language_weight`) is retained in v2. +Selects the scoring model. `v3` (default, Diet Egg) uses alltime merge rate +as the sole signal with no graph construction. `v2` (Better Egg) combines a +simplified graph score with merge rate and account age via logistic +regression. `v1` (Good Egg) uses graph-based scoring only. + +When set to `v2`, the parameters under the `v2:` block are used and the +graph construction is simplified (no self-contribution penalty, no language +normalization in repo quality, no diversity/volume adjustment). Language +match personalization weighting (`same_language_weight`) is retained in v2. + +v3 does not use graph construction, so the `graph_scoring`, `recency`, +`edge_weights`, and `language_normalization` sections have no effect. The +`thresholds` section still controls trust level classification. ### v2 (Better Egg) @@ -215,7 +223,7 @@ The following environment variables override individual config values: | `GOOD_EGG_HIGH_TRUST` | `thresholds.high_trust` | float | | `GOOD_EGG_MEDIUM_TRUST` | `thresholds.medium_trust` | float | | `GOOD_EGG_HALF_LIFE_DAYS` | `recency.half_life_days` | int | -| `GOOD_EGG_SCORING_MODEL` | `scoring_model` | str (`v1` or `v2`) | +| `GOOD_EGG_SCORING_MODEL` | `scoring_model` | str (`v1`, `v2`, or `v3`) | | `GOOD_EGG_SKIP_KNOWN_CONTRIBUTORS` | `skip_known_contributors` | bool (`true`/`false`) | ## Programmatic Configuration diff --git a/docs/github-action.md b/docs/github-action.md index 1a98d4d..8e8e62c 100644 --- a/docs/github-action.md +++ b/docs/github-action.md @@ -37,7 +37,7 @@ This posts a trust score comment on each pull request: | `comment` | No | `true` | Post a PR comment with the trust score | | `check-run` | No | `false` | Create a check run with the trust score | | `fail-on-low` | No | `false` | Fail the action if trust level is LOW | -| `scoring-model` | No | `v1` | Scoring model: `v1` (Good Egg) or `v2` (Better Egg) | +| `scoring-model` | No | `v3` | Scoring model: `v3` (Diet Egg), `v2` (Better Egg), or `v1` (Good Egg) | | `skip-known-contributors` | No | `true` | Skip scoring for authors with merged PRs in the repo | ## Outputs @@ -47,7 +47,7 @@ This posts a trust score comment on each pull request: | `score` | Normalized trust score (0.0 - 1.0) | | `trust-level` | Trust level: HIGH, MEDIUM, LOW, UNKNOWN, BOT, or EXISTING_CONTRIBUTOR | | `user` | GitHub username that was scored | -| `scoring-model` | Scoring model used: `v1` (Good Egg) or `v2` (Better Egg) | +| `scoring-model` | Scoring model used: `v3` (Diet Egg), `v2` (Better Egg), or `v1` (Good Egg) | | `skipped` | Whether scoring was skipped for an existing contributor (`true`/`false`) | ## Custom Configuration @@ -179,9 +179,10 @@ jobs: You can check whether scoring was skipped via the `skipped` output. -## Using Better Egg (v2) +## Selecting a Scoring Model -To use the v2 scoring model, set the `scoring-model` input: +The default model is v3 (Diet Egg), which scores by alltime merge rate. To +use an older model, set the `scoring-model` input: ```yaml jobs: @@ -191,12 +192,12 @@ jobs: - uses: 2ndSetAI/good-egg@v0 with: github-token: ${{ secrets.GITHUB_TOKEN }} - scoring-model: v2 + scoring-model: v2 # or v1 ``` -When using v2, PR comments are branded "Better Egg" and include a component -score breakdown showing graph score, merge rate, and account age -contributions. The `scoring-model` output reflects which model was used. +PR comments are branded according to the model: "Diet Egg" for v3, "Better +Egg" for v2, "Good Egg" for v1. v2 and v3 include a component score +breakdown. The `scoring-model` output reflects which model was used. You can also set `scoring-model` via the `GOOD_EGG_SCORING_MODEL` environment variable, but the input takes precedence. @@ -209,5 +210,7 @@ See the [examples/](../examples/) directory for complete workflow files: that posts a PR comment - [strict-workflow.yml](../examples/strict-workflow.yml) -- comment, check run, and fail-on-low +- [diet-egg-workflow.yml](../examples/diet-egg-workflow.yml) -- v3 + scoring model (default) with component breakdown - [better-egg-workflow.yml](../examples/better-egg-workflow.yml) -- v2 scoring model with component breakdown diff --git a/docs/library.md b/docs/library.md index 2aa5efc..8c2894b 100644 --- a/docs/library.md +++ b/docs/library.md @@ -114,26 +114,22 @@ result = await score_pr_author( ) ``` -### v2 (Better Egg) Configuration +### Scoring Model Selection -To use the v2 scoring model, set `scoring_model` on the config: +The default model is v3 (Diet Egg). To use an older model, set +`scoring_model` on the config: ```python from good_egg import GoodEggConfig, score_pr_author -config = GoodEggConfig( - scoring_model="v2", - v2={ - "graph": {"half_life_days": 180, "max_age_days": 730}, - "features": {"merge_rate": True, "account_age": True}, - "combined_model": { - "intercept": -0.8094, - "graph_score_weight": 1.9138, - "merge_rate_weight": -0.7783, - "account_age_weight": 0.1493, - }, - }, -) +# v3 (default) -- merge rate only +config = GoodEggConfig() + +# v2 -- graph + merge rate + account age +config = GoodEggConfig(scoring_model="v2") + +# v1 -- graph only +config = GoodEggConfig(scoring_model="v1") result = await score_pr_author( login="octocat", @@ -142,12 +138,13 @@ result = await score_pr_author( config=config, ) -# v2 results include component scores +# v3 and v2 results include component scores if result.component_scores: - print(f"Graph score: {result.component_scores['graph_score']:.3f}") - print(f"Merge rate: {result.component_scores['merge_rate']:.3f}") - print(f"Log account age: {result.component_scores['log_account_age']:.3f}") - print(f"Normalized score: {result.normalized_score:.3f}") + print(f"Merge rate: {result.component_scores.get('merge_rate')}") + +# v3 includes a fresh account advisory +if result.fresh_account and result.fresh_account.is_fresh: + print(f"Fresh account: {result.fresh_account.account_age_days} days old") print(f"Scoring model: {result.scoring_model}") ``` @@ -176,7 +173,7 @@ the following fields: |-------|------|-------------| | `user_login` | `str` | GitHub username that was scored | | `context_repo` | `str` | Repository used as scoring context | -| `raw_score` | `float` | Pre-normalization score: graph score (v1) or logit (v2) | +| `raw_score` | `float` | Pre-normalization score: merge rate (v3), logit (v2), or graph score (v1) | | `normalized_score` | `float` | Normalized score (0.0 - 1.0) | | `trust_level` | `TrustLevel` | HIGH, MEDIUM, LOW, UNKNOWN, BOT, or EXISTING_CONTRIBUTOR | | `account_age_days` | `int` | Age of the GitHub account in days | @@ -185,9 +182,10 @@ the following fields: | `top_contributions` | `list[ContributionSummary]` | Top repositories contributed to | | `language_match` | `bool` | Whether the user's top language matches the context repo | | `flags` | `dict[str, bool]` | Flags (is_bot, is_new_account, etc.) | -| `scoring_model` | `str` | Scoring model used: `v1` or `v2` | -| `component_scores` | `dict[str, float] \| None` | Component breakdown (v2 only): `graph_score`, `merge_rate`, `log_account_age` | +| `scoring_model` | `str` | Scoring model used: `v1`, `v2`, or `v3` | +| `component_scores` | `dict[str, float]` | Component breakdown (v3: `merge_rate`; v2: `graph_score`, `merge_rate`, `log_account_age`) | | `scoring_metadata` | `dict[str, Any]` | Internal scoring details | +| `fresh_account` | `FreshAccountAdvisory \| None` | Advisory for accounts under 365 days old (None for bots and existing contributors) | `TrustScore` is a Pydantic model, so you can serialize it: diff --git a/docs/mcp-server.md b/docs/mcp-server.md index 4cbe7ea..0f9e1fd 100644 --- a/docs/mcp-server.md +++ b/docs/mcp-server.md @@ -82,15 +82,17 @@ Returns the full trust score as JSON, including all fields from the |------|------|----------|-------------| | `username` | `string` | Yes | GitHub username to score | | `repo` | `string` | Yes | Target repository in `owner/repo` format | -| `scoring_model` | `string` | No | Scoring model: `v1` (Good Egg, default) or `v2` (Better Egg) | +| `scoring_model` | `string` | No | Scoring model: `v3` (Diet Egg, default), `v2` (Better Egg), or `v1` (Good Egg) | | `force_score` | `boolean` | No | Force full scoring even for known contributors (default: `false`) | **Returns:** Full `TrustScore` JSON with all fields (user_login, context_repo, raw_score, normalized_score, trust_level, account_age_days, total_merged_prs, unique_repos_contributed, top_contributions, language_match, flags, scoring_model, component_scores, -scoring_metadata). When `scoring_model` is `v2`, the response includes -`component_scores` with graph_score, merge_rate, and log_account_age. +scoring_metadata, fresh_account). v3 includes `component_scores` with +`merge_rate`. v2 includes `graph_score`, `merge_rate`, and +`log_account_age`. The `fresh_account` field contains a Fresh Egg advisory +for accounts under 365 days old (null for bots and existing contributors). ### check_pr_author @@ -102,17 +104,21 @@ Returns a compact summary suitable for quick checks. |------|------|----------|-------------| | `username` | `string` | Yes | GitHub username to check | | `repo` | `string` | Yes | Target repository in `owner/repo` format | -| `scoring_model` | `string` | No | Scoring model: `v1` (Good Egg, default) or `v2` (Better Egg) | +| `scoring_model` | `string` | No | Scoring model: `v3` (Diet Egg, default), `v2` (Better Egg), or `v1` (Good Egg) | | `force_score` | `boolean` | No | Force full scoring even for known contributors (default: `false`) | -**Returns (v1):** +**Returns (v3, default):** ```json { "user_login": "octocat", "trust_level": "HIGH", "normalized_score": 0.82, - "total_merged_prs": 47 + "total_merged_prs": 47, + "scoring_model": "v3", + "component_scores": { + "merge_rate": 0.82 + } } ``` @@ -143,10 +149,10 @@ Returns an expanded breakdown with contributions, flags, and metadata. |------|------|----------|-------------| | `username` | `string` | Yes | GitHub username to analyse | | `repo` | `string` | Yes | Target repository in `owner/repo` format | -| `scoring_model` | `string` | No | Scoring model: `v1` (Good Egg, default) or `v2` (Better Egg) | +| `scoring_model` | `string` | No | Scoring model: `v3` (Diet Egg, default), `v2` (Better Egg), or `v1` (Good Egg) | | `force_score` | `boolean` | No | Force full scoring even for known contributors (default: `false`) | -**Returns (v1):** +**Returns (v3, default):** ```json { @@ -154,7 +160,7 @@ Returns an expanded breakdown with contributions, flags, and metadata. "context_repo": "octocat/Hello-World", "trust_level": "HIGH", "normalized_score": 0.82, - "raw_score": 0.0045, + "raw_score": 0.82, "account_age_days": 3650, "total_merged_prs": 47, "unique_repos_contributed": 12, @@ -171,11 +177,18 @@ Returns an expanded breakdown with contributions, flags, and metadata. "is_bot": false, "is_new_account": false }, - "scoring_metadata": {} + "scoring_model": "v3", + "component_scores": { + "merge_rate": 0.82 + }, + "scoring_metadata": { + "closed_pr_count": 10 + }, + "fresh_account": null } ``` -**Returns (v2):** +**Returns (v1):** ```json { @@ -183,7 +196,7 @@ Returns an expanded breakdown with contributions, flags, and metadata. "context_repo": "octocat/Hello-World", "trust_level": "HIGH", "normalized_score": 0.82, - "raw_score": 0.2871, + "raw_score": 0.0045, "account_age_days": 3650, "total_merged_prs": 47, "unique_repos_contributed": 12, @@ -200,12 +213,6 @@ Returns an expanded breakdown with contributions, flags, and metadata. "is_bot": false, "is_new_account": false }, - "scoring_model": "v2", - "component_scores": { - "graph_score": 0.78, - "merge_rate": 0.91, - "log_account_age": 3.45 - }, "scoring_metadata": {} } ``` diff --git a/docs/methodology.md b/docs/methodology.md index cf1bcba..74ff0f6 100644 --- a/docs/methodology.md +++ b/docs/methodology.md @@ -101,9 +101,14 @@ These raw weights are normalized to sum to 1.0, so actual values in the random w ### Scoring and Normalization -The directed graph is scored using personalized graph-based ranking with a damping factor (alpha) of 0.85. This produces a raw score for the user node. +**v3 (default):** The score is the alltime merge rate: merged PRs divided +by total PRs (merged + closed). This value is used directly as both +`raw_score` and `normalized_score`, since it is already in [0, 1]. No +graph construction is performed. -**v1:** Normalization converts the raw graph score to a 0-1 range: +**v1:** The directed graph is scored using personalized graph-based ranking +with a damping factor (alpha) of 0.85. Normalization converts the raw +graph score to a 0-1 range: ``` baseline = 1 / num_nodes @@ -162,11 +167,57 @@ GitHub rate limits bound how much data can be fetched per user. Good Egg is desi --- +## Diet Egg (v3) + +The v3 scoring model -- branded "Diet Egg" in PR comments -- is the default +since v3 was introduced. It uses alltime merge rate as the sole scoring +input, dropping graph score and log account age from the v2 logistic +regression. + +### Motivation + +Experimental data from the validation study showed that: + +1. **Graph score (hub_score) hurts performance for unknown contributors.** + The graph is most useful for contributors with extensive cross-project + history, but for the primary use case -- evaluating unfamiliar PR + authors -- it adds noise. +2. **Log account age adds nothing significant.** While statistically + significant in isolation, account age does not improve ranking + performance when combined with merge rate. + +Merge rate alone provides a simple, fast, and effective signal. v3 requires +no graph construction, no pagerank computation, and no logistic regression. + +### Fresh Egg Advisory + +Accounts less than 365 days old receive a "Fresh Egg" advisory in the +output. This is informational only and does not affect the score. In the +validation data, fresh accounts correlate with approximately 16 percentage +points lower merge rates. + +The advisory is attached to all scoring paths (v1, v2, v3) and to the +insufficient-data short circuit. It is not attached to bot accounts (whose +synthetic profiles have unreliable age data) or to existing contributor +early returns (where no profile data is fetched). + +### Component Scores + +v3 output includes a single component: + +| Component | Description | +|-----------|-------------| +| `merge_rate` | Fraction of PRs that were merged: `merged / (merged + closed)` | + +The `scoring_metadata` contains `closed_pr_count` for transparency. + +--- + ## Better Egg (v2) The v2 scoring model -- branded "Better Egg" in PR comments -- extends the graph-based approach with external features combined via logistic regression. -It is opt-in via `scoring_model: v2` in configuration; v1 remains the default. +It is available via `scoring_model: v2` in configuration. ### Motivation diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index b06ed52..68bf477 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -26,6 +26,27 @@ backoff. If you see persistent failures: | `Could not extract PR number` | Not a PR event | Ensure workflow triggers on `pull_request` | | `Invalid GITHUB_REPOSITORY` | Malformed env var | Check Actions environment | +## v3 (Diet Egg) Scoring + +### v3 score differs from v1 or v2 + +This is expected. v3 uses alltime merge rate as the sole signal, with no +graph construction. Prolific contributors who close many of their own PRs +(drafts, experiments) will have lower scores than in v1/v2 because those +closed PRs pull down their merge rate. + +### "Diet Egg" appears in PR comments + +PR comments use the "Diet Egg" branding when `scoring_model` is set to +`v3` (the default). This is intentional. To use an older model, set +`scoring_model: v1` or `scoring_model: v2`. + +### "Fresh Egg" advisory appears + +Accounts under 365 days old get a "Fresh Egg" advisory. This is +informational only and does not affect the score. It is not shown for bot +accounts or existing contributors. + ## v2 (Better Egg) Scoring ### v2 score differs significantly from v1 @@ -46,9 +67,7 @@ has sufficient rate limit remaining. ### "Better Egg" appears in PR comments PR comments use the "Better Egg" branding when `scoring_model` is set to -`v2`. This is intentional and helps distinguish v2 results from v1. To -switch back, set `scoring_model: v1` or remove the setting (v1 is the -default). +`v2`. This is intentional and helps distinguish v2 results from v1. ## Getting Help diff --git a/examples/.good-egg.yml b/examples/.good-egg.yml index 0718e7b..025f3ee 100644 --- a/examples/.good-egg.yml +++ b/examples/.good-egg.yml @@ -1,6 +1,11 @@ # Good Egg configuration # Copy this file to your repository root as .good-egg.yml +# Scoring model: v3 (Diet Egg, default), v2 (Better Egg), or v1 (Good Egg) +# v3 uses alltime merge rate as the sole signal. v2 adds graph scoring and +# account age. v1 uses graph scoring only. +# scoring_model: v3 + # Skip scoring for authors who already have merged PRs in the target repo. # Set to false to always run full scoring. # skip_known_contributors: true @@ -84,7 +89,7 @@ language_normalization: # -------------------------------------------------------------------------- # v2 (Better Egg) scoring model # -------------------------------------------------------------------------- -# Uncomment the lines below to enable the v2 combined model. +# Uncomment the lines below to use the v2 combined model instead of v3. # See docs/methodology.md for how v2 works. # scoring_model: v2 diff --git a/examples/diet-egg-workflow.yml b/examples/diet-egg-workflow.yml new file mode 100644 index 0000000..6876b6e --- /dev/null +++ b/examples/diet-egg-workflow.yml @@ -0,0 +1,27 @@ +# Diet Egg (v3) workflow -- uses alltime merge rate as the sole scoring +# signal. This is the default model, so scoring-model does not need to be +# set explicitly. Shown here for clarity. +name: Diet Egg + +on: + pull_request: + types: [opened, reopened, synchronize] + +permissions: + pull-requests: write + +jobs: + score: + runs-on: ubuntu-latest + steps: + - id: egg + uses: 2ndSetAI/good-egg@v0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Print results + run: | + echo "Score: ${{ steps.egg.outputs.score }}" + echo "Trust level: ${{ steps.egg.outputs.trust-level }}" + echo "Model: ${{ steps.egg.outputs.scoring-model }}" + echo "User: ${{ steps.egg.outputs.user }}" diff --git a/examples/library_usage.py b/examples/library_usage.py index 71314d5..91b4353 100644 --- a/examples/library_usage.py +++ b/examples/library_usage.py @@ -1,4 +1,4 @@ -"""Example: Score a GitHub user with Good Egg.""" +"""Example: Score a GitHub user with Good Egg (v3 / Diet Egg).""" from __future__ import annotations @@ -17,6 +17,7 @@ async def main() -> None: ) print(f"User: {result.user_login}") print(f"Trust level: {result.trust_level}") + print(f"Scoring model: {result.scoring_model}") if result.flags.get("scoring_skipped"): pr_count = result.scoring_metadata.get("context_repo_merged_pr_count", 0) @@ -26,6 +27,19 @@ async def main() -> None: print(f"Merged PRs: {result.total_merged_prs}") print(f"Unique repos: {result.unique_repos_contributed}") + # v3 component scores + if result.component_scores: + merge_rate = result.component_scores.get("merge_rate") + if merge_rate is not None: + print(f"Merge rate: {merge_rate:.0%}") + + # Fresh Egg advisory + if result.fresh_account and result.fresh_account.is_fresh: + print( + f"Fresh account: {result.fresh_account.account_age_days} days old" + f" (< {result.fresh_account.threshold_days} days)" + ) + if __name__ == "__main__": asyncio.run(main())