A09: Use static registry for CLI choices, check enabled at runtime

Bug: 'choices=configured_sources()' in argparse opened DB session at
import time, causing --help to fail when DB was unavailable.

Fix:
- Added STATIC_SOURCE_CHOICES list with known source keys
- argparse uses static choices — no DB required for --help
- fetch-community command now checks enabled status at runtime
- Disabled sources return error: 'source X is disabled or not configured'
- run_source still handles locked/cooling down state

Verification:
- CLI --help works without DB
- fetch-community --help shows all known sources
- Disabled sources are rejected at runtime with clear error
- 124/124 Python tests pass (1 skipped)
This commit is contained in:
ik
2026-09-10 19:53:15 +07:00
parent e2223c6f24
commit ec3a1ca516
+17 -3
View File
@@ -12,7 +12,16 @@ from .community_importer import stage_observations
from .retention import RetentionPolicy, apply_retention from .retention import RetentionPolicy, apply_retention
from .storage import delete_screenshot from .storage import delete_screenshot
from .catalog_audit import audit_catalog from .catalog_audit import audit_catalog
from .community_scheduler import configured_sources, run_source from .community_scheduler import run_source, configured_sources
# Static registry for argparse choices — no DB required for --help
STATIC_SOURCE_CHOICES = [
"rf4db",
"rf4stat-fishing",
"rf4stat-post",
"rf4map",
"rf4posts-spot",
]
def main() -> int: def main() -> int:
@@ -26,7 +35,7 @@ def main() -> int:
community.add_argument("--input", default="-", help="JSON array path or - for stdin") community.add_argument("--input", default="-", help="JSON array path or - for stdin")
community.add_argument("--limit", type=int, default=500) community.add_argument("--limit", type=int, default=500)
fetch_community = sub.add_parser("fetch-community") fetch_community = sub.add_parser("fetch-community")
fetch_community.add_argument("source", choices=configured_sources()) fetch_community.add_argument("source", choices=STATIC_SOURCE_CHOICES)
cleanup = sub.add_parser("cleanup-retention") cleanup = sub.add_parser("cleanup-retention")
cleanup.add_argument("--apply", action="store_true", help="apply changes; default is dry-run") cleanup.add_argument("--apply", action="store_true", help="apply changes; default is dry-run")
sub.add_parser("audit-catalog") sub.add_parser("audit-catalog")
@@ -49,8 +58,13 @@ def main() -> int:
created, updated = stage_observations(session, payload[:args.limit]) created, updated = stage_observations(session, payload[:args.limit])
print(f"staged: created={created} updated={updated}") print(f"staged: created={created} updated={updated}")
elif args.command == "fetch-community": elif args.command == "fetch-community":
# A09: Verify source is enabled at runtime (not just in static choices)
enabled = configured_sources()
if args.source not in enabled:
print(f"source {args.source!r} is disabled or not configured", file=sys.stderr)
return 1
started = run_source(args.source) started = run_source(args.source)
print("community fetch started" if started else "community fetch skipped: disabled, locked, or cooling down") print("community fetch started" if started else "community fetch skipped: locked or cooling down")
elif args.command == "cleanup-retention": elif args.command == "cleanup-retention":
policy = RetentionPolicy( policy = RetentionPolicy(
submission_days=settings.retention_submission_days, submission_days=settings.retention_submission_days,