Coverage for integrations / social / __init__.py: 81.2%
288 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 04:49 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 04:49 +0000
1"""
2HevolveSocial - Agent Social Network
3A community-driven social network where both humans and AI agents are equal participants.
4"""
5import logging
7logger = logging.getLogger('hevolve_social')
9# Lazy imports to avoid circular dependencies
10_social_bp = None
12# ── Idempotency sentinel (2026-04-19) ──────────────────────────────
13# init_social is expensive: registers ~18 blueprints, seeds DB tables,
14# starts gossip/peer discovery, pulls autogen→openai→langchain via
15# init_agent_engine. Flask's register_blueprint raises on duplicate
16# name, so a second call would crash the app. Defend against double-
17# init by tracking whether we've already run. (Nunba's main.py has
18# its own idempotency guard too; this is belt-and-suspenders for any
19# downstream caller that imports this module and calls init_social
20# again — tests, reloader, future cloud entry.)
21_INIT_DONE = False
24def get_social_blueprint():
25 global _social_bp
26 if _social_bp is None:
27 from .api import social_bp as bp
28 _social_bp = bp
29 return _social_bp
32def init_social(app):
33 """Initialize the social network module. Call after app = Flask(...).
35 This function is idempotent — calling it twice is safe. The second
36 call short-circuits and logs a debug message. Rationale: this call
37 registers 18+ blueprints, and Flask rejects duplicate blueprint
38 names; skipping the second call is less surprising than raising."""
39 global _INIT_DONE
40 if _INIT_DONE:
41 logger.debug("init_social: already initialized, skipping second call")
42 return
43 _INIT_DONE = True
44 # Block dev mode on central
45 import os as _os_boot
46 node_tier = _os_boot.environ.get('HEVOLVE_NODE_TIER', 'flat')
47 if node_tier == 'central' and _os_boot.environ.get('HEVOLVE_DEV_MODE', '').lower() == 'true':
48 _os_boot.environ['HEVOLVE_DEV_MODE'] = 'false'
49 logger.critical("SECURITY: Dev mode FORCED OFF on central instance")
51 from .models import init_db, DB_PATH
52 try:
53 init_db()
54 # Apply pending schema migrations against the canonical DB so a
55 # daemon booting on a pre-existing v36/37/38 SQLite catches up
56 # to SCHEMA_VERSION (currently 39: users.voice_profile column).
57 # Idempotent — see tests/unit/test_voice_profile_migration.py.
58 # Brings HARTOS daemon parity with Nunba main.py per MEMORY.md.
59 from .migrations import run_migrations
60 run_migrations()
61 logger.info(f"HevolveSocial database initialized + migrated ({DB_PATH})")
62 except Exception as e:
63 logger.warning(f"HevolveSocial DB init failed (non-fatal): {e}")
65 # Phase 7a / Phase 8 — install global tenant filter on Session.
66 # Migration v40 added `tenant_id` columns to ~34 social tables;
67 # this teaches the ORM about them and filters every SELECT by
68 # the current request's tenant. No-op when g.tenant_id is None
69 # (flat/regional pass-through), so single-tenant deploys are
70 # unaffected. Plan reference: sunny-gliding-eich.md, Part E.1.
71 try:
72 from .tenant_filter import (
73 install_tenant_filter, register_tenant_aware,
74 )
75 install_tenant_filter()
76 from .models import (
77 User, Post, Comment, Community, Vote, Follow,
78 CommunityMembership, Notification, Report,
79 )
80 for _cls in (User, Post, Comment, Community, Vote, Follow,
81 CommunityMembership, Notification, Report):
82 register_tenant_aware(_cls)
83 except Exception as e:
84 logger.warning(f"HevolveSocial tenant filter install skipped: {e}")
86 # Seed default achievements
87 try:
88 from .gamification_service import GamificationService
89 from .models import get_db
90 db = get_db()
91 try:
92 count = GamificationService.seed_achievements(db)
93 if count > 0:
94 db.commit()
95 logger.info(f"HevolveSocial: seeded {count} achievements")
96 finally:
97 db.close()
98 except Exception as e:
99 logger.debug(f"HevolveSocial achievement seeding skipped: {e}")
101 # Seed default ad placements
102 try:
103 from .ad_service import AdService
104 from .models import get_db as _get_db
105 db = _get_db()
106 try:
107 count = AdService.seed_placements(db)
108 if count > 0:
109 db.commit()
110 logger.info(f"HevolveSocial: seeded {count} ad placements")
111 finally:
112 db.close()
113 except Exception as e:
114 logger.debug(f"HevolveSocial ad placement seeding skipped: {e}")
116 # Register conversations blueprint (Phase 7c.3 — DM/group chat).
117 # Distinct from api_channels (legacy 31-channel external adapter)
118 # — these blueprints have non-overlapping URL prefixes.
119 try:
120 from .api_conversations import conversations_bp
121 app.register_blueprint(conversations_bp)
122 logger.info("HevolveSocial conversations registered at "
123 "/api/social/conversations/")
124 except Exception as e:
125 logger.warning(f"HevolveSocial conversations blueprint skipped: {e}")
127 # Register calls blueprint (Phase 7d — voice/video/screen).
128 # Flag-gated by `calls_v1` server-side; off → 503 on every endpoint.
129 # The blueprint's URL prefix is /api/social so the routes live at
130 # /api/social/calls/* (no nesting under /conversations).
131 try:
132 from .api_calls import calls_bp
133 app.register_blueprint(calls_bp)
134 logger.info("HevolveSocial calls registered at /api/social/calls/")
135 except Exception as e:
136 logger.warning(f"HevolveSocial calls blueprint skipped: {e}")
138 # Register gamification blueprint
139 try:
140 from .api_gamification import gamification_bp
141 app.register_blueprint(gamification_bp)
142 logger.info("HevolveSocial gamification endpoints registered")
143 except Exception as e:
144 logger.warning(f"HevolveSocial gamification blueprint skipped: {e}")
146 # Register hive contest blueprint (Claude Code onramp + leaderboard)
147 try:
148 from .api_hive_contest import hive_contest_bp
149 app.register_blueprint(hive_contest_bp)
150 logger.info("HevolveSocial hive contest registered at /api/hive/contest/")
151 except Exception as e:
152 logger.warning(f"HevolveSocial hive contest blueprint skipped: {e}")
154 # Register compute-earnings blueprint (idle-compute self-advertise +
155 # live drawer SSE + opted-in user wallet readback)
156 try:
157 from .api_compute_earnings import compute_earnings_bp
158 app.register_blueprint(compute_earnings_bp)
159 logger.info("HevolveSocial compute earnings registered at /api/compute/earnings/")
160 except Exception as e:
161 logger.warning(f"HevolveSocial compute earnings blueprint skipped: {e}")
163 # Register hive contest UI (single-page local view — reads the same
164 # /api/hive/contest/* endpoints, used by the HART shell panel and
165 # by a direct browser visit for operators).
166 try:
167 from .ui_hive_contest import hive_contest_ui_bp
168 app.register_blueprint(hive_contest_ui_bp)
169 logger.info("HevolveSocial hive contest UI registered at /hive-contest")
170 except Exception as e:
171 logger.warning(f"HevolveSocial hive contest UI blueprint skipped: {e}")
173 # Register MCP tool registry blueprint (servers, tools, discover)
174 try:
175 from .api_mcp import mcp_bp
176 app.register_blueprint(mcp_bp)
177 logger.info("HevolveSocial MCP endpoints registered at /api/social/mcp/")
178 except Exception as e:
179 logger.warning(f"HevolveSocial marketplace+MCP blueprint skipped: {e}")
181 # Register sharing blueprint — canonical OG / share / embed home per
182 # memory/feedback_unification_reuse_contract.md. Already serves
183 # /api/social/share/<token>, /api/social/og-image/<type>/<id>,
184 # /api/social/embed/<type>/<id>. F1.5 wave will EXTEND this same
185 # blueprint with canonical short URLs (/i/, /c/, /u/, /p/) by
186 # promoting ``_get_og_metadata`` to public + adding `invite` resource
187 # type — NOT a parallel og_bp.
188 try:
189 from .api_sharing import sharing_bp
190 app.register_blueprint(sharing_bp)
191 logger.info("HevolveSocial sharing endpoints registered at /api/social/share/")
192 except Exception as e:
193 logger.warning(f"HevolveSocial sharing blueprint skipped: {e}")
195 # Register multiplayer games + compute lending blueprint
196 try:
197 from .api_games import games_bp
198 app.register_blueprint(games_bp)
199 logger.info("HevolveSocial games + compute endpoints registered at /api/social/games/, /api/social/compute/")
200 except Exception as e:
201 logger.warning(f"HevolveSocial games blueprint skipped: {e}")
203 # Register discovery blueprint (.well-known/hevolve-social.json)
204 try:
205 from .discovery import discovery_bp
206 app.register_blueprint(discovery_bp)
207 logger.info("HevolveSocial discovery endpoint registered at /.well-known/hevolve-social.json")
208 except Exception as e:
209 logger.debug(f"HevolveSocial discovery blueprint skipped: {e}")
211 # Register admin API blueprint (channels management, requires admin auth)
212 try:
213 from integrations.channels.admin.api import admin_bp
214 app.register_blueprint(admin_bp)
215 logger.info("HevolveSocial admin API registered at /api/admin")
216 except Exception as e:
217 logger.debug(f"HevolveSocial admin blueprint skipped: {e}")
219 # Register OAuth click-through blueprint (PR O). /start needs auth,
220 # /callback is public (state-token authenticated) — separate blueprint
221 # so admin_bp's before_request gate doesn't 401 the provider redirect.
222 try:
223 from integrations.channels.oauth_api import oauth_bp
224 app.register_blueprint(oauth_bp)
225 logger.info("HevolveSocial OAuth API registered at /api/oauth")
226 except Exception as e:
227 logger.debug(f"HevolveSocial OAuth blueprint skipped: {e}")
229 # Register user-facing channel bindings API (catalog, bindings, pairing, presence)
230 try:
231 from .api_channels import channel_user_bp
232 app.register_blueprint(channel_user_bp)
233 logger.info("HevolveSocial channel user API registered at /api/social/channels/")
234 except Exception as e:
235 logger.debug(f"HevolveSocial channel user blueprint skipped: {e}")
237 # Register agent dashboard blueprint (truth-grounded unified agent view)
238 try:
239 from .api_dashboard import dashboard_bp
240 app.register_blueprint(dashboard_bp)
241 logger.info("HevolveSocial dashboard registered at /api/social/dashboard/")
242 except Exception as e:
243 logger.debug(f"HevolveSocial dashboard blueprint skipped: {e}")
245 # Register thought experiment tracker blueprint
246 try:
247 from .api_tracker import tracker_bp
248 app.register_blueprint(tracker_bp)
249 logger.info("HevolveSocial tracker registered at /api/social/tracker/")
250 except Exception as e:
251 logger.debug(f"HevolveSocial tracker blueprint skipped: {e}")
253 # Register fleet OTA update approval blueprint
254 try:
255 from .api_fleet_update import fleet_update_bp
256 app.register_blueprint(fleet_update_bp)
257 logger.info("HevolveSocial fleet update registered at /api/social/fleet/")
258 except Exception as e:
259 logger.debug(f"HevolveSocial fleet update blueprint skipped: {e}")
261 # Register regional host request + approval blueprint
262 try:
263 from .api_regional_host import regional_host_bp
264 app.register_blueprint(regional_host_bp)
265 logger.info("HevolveSocial regional host registered at /api/social/regional-host/")
266 except Exception as e:
267 logger.debug(f"HevolveSocial regional host blueprint skipped: {e}")
269 # Register sync & backup blueprint
270 try:
271 from .sync_api import sync_bp
272 app.register_blueprint(sync_bp)
273 logger.info("HevolveSocial sync registered at /api/social/sync/")
274 except Exception as e:
275 logger.debug(f"HevolveSocial sync blueprint skipped: {e}")
277 # Register audit trail blueprint
278 try:
279 from .api_audit import audit_bp
280 app.register_blueprint(audit_bp)
281 logger.info("HevolveSocial audit registered at /api/social/audit/")
282 except Exception as e:
283 logger.debug(f"HevolveSocial audit blueprint skipped: {e}")
285 # Register content generation task tracking blueprint
286 try:
287 from integrations.agent_engine.api_content_gen import content_gen_bp
288 app.register_blueprint(content_gen_bp)
289 logger.info("HevolveSocial content gen registered at /api/social/content-gen/")
290 except Exception as e:
291 logger.debug(f"HevolveSocial content gen blueprint skipped: {e}")
293 # Register continual learning CCT management blueprint
294 try:
295 from integrations.agent_engine.api_learning import learning_bp
296 app.register_blueprint(learning_bp)
297 logger.info("Learning CCT endpoints registered at /api/learning/")
298 except Exception as e:
299 logger.debug(f"Learning blueprint skipped: {e}")
301 # Register OS-wide theme management blueprint
302 try:
303 from .api_theme import theme_bp
304 app.register_blueprint(theme_bp)
305 logger.info("HevolveSocial theme registered at /api/social/theme/")
306 except Exception as e:
307 logger.debug(f"HevolveSocial theme blueprint skipped: {e}")
309 # Register thought experiments blueprint
310 try:
311 from .api_thought_experiments import thought_experiments_bp
312 app.register_blueprint(thought_experiments_bp)
313 logger.info("Thought experiment endpoints registered at /api/social/experiments/")
314 except Exception as e:
315 logger.debug(f"Thought experiments blueprint skipped: {e}")
317 # Register encounter (P2P BLE meetup + mutual-like icebreaker) blueprint.
318 # PR-A alpha skeleton — in-memory state; DB migration v38 lands
319 # in PR-A beta. Full design: project_encounter_icebreaker.md.
320 try:
321 from .encounter_api import encounter_bp
322 app.register_blueprint(encounter_bp)
323 logger.info("HevolveSocial encounter registered at /api/social/encounter/")
324 except Exception as e:
325 logger.debug(f"HevolveSocial encounter blueprint skipped: {e}")
327 # Register UserConsent UI blueprint (W0c F3 prereq). JWT-authed,
328 # append-only consent surface — the SINGLE HTTP write path for
329 # the user_consents table after the consent-surface consolidation
330 # (orchestrator review acd11f55, 2026-04-25). consent_service.py
331 # retains the in-process ConsentService static-method API for
332 # internal callers; its legacy /api/consent/<user_id>/* HTTP
333 # route family was removed in the consolidation commit.
334 try:
335 from .consent_api import consent_bp
336 app.register_blueprint(consent_bp)
337 logger.info("HevolveSocial consent registered at /api/social/consent/")
338 except Exception as e:
339 logger.debug(f"HevolveSocial consent blueprint skipped: {e}")
341 # NOTE: compute_pledge_bp (api_compute_pledge.py) was consolidated into tracker_bp
342 # and the stale file deleted 2026-04-15. All pledge endpoints live at
343 # /api/social/tracker/experiments/*/pledge* and /api/social/tracker/pledges/*
344 # — single source of truth.
346 # Initialize node keypair for integrity verification
347 try:
348 from security.node_integrity import get_or_create_keypair, get_public_key_hex
349 get_or_create_keypair()
350 pubkey = get_public_key_hex()
351 logger.info(f"HevolveSocial node keypair initialized: {pubkey[:16]}...")
352 except Exception as e:
353 logger.debug(f"HevolveSocial keypair init skipped: {e}")
355 # ── Master Key Boot Verification ──
356 _boot_verified = False
357 _boot_manifest = None
358 try:
359 from security.master_key import full_boot_verification, is_dev_mode, get_enforcement_mode
360 verification = full_boot_verification()
361 enforcement = get_enforcement_mode()
362 _boot_verified = verification['passed'] or is_dev_mode() or enforcement in ('off', 'warn')
363 _boot_manifest = verification.get('manifest')
364 if verification['passed']:
365 logger.info(f"HevolveSocial boot verification PASSED: {verification['details']}")
366 elif _boot_verified:
367 logger.warning(f"HevolveSocial boot verification not passed but allowed "
368 f"(enforcement={enforcement}): {verification['details']}")
369 else:
370 logger.critical(f"HevolveSocial boot verification FAILED: {verification['details']}")
371 except Exception as e:
372 _boot_verified = True # Allow if master_key module unavailable
373 logger.debug(f"HevolveSocial boot verification skipped: {e}")
375 # ── Tier authorization (central must prove master key) ──
376 try:
377 from security.key_delegation import verify_tier_authorization
378 tier_auth = verify_tier_authorization()
379 if not tier_auth.get('authorized'):
380 logger.critical(f"Tier authorization FAILED: {tier_auth.get('details', 'unknown')}")
381 if node_tier == 'central':
382 _boot_verified = False
383 logger.critical("Central node cannot start without tier authorization")
384 except Exception as e:
385 logger.warning(f"Tier authorization check unavailable: {e}")
387 # ── System Requirements (HART OS Equilibrium) ──
388 # Detect hardware, classify contribution tier, auto-gate features.
389 # Must run BEFORE gossip/agents so env vars are set before they check.
390 _node_capabilities = None
391 try:
392 from security.system_requirements import run_system_check, get_tier_name
393 _node_capabilities = run_system_check()
394 _tier_name = get_tier_name()
395 logger.info(
396 f"HevolveSocial equilibrium: tier={_tier_name}, "
397 f"enabled={len(_node_capabilities.enabled_features)} features, "
398 f"disabled={len(_node_capabilities.disabled_features)} features"
399 )
400 if _node_capabilities.disabled_features:
401 for _feat, _reason in _node_capabilities.disabled_features.items():
402 logger.info(f" Feature '{_feat}' not loaded: {_reason}")
403 except Exception as e:
404 logger.warning(f"HevolveSocial system requirements check skipped: {e}")
405 # Auto-enable agent engine if not explicitly disabled
406 import os as _os_fb
407 if _os_fb.environ.get('HEVOLVE_AGENT_ENGINE_ENABLED') is None:
408 _os_fb.environ['HEVOLVE_AGENT_ENGINE_ENABLED'] = 'true'
410 # Start decentralized gossip peer discovery (background thread)
411 if _boot_verified:
412 try:
413 from .peer_discovery import gossip
414 gossip.start()
415 logger.info(f"HevolveSocial gossip started: node={gossip.node_id[:8]}, "
416 f"seeds={len(gossip.seed_peers)}")
417 except Exception as e:
418 logger.debug(f"HevolveSocial gossip start skipped: {e}")
420 # Start zero-config LAN auto-discovery (additive to seed peers)
421 import os as _os_disc
422 if _os_disc.environ.get('HEVOLVE_AUTO_DISCOVERY', 'true').lower() != 'false':
423 try:
424 from .peer_discovery import auto_discovery
425 auto_discovery.start()
426 logger.info(f"HevolveSocial auto-discovery started "
427 f"(UDP port {auto_discovery._port})")
428 except Exception as e:
429 logger.debug(f"HevolveSocial auto-discovery skipped: {e}")
431 # Start runtime integrity monitor if we have a signed manifest
432 if _boot_manifest:
433 try:
434 from security.runtime_monitor import start_monitor
435 start_monitor(_boot_manifest)
436 logger.info("HevolveSocial runtime integrity monitor started")
437 except Exception as e:
438 logger.debug(f"HevolveSocial runtime monitor start skipped: {e}")
439 else:
440 logger.critical("HevolveSocial: gossip NOT started - boot verification failed (hard mode)")
442 # Start sync engine for regional/local tiers
443 if _boot_verified:
444 try:
445 from security.key_delegation import get_node_tier
446 node_tier = get_node_tier()
447 if node_tier in ('regional', 'local'):
448 from .sync_engine import sync_engine
449 sync_engine.start_background_sync()
450 logger.info(f"HevolveSocial sync engine started (tier={node_tier})")
451 except Exception as e:
452 logger.debug(f"HevolveSocial sync engine start skipped: {e}")
454 # Start distributed coding agent if enabled. Default flipped to
455 # 'true' on 2026-05-07 — the daemon consumes self_heal goals
456 # produced by error_advice (#102) and SelfHealingDispatcher; with
457 # default 'false' the queue piled up indefinitely (15 stale goals
458 # back to 2026-04-27 in the live DB at audit time). Safety is in
459 # the daemon itself (no idle agents → early return; budget gate;
460 # 30s poll cadence). Servers that don't want it set explicitly.
461 import os as _os2
462 if _os2.environ.get('HEVOLVE_CODING_AGENT_ENABLED', 'true').lower() == 'true':
463 try:
464 from integrations.coding_agent import init_coding_agent
465 init_coding_agent(app)
466 logger.info("HevolveSocial distributed coding agent initialized")
467 except Exception as e:
468 logger.debug(f"HevolveSocial coding agent init skipped: {e}")
470 # Agent engine init is the SINGLE responsibility of Nunba's
471 # `main.py:_deferred_social_init` (or any standalone HARTOS launcher
472 # that calls `init_agent_engine` directly). Calling it from inside
473 # `init_social` produced a double-invocation in Nunba (main.py calls
474 # init_social → init_social calls init_agent_engine → main.py calls
475 # init_agent_engine again right after), and the deadlock smoking
476 # gun on 2026-04-28 was exactly this path: the second invocation
477 # fired while hartos-init's `from hart_intelligence import app` was
478 # still mid-import, deadlocking on the per-module import lock.
479 # Idempotency in init_agent_engine itself (added 2026-04-28) makes
480 # the second call a no-op, but the cleaner contract is: ONE caller,
481 # ONE call site. init_social no longer initialises the agent engine
482 # — its caller does.
483 logger.debug("HevolveSocial: agent engine init delegated to caller "
484 "(see Nunba main.py:_deferred_social_init or HARTOS launcher)")
486 # Register with central registry if configured
487 import os
488 registry_url = os.environ.get('HEVOLVE_REGISTRY_URL', '')
489 if registry_url and _boot_verified:
490 try:
491 from .integrity_service import IntegrityService
492 from .peer_discovery import gossip as _gossip
493 from security.node_integrity import get_public_key_hex as _get_pubkey
494 IntegrityService.register_with_registry(
495 registry_url, _gossip.node_id, _get_pubkey(), _gossip.version)
496 logger.info(f"HevolveSocial registered with registry: {registry_url}")
497 except Exception as e:
498 logger.debug(f"HevolveSocial registry registration skipped: {e}")
500 # ── NodeWatchdog - start LAST, monitors all daemon threads ──
501 try:
502 from security.node_watchdog import start_watchdog
503 watchdog = start_watchdog()
505 # Register gossip — interval must exceed worst-case gossip round
506 # (3 peers × 10s timeout = 30s max) to avoid false FROZEN alerts.
507 if _boot_verified:
508 try:
509 from .peer_discovery import gossip as _g
510 if _g._running:
511 watchdog.register('gossip', expected_interval=120,
512 restart_fn=_g.start, stop_fn=_g.stop)
513 except Exception:
514 pass
516 # Register auto-discovery
517 try:
518 from .peer_discovery import auto_discovery as _ad
519 if _ad._running:
520 watchdog.register('auto_discovery',
521 expected_interval=_ad._beacon_interval,
522 restart_fn=_ad.start, stop_fn=_ad.stop)
523 except Exception:
524 pass
526 # Register runtime monitor
527 if _boot_manifest:
528 try:
529 from security.runtime_monitor import get_monitor
530 mon = get_monitor()
531 if mon and mon._running:
532 watchdog.register('runtime_monitor',
533 expected_interval=mon._check_interval,
534 restart_fn=mon.start, stop_fn=mon.stop)
535 except Exception:
536 pass
538 # Register sync engine
539 try:
540 from .sync_engine import sync_engine as _se
541 if _se._running:
542 watchdog.register('sync_engine',
543 expected_interval=_se._interval,
544 restart_fn=_se.start_background_sync,
545 stop_fn=_se.stop_background_sync)
546 except Exception:
547 pass
549 # Register agent daemon
550 try:
551 from integrations.agent_engine.agent_daemon import agent_daemon as _agent_d
552 if _agent_d._running:
553 watchdog.register('agent_daemon',
554 expected_interval=_agent_d._interval,
555 restart_fn=_agent_d.start, stop_fn=_agent_d.stop)
556 except Exception:
557 pass
559 # Register coding daemon
560 try:
561 from integrations.coding_agent.coding_daemon import coding_daemon as _coding_d
562 if _coding_d._running:
563 watchdog.register('coding_daemon',
564 expected_interval=_coding_d._interval,
565 restart_fn=_coding_d.start, stop_fn=_coding_d.stop)
566 except Exception:
567 pass
569 # Register model lifecycle manager — interval must exceed worst-case
570 # tick duration (nvidia-smi 5s + pressure checks + federation report).
571 try:
572 from integrations.service_tools.model_lifecycle import get_model_lifecycle_manager
573 _lifecycle = get_model_lifecycle_manager()
574 _lifecycle.start()
575 if _lifecycle._running:
576 watchdog.register('model_lifecycle',
577 expected_interval=max(_lifecycle._interval * 3, 60),
578 restart_fn=_lifecycle.start,
579 stop_fn=_lifecycle.stop)
580 logger.info("Model lifecycle manager started")
581 except Exception as e:
582 logger.debug(f"Model lifecycle manager start skipped: {e}")
584 # Distributed worker loop — claims tasks from shared Redis queue.
585 # Self-gates: start() is a no-op when Redis is unreachable.
586 try:
587 from integrations.distributed_agent.worker_loop import worker_loop as _wl
588 _wl.start()
589 if _wl._running:
590 watchdog.register('distributed_worker',
591 expected_interval=_wl._interval * 4,
592 restart_fn=_wl.start,
593 stop_fn=_wl.stop)
594 logger.info("Distributed worker loop started")
595 except Exception as e:
596 logger.debug(f"Distributed worker loop start skipped: {e}")
598 # Hive benchmark prover — rotates model benchmarks every 6 hours
599 # and publishes baseline+score deltas into the ledger.
600 try:
601 from integrations.agent_engine.hive_benchmark_prover import (
602 get_benchmark_prover, _LOOP_INTERVAL_SECONDS as _hbp_interval,
603 )
604 _hbp = get_benchmark_prover()
605 _hbp.start_continuous_loop()
606 if _hbp._loop_running:
607 watchdog.register('hive_benchmark_prover',
608 expected_interval=_hbp_interval * 2,
609 restart_fn=_hbp.start_continuous_loop,
610 stop_fn=_hbp.stop)
611 logger.info("Hive benchmark prover started")
612 except Exception as e:
613 logger.debug(f"Hive benchmark prover start skipped: {e}")
615 watchdog.start()
616 logger.info(f"NodeWatchdog started: monitoring "
617 f"{len(watchdog._threads)} threads")
618 except Exception as e:
619 logger.debug(f"NodeWatchdog start skipped: {e}")
621 # Sync trained agents as social users on first request
622 @app.before_request
623 def _sync_agents_once():
624 if not getattr(app, '_social_agents_synced', False):
625 app._social_agents_synced = True
626 try:
627 from .agent_bridge import sync_trained_agents
628 count = sync_trained_agents()
629 if count > 0:
630 logger.info(f"HevolveSocial: synced {count} trained agents as social users")
631 except Exception as e:
632 logger.debug(f"HevolveSocial agent sync skipped: {e}")
635# Module-level lazy attribute: from integrations.social import social_bp
636def __getattr__(name):
637 if name == 'social_bp':
638 return get_social_blueprint()
639 raise AttributeError(f"module {__name__!r} has no attribute {name!r}")