refactor(imports): target facade implementations directly

This commit is contained in:
SToneX
2026-08-30 23:12:41 +08:00
parent 7ed4f28c5c
commit 237408850e
58 changed files with 159 additions and 112 deletions
+3 -3
View File
@@ -47,9 +47,9 @@ CATALOG = ROOT / "src" / "treg" / "catalog"
sys.path.insert(0, str(ROOT / "src"))
# The enums the SERVER reads the same files with. Imported, never re-typed: a validator that
# accepts a unit `cost_view` cannot price is worse than no validator.
from treg.catalog_store import COST_SOURCES as _SOURCES # noqa: E402
from treg.catalog_store import COST_UNITS as _UNITS # noqa: E402
from treg.catalog_store import CONFIDENCES as _CONFIDENCES # noqa: E402
from treg.domain.catalog.store import COST_SOURCES as _SOURCES # noqa: E402
from treg.domain.catalog.store import COST_UNITS as _UNITS # noqa: E402
from treg.domain.catalog.store import CONFIDENCES as _CONFIDENCES # noqa: E402
SCOPES = {"any_account", "own_account"}
METHODS = {"GET", "POST", "PUT", "PATCH", "DELETE"}
+2 -1
View File
@@ -20,7 +20,8 @@ sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
from sqlalchemy.exc import OperationalError # noqa: E402
from treg import ledger, reconcile # noqa: E402
from treg import reconcile # noqa: E402
from treg.domain import money as ledger # noqa: E402
from treg.config import get_settings # noqa: E402
from treg.infra.db import session_maker # noqa: E402
from treg.domain.capacity.collectors import ( # noqa: E402,F401 — re-exported for older callers
+1 -1
View File
@@ -24,7 +24,7 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
from treg import catalog_store as cs # noqa: E402
from treg.domain.catalog import store as cs # noqa: E402
# ---- the frozen pre-change engine (every token must match; score = sum of field weights) --------
+2 -1
View File
@@ -26,9 +26,10 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import defer
from sqlmodel import select
from . import audit, catalog_store, crypto, localrun, ratestore, runner, sandbox as demo_sandbox
from . import audit, crypto, localrun, ratestore, runner, sandbox as demo_sandbox
from .caller_metadata import _client_of
from .config import get_settings
from .domain.catalog import store as catalog_store
from .infra.db import get_session, session_maker
from .domain.governance.teams import _unique_slug
from .domain.identity.access import (
+2 -1
View File
@@ -14,7 +14,8 @@ from sqlalchemy import func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import audit, crypto, demo as demo_seed, email as email_sender, ratestore
from .. import audit, crypto, email as email_sender, ratestore
from ..application.onboard import demo as demo_seed
from ..infra import db as database
from ..config import get_settings
from ..domain.identity import session as sess
+3 -3
View File
@@ -45,8 +45,8 @@ from .. import adsconv
from .. import analytics
from ..infra import db as _db
from .. import email as email_mod
from .. import ledger
from .. import referrals
from ..domain import money as ledger
from ..domain import referrals
from ..config import get_settings
from ..infra import stripe as stripe_adapter
from ..models import CreditBlock, LedgerEntry, Membership, Org, User
@@ -55,7 +55,7 @@ from ..models import CreditBlock, LedgerEntry, Membership, Org, User
# _run_autotopup retains its relative local import; removing the alias breaks task-owned sessions.
sys.modules.setdefault("treg.application.db", _db)
log = logging.getLogger("treg.billing")
log = logging.getLogger("treg.application.billing")
MICRO_PER_CENT = 10_000
MICRO_PER_USD = 1_000_000
+7 -5
View File
@@ -7,13 +7,15 @@ from sqlalchemy import func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from ... import billing, catalog_store, ledger
from ...application import billing
from ...caller_metadata import TAG_DEFAULT
from ...config import get_settings
from ...infra.db import session_maker
from ...domain import money as ledger
from ...domain.catalog import store as catalog_store
from ...domain.governance import budgets as budget_policy
from ...domain.governance.usage import _day_start_utc
from ...domain.identity.access import Caller
from ...infra.db import session_maker
from ...models import CallRecord, Org, TagBudget
from .intake import CallMeta, _NO_META
from .resolve import MarketplaceCall
@@ -48,7 +50,7 @@ async def _enforce_trial_allowance(caller: Caller, provider: str, db: AsyncSessi
CallRecord.status_code >= 200, CallRecord.status_code < 300,
CallRecord.created_at >= day_start))).scalar_one()
except Exception as exc: # noqa: BLE001 — cannot verify the pool ⇒ do not drain it
logging.getLogger("treg.ledger").warning(
logging.getLogger("treg.domain.money").warning(
"trial-allowance check failed for org %s / %s: %s", caller.org_id, provider, exc)
raise ReservationFailed("trial_allowance_unavailable", status_code=429, detail=(
f"cannot verify today's {provider} trial usage right now — retry shortly, or use "
@@ -73,7 +75,7 @@ async def _enforce_platform_daily_cap(caller: Caller, add_micro: int, db: AsyncS
try:
spent = await ledger.spent_today(db, caller.org_id)
except Exception as exc: # noqa: BLE001 — cannot verify the ceiling ⇒ do not spend
logging.getLogger("treg.ledger").warning(
logging.getLogger("treg.domain.money").warning(
"platform daily-cap check failed for org %s: %s", caller.org_id, exc)
raise ReservationFailed("platform_cap_unavailable", status_code=429, detail=(
"cannot verify today's platform spend right now — refusing to spend the team balance "
@@ -152,7 +154,7 @@ async def _enforce_tag_budgets(caller: Caller, meta: CallMeta, db: AsyncSession,
raise ReservationFailed(
kind, status_code=exc.status_code, detail=exc.detail) from exc
except Exception as exc: # noqa: BLE001 — cannot verify a ceiling ⇒ do not spend
logging.getLogger("treg.ledger").warning(
logging.getLogger("treg.domain.money").warning(
"tag budget check failed for org %s (%s=%s): %s", caller.org_id, dim, val, exc)
raise ReservationFailed("tag_budget_unavailable", status_code=429, detail={
"error": "tag_budget_unavailable", "dim": dim, "val": val,
+3 -2
View File
@@ -12,14 +12,15 @@ from urllib.parse import quote, urlsplit
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from ... import catalog_store, oauth_providers
from ... import oauth_providers
from ... import sandbox as demo_sandbox
from ...config import get_settings, platform_setting_name
from ...domain.capacity.routes_view import view as overflow_routes_view
from ...domain.capacity.view import view as capacity_view
from ...infra.db import session_maker
from ...domain.catalog import store as catalog_store
from ...domain.governance import access as access_policy
from ...domain.identity.access import Caller
from ...infra.db import session_maker
from ...models import CapabilityPin, Org, Secret, Tool
from ..connect import _host_of, _provider_bindings
from .types import ResolutionFailed, ResolvedTarget
+2 -1
View File
@@ -11,10 +11,11 @@ from urllib.parse import parse_qsl, urlencode, urlsplit
import httpx
from ... import analytics, archive, audit, catalog_store, oauth
from ... import analytics, archive, audit, oauth
from ... import sandbox as demo_sandbox
from ...client_identity import _norm_client
from ...config import get_settings
from ...domain.catalog import store as catalog_store
from ...infra.db import session_maker
from ...models import Secret
from ...sandbox_identity import visitor_name
+6 -4
View File
@@ -10,10 +10,12 @@ from collections.abc import Callable
from sqlalchemy import update
from sqlalchemy.exc import TimeoutError as PoolTimeoutError
from ... import adsconv, catalog_store, ledger
from ... import adsconv
from ...domain.capacity import marks as capacity_marks
from ...domain.capacity import overflow_spend as overflow_spend_ledger
from ...domain.capacity import signatures as capacity_signatures
from ...domain import money as ledger
from ...domain.catalog import store as catalog_store
from ...infra.db import session_maker
from ...models import Org
from ...timeutil import utcnow_naive as _utcnow_naive
@@ -447,7 +449,7 @@ async def _platform_settle(
await asyncio.sleep(0.5)
charged = await _close()
except Exception as exc: # noqa: BLE001 — loudly, but never into the caller's response
logging.getLogger("treg.ledger").error(
logging.getLogger("treg.domain.money").error(
"settle/release failed for call %s (%s, status %s): %s",
call_id, mk.endpoint_id, status_code, exc, exc_info=True)
return charged, observed
@@ -469,7 +471,7 @@ async def _finish_cancelled_call(
try:
await response.close()
except (Exception, asyncio.CancelledError): # noqa: BLE001
logging.getLogger("treg.proxy").error(
logging.getLogger("treg.infra.upstream.relay").error(
"upstream close failed for cancelled call %s", call_ref, exc_info=True)
if mk is not None and mk.metered:
# `ledger.reserve` may have committed without returning, so `mk.call_id` is not an
@@ -491,7 +493,7 @@ async def _finish_cancelled_call(
)
await cleanup_db.commit()
except (Exception, asyncio.CancelledError): # noqa: BLE001
logging.getLogger("treg.ledger").error(
logging.getLogger("treg.domain.money").error(
"cancellation release failed for call %s", call_ref, exc_info=True)
try:
await _release_idempotent_claim(claim)
+2 -1
View File
@@ -12,8 +12,9 @@ from sqlalchemy import or_
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import catalog_store, crypto, health, oauth, oauth_providers
from .. import crypto, health, oauth, oauth_providers
from ..config import get_settings
from ..domain.catalog import store as catalog_store
from ..infra.db import session_maker
from ..models import PendingOAuth, Secret, Tool
from ..timeutil import as_naive as _as_naive
+4 -2
View File
@@ -8,10 +8,12 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import adsconv, health, ledger, referrals, sandbox as demo_sandbox
from ..infra.db import session_maker
from .. import adsconv, health, sandbox as demo_sandbox
from ..domain import money as ledger
from ..domain import referrals
from ..domain.governance.teams import _make_org_membership, _slugify
from ..domain.identity.access import _is_machine_email, _norm_email
from ..infra.db import session_maker
from ..models import Org, User
from ..timeutil import utcnow_naive as _utcnow_naive
+3 -3
View File
@@ -270,7 +270,7 @@ async def _store(
from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from . import catalog_store
from .domain.catalog import store as catalog_store
from .infra.db import session_maker
from .models import ArchiveKey, ArchiveSnapshot
@@ -429,7 +429,7 @@ async def lookup(
return None
from sqlalchemy import select
from . import catalog_store
from .domain.catalog import store as catalog_store
from .infra.db import session_maker
from .models import ArchiveKey, ArchiveSnapshot
@@ -639,7 +639,7 @@ async def refresh_once(client) -> int:
return 0
from sqlalchemy import func, select
from . import catalog_store
from .domain.catalog import store as catalog_store
from .infra.db import session_maker
from .models import ArchiveKey, ArchiveSnapshot
+1 -1
View File
@@ -49,7 +49,7 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import ledger
from . import money as ledger
from ..config import get_settings
from ..models import CreditBlock, Membership, Org, Referral, User
+2 -1
View File
@@ -15,7 +15,8 @@ import httpx
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from . import crypto, injectors, oauth
from . import crypto, oauth
from .infra.upstream import injectors
from .infra.upstream.ssrf import host_is_public, safe_webhook_url
from .models import Invite, Membership, PendingOAuth, Secret, Tool, User
from .timeutil import utcnow_naive
+1 -1
View File
@@ -53,7 +53,7 @@ class PostgresEndpointObservationReader:
ids = list(dict.fromkeys(endpoint_ids))
if not ids:
return {}
from .. import catalog_store # the per-success set is a catalog fact, read at query time
from ..domain.catalog import store as catalog_store # the per-success set is a catalog fact, read at query time
cat = catalog_store.load()
per_success = {i for i in ids if ((cat.by_id.get(i) or {}).get("cost") or {}).get("type") == "per_success"}
async with self._session_factory() as db:
+1 -1
View File
@@ -21,7 +21,7 @@ from datetime import datetime, timezone
from typing import TYPE_CHECKING
from .injectors import _token_from_json # light: pure JSON/token helpers, no DB
from .infra.upstream.injectors import _token_from_json # light: pure JSON/token helpers, no DB
# The DB/crypto/oauth deps are used at runtime ONLY in `render_grant` (the server-side grant path — the
# CLI client never calls it). Keeping them out of the module's top-level imports lets the CLI install
+3 -2
View File
@@ -51,7 +51,8 @@ from mcp.server.transport_security import TransportSecuritySettings
from mcp.shared.exceptions import MCPError
from mcp.types import METHOD_NOT_FOUND, ToolAnnotations
from . import audit, catalog_store
from . import audit
from .domain.catalog import store as catalog_store
from .config import PUBLIC_HOST_ALIASES, get_settings
from .domain.catalog.stats import EndpointObservationReader
@@ -1368,7 +1369,7 @@ class RequireAuthForProtectedTools:
return None # a live access token, or a per-org token the tool validates itself
async def _challenge(self, send, *, invalid: bool = False) -> None:
from . import mcp_oauth
from .domain.identity import mcp_oauth
base = get_settings().public_url.rstrip("/")
suffix = "/mcp/v2" if self.resource_version == "v2" else ""
+1 -1
View File
@@ -305,6 +305,6 @@ async def shared_plan_recovery(db: AsyncSession, since: datetime) -> dict:
def _catalog():
"""Deferred so reconcile stays importable without the catalog package in odd contexts, and so
tests can monkeypatch the module in one obvious place."""
from . import catalog_store
from .domain.catalog import store as catalog_store
return catalog_store
+3 -2
View File
@@ -4,10 +4,11 @@ from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from .. import billing, ledger
from ..application import billing
from ..config import get_settings
from ..infra.db import get_session
from ..domain import money as ledger
from ..domain.identity.access import Caller, _role_at_least, require_member
from ..infra.db import get_session
from ..models import Org
from .auth_helpers import _is_https
from .orgs import _require_admin_of
+4 -2
View File
@@ -9,7 +9,7 @@ from fastapi.responses import Response, StreamingResponse
from starlette.background import BackgroundTask
from sqlalchemy.ext.asyncio import AsyncSession
from .. import audit, catalog_store, ledger, oauth_providers
from .. import audit, oauth_providers
from .. import sandbox as demo_sandbox
from ..application.call.idempotency import (
_release_idempotent_claim as release_idempotent_claim,
@@ -33,10 +33,12 @@ from ..application.call.intake import (
from ..application.call.types import CallerSnapshot, CallFailure, CallInput, UpstreamResponse
from ..caller_metadata import _client_of
from ..config import get_settings
from ..infra.db import get_session
from ..domain import money as ledger
from ..domain.catalog import store as catalog_store
from ..domain.governance import access as access_policy
from ..domain.governance import publicdemo as publicdemo_policy
from ..domain.identity.access import Caller, require_member
from ..infra.db import get_session
from ..models import Tool
from .auth import _client_ip
from .orgs import count_today
+2 -1
View File
@@ -8,8 +8,9 @@ import logging
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import Response
from .. import audit, catalog_store, oauth_providers
from .. import audit, oauth_providers
from ..config import get_settings
from ..domain.catalog import store as catalog_store
from ..domain.catalog import stats as endpoint_stats
+4 -2
View File
@@ -12,12 +12,13 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import crypto, demo as demo_seed, email as email_sender, health, ledger, localrun
from .. import crypto, email as email_sender, health, localrun
from .. import providers as _providers
from ..application.onboard import demo as demo_seed
from ..application import signup as signup_use_cases
from ..caller_metadata import TAG_DEFAULT, _MAX_BUDGET_DIMS, _META_KEY_RE, _client_of, _norm_client
from ..config import get_settings
from ..infra.db import get_session
from ..domain import money as ledger
from ..domain.governance import budgets as budget_policy
from ..domain.governance import access as access_policy
from ..domain.governance import usage as usage_policy
@@ -41,6 +42,7 @@ from ..domain.identity.access import (
require_identity,
require_member,
)
from ..infra.db import get_session
from ..models import (
ROLE_RANK,
AdConversion,
+2 -1
View File
@@ -15,7 +15,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import convert as _convert
from .. import crypto, health, injectors, sandbox as demo_sandbox
from .. import crypto, health, sandbox as demo_sandbox
from ..infra import db as _db
from .. import providers as _providers
from .. import skills as _skills
@@ -33,6 +33,7 @@ from ..domain.identity.access import (
_role_at_least,
require_member,
)
from ..infra.upstream import injectors
from ..models import Bundle, Secret, Tool
from .orgs import _resolve_project
+1 -1
View File
@@ -2,7 +2,7 @@
from fastapi import Request
from .. import referrals
from ..domain import referrals
from .auth_helpers import _is_https
+3 -1
View File
@@ -17,7 +17,9 @@ from fastapi.responses import (FileResponse, HTMLResponse, JSONResponse, PlainTe
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from .. import adsconv, agent_pages, catalog_store, oauth_providers, referrals
from .. import adsconv, agent_pages, oauth_providers
from ..domain import referrals
from ..domain.catalog import store as catalog_store
from ..domain.identity import session as sess
from ..config import PUBLIC_HOST_ALIASES, get_settings
from ..infra.db import get_session
+2 -1
View File
@@ -22,7 +22,8 @@ from __future__ import annotations
import json
import re
from . import crypto, injectors
from . import crypto
from .infra.upstream import injectors
from .models import Org, Secret, Tool
from .sandbox_identity import visitor_name
+1 -1
View File
@@ -11,7 +11,7 @@ from httpx import AsyncClient
from treg import audit
from treg.config import get_settings
from treg.ledger import with_margin
from treg.domain.money import with_margin
from test_marketplace_call import EP, EP_DFS, EP_MICRO
+3 -2
View File
@@ -12,9 +12,10 @@ from sqlalchemy.exc import TimeoutError as PoolTimeoutError
from treg.application.call import service as call_service
from treg.routers import call as call_routes
from treg import audit, ledger
from treg import audit
from treg.domain import money as ledger
from treg.infra.db import session_maker
from treg.ledger import with_margin
from treg.domain.money import with_margin
from treg.models import CallRecord
from test_marketplace_call import (
+2 -1
View File
@@ -15,7 +15,8 @@ import re
import pytest
from httpx import ASGITransport, AsyncClient
from treg import agent_pages, catalog_store
from treg import agent_pages
from treg.domain.catalog import store as catalog_store
from treg.api import app
from treg.config import get_settings
+1 -1
View File
@@ -178,7 +178,7 @@ async def test_key_hash_is_unique(clients):
from httpx import AsyncClient
from sqlalchemy import select
from treg import catalog_store
from treg.domain.catalog import store as catalog_store
from treg.config import get_settings
from treg.infra.db import session_maker
+2 -1
View File
@@ -11,7 +11,8 @@ from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from sqlmodel import select
from treg import crypto, session as sess
from treg import crypto
from treg.domain.identity import session as sess
from treg.api import app
from treg.config import get_settings
from treg.infra.db import reset_db, session_maker
+3 -1
View File
@@ -27,7 +27,9 @@ from sqlmodel import select
from conftest import make_upstream
from treg import adsconv, billing, ledger
from treg import adsconv
from treg.application import billing
from treg.domain import money as ledger
from treg.api import app
from treg.config import get_settings
from treg.infra.db import reset_db, session_maker
+2 -1
View File
@@ -15,7 +15,8 @@ from fastapi import FastAPI, Request
from httpx import ASGITransport, AsyncClient
from sqlmodel import select
from treg import audit, crypto, oauth, session as sess
from treg import audit, crypto, oauth
from treg.domain.identity import session as sess
from treg.api import app
from treg.config import get_settings
from treg.infra.db import reset_db, session_maker
+1 -1
View File
@@ -15,7 +15,7 @@ from httpx import AsyncClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from treg import ledger
from treg.domain import money as ledger
from treg.application.call import service as call_service
from treg.application.call.types import GatewayFailed
from treg.routers import call as call_routes
+1 -1
View File
@@ -7,7 +7,7 @@ import asyncio
from httpx import AsyncClient
from sqlalchemy import select
from treg import ledger
from treg.domain import money as ledger
from treg.application.call import settle as call_settle
from treg.application.call.resolve import MarketplaceCall
from treg.infra.db import session_maker
+2 -1
View File
@@ -29,7 +29,8 @@ from treg import api as A
from treg.domain.catalog import stats as catalog_stats
from treg.application.call import service as call_service
from treg.routers import call as call_routes
from treg import audit, ledger
from treg import audit
from treg.domain import money as ledger
from treg.config import get_settings
from treg.infra.db import _engine, session_maker
from treg.infra.upstream.relay import relay as upstream_relay
+1 -1
View File
@@ -326,7 +326,7 @@ async def test_shadow_mode_probes_records_spend_and_returns_the_vendor_error(cli
async def test_cancellation_cleanup_releases_both_holds_exactly_once(clients: AsyncClient, overflow_on):
from treg import ledger
from treg.domain import money as ledger
from treg.application.call.settle import _finish_cancelled_call
from treg.application.call.resolve import MarketplaceCall
from treg.models import Tool
+6 -6
View File
@@ -14,7 +14,7 @@ import re
from httpx import AsyncClient
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
from treg import oauth_providers as P
@@ -726,7 +726,7 @@ def test_a_free_route_needs_no_price_provenance():
number, so demanding provenance refused 61 endpoints across 8 providers — 28 of Hunter's 35 —
treating "costs nothing" as if it meant "we don't know", which is the one distinction the cost
model is otherwise careful to keep apart."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
free = {"type": "free", "value": 0, "currency": "USD", "unit": "call"}
ep = {"cost": free, "provider": "hunter", "scope": "any_account", "kind": "data"}
@@ -736,7 +736,7 @@ def test_a_free_route_needs_no_price_provenance():
def test_a_PAID_route_still_needs_provenance():
"""The relaxation must not leak: a route with a real price and no provenance stays refused, or
we would bill a team using a number nobody checked."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
unchecked = {"type": "per_call", "value": 0.05, "currency": "USD", "unit": "call"}
ep = {"cost": unchecked, "provider": "hunter", "scope": "any_account", "kind": "data"}
@@ -748,7 +748,7 @@ def test_a_PAID_route_still_needs_provenance():
def test_an_unpriced_route_is_still_refused():
"""The original rule, unchanged: no usd → refuse, so treg never pays a provider and charges $0."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
ep = {"cost": {"type": "per_call", "currency": "credit", "unit": "credit"},
"provider": "pdl", "scope": "any_account", "kind": "data"}
@@ -814,7 +814,7 @@ def test_a_shared_plan_rate_converts_like_any_credit():
"""The whole design: a flat-fee provider is modelled as a credit provider whose credit is one
call on treg's shared plan. cost_view needs ZERO changes — this asserts the pilot entry flows
through the existing conversion."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
c = cs.load()
out = c.cost_view({"type": "per_call", "value": 1, "currency": "credit"}, "alphavantage")
@@ -852,7 +852,7 @@ def test_trial_pools_flow_from_fx_to_eligibility_and_display():
"""The real file's three pools, end to end through the loader: a $0 price that is platform
eligible AND carries its allowance wherever the cost is shown — a bare $0.00 would read as
unlimited."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
c = cs.load()
assert c.trial_pools == {"finnhub": 50, "twelvedata": 20, "tiingo": 20}
+1 -1
View File
@@ -622,7 +622,7 @@ async def test_slack_style_ok_false_is_reported_not_swallowed(clients: AsyncClie
sid = r.json()["id"]
# /auth.test returns ok:false unless the token contains "good"; swap in a bad one to trigger it
async with __import__("treg").db.session_maker() as db:
async with session_maker() as db:
from sqlmodel import select as _select
from treg import crypto as _crypto
+3 -3
View File
@@ -12,7 +12,7 @@ from datetime import datetime, timedelta, timezone
import pytest
from httpx import AsyncClient
from treg import endpoint_stats
from treg.domain.catalog import stats as endpoint_stats
from treg.api import app
from treg.infra.db import session_maker
from treg.infra.catalog_observations import CachedEndpointObservationReader
@@ -255,7 +255,7 @@ async def test_never_worked_is_read_off_DECIDED_samples_only(clients: AsyncClien
""""Never worked" has to mean the provider failed the calls that were ITS to answer. Above the
floor `ok_rate == 0` says exactly that — 4xx is already excluded from the rate — so ranking can
demote a genuinely broken endpoint without a single caller error being able to trigger it."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
for _ in range(6):
await _record(EP, 503) # the provider failing, decisively
assert (await _observed([EP]))[EP]["ok_rate"] == 0.0
@@ -304,7 +304,7 @@ async def test_a_relayed_405_is_the_CATALOGS_failure_not_the_callers(clients: As
async def test_a_405_endpoint_sinks_in_the_ranking(clients: AsyncClient):
"""The payoff for report #4: the row that cannot be called stops being offered first."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
for _ in range(7):
await _record(EP, 405)
stats = {EP: (await _observed([EP]))[EP],
+1 -1
View File
@@ -8,7 +8,7 @@ from __future__ import annotations
import pytest
from treg.injectors import inject
from treg.infra.upstream.injectors import inject
def _b(**kw) -> dict:
+6 -6
View File
@@ -19,7 +19,7 @@ from sqlmodel import select
from conftest import make_upstream
from treg import ledger
from treg.domain import money as ledger
from treg.api import app
from treg.config import get_settings
from treg.infra.db import reset_db, session_maker
@@ -211,7 +211,7 @@ async def test_concurrent_sweeps_pay_a_referral_once(c: AsyncClient):
"""
from datetime import timedelta
from treg import referrals
from treg.domain import referrals
from treg.models import Referral
r = await c.post("/users", json={"email": "referrer@superdesign.dev"})
@@ -259,7 +259,7 @@ async def test_sweep_grants_and_stamps_commit_together(c: AsyncClient, monkeypat
where each grant committed itself, leaves the referee's money durable with no stamp."""
from datetime import timedelta
from treg import referrals
from treg.domain import referrals
from treg.models import Referral
r = await c.post("/users", json={"email": "atomic-ref@superdesign.dev"})
@@ -305,7 +305,7 @@ async def test_referee_instant_grant_failure_after_staging_never_raises(
(MissingGreenlet), which broke the never-raises contract exactly when it mattered."""
import logging as _logging
from treg import referrals
from treg.domain import referrals
from treg.models import Referral
r = await c.post("/users", json={"email": "ref-boom-a@superdesign.dev"})
@@ -348,7 +348,7 @@ async def test_sweep_grant_failure_after_staging_never_raises(c: AsyncClient, mo
import logging as _logging
from datetime import timedelta
from treg import referrals
from treg.domain import referrals
from treg.models import Referral
r = await c.post("/users", json={"email": "sweep-boom-ref@superdesign.dev"})
@@ -392,7 +392,7 @@ async def test_referrals_page_survives_a_sweep_rollback(c: AsyncClient, monkeypa
the user row and `user.id` in the handler would 500 the page it protects."""
import logging as _logging
from treg import referrals
from treg.domain import referrals
from treg.application import referrals as referrals_app
r = await c.post("/users", json={"email": "page-boom@superdesign.dev"})
+1 -1
View File
@@ -7,7 +7,7 @@ from httpx import AsyncClient
from sqlalchemy import delete
from sqlmodel import select
from treg import ledger
from treg.domain import money as ledger
from treg.infra.db import session_maker
from treg.models import Hold, LedgerEntry
+5 -3
View File
@@ -13,7 +13,7 @@ from __future__ import annotations
import pytest
from httpx import ASGITransport, AsyncClient
from treg import session as sess
from treg.domain.identity import session as sess
from treg.api import app
from treg.config import get_settings
@@ -105,7 +105,8 @@ async def test_canonical_host_is_untouched(raw_client):
async def test_legacy_mcp_host_and_oauth_audience_stay_valid():
# The transport allow-list and the token-audience set must both keep honouring the legacy name —
# every pre-move .mcp.json and OAuth grant depends on it.
from treg import mcp, mcp_oauth
from treg import mcp
from treg.domain.identity import mcp_oauth
# List MEMBERSHIP (exact strings), not substring checks — .count() keeps CodeQL from reading
# these as URL-substring sanitization.
@@ -169,7 +170,8 @@ async def test_env_revert_is_a_complete_rollback(monkeypatch):
treg.to is never a redirect SOURCE, so a browser-cached old→new 301 meets no new→old answer."""
from httpx import ASGITransport, AsyncClient
from treg import mcp, mcp_oauth
from treg import mcp
from treg.domain.identity import mcp_oauth
from treg.api import app
from treg.routers.auth import _login_callback_base
+2 -1
View File
@@ -11,7 +11,8 @@ from __future__ import annotations
from httpx import AsyncClient
import treg.api as api_mod
from treg import pubfeed, sandbox
from treg import sandbox
from treg.application.onboard import pubfeed
from treg.domain.governance import publicdemo as publicdemo_policy
ENV_KEY = "rk_test_ENV_ONLY_KEY"
+2 -1
View File
@@ -8,7 +8,8 @@ from __future__ import annotations
import pytest
from httpx import ASGITransport, AsyncClient
from treg import crypto, session as sess
from treg import crypto
from treg.domain.identity import session as sess
from treg.api import app
from treg.config import get_settings
from treg.infra.db import reset_db, session_maker
+8 -6
View File
@@ -22,7 +22,9 @@ from datetime import datetime, timezone
import pytest
from httpx import AsyncClient
from treg import api as A, audit, catalog_store, ledger, oauth_providers
from treg import api as A, audit, oauth_providers
from treg.domain import money as ledger
from treg.domain.catalog import store as catalog_store
from treg.application.call import resolve as call_resolution
from treg.application.call import settle as call_settle
from treg.application.call import service as call_service
@@ -900,7 +902,7 @@ def test_brightdata_documented_prices_are_billable(platform_on):
on our token, so its prices can only ever be `documented` ($1.50/1000 records from the public
pricing page) — and documented is now billable. The provider that motivated the policy must
actually have eligible endpoints, or "enable all" silently enabled nothing."""
from treg import catalog_store
from treg.domain.catalog import store as catalog_store
cat = catalog_store.load()
rows = cat.for_provider("brightdata")
@@ -1219,7 +1221,7 @@ async def test_the_sweep_clears_labels_NOBODY_COMES_BACK_FOR(clients: AsyncClien
drops it. Without a sweep those rows accumulate forever, and they hold response BODIES. Any later
call by the same caller clears them.
Lazy and caller-scoped, matching the hold reaper in ledger.py: a background timer would need a
Lazy and caller-scoped, matching the hold reaper in domain/money: a background timer would need a
scheduler and a leader election on a multi-instance deploy, and would still only run on a timer.
"""
from datetime import timedelta
@@ -1446,7 +1448,7 @@ async def test_another_orgs_usage_never_burns_MY_trial(clients: AsyncClient, tri
# the balance said $0.10, which is the one disagreement a published price must never have.
def _x_endpoints():
from treg import catalog_store
from treg.domain.catalog import store as catalog_store
return [e for e in catalog_store.load().by_id.values() if e.get("provider") == "x"]
@@ -1530,7 +1532,7 @@ async def test_the_rate_card_is_per_resource_type_not_one_read_and_one_write(cli
"""The regression that shipped and was caught in review: every write billed at the post-creation
rate. X prices each action separately, and the catalog has to say so — creating a list is $0.010,
managing one $0.005, and deleting an interaction $0.010, none of them $0.015."""
from treg import catalog_store
from treg.domain.catalog import store as catalog_store
by_id = catalog_store.load().by_id
assert by_id["x.x.create-lists"]["cost"]["value"] == 0.010, "List: Create is $0.010 per request"
assert by_id["x.x.update-lists"]["cost"]["value"] == 0.005, "List: Manage is $0.005 per request"
@@ -1543,7 +1545,7 @@ def test_the_owned_read_discount_is_never_claimed():
"""$0.001 owned reads need the caller to own the developer app. On a registry connect the app is
treg's, so no X entry may quote that rate as a per-CALL own-account price — the way `/2/users/me`
did until 2026-08-18, under-billing the reads treg pays the most for."""
from treg import catalog_store
from treg.domain.catalog import store as catalog_store
me = catalog_store.load().by_id["x.x.user.profile"]
assert me["cost"]["value"] == 0.010 and me["cost"]["type"] == "per_result", (
"/2/users/me is an ordinary User read for a registry connect")
+8 -8
View File
@@ -887,7 +887,7 @@ async def test_an_EXPIRED_access_token_gets_401_invalid_token(clients):
refresh grant. Our first challenge only covered the missing-header case, so an expired token
sailed through to the tool's friendly prose in a 200 — and Claude Code, told nothing, gave up
with "requires re-authorization" instead of refreshing."""
from treg import mcp_oauth
from treg.domain.identity import mcp_oauth
dead = mcp_oauth.make_access_token(user_id=7, org_id=3, audience=mcp_oauth.mcp_resource_url(),
scope="treg:call", ttl=-60) # born expired
async with mcp_session(clients) as c:
@@ -905,7 +905,7 @@ async def test_an_EXPIRED_access_token_gets_401_invalid_token(clients):
async def test_a_wrong_audience_access_token_gets_401_invalid_token(clients):
"""A grant consented to a DIFFERENT resource must not be honoured here — and the refusal should
still be the machine-readable 401, not tool prose."""
from treg import mcp_oauth
from treg.domain.identity import mcp_oauth
other = mcp_oauth.make_access_token(user_id=7, org_id=3,
audience="https://evil.example/mcp/", scope="treg:call")
async with mcp_session(clients) as c:
@@ -1172,7 +1172,7 @@ async def test_catalog_query_arrays_use_the_endpoints_declared_wire_encoding(mon
team tool keeps the longstanding repeated-key default. This goes through `call`, not only
`_query_values`: the first version stayed green if the MCP call site stopped using the helper.
"""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
from treg import mcp as _mcp
cat = cs.load()
@@ -1226,7 +1226,7 @@ async def test_search_survives_missing_a_few_words_of_an_agent_sentence(clients)
endpoints matched 6 of its 7 words — the only miss was "linkedin" on rows shelved under
`companies`, or "open" on the one shelved under `linkedin`. A query may now miss one word in
three, and idf weighting keeps the order on the rare words rather than the filler."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
# the two logged SearchMiss queries, verbatim
rows, total = cs.search("company job postings hiring open jobs linkedin", cat, 8)
@@ -1276,7 +1276,7 @@ async def test_search_breaks_ties_on_what_treg_has_MEASURED(clients):
"""Token scoring ties by the dozen — every "ad library" match scores 6 — so with a default limit
of 8 the rows an agent saw were decided by file order: seven tikhub rows, one of them
uncallable, and the cheapest endpoint with a perfect record cut off below the fold."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
ranked, _, truncated = cs.rank_band("ad library", cat, 8)
assert not truncated, "24 matches sit well inside the band"
@@ -1316,7 +1316,7 @@ async def test_the_tie_band_covers_the_WHOLE_equal_scoring_group(clients, monkey
band therefore keeps taking while the score stays equal — and when a query ties so broadly that
even the ceiling can't hold the group, it SAYS so rather than presenting an unranked tail as a
ranked answer."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
rows, total, truncated = cs.rank_band("ad library", cat, 8)
scores = [s for _, s in rows]
@@ -1351,7 +1351,7 @@ async def test_a_near_miss_never_suggests_a_DIFFERENT_provider(clients):
`hunter.people.email.find` — it is another vendor, another price and another credential, so on a
path that spends money that is provider routing wearing a spellcheck's clothes. treg compares
providers and the caller chooses."""
from treg import catalog_store as cs
from treg.domain.catalog import store as cs
cat = cs.load()
assert cs.near_ids("lusha.companies-signals", cat) == ["lusha.x.companies-signals"]
for crossing in ("apollo.people.email.find", "fake.companies-signals", "hunter.tiktok.video.comments"):
@@ -1391,7 +1391,7 @@ async def test_the_SEARCH_TOOL_itself_ranks_on_evidence_not_just_the_helper(clie
"""The helpers were tested; the wiring was not. `rerank()` could have been dropped from both
call sites and every ranking test would still have passed, because they call the helper
directly. This one goes through the MCP tool with real rows in the database."""
from treg import endpoint_stats
from treg.domain.catalog import stats as endpoint_stats
from treg.infra.db import session_maker
from treg.models import CallRecord
+2 -1
View File
@@ -10,7 +10,8 @@ from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from starlette.routing import Mount
from treg import mcp, mcp_oauth
from treg import mcp
from treg.domain.identity import mcp_oauth
from treg.routers import auth as auth_routes
from treg.bootstrap import create_app
from treg.config import Settings, get_settings
+11 -8
View File
@@ -16,7 +16,8 @@ import time
import pytest
from treg import mcp, mcp_oauth, session
from treg import mcp
from treg.domain.identity import mcp_oauth, session
from treg.routers import auth as auth_routes
from treg.config import Settings, get_settings
@@ -205,7 +206,7 @@ async def test_loopback_http_is_allowed_because_a_CLI_cannot_hold_a_certificate(
async def test_redirect_matching_is_EXACT_not_prefix():
"""The classic defeat of this check. `https://good.test/cb.evil` starts with the registered URI,
and an open redirect under a registered host turns one sloppy page into stolen codes."""
from treg.mcp_oauth import redirect_uri_allowed
from treg.domain.identity.mcp_oauth import redirect_uri_allowed
class C:
redirect_uris = ["https://good.test/cb"]
@@ -222,7 +223,7 @@ async def test_loopback_redirect_allows_ANY_port_but_not_other_drift():
to vary — treg's pure exact-match rejected `http://localhost:3118/callback` against a registered
`http://localhost/callback` and broke every native client. Port varies; scheme, host and path do
NOT, and the loopback exception must not leak to public hosts."""
from treg.mcp_oauth import redirect_uri_allowed
from treg.domain.identity.mcp_oauth import redirect_uri_allowed
class C: # exactly what Claude Code's client-id metadata document registers
redirect_uris = ["http://localhost/callback", "http://127.0.0.1/callback"]
@@ -253,7 +254,7 @@ async def test_loopback_redirect_allows_ANY_port_but_not_other_drift():
async def test_cimd_refuses_unsafe_urls(url):
"""`client_id` is a URL our SERVER fetches, which makes it a request-forgery primitive unless
fenced. Reuses the same guard the webhook and tool base_url paths already use."""
from treg.mcp_oauth import fetch_client_id_metadata
from treg.domain.identity.mcp_oauth import fetch_client_id_metadata
assert await fetch_client_id_metadata(url) is None
@@ -263,7 +264,8 @@ async def test_cimd_document_must_claim_its_own_url(monkeypatch):
the consent users granted them."""
import httpx
from treg import health, mcp_oauth
from treg import health
from treg.domain.identity import mcp_oauth
monkeypatch.setattr(health, "safe_webhook_url", lambda u: True)
monkeypatch.setattr(health, "host_is_public", lambda h: True)
@@ -282,7 +284,8 @@ async def test_cimd_accepts_a_well_formed_document(monkeypatch):
"""Not vacuous: the refusals above only mean something if a good document DOES load."""
import httpx
from treg import health, mcp_oauth
from treg import health
from treg.domain.identity import mcp_oauth
monkeypatch.setattr(health, "safe_webhook_url", lambda u: True)
monkeypatch.setattr(health, "host_is_public", lambda h: True)
@@ -335,7 +338,7 @@ async def _signed_in(clients, email="oauth-user@superdesign.dev"):
clients.headers["X-Treg-Token"] = prev
from sqlmodel import select
from treg import session as _sess
from treg.domain.identity import session as _sess
from treg.infra.db import session_maker
from treg.models import User
@@ -1045,7 +1048,7 @@ async def _as(email: str) -> dict:
"""Headers that act as a given user — an identity token, minted the way `treg login` does."""
from sqlmodel import select
from treg import session as _sess
from treg.domain.identity import session as _sess
from treg.infra.db import session_maker
from treg.models import User
+1 -1
View File
@@ -11,7 +11,7 @@ import pytest
from httpx import AsyncClient
import treg.api as api_mod
from treg import pubfeed
from treg.application.onboard import pubfeed
from treg.application import onboard as onboard_use_cases
SECRET = "whsec_test_secret"
+3 -1
View File
@@ -27,7 +27,9 @@ from sqlmodel import select
from conftest import make_upstream
from treg import billing, ledger, referrals
from treg.application import billing
from treg.domain import money as ledger
from treg.domain import referrals
from treg.api import app
from treg.config import get_settings
from treg.infra.db import reset_db, session_maker
+2 -1
View File
@@ -10,7 +10,8 @@ import pytest
from httpx import AsyncClient
from sqlmodel import select
from treg import audit, ledger
from treg import audit
from treg.domain import money as ledger
from treg.application.call import route as call_route
from treg.application.call import service as call_service
from treg.application.call.types import UpstreamResponse
+2 -1
View File
@@ -10,7 +10,8 @@ import pytest
from httpx import ASGITransport, AsyncClient
from sqlmodel import select
from treg import api, maintenance, session as sess
from treg import api, maintenance
from treg.domain.identity import session as sess
from treg.__main__ import _prepare_serve
from treg.api import LOCAL_ORG_NAME, LOCAL_USER_EMAIL, app
from treg.config import Settings, get_settings
+2 -1
View File
@@ -17,7 +17,8 @@ import pytest
from httpx import AsyncClient
from sqlmodel import select
from treg import audit, crypto, ledger
from treg import audit, crypto
from treg.domain import money as ledger
from treg.application.call import service as call_service
from treg.application.call import settle as call_settle
from treg.application.call.types import UpstreamResponse
+3 -2
View File
@@ -14,7 +14,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from starlette.requests import Request
from treg import audit, crypto, ledger, localproxy
from treg import audit, crypto, localproxy
from treg.domain import money as ledger
from treg.application.call import idempotency as call_idem
from treg.application.call import reserve as call_reserve
from treg.application.call import service as call_service
@@ -247,7 +248,7 @@ async def test_attack_4_concurrent_prechecks_overshoot_is_bounded_not_exact(
# because the balance is a materialized column it can gate on with one conditional UPDATE, while
# a per-tag total is an aggregate with no such column. Tightening it would need a second
# materialized authority on spend (reset daily, decremented on release, corrected on settle
# divergence) — four new ways to disagree with ledger.py, which is the only module allowed to
# divergence) — four new ways to disagree with domain/money, which is the only module allowed to
# move money. The hard gates (org balance, per-org daily cap) sit behind this one.
#
# What must hold: the overshoot is bounded and every committed call is accounted for. Never
+1 -1
View File
@@ -14,7 +14,7 @@ import json
import pytest
from httpx import ASGITransport, AsyncClient
from treg import session as sess
from treg.domain.identity import session as sess
from treg.api import app
from treg.infra.db import reset_db