Skip to content
Merged
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
11 changes: 3 additions & 8 deletions apps/api/routers/search/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,14 +525,9 @@ async def leaderboard_x402(request: Request, limit: int = 20, db=Depends(get_db)
service_id = '0x' + svc['service_id']
svc['service_id'] = service_id

score = 50.0
tier = svc.get('coverage_tier', 0)
if tier >= 2: score += 20
elif tier >= 1: score += 5
if svc.get('consecutive_failures', 1) == 0: score += 10
if svc.get('payment_protocol') == 'x402': score += 5
if svc.get('payment_count', 0) > 0: score += min(svc['payment_count'] * 2, 8)
svc['wri'] = round(min(score, 100), 1)
# Interim placeholder; authoritative scoring is the private rank service
# (RANK_SERVICE_URL). No signal weights live in this public container.
svc['wri'] = round(float(svc.get('wri_score') or 50.0), 1)

price = svc.get('pricing_usdc')
svc['price_display'] = f"${price:.7f}/req".rstrip('0').rstrip('.') + '/req' if price and price > 0 else "Free"
Expand Down
1 change: 0 additions & 1 deletion apps/api/scripts/deps_live_proof.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#3 base deps build → snapshot → boot a run sandbox (gateway-only egress) with
httpx + wayforth-sdk importable and PyPI unreachable (unblocks Step 2).
§0 two-allowlist separation: build can't reach the gateway; run can't reach the mirror.
TODO(canary): a wheel that POSTs to an external host → blocked at run egress.
"""
from __future__ import annotations

Expand Down
4 changes: 2 additions & 2 deletions apps/crawler/backfill_scores.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ async def backfill():
""")

sys.path.insert(0, os.path.dirname(__file__))
from health_monitor import compute_wri_simple
from health_monitor import _interim_score

inserted = 0
for svc in services:
wri = compute_wri_simple(dict(svc))
wri = _interim_score(dict(svc))
for hours_ago in [18, 12, 6]:
await db.execute("""
INSERT INTO service_score_history
Expand Down
10 changes: 3 additions & 7 deletions apps/crawler/backfill_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ async def fix():
inserted = 0
for svc in services:
hex_id = "0x" + hashlib.sha256(svc['endpoint_url'].encode()).hexdigest()
score = 50.0
tier = svc['coverage_tier']
if tier >= 2: score += 20
elif tier >= 1: score += 5
if (svc.get('consecutive_failures') or 1) == 0: score += 10
if svc.get('payment_protocol') == 'x402': score += 5
wri = round(min(score, 100), 1)
# Interim placeholder; authoritative scoring is the private rank service
# (RANK_SERVICE_URL), recalculated via promoter.run_rank_recalculate.
wri = 50.0
for h in [18, 12, 6]:
await db.execute("""
INSERT INTO service_score_history
Expand Down
10 changes: 3 additions & 7 deletions apps/crawler/backfill_v7.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@ async def backfill():
inserted = 0
for svc in services:
hex_id = "0x" + hashlib.sha256(svc['endpoint_url'].encode()).hexdigest()
score = 50.0
tier = svc['coverage_tier']
if tier >= 2: score += 20
elif tier >= 1: score += 5
if svc.get('consecutive_failures', 1) == 0: score += 20
if svc.get('payment_protocol') == 'x402': score += 5
wri = round(min(score, 100), 1)
# Interim placeholder; authoritative scoring is the private rank service
# (RANK_SERVICE_URL), recalculated via promoter.run_rank_recalculate.
wri = 50.0
for hours_ago in [18, 12, 6]:
await db.execute("""
INSERT INTO service_score_history
Expand Down
10 changes: 3 additions & 7 deletions apps/crawler/fix_backfill.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@ async def fix():
inserted = 0
for svc in services:
hex_id = "0x" + hashlib.sha256(svc['endpoint_url'].encode()).hexdigest()
score = 50.0
tier = svc['coverage_tier']
if tier >= 2: score += 20
elif tier >= 1: score += 5
if svc.get('consecutive_failures', 1) == 0: score += 20
if svc.get('payment_protocol') == 'x402': score += 5
wri = round(min(score, 100), 1)
# Interim placeholder; authoritative scoring is the private rank service
# (RANK_SERVICE_URL), recalculated via promoter.run_rank_recalculate.
wri = 50.0
for hours_ago in [18, 12, 6]:
await db.execute("""
INSERT INTO service_score_history
Expand Down
22 changes: 7 additions & 15 deletions apps/crawler/health_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,10 @@ async def probe_service(client: httpx.AsyncClient, service: dict) -> bool:
return False


def compute_wri_simple(svc: dict) -> float:
score = 50.0
tier = svc.get("coverage_tier", 0)
if tier >= 2:
score += 20
elif tier >= 1:
score += 5
if svc.get("consecutive_failures", 1) == 0:
score += 20
if svc.get("payment_protocol") == "x402":
score += 5
return round(min(score, 100), 1)
def _interim_score(svc: dict) -> float:
"""Interim placeholder written during health probes; the authoritative composite
score is computed by the private rank service (RANK_SERVICE_URL)."""
return 50.0


async def fire_tier_promotion_email(db, service_id: str, service_name: str, new_tier: int) -> None:
Expand Down Expand Up @@ -136,7 +128,7 @@ async def run_health_check(pool=None) -> None:
INSERT INTO service_score_history
(service_id, wri_score, tier, consecutive_failures, recorded_at)
VALUES ($1, $2, $3, $4, NOW())
""", str(svc["id"]), compute_wri_simple(snapshot), svc["coverage_tier"], 0)
""", str(svc["id"]), _interim_score(snapshot), svc["coverage_tier"], 0)
logger.info(f"✅ {svc['name']} — UP")
else:
failures = (svc["consecutive_failures"] or 0) + 1
Expand All @@ -159,7 +151,7 @@ async def run_health_check(pool=None) -> None:
INSERT INTO service_score_history
(service_id, wri_score, tier, consecutive_failures, recorded_at)
VALUES ($1, $2, $3, $4, NOW())
""", str(svc["id"]), compute_wri_simple(snapshot), 1, failures)
""", str(svc["id"]), _interim_score(snapshot), 1, failures)
await fire_tier_change_webhook(pool, str(svc["id"]), 2, 1, svc["name"])
logger.warning(f"⬇️ {svc['name']} — DEMOTED to Tier 1 after {failures} failures")
else:
Expand All @@ -178,7 +170,7 @@ async def run_health_check(pool=None) -> None:
INSERT INTO service_score_history
(service_id, wri_score, tier, consecutive_failures, recorded_at)
VALUES ($1, $2, $3, $4, NOW())
""", str(svc["id"]), compute_wri_simple(snapshot), svc["coverage_tier"], failures)
""", str(svc["id"]), _interim_score(snapshot), svc["coverage_tier"], failures)
logger.warning(f"⚠️ {svc['name']} — DOWN ({failures}/{CONSECUTIVE_FAILURE_THRESHOLD} failures)")

logger.info("Health check complete")
Expand Down
17 changes: 8 additions & 9 deletions apps/crawler/promoter.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,15 +244,14 @@ async def bulk_demote_stale_tier2(db_conn: asyncpg.Connection) -> int:
return count


async def run_wri_recalculate() -> None:
"""Trigger WRI score recalculation via the wayforth-rank private service.
async def run_rank_recalculate() -> None:
"""Trigger score recalculation via the private rank service.

No-ops if RANK_SERVICE_URL or RANK_SERVICE_KEY is not configured.
The v2 formula lives in wayforth-rank; this call keeps formula weights
out of the public crawler code.
Scoring is computed by the private rank service; no weights live here.
"""
if not RANK_SERVICE_URL or not RANK_SERVICE_KEY:
logger.info("run_wri_recalculate: RANK_SERVICE_URL/KEY not set, skipping")
logger.info("run_rank_recalculate: RANK_SERVICE_URL/KEY not set, skipping")
return
try:
async with httpx.AsyncClient(timeout=120.0) as client:
Expand All @@ -262,10 +261,10 @@ async def run_wri_recalculate() -> None:
)
r.raise_for_status()
data = r.json()
logger.info("run_wri_recalculate: updated=%d unmatched=%d",
logger.info("run_rank_recalculate: updated=%d unmatched=%d",
data.get("updated", 0), len(data.get("unmatched_slugs", [])))
except Exception as exc:
logger.error("run_wri_recalculate failed: %s", exc)
logger.error("run_rank_recalculate failed: %s", exc)


# Representative search→execute pairs for daily signal seeding.
Expand All @@ -285,7 +284,7 @@ async def run_wri_recalculate() -> None:


async def run_signal_feed(api_key: str, base_url: str) -> None:
"""Feed searchexecute pairs to generate WayforthRank signal data.
"""Feed search-execute pairs to generate ranking signal data.

Runs daily at 06:00 UTC only (gated in run_promotion_cycle).
Requires WAYFORTH_TEST_API_KEY and WAYFORTH_BASE_URL in the crawler service env.
Expand Down Expand Up @@ -409,7 +408,7 @@ async def _do_tier1(svc: dict) -> bool:
)

await run_health_check(pool)
await run_wri_recalculate()
await run_rank_recalculate()
await build_service_graph(pool)
logger.info("Service graph updated")
await run_x402_monitor(pool)
Expand Down
Loading