Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gittensor/validator/issue_discovery/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"""

import asyncio
import os
from dataclasses import dataclass, field
from datetime import datetime, timedelta, timezone
from typing import Dict, List, Optional, Set, Tuple
Expand All @@ -57,6 +56,7 @@
calculate_base_score_for_pr_files,
check_merged_branch_eligibility,
)
from gittensor.validator.utils.config import dev_mode_enabled
from gittensor.validator.utils.datetime_utils import calculate_time_decay
from gittensor.validator.utils.load_weights import (
LanguageConfig,
Expand Down Expand Up @@ -121,7 +121,7 @@ def _should_include_issue(issue: MirrorIssue) -> bool:
discovery rewards in repos they maintain — mirrors the PR-side maintainer
skip in ``oss_contributions/mirror/load.py``. Bypassed under DEV_MODE.
"""
if not os.environ.get('DEV_MODE') and issue.author_association in MAINTAINER_ASSOCIATIONS:
if not dev_mode_enabled() and issue.author_association in MAINTAINER_ASSOCIATIONS:
return False
return True

Expand Down
4 changes: 2 additions & 2 deletions gittensor/validator/oss_contributions/mirror/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
merged_count used by ``check_eligibility`` isn't inflated by ineligible PRs.
"""

import os
from datetime import datetime, timedelta, timezone
from typing import Dict, Optional

Expand All @@ -26,6 +25,7 @@
from gittensor.utils.mirror.models import MirrorPullRequest
from gittensor.validator.oss_contributions.mirror.scored_pr import ScoredPR
from gittensor.validator.oss_contributions.mirror.scoring import _should_skip_merged_mirror_pr
from gittensor.validator.utils.config import dev_mode_enabled
from gittensor.validator.utils.load_weights import RepositoryConfig, resolve_scoring


Expand Down Expand Up @@ -103,7 +103,7 @@ def _maybe_add_pr(

# Silent maintainer skip — logging every maintainer-merged PR would dominate
# the skip-reason log.
if not os.environ.get('DEV_MODE') and pr.author_association in MAINTAINER_ASSOCIATIONS:
if not dev_mode_enabled() and pr.author_association in MAINTAINER_ASSOCIATIONS:
return

if pr.state == 'OPEN':
Expand Down
4 changes: 2 additions & 2 deletions gittensor/validator/oss_contributions/mirror/scoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

import asyncio
import math
import os
from dataclasses import dataclass
from typing import Dict, List, Optional, Tuple

Expand All @@ -48,6 +47,7 @@
from gittensor.validator.oss_contributions.scoring import (
calculate_review_quality_multiplier,
)
from gittensor.validator.utils.config import dev_mode_enabled
from gittensor.validator.utils.datetime_utils import calculate_time_decay
from gittensor.validator.utils.isolated_scoring import isolated_calculate_token_score
from gittensor.validator.utils.load_weights import (
Expand Down Expand Up @@ -260,7 +260,7 @@ def _should_skip_merged_mirror_pr(scored: ScoredPR, repo_config: RepositoryConfi
return True, f'PR #{pr.pr_number} is MERGED but missing merged_at'

# Defensive recheck — load already drops these (with DEV_MODE bypass)
if not os.environ.get('DEV_MODE') and pr.author_association in MAINTAINER_ASSOCIATIONS:
if not dev_mode_enabled() and pr.author_association in MAINTAINER_ASSOCIATIONS:
return True, f'PR #{pr.pr_number} author is {pr.author_association}'

if pr.merged_by_login and pr.merged_by_login.lower() == pr.author_login.lower():
Expand Down
13 changes: 13 additions & 0 deletions gittensor/validator/utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@
# optional env vars
STORE_DB_RESULTS = os.getenv('STORE_DB_RESULTS', 'false').lower() == 'true'

_TRUTHY_ENV_VALUES = frozenset({'1', 'true', 'yes', 'on'})


def dev_mode_enabled() -> bool:
"""Whether DEV_MODE bypasses the maintainer filters.

Read at call time rather than import time so tests and operators can toggle it
per process. Matched by value, not presence: DEV_MODE=false must disable the
bypass on a production validator.
"""
return os.getenv('DEV_MODE', '').strip().lower() in _TRUTHY_ENV_VALUES


# log values
bt.logging.info(f'VALIDATOR_WAIT: {VALIDATOR_WAIT}')
bt.logging.info(f'VALIDATOR_STEPS_INTERVAL: {VALIDATOR_STEPS_INTERVAL}')
Expand Down
10 changes: 7 additions & 3 deletions neurons/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# DEALINGS IN THE SOFTWARE.


import os
import time
from functools import partial
from typing import Dict, List, Set
Expand All @@ -36,7 +35,12 @@
priority_pat_broadcast,
priority_pat_check,
)
from gittensor.validator.utils.config import STORE_DB_RESULTS, WANDB_PROJECT, WANDB_VALIDATOR_NAME
from gittensor.validator.utils.config import (
STORE_DB_RESULTS,
WANDB_PROJECT,
WANDB_VALIDATOR_NAME,
dev_mode_enabled,
)
from gittensor.validator.utils.load_weights import RepositoryConfig
from gittensor.validator.utils.storage import DatabaseStorage
from neurons.base.validator import BaseValidatorNeuron
Expand All @@ -55,7 +59,7 @@ class Validator(BaseValidatorNeuron):
def __init__(self, config=None):
super(Validator, self).__init__(config=config)

if os.environ.get('DEV_MODE'):
if dev_mode_enabled():
bt.logging.warning('⚠ DEV_MODE is active — maintainer PR filtering is bypassed')

# Ensure PAT storage file exists on boot
Expand Down
18 changes: 18 additions & 0 deletions tests/validator/oss_contributions/mirror/test_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,24 @@ def test_dev_mode_bypasses_maintainer_skip(self, monkeypatch):

assert len(eval_.merged_prs) == 1

@pytest.mark.parametrize('dev_mode', ['0', 'false', 'off', 'no', '', ' '])
def test_dev_mode_disabled_values_keep_maintainer_skip(self, dev_mode, monkeypatch):
# An explicitly-disabled DEV_MODE must not bypass the filter on a
# production validator.
monkeypatch.setenv('DEV_MODE', dev_mode)
client = Mock()
client.get_miner_pulls.return_value = _build_response(
[
_pr_dict(1, author_association='OWNER'),
_pr_dict(2, author_association='CONTRIBUTOR'),
]
)
eval_ = _eval()
load_miner_prs(eval_, _mirror_repos('entrius/gittensor-ui'), client=client)

assert len(eval_.merged_prs) == 1
assert eval_.merged_prs[0].pr.pr_number == 2


# ============================================================================
# Lookback window (sent to the mirror; windowing happens server-side)
Expand Down
Loading