Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-governance/src/lexigram/ai/governance/relay_channels/di.py: 54%

26 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 07:19 +0800

1"""DI registrations and gateway hooks for durable relay channels. 

2 

3The governance provider root keeps the channel store unbounded during 

4``register()`` (it needs a database that is only resolvable in 

5``boot()``). :func:`boot_relay_channels` resolves the database through 

6its contract and binds ``RelayChannelStoreProtocol`` to the SQL store 

7so the gateway's boot reconcile and the admin CRUD actions resolve the 

8same instance through the container. When no database is bound, the 

9protocol stays unbounded and the gateway keeps its static-configure 

10default behavior. 

11 

12Nothing in this module imports gateway implementations. 

13""" 

14 

15from __future__ import annotations 

16 

17from typing import TYPE_CHECKING 

18 

19from lexigram.ai.governance import GovernanceConfig 

20from lexigram.ai.governance.relay_channels import SqlRelayChannelStore 

21from lexigram.contracts.ai.relay.store import RelayChannelStoreProtocol 

22from lexigram.contracts.data import DatabaseProviderProtocol 

23from lexigram.logging import get_logger 

24 

25if TYPE_CHECKING: 

26 from lexigram.contracts.core.di import ( 

27 BootContainerProtocol, 

28 ContainerRegistrarProtocol, 

29 ) 

30 

31logger = get_logger(__name__) 

32 

33__all__ = ["boot_relay_channels", "register_relay_channels"] 

34 

35 

36def register_relay_channels( 

37 container: ContainerRegistrarProtocol, 

38 config: object, 

39) -> None: 

40 """Register durable relay channel services. 

41 

42 Nothing is bound when governance is disabled. The SQL store is 

43 built and bound during :func:`boot_relay_channels` once the 

44 database contract is resolvable; until then the gateway keeps its 

45 static channel configuration. 

46 

47 Args: 

48 container: The container registrar to bind into. 

49 config: Governance configuration; ``enabled`` gates the store. 

50 """ 

51 del container 

52 if not isinstance(config, GovernanceConfig) or not config.enabled: 

53 logger.info("relay_channels_disabled", reason="governance disabled") 

54 return 

55 logger.info("relay_channels_registered") 

56 

57 

58async def boot_relay_channels( 

59 container: BootContainerProtocol, 

60 config: object, 

61) -> None: 

62 """Build the SQL channel store and bind it under its contract. 

63 

64 Resolution is contract-scoped (only 

65 :class:`~lexigram.contracts.data.DatabaseProviderProtocol`). When 

66 the database is missing, nothing is bound and a startup diagnostic 

67 is logged so the missing dependency is discoverable; the gateway 

68 keeps its static-configure default. 

69 

70 Args: 

71 container: The boot container used to resolve contracts. 

72 config: Governance configuration driving the bootstrap. 

73 """ 

74 if not isinstance(config, GovernanceConfig) or not config.enabled: 

75 logger.info("relay_channels_boot_skipped", reason="governance disabled") 

76 return 

77 

78 database = await container.resolve_optional(DatabaseProviderProtocol) 

79 if database is None: 

80 logger.warning( 

81 "relay_channels_missing_dependency", 

82 missing="DatabaseProviderProtocol", 

83 ) 

84 return 

85 

86 store = SqlRelayChannelStore(database) 

87 container.singleton(RelayChannelStoreProtocol, store) 

88 logger.info("relay_channels_booted", store="SqlRelayChannelStore")