select-opt dry-run: foothold verified_reuse first, build-config default w/ fallback, GPU enum map (45/45)

This commit is contained in:
Victor Cao
2026-10-16 22:00:52 +08:00
parent bed3bc11ca
commit 68f24e6794
7 changed files with 193 additions and 56 deletions

View File

@@ -4,7 +4,7 @@ import unittest
import os
from unittest.mock import patch
from pathlib import Path
from src.config_params import build_config_params, config_params_source, GAP
from src.config_params import build_config_params, config_params_source, build_config_params_with_meta, GAP
from src.build_config_client import BuildConfigError
from scripts.dry_run import _render
@@ -16,32 +16,68 @@ class TestConfigParams(unittest.TestCase):
self.addCleanup(env.stop)
def test_source_selection_and_failure(self):
with patch("urllib.request.urlopen") as network:
self.assertEqual(config_params_source(), "sample")
build_config_params()
network.assert_not_called()
self.assertIn("discovered via capture", GAP)
with patch.dict(os.environ, {"CONFIG_PARAMS_SOURCE": "build-config"}):
with self.assertRaisesRegex(BuildConfigError, "missing/invalid credential"):
build_config_params("gpu")
with patch.dict(os.environ, {"ALLOW_BUILD_CONFIG": "1", "XC_TOKEN": "test-secret"}), patch("src.config_params.build_config", return_value="api: yaml") as client:
self.assertEqual(config_params_source(), "build-config")
self.assertEqual(build_config_params("gpu"), "api: yaml")
client.assert_called_once_with("gpu", "vllm", "text-generation")
with patch.dict(os.environ, {"CONFIG_PARAMS_SOURCE": "build-config"}), patch("src.config_params.build_config", side_effect=BuildConfigError("transport/timeout")):
with self.assertRaisesRegex(BuildConfigError, "transport/timeout"):
build_config_params("gpu")
# No token → sample, no network
with patch('src.config_params.resolve_token', side_effect=ValueError), patch('src.config_params.build_config') as client:
self.assertEqual(config_params_source(), 'sample')
yaml, meta = build_config_params_with_meta('壁砺')
self.assertEqual(meta['auth'], 'missing')
self.assertEqual(meta['configParams_source'], 'sample')
client.assert_not_called()
# Token alone → prefer build-config (kickoff default)
for gpu, enum in [('壁砺', 'Biren_166m'), ('壁砺166M', 'Biren_166m'),
('Biren_166m', 'Biren_166m'), ('曦望', 'Sunrise_pt-200-x1'),
('曦望 S2', 'Sunrise_pt-200-x1'), ('Sunrise_pt-200-x1', 'Sunrise_pt-200-x1')]:
with self.subTest(gpu=gpu), patch('src.config_params.resolve_token', return_value='synthetic'), patch('src.config_params.build_config', return_value='api: yaml') as client:
self.assertEqual(config_params_source(), 'build-config')
yaml, meta = build_config_params_with_meta(gpu)
self.assertEqual(yaml, 'api: yaml')
self.assertEqual(meta['configParams_source'], 'build-config')
self.assertEqual(meta['auth'], 'ok')
client.assert_called_once_with(enum, 'vllm', 'text-generation')
# Failure → sample + GAP reason
with patch('src.config_params.resolve_token', return_value='synthetic'), patch('src.config_params.build_config', side_effect=BuildConfigError('transport/timeout')):
yaml, meta = build_config_params_with_meta('壁砺')
self.assertEqual(meta['configParams_source'], 'sample')
self.assertEqual(meta['configParams_fallback_reason'], 'GAP: transport/timeout')
self.assertIn('max_model_len: 4096', yaml)
# Forced build-config also soft-falls back in with_meta
with patch.dict(os.environ, {'CONFIG_PARAMS_SOURCE': 'build-config'}), patch('src.config_params.resolve_token', return_value='synthetic'), patch('src.config_params.build_config', side_effect=BuildConfigError('transport/timeout')):
yaml, meta = build_config_params_with_meta('壁砺')
self.assertEqual(meta['configParams_fallback_reason'], 'GAP: transport/timeout')
# Unmapped GPU → no API call
for gpu in ('天垓150', '智铠 mrv-100', 'MetaX_c-500', '<GPU>', None):
with patch('src.config_params.resolve_token', return_value='synthetic'), patch('src.config_params.build_config') as client:
_, meta = build_config_params_with_meta(gpu)
self.assertIn('GAP: gpu enum unmapped', meta['configParams_fallback_reason'])
client.assert_not_called()
# Force sample even with token
with patch.dict(os.environ, {'CONFIG_PARAMS_SOURCE': 'sample'}), patch('src.config_params.resolve_token', return_value='synthetic'), patch('src.config_params.build_config') as client:
self.assertEqual(config_params_source(), 'sample')
build_config_params('壁砺')
client.assert_not_called()
def test_report_api_failure_metadata(self):
with patch('src.config_params.resolve_token', return_value='synthetic'), patch('src.config_params.build_config', side_effect=BuildConfigError('transport/timeout')):
report = _render([{'model_address': 'org/a', 'try_next_gpus': ['壁砺'],
'foothold_class': 'verified_reuse', 'evidence_source': 'pending-foothold',
'no_download': False}], 'test', 'fixture')
for value in ('foothold_class=verified_reuse', 'evidence_source=pending-foothold', 'no_download=False',
'configParams_source=sample', 'configParams_fallback_reason=GAP: transport/timeout'):
self.assertIn(value, report)
def test_official_sample_exact(self):
scrape = Path('/workspace/modelhub-adapt/logs/api-docs-scrape-2026-10-16.md')
if scrape.is_file():
body = json.loads(re.search(r'```json\n(.*?)\n```', scrape.read_text(), re.S)[1])
self.assertEqual(build_config_params(), body['configParams'])
self.assertIn('max_model_len: 4096', build_config_params())
self.assertIn('framework: vllm', build_config_params())
with patch('src.config_params.resolve_token', side_effect=ValueError):
self.assertEqual(build_config_params(), body['configParams'])
with patch('src.config_params.resolve_token', side_effect=ValueError):
self.assertIn('max_model_len: 4096', build_config_params())
self.assertIn('framework: vllm', build_config_params())
self.assertIn('NOT production-ready', GAP)
def test_report_draft_and_gap(self):
report = _render([{'model_address': 'org/a', 'try_next_gpus': ['壁砺']}], 'test', 'fixture')
for value in ('代提候选 / 需 Victor 确认', 'configParams source', 'configParams_source=sample', 'GAP:', 'truncated', 'max_model_len: 4096', 'perf_order=unset', 'order_source=experience'):
with patch('src.config_params.resolve_token', side_effect=ValueError):
report = _render([{'model_address': 'org/a', 'try_next_gpus': ['壁砺']}], 'test', 'fixture')
for value in ('代提候选 / 需 Victor 确认', 'configParams source', 'configParams_source=sample', 'foothold_class=unknown', 'evidence_source=GAP', 'no_download=False', 'GAP:', 'truncated', 'max_model_len: 4096', 'perf_order=unset', 'order_source=experience'):
self.assertIn(value, report)

View File

@@ -47,3 +47,40 @@ class TestPendingPool(unittest.TestCase):
self.assertEqual(len(rows), 1)
self.assertEqual(rows[0]['try_next_gpus'], ['天垓150'])
self.assertEqual(rows[0]['perf_order'], 'unset')
def test_foothold_evidence_and_stable_verified_priority(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
md = root / 'pending.md'
md.write_text('## Section B\n| 1 | `org/b` | 0 | 壁砺 |\n## Section A\n| 1 | `org/unknown` | 曦望 | 壁砺 | 已验证成功 |\n| 2 | `org/flight` | 验证失败; 正在验证 | 壁砺 | — |\n| 3 | `org/verified` | 他人:已验证成功; 正在验证 | 壁砺 | — |\n| 4 | `org/fail` | 验证失败 | 曦望 | — |\n| 5 | `org/pass` | 既有:验证通过 | 曦望 | — |\n| 6 | `org/queue` | 验证排队中 | 壁砺 | — |\n| 7 | `org/progress` | 验证进行中 | 壁砺 | — |\n')
rows = build_ordered_candidates(md, dnr_path=root/'none', banned_path=root/'none')
self.assertEqual([r['model_address'] for r in rows],
['org/verified', 'org/pass', 'org/unknown', 'org/flight',
'org/fail', 'org/queue', 'org/progress', 'org/b'])
self.assertEqual([r['foothold_class'] for r in rows],
['verified_reuse', 'verified_reuse', 'unknown', 'in_flight',
'failed_foothold', 'in_flight', 'in_flight', 'unknown'])
for row in rows:
self.assertEqual(row['evidence_source'], 'GAP' if row['foothold_class'] == 'unknown' else 'pending-foothold')
self.assertEqual(rows[0]['foothold_text'], '他人:已验证成功; 正在验证')
txt = root / 'pending.txt'
txt.write_text('org/a\t#A done:曦望; try:壁砺\norg/v\t#A 验证通过; try:壁砺\n')
parsed = parse_pending_txt(txt)
self.assertEqual(parsed[0]['foothold_class'], 'unknown')
self.assertEqual(parsed[0]['evidence_source'], 'GAP')
self.assertEqual(parsed[1]['foothold_class'], 'verified_reuse')
def test_no_download_marker_without_inventing(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
md = root / 'pending.md'
md.write_text('## Section A\n| 1 | `org/plain` | 曦望:验证排队中 | 壁砺 | — |\n| 2 | `org/cached` | 壁砺:已下载; 曦望:免下载 | 天垓150 | — |\n| 3 | `org/verified` | 壁砺:已验证成功 | 天垓150 | — |\n')
rows = build_ordered_candidates(md, dnr_path=root/'none', banned_path=root/'none')
by = {r['model_address']: r for r in rows}
self.assertFalse(by['org/plain']['no_download'])
self.assertEqual(by['org/plain']['evidence_source'], 'pending-foothold')
self.assertTrue(by['org/cached']['no_download'])
self.assertEqual(by['org/cached']['evidence_source'], 'pending-foothold')
self.assertFalse(by['org/verified']['no_download']) # verified alone does not invent no_download
self.assertEqual([r['model_address'] for r in rows],
['org/cached', 'org/verified', 'org/plain'])