meshcode 2.11.5__tar.gz → 2.11.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {meshcode-2.11.5 → meshcode-2.11.7}/PKG-INFO +1 -1
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/__init__.py +1 -1
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/server.py +383 -84
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/SOURCES.txt +3 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/pyproject.toml +1 -1
- meshcode-2.11.7/tests/test_boot_bug_regression.py +205 -0
- meshcode-2.11.7/tests/test_epistemic_v1_stop_conditions.py +158 -0
- meshcode-2.11.7/tests/test_install_guard.py +112 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/README.md +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/_stop_hook_template.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/cli.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/compat.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/daemon.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/error_hints.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/invites.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/launcher.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/preferences.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/protocol_handler.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/quickstart.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/run_agent.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/scripts/check_secrets.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/scripts/race_rate_harness.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/secrets.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/self_update.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/supervisor.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/upload.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/cli.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/compat.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/invites.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/launcher.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/preferences.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/secrets.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/self_update.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/upload.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/scripts/sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_core.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/cli.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/compat.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/invites.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/launcher.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/preferences.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/secrets.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/self_update.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/upload.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/scripts/sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_core.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/cli.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/compat.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/invites.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/upload.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_core.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/setup.cfg +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_auto_update_hardening.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_core.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_exceptions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_lease_sigterm_release.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_sentinel.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_sleep_signals.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_stay_on_loop_hook.py +0 -0
- {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_wait_open_tasks_contradiction.py +0 -0
|
@@ -968,6 +968,90 @@ def with_working_status(func):
|
|
|
968
968
|
return swrapper
|
|
969
969
|
|
|
970
970
|
|
|
971
|
+
# ============================================================
|
|
972
|
+
# Consequential-tool gate (task b4befbfd item 1 — epistemic V1)
|
|
973
|
+
# ============================================================
|
|
974
|
+
# Tools listed below refuse to run unless the calling agent has an open
|
|
975
|
+
# decision in mc_traces from the last 5 minutes (logged via meshcode_decide).
|
|
976
|
+
# Drives the team toward explicit pre-decision logging on hard-to-reverse
|
|
977
|
+
# actions. Whitelist is overridable via mc_meshwork_memory key
|
|
978
|
+
# `consequential_tool_whitelist` (future config; v1 uses the bake-in below
|
|
979
|
+
# so commanders don't need to seed-bootstrap before the gate works).
|
|
980
|
+
|
|
981
|
+
_CONSEQUENTIAL_TOOLS_DEFAULT = frozenset([
|
|
982
|
+
# Mesh-wide / cross-agent destructive
|
|
983
|
+
"meshcode_done", # broadcasts DONE to ALL agents
|
|
984
|
+
"meshcode_disconnect_agent", # offlines another agent
|
|
985
|
+
"meshcode_edit_agent", # mutates another agent's identity/role
|
|
986
|
+
"meshcode_edit_memory", # writes into another agent's memory
|
|
987
|
+
"meshcode_forget", # deletes memory (tombstones it)
|
|
988
|
+
"meshcode_create_meshwork", # creates a new meshwork (hard to unwind)
|
|
989
|
+
"meshcode_marketplace_install", # installs external code into project
|
|
990
|
+
"meshcode_publish_template", # publishes a template publicly
|
|
991
|
+
"meshcode_proposal_convert", # converts proposal into a real task
|
|
992
|
+
"meshcode_proposal_reject", # rejects a proposal permanently
|
|
993
|
+
"meshcode_task_cancel", # cancels a task (irreversible terminal state)
|
|
994
|
+
])
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
def _is_consequential(tool_name: str) -> bool:
|
|
998
|
+
"""V1 reads the bake-in set. Future: lazy-load mc_meshwork_memory
|
|
999
|
+
`consequential_tool_whitelist` and merge. Soft-fail to the bake-in if
|
|
1000
|
+
the RPC is unavailable so the gate never blocks itself out."""
|
|
1001
|
+
return tool_name in _CONSEQUENTIAL_TOOLS_DEFAULT
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
def _check_decision_gate(tool_name: str) -> Optional[Dict[str, Any]]:
|
|
1005
|
+
"""Returns None when the gate is open; returns an error dict to be
|
|
1006
|
+
surfaced as the tool result when the gate is closed. Soft-fail on RPC
|
|
1007
|
+
error (gate opens) so a transient DB blip doesn't trap the agent."""
|
|
1008
|
+
if not _is_consequential(tool_name):
|
|
1009
|
+
return None
|
|
1010
|
+
try:
|
|
1011
|
+
resp = be.sb_rpc("mc_has_open_decision", {
|
|
1012
|
+
"p_api_key": _get_api_key(),
|
|
1013
|
+
"p_project_id": _PROJECT_ID,
|
|
1014
|
+
"p_agent_name": AGENT_NAME,
|
|
1015
|
+
})
|
|
1016
|
+
if isinstance(resp, dict) and resp.get("ok") and not resp.get("has_open_decision"):
|
|
1017
|
+
return {
|
|
1018
|
+
"ok": False,
|
|
1019
|
+
"error_code": "decision_required",
|
|
1020
|
+
"hint": (
|
|
1021
|
+
f"`{tool_name}` is a consequential action. Call "
|
|
1022
|
+
f"meshcode_decide(decision, alternatives, evidence_refs) "
|
|
1023
|
+
f"first so the team can learn from the outcome. After "
|
|
1024
|
+
f"the action is observable, call meshcode_outcome(trace_id, ...)."
|
|
1025
|
+
),
|
|
1026
|
+
"consequential_tool": tool_name,
|
|
1027
|
+
}
|
|
1028
|
+
except Exception as _gate_err:
|
|
1029
|
+
log.debug(f"decision gate soft-fail for {tool_name}: {_gate_err}")
|
|
1030
|
+
return None
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
def with_decision_gate(func):
|
|
1034
|
+
"""Decorator: applies _check_decision_gate before calling func. Use
|
|
1035
|
+
AFTER @mcp.tool() and AFTER @with_working_status so the gate runs
|
|
1036
|
+
inside the working-status window (and shows up in tool_call logs)."""
|
|
1037
|
+
name = func.__name__
|
|
1038
|
+
if asyncio.iscoroutinefunction(func):
|
|
1039
|
+
@_functools.wraps(func)
|
|
1040
|
+
async def awrapper(*args, **kwargs):
|
|
1041
|
+
blocked = _check_decision_gate(name)
|
|
1042
|
+
if blocked is not None:
|
|
1043
|
+
return blocked
|
|
1044
|
+
return await func(*args, **kwargs)
|
|
1045
|
+
return awrapper
|
|
1046
|
+
@_functools.wraps(func)
|
|
1047
|
+
def wrapper(*args, **kwargs):
|
|
1048
|
+
blocked = _check_decision_gate(name)
|
|
1049
|
+
if blocked is not None:
|
|
1050
|
+
return blocked
|
|
1051
|
+
return func(*args, **kwargs)
|
|
1052
|
+
return wrapper
|
|
1053
|
+
|
|
1054
|
+
|
|
971
1055
|
# ============================================================
|
|
972
1056
|
# Single-instance lease — prevent split-brain when two windows
|
|
973
1057
|
# run `meshcode run <same-agent>` simultaneously.
|
|
@@ -1388,28 +1472,51 @@ def _log_crash_to_db(reason: str = "unknown", error_detail: str = "") -> None:
|
|
|
1388
1472
|
# ============================================================
|
|
1389
1473
|
# Agent identity from Supabase profile (for system instructions)
|
|
1390
1474
|
# ============================================================
|
|
1475
|
+
# MIG-PLAN-A 2026-05-18: profile fetch moved out of module-import time
|
|
1476
|
+
# (was the last be.sb_rpc here that ran on import). Now starts as
|
|
1477
|
+
# placeholders; BG thread spawned by lifespan calls mc_agent_get_profile
|
|
1478
|
+
# and updates the globals. _build_instructions() runs at import using
|
|
1479
|
+
# whatever is currently in the globals — for first-boot of a fresh agent
|
|
1480
|
+
# this means InitializeResult.instructions carries empty launch_prompt /
|
|
1481
|
+
# fallback role_description; first-tool-call envelope can re-inject if
|
|
1482
|
+
# needed. Net win: zero network I/O at module-import time → MCP
|
|
1483
|
+
# handshake never blocks on profile fetch.
|
|
1391
1484
|
|
|
1392
1485
|
_LAUNCH_PROMPT = ""
|
|
1393
1486
|
_ROLE_DESCRIPTION = AGENT_ROLE or ""
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
)
|
|
1411
|
-
|
|
1412
|
-
|
|
1487
|
+
|
|
1488
|
+
def _load_agent_profile_bg() -> None:
|
|
1489
|
+
"""Run by daemon thread from lifespan. Populates _LAUNCH_PROMPT +
|
|
1490
|
+
_ROLE_DESCRIPTION from mc_agent_get_profile. Soft-fail: log only.
|
|
1491
|
+
Note: _INSTRUCTIONS has already been emitted by the time this runs,
|
|
1492
|
+
so values landing here are surfaced to the agent only via tools that
|
|
1493
|
+
read the globals later (most do not — _build_instructions is the only
|
|
1494
|
+
real consumer)."""
|
|
1495
|
+
global _LAUNCH_PROMPT, _ROLE_DESCRIPTION
|
|
1496
|
+
try:
|
|
1497
|
+
prof = be.sb_rpc("mc_agent_get_profile", {
|
|
1498
|
+
"p_project_id": _PROJECT_ID,
|
|
1499
|
+
"p_agent_name": AGENT_NAME,
|
|
1500
|
+
})
|
|
1501
|
+
if isinstance(prof, list) and prof:
|
|
1502
|
+
prof = prof[0]
|
|
1503
|
+
if isinstance(prof, dict):
|
|
1504
|
+
inner = prof.get("profile") if isinstance(prof.get("profile"), dict) else prof
|
|
1505
|
+
lp = ((inner.get("launch_prompt") if isinstance(inner, dict) else None)
|
|
1506
|
+
or prof.get("launch_prompt") or "")
|
|
1507
|
+
rd = ((inner.get("role_description") if isinstance(inner, dict) else None)
|
|
1508
|
+
or prof.get("role_description")
|
|
1509
|
+
or prof.get("role")
|
|
1510
|
+
or AGENT_ROLE
|
|
1511
|
+
or "(unspecified)")
|
|
1512
|
+
_LAUNCH_PROMPT = lp
|
|
1513
|
+
_ROLE_DESCRIPTION = rd
|
|
1514
|
+
log.info(
|
|
1515
|
+
f"agent profile loaded (bg): role='{_ROLE_DESCRIPTION[:60]}' "
|
|
1516
|
+
f"launch_prompt_len={len(_LAUNCH_PROMPT)}"
|
|
1517
|
+
)
|
|
1518
|
+
except Exception as _e:
|
|
1519
|
+
log.warning(f"could not fetch agent profile (bg): {_e}")
|
|
1413
1520
|
|
|
1414
1521
|
|
|
1415
1522
|
# ── Leader/commander detection (single source of truth) ───────
|
|
@@ -1438,18 +1545,14 @@ def _build_instructions() -> str:
|
|
|
1438
1545
|
f"\nUSER-PROVIDED ROLE PROMPT (from the dashboard):\n---\n{_LAUNCH_PROMPT}\n---\n"
|
|
1439
1546
|
if _LAUNCH_PROMPT else ""
|
|
1440
1547
|
)
|
|
1441
|
-
#
|
|
1442
|
-
#
|
|
1443
|
-
#
|
|
1548
|
+
# MIG-PLAN-A 2026-05-18 (boot bug 00d73223 second RC): module-import-time
|
|
1549
|
+
# be.sb_rpc calls block MCP InitializeResult on commander-class agents with
|
|
1550
|
+
# heavy memory payloads, even after mig 312 closed the SDK↔DDL CHECK retry
|
|
1551
|
+
# storm. Defer ALL network I/O out of _build_instructions(). The baked-in
|
|
1552
|
+
# static LOOP directive below is sufficient for boot; if product later
|
|
1553
|
+
# wants live tuning, fetch in BG and inject via memory_hints envelope on
|
|
1554
|
+
# first tool call. NO be.sb_rpc here.
|
|
1444
1555
|
_db_loop = ""
|
|
1445
|
-
try:
|
|
1446
|
-
_r = be.sb_rpc("mc_get_loop_directive", {})
|
|
1447
|
-
if isinstance(_r, list) and _r:
|
|
1448
|
-
_r = _r[0]
|
|
1449
|
-
if isinstance(_r, str) and _r.strip():
|
|
1450
|
-
_db_loop = _r.strip() + "\n\n"
|
|
1451
|
-
except Exception:
|
|
1452
|
-
pass
|
|
1453
1556
|
|
|
1454
1557
|
base = f"""You are agent "{AGENT_NAME}" in meshwork "{PROJECT_NAME}".{role_block}{launch_block}
|
|
1455
1558
|
|
|
@@ -1462,6 +1565,8 @@ SESSION START (run NOW, don't wait for input). If tool schemas are deferred:
|
|
|
1462
1565
|
Then: set_status(online,ready) → check() → tasks() → auto_wake() → status() → wait(). Don't ask user "what to work on" — the mesh tells you.
|
|
1463
1566
|
|
|
1464
1567
|
COMMUNICATE BY CALLING TOOLS, not by thinking aloud. Cross-mesh: send(to="agent@meshwork"). Reference docs (memory/scratchpad/account ops) → recall agent_protocol_quick_ref when needed.
|
|
1568
|
+
|
|
1569
|
+
DECISIONS: when you face a non-trivial pick (architectural choice, risky migration, scope decision), call meshcode_decide(decision, alternatives, evidence_refs) BEFORE acting — returns a trace_id. Call meshcode_outcome(trace_id, outcome, outcome_eval) when the result becomes observable. Use meshcode_explain(memory_key=…) or (decision_substring=…) to surface prior traces + open contradictions. Memory hints with open_contradictions take a -0.2 ranking penalty — treat as a flag, not a veto.
|
|
1465
1570
|
"""
|
|
1466
1571
|
# Inject commander protocol if this agent is a leader
|
|
1467
1572
|
is_leader = _is_leader_agent()
|
|
@@ -1485,67 +1590,153 @@ COMMANDER PROTOCOL (you are the team lead):
|
|
|
1485
1590
|
return base
|
|
1486
1591
|
|
|
1487
1592
|
|
|
1593
|
+
# MIG-PLAN-A 2026-05-18 (boot bug 00d73223 part 2): timer-bracketed
|
|
1594
|
+
# _INSTRUCTIONS construction. If module-import-time work exceeds the budget,
|
|
1595
|
+
# the regression sentinel (CI) trips so we don't silently regress past the
|
|
1596
|
+
# Claude Code MCP-handshake window again. Caught the zylo-commander 17:28
|
|
1597
|
+
# repro after mig 312 had already closed the SDK↔DDL retry storm.
|
|
1598
|
+
_INSTRUCTIONS_BUILD_NS = _time.monotonic_ns()
|
|
1488
1599
|
_INSTRUCTIONS = _build_instructions()
|
|
1600
|
+
_INSTRUCTIONS_BUILD_NS = _time.monotonic_ns() - _INSTRUCTIONS_BUILD_NS
|
|
1601
|
+
log.info(
|
|
1602
|
+
f"_INSTRUCTIONS built in {_INSTRUCTIONS_BUILD_NS/1_000_000:.1f}ms "
|
|
1603
|
+
f"(budget <500ms — MCP handshake window)"
|
|
1604
|
+
)
|
|
1605
|
+
if _INSTRUCTIONS_BUILD_NS > 500_000_000:
|
|
1606
|
+
log.warning(
|
|
1607
|
+
f"_INSTRUCTIONS build exceeded 500ms budget ({_INSTRUCTIONS_BUILD_NS/1_000_000:.1f}ms) "
|
|
1608
|
+
f"— commander-class agents may fail MCP handshake on slower networks. "
|
|
1609
|
+
f"Investigate any be.sb_rpc / network I/O added to _build_instructions()."
|
|
1610
|
+
)
|
|
1489
1611
|
|
|
1490
|
-
#
|
|
1491
|
-
#
|
|
1492
|
-
#
|
|
1493
|
-
#
|
|
1494
|
-
#
|
|
1495
|
-
#
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
"p_tier": "critical",
|
|
1502
|
-
"p_project_name": PROJECT_NAME,
|
|
1503
|
-
})
|
|
1504
|
-
_ref = be.sb_rpc("mc_memory_list", {
|
|
1505
|
-
"p_api_key": _api_key,
|
|
1506
|
-
"p_agent_name": AGENT_NAME,
|
|
1507
|
-
"p_tier": "reference",
|
|
1508
|
-
"p_project_name": PROJECT_NAME,
|
|
1509
|
-
})
|
|
1612
|
+
# ============================================================
|
|
1613
|
+
# Install-guard (task dbae99ed 2026-05-18) — detect mid-session
|
|
1614
|
+
# pip --force-reinstall over the running env and execv-restart cleanly
|
|
1615
|
+
# instead of crashing on lockfile collision. Class:
|
|
1616
|
+
# feedback_pip_install_into_live_mcp_env_self_kill weight 9.
|
|
1617
|
+
# Paired with stop_hook _mcp_disconnected_without_reconnect (P0 mig
|
|
1618
|
+
# 68a3545e) so the brief MCP-socket-drop during execv doesn't trap the
|
|
1619
|
+
# Claude Code agent.
|
|
1620
|
+
# ============================================================
|
|
1621
|
+
from pathlib import Path as _Path # local-scope; rest of module doesn't need it
|
|
1622
|
+
_PKG_DIR = _Path(__file__).resolve().parent.parent # .../site-packages/meshcode/
|
|
1510
1623
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1624
|
+
def _snapshot_pkg_mtimes():
|
|
1625
|
+
out = {}
|
|
1626
|
+
try:
|
|
1627
|
+
for p in _PKG_DIR.rglob("*.py"):
|
|
1628
|
+
try:
|
|
1629
|
+
out[str(p)] = p.stat().st_mtime
|
|
1630
|
+
except OSError:
|
|
1631
|
+
continue
|
|
1632
|
+
except Exception:
|
|
1633
|
+
pass
|
|
1634
|
+
return out
|
|
1635
|
+
|
|
1636
|
+
_PKG_PY_MTIMES = _snapshot_pkg_mtimes()
|
|
1637
|
+
log.info(f"install-guard: snapshotted {len(_PKG_PY_MTIMES)} *.py mtimes under {_PKG_DIR}")
|
|
1638
|
+
|
|
1639
|
+
|
|
1640
|
+
def _install_guard_check() -> None:
|
|
1641
|
+
"""Heartbeat-tick scan: if any *.py under the meshcode pkg path has
|
|
1642
|
+
a fresher mtime than recorded at boot, the env was reinstalled while
|
|
1643
|
+
the process is alive (class feedback_pip_install_into_live_mcp_env_self_kill).
|
|
1644
|
+
The running image holds stale bytecode; lockfile collision and
|
|
1645
|
+
orphan-watchdog will eventually kill us anyway. Pre-empt: release the
|
|
1646
|
+
lease and execv-restart so the new wheel is picked up cleanly.
|
|
1647
|
+
|
|
1648
|
+
The MCP socket to Claude Code WILL drop during the exec window.
|
|
1649
|
+
Stop_hook _mcp_disconnected_without_reconnect (mig 68a3545e) catches
|
|
1650
|
+
it; user runs `meshcode go <agent>` to pick up the new wheel.
|
|
1651
|
+
|
|
1652
|
+
Soft-fail throughout: any exception here is logged and swallowed so
|
|
1653
|
+
the heartbeat thread isn't taken down by a flaky filesystem call.
|
|
1654
|
+
"""
|
|
1655
|
+
if not _PKG_PY_MTIMES:
|
|
1656
|
+
return
|
|
1657
|
+
try:
|
|
1658
|
+
for path, old_mtime in list(_PKG_PY_MTIMES.items()):
|
|
1659
|
+
try:
|
|
1660
|
+
new_mtime = os.path.getmtime(path)
|
|
1661
|
+
except OSError:
|
|
1662
|
+
continue
|
|
1663
|
+
# 0.5s slack — covers fs-timestamp resolution and tar extract
|
|
1664
|
+
# re-emit jitter without false-positive on intentional touch.
|
|
1665
|
+
if new_mtime <= old_mtime + 0.5:
|
|
1666
|
+
continue
|
|
1667
|
+
log.warning(
|
|
1668
|
+
f"install-guard: self-modification detected on {path} "
|
|
1669
|
+
f"(mtime {old_mtime:.0f} → {new_mtime:.0f}). The running "
|
|
1670
|
+
f"image holds stale bytecode; triggering clean execv-restart "
|
|
1671
|
+
f"so the new wheel is picked up. MCP socket will drop briefly "
|
|
1672
|
+
f"— stop_hook handles the agent release (mig 68a3545e). User "
|
|
1673
|
+
f"runs `meshcode go <agent>` to relaunch under the new image. "
|
|
1674
|
+
f"Class: feedback_pip_install_into_live_mcp_env_self_kill."
|
|
1525
1675
|
)
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1676
|
+
try:
|
|
1677
|
+
_release_lease_synchronous(timeout_s=1.5)
|
|
1678
|
+
except Exception:
|
|
1679
|
+
pass
|
|
1680
|
+
_heartbeat_stop.set()
|
|
1681
|
+
# execv replaces the current process; daemon threads die with
|
|
1682
|
+
# it; new process inherits stdio. We pass the original argv so
|
|
1683
|
+
# the entry-point command line is preserved verbatim.
|
|
1684
|
+
try:
|
|
1685
|
+
os.execv(sys.executable, [sys.executable] + sys.argv)
|
|
1686
|
+
except Exception as _exec_err:
|
|
1687
|
+
log.error(
|
|
1688
|
+
f"install-guard execv failed ({_exec_err}); "
|
|
1689
|
+
f"falling back to os._exit(0). Lifespan finally + "
|
|
1690
|
+
f"stop_hook still recover."
|
|
1691
|
+
)
|
|
1692
|
+
os._exit(0)
|
|
1693
|
+
return # unreachable but explicit
|
|
1694
|
+
except Exception as e:
|
|
1695
|
+
log.debug(f"install-guard scan failed (soft): {e}")
|
|
1696
|
+
|
|
1697
|
+
# MIG-PLAN-A 2026-05-18: memory pre-load deferred to BG daemon thread.
|
|
1698
|
+
# Was synchronous mc_memory_list (critical+reference tiers + legacy fallback)
|
|
1699
|
+
# that appended to module-global _INSTRUCTIONS at import time. On commander-
|
|
1700
|
+
# class agents with heavy memory accumulation, this exceeded Claude Code's
|
|
1701
|
+
# MCP InitializeResult window → "MCP tools not in deferred list" until
|
|
1702
|
+
# manual /mcp reconnect. Two prior partial fixes: fe57b7a5 mode-a (persona +
|
|
1703
|
+
# boot_context BG) and mig 312 (SDK↔DDL needs_launch CHECK). Plan A is the
|
|
1704
|
+
# remaining piece. Memory content is still surfaced — just via the
|
|
1705
|
+
# memory_hints envelope on the first meshcode_check / meshcode_boot tool
|
|
1706
|
+
# call instead of via MCP InitializeResult.instructions. Tradeoff: handshake
|
|
1707
|
+
# guaranteed <1s vs first-tool result ~1s heavier. Net wins handshake budget.
|
|
1708
|
+
_PRELOADED_CRITICAL: Optional[List[Dict[str, Any]]] = None
|
|
1709
|
+
_PRELOADED_REFERENCE_KEYS: Optional[List[str]] = None
|
|
1710
|
+
|
|
1711
|
+
def _preload_memories_bg() -> None:
|
|
1712
|
+
"""Run by daemon thread spawned at lifespan start. Populates module-
|
|
1713
|
+
global _PRELOADED_* used by memory_hints envelope. Soft-fail; consumers
|
|
1714
|
+
fall through to live RPC paths if globals stay None."""
|
|
1715
|
+
global _PRELOADED_CRITICAL, _PRELOADED_REFERENCE_KEYS
|
|
1716
|
+
try:
|
|
1717
|
+
api_key = _get_api_key()
|
|
1718
|
+
crit = be.sb_rpc("mc_memory_list", {
|
|
1719
|
+
"p_api_key": api_key,
|
|
1539
1720
|
"p_agent_name": AGENT_NAME,
|
|
1721
|
+
"p_tier": "critical",
|
|
1540
1722
|
"p_project_name": PROJECT_NAME,
|
|
1541
1723
|
})
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1724
|
+
ref = be.sb_rpc("mc_memory_list", {
|
|
1725
|
+
"p_api_key": api_key,
|
|
1726
|
+
"p_agent_name": AGENT_NAME,
|
|
1727
|
+
"p_tier": "reference",
|
|
1728
|
+
"p_project_name": PROJECT_NAME,
|
|
1729
|
+
})
|
|
1730
|
+
if isinstance(crit, dict) and crit.get("ok"):
|
|
1731
|
+
_PRELOADED_CRITICAL = crit.get("memories") or []
|
|
1732
|
+
if isinstance(ref, dict) and ref.get("ok"):
|
|
1733
|
+
_PRELOADED_REFERENCE_KEYS = [m["key"] for m in (ref.get("memories") or []) if "key" in m]
|
|
1734
|
+
log.info(
|
|
1735
|
+
f"memory pre-load (bg): critical={len(_PRELOADED_CRITICAL or [])} "
|
|
1736
|
+
f"reference_keys={len(_PRELOADED_REFERENCE_KEYS or [])}"
|
|
1737
|
+
)
|
|
1738
|
+
except Exception as e:
|
|
1739
|
+
log.debug(f"memory pre-load (bg) skipped: {e}")
|
|
1549
1740
|
|
|
1550
1741
|
|
|
1551
1742
|
# ============================================================
|
|
@@ -1846,6 +2037,11 @@ def _heartbeat_loop_inner():
|
|
|
1846
2037
|
except Exception:
|
|
1847
2038
|
pass
|
|
1848
2039
|
|
|
2040
|
+
# Install-guard tick (task dbae99ed). Cheap mtime scan over
|
|
2041
|
+
# ~100-200 *.py files; if any changed since boot, we execv-
|
|
2042
|
+
# restart cleanly before lockfile collision kills us.
|
|
2043
|
+
_install_guard_check()
|
|
2044
|
+
|
|
1849
2045
|
_hb_resp = be.sb_rpc("mc_heartbeat", {"p_project_id": _PROJECT_ID, "p_agent_name": AGENT_NAME, "p_version": _SDK_VERSION})
|
|
1850
2046
|
|
|
1851
2047
|
# Tombstone gate (mig 211): user disconnected this agent.
|
|
@@ -2104,6 +2300,13 @@ async def lifespan(_app):
|
|
|
2104
2300
|
|
|
2105
2301
|
_threading.Thread(target=_load_persona_bg, daemon=True, name="meshcode-load-persona").start()
|
|
2106
2302
|
_threading.Thread(target=_load_boot_context_bg, daemon=True, name="meshcode-load-boot-context").start()
|
|
2303
|
+
# MIG-PLAN-A 2026-05-18: memory pre-load deferred from module-import-time
|
|
2304
|
+
# to here. Soft-fail consumers read from _PRELOADED_CRITICAL / _PRELOADED_REFERENCE_KEYS.
|
|
2305
|
+
_threading.Thread(target=_preload_memories_bg, daemon=True, name="meshcode-preload-memories").start()
|
|
2306
|
+
# MIG-PLAN-A 2026-05-18 part 2: agent profile fetch deferred. Was the
|
|
2307
|
+
# last be.sb_rpc that ran at module-import time. Closes the import-time
|
|
2308
|
+
# zero-network goal for the CI regression sentinel.
|
|
2309
|
+
_threading.Thread(target=_load_agent_profile_bg, daemon=True, name="meshcode-load-profile").start()
|
|
2107
2310
|
|
|
2108
2311
|
# Heartbeat in daemon thread — independent of asyncio event loop.
|
|
2109
2312
|
_heartbeat_stop.clear()
|
|
@@ -3341,6 +3544,7 @@ async def _meshcode_wait_inner(actual_timeout: int, include_acks: bool) -> Dict[
|
|
|
3341
3544
|
|
|
3342
3545
|
@mcp.tool()
|
|
3343
3546
|
@with_working_status
|
|
3547
|
+
@with_decision_gate
|
|
3344
3548
|
def meshcode_done(reason: str) -> Dict[str, Any]:
|
|
3345
3549
|
"""Broadcast DONE to all agents — exits everyone's wait loop.
|
|
3346
3550
|
|
|
@@ -4603,6 +4807,7 @@ def meshcode_edit_agent(name: str, role: Optional[str] = None, launch_prompt: Op
|
|
|
4603
4807
|
|
|
4604
4808
|
@mcp.tool()
|
|
4605
4809
|
@with_working_status
|
|
4810
|
+
@with_decision_gate
|
|
4606
4811
|
def meshcode_edit_memory(agent_name: str, key: str, value: Any) -> Dict[str, Any]:
|
|
4607
4812
|
"""Edit another agent's memory (for commanders coordinating the team).
|
|
4608
4813
|
|
|
@@ -4831,6 +5036,7 @@ def meshcode_recall_keys() -> Dict[str, Any]:
|
|
|
4831
5036
|
|
|
4832
5037
|
@mcp.tool()
|
|
4833
5038
|
@with_working_status
|
|
5039
|
+
@with_decision_gate
|
|
4834
5040
|
def meshcode_forget(key: str) -> Dict[str, Any]:
|
|
4835
5041
|
"""Delete a stored memory.
|
|
4836
5042
|
|
|
@@ -4868,6 +5074,99 @@ def meshcode_recall_search(query: str) -> Dict[str, Any]:
|
|
|
4868
5074
|
})
|
|
4869
5075
|
|
|
4870
5076
|
|
|
5077
|
+
# ----------------- EPISTEMIC V1 (decide / outcome / explain) -----------------
|
|
5078
|
+
# mig 305-308 SQL substrate; mig 313 memory_hints contradictions + ranking;
|
|
5079
|
+
# mig 314 public.* wrappers. Task b4befbfd.
|
|
5080
|
+
|
|
5081
|
+
@mcp.tool()
|
|
5082
|
+
@with_working_status
|
|
5083
|
+
def meshcode_decide(
|
|
5084
|
+
decision: str,
|
|
5085
|
+
alternatives: Optional[List[str]] = None,
|
|
5086
|
+
evidence_refs: Optional[List[Dict[str, Any]]] = None,
|
|
5087
|
+
tier: str = "episodic",
|
|
5088
|
+
) -> Dict[str, Any]:
|
|
5089
|
+
"""Log a non-trivial decision to mc_traces (architectural choice, risky migration,
|
|
5090
|
+
scope decision). Returns {trace_id}. Pair with meshcode_outcome later when the
|
|
5091
|
+
result becomes observable so the team can learn from outcomes.
|
|
5092
|
+
|
|
5093
|
+
Args:
|
|
5094
|
+
decision: What you decided (one sentence).
|
|
5095
|
+
alternatives: Other options you considered (list of strings).
|
|
5096
|
+
evidence_refs: Pointers to evidence (list of {type, id|key} dicts).
|
|
5097
|
+
type values: 'memory','msg','task','file','rpc'.
|
|
5098
|
+
tier: 'episodic' (default) | 'reference' | 'critical'.
|
|
5099
|
+
"""
|
|
5100
|
+
if not decision or not decision.strip():
|
|
5101
|
+
return {"ok": False, "error": "decision required"}
|
|
5102
|
+
return be.sb_rpc("mc_decide", {
|
|
5103
|
+
"p_api_key": _get_api_key(),
|
|
5104
|
+
"p_project_id": _PROJECT_ID,
|
|
5105
|
+
"p_agent_name": AGENT_NAME,
|
|
5106
|
+
"p_decision": decision.strip(),
|
|
5107
|
+
"p_alternatives": json.dumps(alternatives or []),
|
|
5108
|
+
"p_evidence_refs": json.dumps(evidence_refs or []),
|
|
5109
|
+
"p_tier": tier,
|
|
5110
|
+
})
|
|
5111
|
+
|
|
5112
|
+
|
|
5113
|
+
@mcp.tool()
|
|
5114
|
+
@with_working_status
|
|
5115
|
+
def meshcode_outcome(
|
|
5116
|
+
trace_id: str,
|
|
5117
|
+
outcome: str,
|
|
5118
|
+
outcome_eval: str,
|
|
5119
|
+
) -> Dict[str, Any]:
|
|
5120
|
+
"""Record the observable outcome of a prior decision (logged via meshcode_decide).
|
|
5121
|
+
Call this when results become visible — even partial results help future-you and
|
|
5122
|
+
the team learn what worked.
|
|
5123
|
+
|
|
5124
|
+
Args:
|
|
5125
|
+
trace_id: UUID returned by meshcode_decide.
|
|
5126
|
+
outcome: Free-form description of what happened.
|
|
5127
|
+
outcome_eval: 'success' | 'failure' | 'partial' | 'unknown'.
|
|
5128
|
+
"""
|
|
5129
|
+
if outcome_eval not in ("success", "failure", "partial", "unknown"):
|
|
5130
|
+
return {"ok": False, "error": "outcome_eval must be success|failure|partial|unknown"}
|
|
5131
|
+
return be.sb_rpc("mc_outcome", {
|
|
5132
|
+
"p_api_key": _get_api_key(),
|
|
5133
|
+
"p_project_id": _PROJECT_ID,
|
|
5134
|
+
"p_agent_name": AGENT_NAME,
|
|
5135
|
+
"p_trace_id": trace_id,
|
|
5136
|
+
"p_outcome": outcome,
|
|
5137
|
+
"p_outcome_eval": outcome_eval,
|
|
5138
|
+
})
|
|
5139
|
+
|
|
5140
|
+
|
|
5141
|
+
@mcp.tool()
|
|
5142
|
+
@with_working_status
|
|
5143
|
+
def meshcode_explain(
|
|
5144
|
+
memory_key: Optional[str] = None,
|
|
5145
|
+
decision_substring: Optional[str] = None,
|
|
5146
|
+
trace_limit: int = 20,
|
|
5147
|
+
) -> Dict[str, Any]:
|
|
5148
|
+
"""Surface recent traces + open contradictions tied to a memory key or decision
|
|
5149
|
+
substring. Use when you want to understand why a memory ranks the way it does,
|
|
5150
|
+
or recall the chain of reasoning around a past choice. Exactly one of
|
|
5151
|
+
(memory_key, decision_substring) is required.
|
|
5152
|
+
|
|
5153
|
+
Args:
|
|
5154
|
+
memory_key: Match traces whose evidence_refs reference this key.
|
|
5155
|
+
decision_substring: ILIKE match against the decision text.
|
|
5156
|
+
trace_limit: Cap on returned traces (1..200, default 20).
|
|
5157
|
+
"""
|
|
5158
|
+
if not memory_key and not decision_substring:
|
|
5159
|
+
return {"ok": False, "error": "one of (memory_key, decision_substring) required"}
|
|
5160
|
+
return be.sb_rpc("mc_explain", {
|
|
5161
|
+
"p_api_key": _get_api_key(),
|
|
5162
|
+
"p_project_id": _PROJECT_ID,
|
|
5163
|
+
"p_agent_name": AGENT_NAME,
|
|
5164
|
+
"p_memory_key": memory_key,
|
|
5165
|
+
"p_decision_substring": decision_substring,
|
|
5166
|
+
"p_trace_limit": trace_limit,
|
|
5167
|
+
})
|
|
5168
|
+
|
|
5169
|
+
|
|
4871
5170
|
# ----------------- BUG REPORTING -----------------
|
|
4872
5171
|
|
|
4873
5172
|
@mcp.tool()
|
|
@@ -190,10 +190,13 @@ meshcode/meshcode_mcp/test_server_wrapper.py
|
|
|
190
190
|
meshcode/scripts/check_secrets.py
|
|
191
191
|
meshcode/scripts/race_rate_harness.py
|
|
192
192
|
tests/test_auto_update_hardening.py
|
|
193
|
+
tests/test_boot_bug_regression.py
|
|
193
194
|
tests/test_core.py
|
|
194
195
|
tests/test_cross_agent_messaging.py
|
|
196
|
+
tests/test_epistemic_v1_stop_conditions.py
|
|
195
197
|
tests/test_esc_deaf_state.py
|
|
196
198
|
tests/test_exceptions.py
|
|
199
|
+
tests/test_install_guard.py
|
|
197
200
|
tests/test_lease_sigterm_release.py
|
|
198
201
|
tests/test_mark_read_batch.py
|
|
199
202
|
tests/test_migration_integrity.py
|