feat(org): model grants, org memory, MCP gateway (v2 phases A1-3..5)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mjalmoudy94
2026-10-14 15:51:44 +03:30
co-authored by Claude Sonnet 5.5
parent c93b25741e
commit dee2f72c46
39 changed files with 9060 additions and 95 deletions
+32 -4
View File
@@ -6,6 +6,7 @@ import pytest
from sqlalchemy.exc import IntegrityError
import app.application.container as container
import app.application.container_org as container_org
from app.application.ports.delivery_hooks import DeliveryHooks, NullDeliveryHooks
from app.application.ports.deploy_target import (
DeployTargetSpec,
@@ -109,7 +110,16 @@ async def test_app_profile_repository_is_tenant_scoped(session_factory):
@pytest.mark.asyncio
async def test_default_model_grants_return_active_models_with_tiers(session_factory):
async def test_granted_models_carry_tiers_and_need_an_owner_grant(session_factory):
"""The real grant service (Phase 3) replaced the "all active models" stub.
The foundation version asserted the placeholder wiring (every active model
usable by every organization). The behaviour the plan changes on purpose is
exactly that: an organization now sees a model only after the owner granted
it. The assertions below are strictly stronger — they still pin the tier
labels, and additionally pin the two switches (the model must be active
*and* granted) plus the per-organization scope.
"""
async with session_factory() as session:
provider = AiProviderRow(id=new_id(), name="agy-test")
session.add(provider)
@@ -135,10 +145,28 @@ async def test_default_model_grants_return_active_models_with_tiers(session_fact
grants = container.build_model_grants(session)
assert isinstance(grants, ModelGrantPort)
granted = {g.ai_model_id: g.tier for g in await grants.granted_models(organization_id="o")}
org_id, _ = await _org_with_user(session, "granted")
other_id, _ = await _org_with_user(session, "untouched")
# Nothing is usable until the owner grants it.
assert await grants.granted_models(organization_id=org_id) == []
assert not await grants.is_granted(organization_id=org_id, ai_model_id="m-fast")
# ``container.py`` is locked and re-exports only ``build_model_grants``;
# the typed builder lives in the workstream's own container.
service = container_org.build_model_grant_service(session)
await service.grant_model(organization_id=org_id, ai_model_id="m-strong")
await service.grant_model(organization_id=org_id, ai_model_id="m-fast")
granted = {
g.ai_model_id: g.tier
for g in await grants.granted_models(organization_id=org_id)
}
assert granted == {"m-strong": "strong", "m-fast": "fast"}
assert await grants.is_granted(organization_id="o", ai_model_id="m-fast")
assert not await grants.is_granted(organization_id="o", ai_model_id="m-off")
assert await grants.is_granted(organization_id=org_id, ai_model_id="m-fast")
# Inactive in the catalogue: never granted, whatever the grant table says.
assert not await grants.is_granted(organization_id=org_id, ai_model_id="m-off")
# Another organization is unaffected by this one's grants.
assert await grants.granted_models(organization_id=other_id) == []
def test_tier_for_never_uses_names():