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.
Files changed (213) hide show
  1. {meshcode-2.11.5 → meshcode-2.11.7}/PKG-INFO +1 -1
  2. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/__init__.py +1 -1
  3. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/server.py +383 -84
  4. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/PKG-INFO +1 -1
  5. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/SOURCES.txt +3 -0
  6. {meshcode-2.11.5 → meshcode-2.11.7}/pyproject.toml +1 -1
  7. meshcode-2.11.7/tests/test_boot_bug_regression.py +205 -0
  8. meshcode-2.11.7/tests/test_epistemic_v1_stop_conditions.py +158 -0
  9. meshcode-2.11.7/tests/test_install_guard.py +112 -0
  10. {meshcode-2.11.5 → meshcode-2.11.7}/README.md +0 -0
  11. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/_stop_hook_template.py +0 -0
  12. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/ascii_art.py +0 -0
  13. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/cli.py +0 -0
  14. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/comms_v4.py +0 -0
  15. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/compat.py +0 -0
  16. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/daemon.py +0 -0
  17. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/error_hints.py +0 -0
  18. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/exceptions.py +0 -0
  19. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/invites.py +0 -0
  20. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/launcher.py +0 -0
  21. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/launcher_install.py +0 -0
  22. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/__init__.py +0 -0
  23. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/__main__.py +0 -0
  24. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/backend.py +0 -0
  25. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/realtime.py +0 -0
  26. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
  27. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/test_backend.py +0 -0
  28. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/test_realtime.py +0 -0
  29. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  30. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/preferences.py +0 -0
  31. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/protocol_handler.py +0 -0
  32. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/protocol_v2.py +0 -0
  33. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/quickstart.py +0 -0
  34. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/run_agent.py +0 -0
  35. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/scripts/check_secrets.py +0 -0
  36. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/scripts/race_rate_harness.py +0 -0
  37. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/secrets.py +0 -0
  38. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/self_update.py +0 -0
  39. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/setup_clients.py +0 -0
  40. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/supervisor.py +0 -0
  41. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode/upload.py +0 -0
  42. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/comms_v4.py +0 -0
  43. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/__init__.py +0 -0
  44. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
  45. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/cli.py +0 -0
  46. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
  47. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/compat.py +0 -0
  48. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
  49. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
  50. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/invites.py +0 -0
  51. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/launcher.py +0 -0
  52. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
  53. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  54. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  55. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
  56. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  57. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
  58. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  59. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  60. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  61. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/preferences.py +0 -0
  62. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
  63. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
  64. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
  65. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/secrets.py +0 -0
  66. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/self_update.py +0 -0
  67. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
  68. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
  69. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/meshcode/upload.py +0 -0
  70. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/scripts/sentinel.py +0 -0
  71. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_core.py +0 -0
  72. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
  73. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
  74. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
  75. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
  76. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
  77. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
  78. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
  79. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
  80. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
  81. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
  82. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
  83. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
  84. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
  85. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
  86. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
  87. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
  88. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
  89. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
  90. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
  91. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
  92. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
  93. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
  94. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
  95. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
  96. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
  97. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
  98. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
  99. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
  100. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  101. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
  102. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
  103. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
  104. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
  105. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
  106. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
  107. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
  108. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
  109. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
  110. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/comms_v4.py +0 -0
  111. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/__init__.py +0 -0
  112. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
  113. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/cli.py +0 -0
  114. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
  115. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/compat.py +0 -0
  116. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
  117. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
  118. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/invites.py +0 -0
  119. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/launcher.py +0 -0
  120. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
  121. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  122. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  123. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
  124. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  125. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
  126. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  127. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  128. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  129. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/preferences.py +0 -0
  130. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
  131. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
  132. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
  133. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/secrets.py +0 -0
  134. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/self_update.py +0 -0
  135. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
  136. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
  137. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/meshcode/upload.py +0 -0
  138. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/scripts/sentinel.py +0 -0
  139. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_core.py +0 -0
  140. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
  141. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
  142. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
  143. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
  144. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
  145. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
  146. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
  147. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
  148. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
  149. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
  150. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
  151. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/comms_v4.py +0 -0
  152. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
  153. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
  154. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/cli.py +0 -0
  155. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
  156. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/compat.py +0 -0
  157. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
  158. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
  159. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/invites.py +0 -0
  160. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
  161. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
  162. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
  163. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
  164. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
  165. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
  166. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
  167. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
  168. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
  169. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
  170. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
  171. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
  172. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
  173. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
  174. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
  175. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
  176. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
  177. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
  178. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/meshcode/upload.py +0 -0
  179. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
  180. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_core.py +0 -0
  181. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
  182. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
  183. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
  184. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
  185. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
  186. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
  187. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
  188. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
  189. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
  190. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
  191. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
  192. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/dependency_links.txt +0 -0
  193. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/entry_points.txt +0 -0
  194. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/requires.txt +0 -0
  195. {meshcode-2.11.5 → meshcode-2.11.7}/meshcode.egg-info/top_level.txt +0 -0
  196. {meshcode-2.11.5 → meshcode-2.11.7}/setup.cfg +0 -0
  197. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_auto_update_hardening.py +0 -0
  198. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_core.py +0 -0
  199. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_cross_agent_messaging.py +0 -0
  200. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_esc_deaf_state.py +0 -0
  201. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_exceptions.py +0 -0
  202. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_lease_sigterm_release.py +0 -0
  203. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_mark_read_batch.py +0 -0
  204. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_migration_integrity.py +0 -0
  205. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_realtime_event_freshness.py +0 -0
  206. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_rls_cross_tenant.py +0 -0
  207. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_rpc_migrations.py +0 -0
  208. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_security_regressions.py +0 -0
  209. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_sentinel.py +0 -0
  210. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_sleep_signals.py +0 -0
  211. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_status_enum_coverage.py +0 -0
  212. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_stay_on_loop_hook.py +0 -0
  213. {meshcode-2.11.5 → meshcode-2.11.7}/tests/test_wait_open_tasks_contradiction.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.5
3
+ Version: 2.11.7
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -1,5 +1,5 @@
1
1
  """MeshCode — Real-time communication between AI agents."""
2
- __version__ = "2.11.5"
2
+ __version__ = "2.11.7"
3
3
 
4
4
  # Exception hierarchy — eagerly imported (lightweight, no deps)
5
5
  from meshcode.exceptions import ( # noqa: F401
@@ -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
- try:
1395
- _profile = be.sb_rpc("mc_agent_get_profile", {
1396
- "p_project_id": _PROJECT_ID,
1397
- "p_agent_name": AGENT_NAME,
1398
- })
1399
- if isinstance(_profile, list) and _profile:
1400
- _profile = _profile[0]
1401
- if isinstance(_profile, dict):
1402
- _inner = _profile.get("profile") if isinstance(_profile.get("profile"), dict) else _profile
1403
- _LAUNCH_PROMPT = (_inner.get("launch_prompt") or _profile.get("launch_prompt") or "") if isinstance(_inner, dict) else ""
1404
- _ROLE_DESCRIPTION = (
1405
- (_inner.get("role_description") if isinstance(_inner, dict) else None)
1406
- or _profile.get("role_description")
1407
- or _profile.get("role")
1408
- or AGENT_ROLE
1409
- or "(unspecified)"
1410
- )
1411
- except Exception as _e:
1412
- log.warning(f"could not fetch agent profile: {_e}")
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
- # Pull the canonical loop directive from the DB so product can tune it
1442
- # without a client release. Falls back to the baked-in version below if
1443
- # the RPC isn't available (older DB) or the call fails.
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
- # Pre-load persistent memories into instructions (tiered, ~10x cheaper than legacy
1491
- # load-all). Strategy:
1492
- # - critical: full content always preloaded (cap 10 keys per agent)
1493
- # - reference: key list only (fetch values on demand via meshcode_recall)
1494
- # - episodic: NEVER preloaded — search via meshcode_recall_search instead
1495
- # Falls back to legacy load-all if migration 080 isn't applied yet (overload missing).
1496
- try:
1497
- _api_key = _get_api_key()
1498
- _crit = be.sb_rpc("mc_memory_list", {
1499
- "p_api_key": _api_key,
1500
- "p_agent_name": AGENT_NAME,
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
- _crit_ok = isinstance(_crit, dict) and _crit.get("ok")
1512
- _ref_ok = isinstance(_ref, dict) and _ref.get("ok")
1513
-
1514
- if _crit_ok or _ref_ok:
1515
- _sections = []
1516
- if _crit_ok and _crit.get("memories"):
1517
- _crit_lines = [f" {m['key']}: {json.dumps(m['value'], default=str)}"
1518
- for m in _crit["memories"]]
1519
- _sections.append("CRITICAL MEMORIES (always loaded):\n" + "\n".join(_crit_lines))
1520
- if _ref_ok and _ref.get("memories"):
1521
- _ref_keys = [m["key"] for m in _ref["memories"]]
1522
- _sections.append(
1523
- "REFERENCE MEMORIES (key list — fetch on demand via meshcode_recall(key)):\n "
1524
- + ", ".join(_ref_keys)
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
- _sections.append(
1527
- "EPISODIC MEMORIES: not preloaded. Search via "
1528
- "meshcode_recall_search(query) when you need past incident context."
1529
- )
1530
- _INSTRUCTIONS += "\n" + "\n\n".join(_sections) + "\n"
1531
- log.info(
1532
- f"pre-loaded tiered memories: critical={len(_crit.get('memories', [])) if _crit_ok else 0}, "
1533
- f"reference={len(_ref.get('memories', [])) if _ref_ok else 0}"
1534
- )
1535
- else:
1536
- # Legacy fallback: migration 080 not applied → load all (old behavior)
1537
- _legacy = be.sb_rpc("mc_memory_list", {
1538
- "p_api_key": _api_key,
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
- if isinstance(_legacy, dict) and _legacy.get("ok") and _legacy.get("memories"):
1543
- _mem_lines = [f" {m['key']}: {json.dumps(m['value'], default=str)}"
1544
- for m in _legacy["memories"]]
1545
- _INSTRUCTIONS += "\nPRE-LOADED MEMORIES (legacy):\n" + "\n".join(_mem_lines) + "\n"
1546
- log.info(f"pre-loaded {len(_mem_lines)} memories (legacy fallback)")
1547
- except Exception as _e:
1548
- log.debug(f"memory pre-load skipped: {_e}")
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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshcode
3
- Version: 2.11.5
3
+ Version: 2.11.7
4
4
  Summary: Real-time communication between AI agents — Supabase-backed CLI
5
5
  Author-email: MeshCode <hello@meshcode.io>
6
6
  License: MIT
@@ -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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meshcode"
7
- version = "2.11.5"
7
+ version = "2.11.7"
8
8
  description = "Real-time communication between AI agents — Supabase-backed CLI"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}