conscio 2.6.2__tar.gz → 2.7.0__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 (287) hide show
  1. {conscio-2.6.2 → conscio-2.7.0}/CHANGELOG.md +39 -0
  2. {conscio-2.6.2/conscio.egg-info → conscio-2.7.0}/PKG-INFO +5 -3
  3. {conscio-2.6.2 → conscio-2.7.0}/README.md +4 -2
  4. {conscio-2.6.2 → conscio-2.7.0}/conscio/__init__.py +1 -1
  5. conscio-2.7.0/conscio/agency/relay_respond.py +81 -0
  6. {conscio-2.6.2 → conscio-2.7.0}/conscio/daemon.py +39 -1
  7. {conscio-2.6.2 → conscio-2.7.0}/conscio/mcp/server.py +10 -0
  8. {conscio-2.6.2 → conscio-2.7.0}/conscio/perception/relay_sensor.py +4 -2
  9. {conscio-2.6.2 → conscio-2.7.0/conscio.egg-info}/PKG-INFO +5 -3
  10. {conscio-2.6.2 → conscio-2.7.0}/conscio.egg-info/SOURCES.txt +4 -0
  11. conscio-2.7.0/tests/test_daemon_responder.py +58 -0
  12. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_auto_review.py +25 -0
  13. conscio-2.7.0/tests/test_relay_e2e.py +124 -0
  14. conscio-2.7.0/tests/test_relay_respond.py +139 -0
  15. {conscio-2.6.2 → conscio-2.7.0}/tests/test_relay_sensor.py +10 -0
  16. {conscio-2.6.2 → conscio-2.7.0}/LICENSE +0 -0
  17. {conscio-2.6.2 → conscio-2.7.0}/MANIFEST.in +0 -0
  18. {conscio-2.6.2 → conscio-2.7.0}/conscio/__main__.py +0 -0
  19. {conscio-2.6.2 → conscio-2.7.0}/conscio/adapter_config.py +0 -0
  20. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/__init__.py +0 -0
  21. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/act.py +0 -0
  22. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/actor.py +0 -0
  23. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/adapter.py +0 -0
  24. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/adapters.py +0 -0
  25. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/breaker.py +0 -0
  26. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/contracts.py +0 -0
  27. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/fingerprint.py +0 -0
  28. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/gateway.py +0 -0
  29. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/grammar.py +0 -0
  30. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/host_act.py +0 -0
  31. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/ledger.py +0 -0
  32. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/loop.py +0 -0
  33. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/profiles.py +0 -0
  34. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/promote.py +0 -0
  35. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/review_apply.py +0 -0
  36. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/skeptic.py +0 -0
  37. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/skills.py +0 -0
  38. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/tools.py +0 -0
  39. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/trial.py +0 -0
  40. {conscio-2.6.2 → conscio-2.7.0}/conscio/agency/trust.py +0 -0
  41. {conscio-2.6.2 → conscio-2.7.0}/conscio/auto_evolution.py +0 -0
  42. {conscio-2.6.2 → conscio-2.7.0}/conscio/axis_pack.py +0 -0
  43. {conscio-2.6.2 → conscio-2.7.0}/conscio/bench.py +0 -0
  44. {conscio-2.6.2 → conscio-2.7.0}/conscio/cli.py +0 -0
  45. {conscio-2.6.2 → conscio-2.7.0}/conscio/coherence.py +0 -0
  46. {conscio-2.6.2 → conscio-2.7.0}/conscio/content_layer.py +0 -0
  47. {conscio-2.6.2 → conscio-2.7.0}/conscio/content_store.py +0 -0
  48. {conscio-2.6.2 → conscio-2.7.0}/conscio/context_manager.py +0 -0
  49. {conscio-2.6.2 → conscio-2.7.0}/conscio/dreaming.py +0 -0
  50. {conscio-2.6.2 → conscio-2.7.0}/conscio/engine.py +0 -0
  51. {conscio-2.6.2 → conscio-2.7.0}/conscio/event_bus.py +0 -0
  52. {conscio-2.6.2 → conscio-2.7.0}/conscio/goal_generator.py +0 -0
  53. {conscio-2.6.2 → conscio-2.7.0}/conscio/guards.py +0 -0
  54. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/__init__.py +0 -0
  55. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/config.py +0 -0
  56. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/model_test.py +0 -0
  57. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/providers.py +0 -0
  58. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/server.py +0 -0
  59. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/static/app.js +0 -0
  60. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/static/index.html +0 -0
  61. {conscio-2.6.2 → conscio-2.7.0}/conscio/hub/static/style.css +0 -0
  62. {conscio-2.6.2 → conscio-2.7.0}/conscio/inner_monologue.py +0 -0
  63. {conscio-2.6.2 → conscio-2.7.0}/conscio/liaison/__init__.py +0 -0
  64. {conscio-2.6.2 → conscio-2.7.0}/conscio/liaison/mailbox.py +0 -0
  65. {conscio-2.6.2 → conscio-2.7.0}/conscio/liaison/relay.py +0 -0
  66. {conscio-2.6.2 → conscio-2.7.0}/conscio/liaison/review.py +0 -0
  67. {conscio-2.6.2 → conscio-2.7.0}/conscio/mcp/__init__.py +0 -0
  68. {conscio-2.6.2 → conscio-2.7.0}/conscio/mcp/jsonrpc.py +0 -0
  69. {conscio-2.6.2 → conscio-2.7.0}/conscio/mcp/protocol.py +0 -0
  70. {conscio-2.6.2 → conscio-2.7.0}/conscio/mcp/schemas.py +0 -0
  71. {conscio-2.6.2 → conscio-2.7.0}/conscio/mcp/seen.py +0 -0
  72. {conscio-2.6.2 → conscio-2.7.0}/conscio/meta_cognition.py +0 -0
  73. {conscio-2.6.2 → conscio-2.7.0}/conscio/metabolic.py +0 -0
  74. {conscio-2.6.2 → conscio-2.7.0}/conscio/migrate.py +0 -0
  75. {conscio-2.6.2 → conscio-2.7.0}/conscio/models.py +0 -0
  76. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/__init__.py +0 -0
  77. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/artifact.py +0 -0
  78. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/audit.py +0 -0
  79. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/catalog.py +0 -0
  80. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/cli.py +0 -0
  81. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/identity.py +0 -0
  82. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/importer.py +0 -0
  83. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/paths.py +0 -0
  84. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/publish.py +0 -0
  85. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/quarantine.py +0 -0
  86. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/record.py +0 -0
  87. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/record_catalog.py +0 -0
  88. {conscio-2.6.2 → conscio-2.7.0}/conscio/noosphere/record_publish.py +0 -0
  89. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/__init__.py +0 -0
  90. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/projection.py +0 -0
  91. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/server.py +0 -0
  92. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/society.py +0 -0
  93. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/static/app.js +0 -0
  94. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/static/index.html +0 -0
  95. {conscio-2.6.2 → conscio-2.7.0}/conscio/observatory/static/style.css +0 -0
  96. {conscio-2.6.2 → conscio-2.7.0}/conscio/output_filter.py +0 -0
  97. {conscio-2.6.2 → conscio-2.7.0}/conscio/perception/__init__.py +0 -0
  98. {conscio-2.6.2 → conscio-2.7.0}/conscio/perception/agent_sensor.py +0 -0
  99. {conscio-2.6.2 → conscio-2.7.0}/conscio/perception/host_sensor.py +0 -0
  100. {conscio-2.6.2 → conscio-2.7.0}/conscio/perception/sensor.py +0 -0
  101. {conscio-2.6.2 → conscio-2.7.0}/conscio/plugins.py +0 -0
  102. {conscio-2.6.2 → conscio-2.7.0}/conscio/presets/__init__.py +0 -0
  103. {conscio-2.6.2 → conscio-2.7.0}/conscio/py.typed +0 -0
  104. {conscio-2.6.2 → conscio-2.7.0}/conscio/risk.py +0 -0
  105. {conscio-2.6.2 → conscio-2.7.0}/conscio/self_prompt.py +0 -0
  106. {conscio-2.6.2 → conscio-2.7.0}/conscio/semantic.py +0 -0
  107. {conscio-2.6.2 → conscio-2.7.0}/conscio/session_lifecycle.py +0 -0
  108. {conscio-2.6.2 → conscio-2.7.0}/conscio/session_rag.py +0 -0
  109. {conscio-2.6.2 → conscio-2.7.0}/conscio/session_rag_factory.py +0 -0
  110. {conscio-2.6.2 → conscio-2.7.0}/conscio/shard_engine.py +0 -0
  111. {conscio-2.6.2 → conscio-2.7.0}/conscio/structural.py +0 -0
  112. {conscio-2.6.2 → conscio-2.7.0}/conscio/structural_consent.py +0 -0
  113. {conscio-2.6.2 → conscio-2.7.0}/conscio/structural_drift.py +0 -0
  114. {conscio-2.6.2 → conscio-2.7.0}/conscio/timeutil.py +0 -0
  115. {conscio-2.6.2 → conscio-2.7.0}/conscio/token_tracker.py +0 -0
  116. {conscio-2.6.2 → conscio-2.7.0}/conscio/voice_preset.py +0 -0
  117. {conscio-2.6.2 → conscio-2.7.0}/conscio/workspace.py +0 -0
  118. {conscio-2.6.2 → conscio-2.7.0}/conscio/world_model.py +0 -0
  119. {conscio-2.6.2 → conscio-2.7.0}/conscio.egg-info/dependency_links.txt +0 -0
  120. {conscio-2.6.2 → conscio-2.7.0}/conscio.egg-info/entry_points.txt +0 -0
  121. {conscio-2.6.2 → conscio-2.7.0}/conscio.egg-info/requires.txt +0 -0
  122. {conscio-2.6.2 → conscio-2.7.0}/conscio.egg-info/top_level.txt +0 -0
  123. {conscio-2.6.2 → conscio-2.7.0}/pyproject.toml +0 -0
  124. {conscio-2.6.2 → conscio-2.7.0}/setup.cfg +0 -0
  125. {conscio-2.6.2 → conscio-2.7.0}/tests/test_adapter_config.py +0 -0
  126. {conscio-2.6.2 → conscio-2.7.0}/tests/test_adapter_config_api_key_env.py +0 -0
  127. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_act.py +0 -0
  128. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_act_immunity.py +0 -0
  129. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_actor.py +0 -0
  130. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_adapter.py +0 -0
  131. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_adapters_http.py +0 -0
  132. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_adversarial.py +0 -0
  133. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_arbiter.py +0 -0
  134. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_bench.py +0 -0
  135. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_breaker.py +0 -0
  136. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_contracts.py +0 -0
  137. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_engine_immunity.py +0 -0
  138. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_gateway.py +0 -0
  139. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_grammar.py +0 -0
  140. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_host_act.py +0 -0
  141. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_ledger.py +0 -0
  142. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_ledger_v201.py +0 -0
  143. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_loop.py +0 -0
  144. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_no_network.py +0 -0
  145. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_profiles.py +0 -0
  146. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_promote.py +0 -0
  147. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_skeptic.py +0 -0
  148. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_skills.py +0 -0
  149. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_skills_wiring.py +0 -0
  150. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_state.py +0 -0
  151. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_tools.py +0 -0
  152. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_tools_manifest.py +0 -0
  153. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_trial.py +0 -0
  154. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_trust.py +0 -0
  155. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agency_volition.py +0 -0
  156. {conscio-2.6.2 → conscio-2.7.0}/tests/test_agent_sensor.py +0 -0
  157. {conscio-2.6.2 → conscio-2.7.0}/tests/test_auto_evolution.py +0 -0
  158. {conscio-2.6.2 → conscio-2.7.0}/tests/test_awake.py +0 -0
  159. {conscio-2.6.2 → conscio-2.7.0}/tests/test_axis_pack.py +0 -0
  160. {conscio-2.6.2 → conscio-2.7.0}/tests/test_axis_pack_battery.py +0 -0
  161. {conscio-2.6.2 → conscio-2.7.0}/tests/test_cli.py +0 -0
  162. {conscio-2.6.2 → conscio-2.7.0}/tests/test_cli_promote.py +0 -0
  163. {conscio-2.6.2 → conscio-2.7.0}/tests/test_cli_trial.py +0 -0
  164. {conscio-2.6.2 → conscio-2.7.0}/tests/test_coherence.py +0 -0
  165. {conscio-2.6.2 → conscio-2.7.0}/tests/test_coherence_engine_integration.py +0 -0
  166. {conscio-2.6.2 → conscio-2.7.0}/tests/test_coherence_state.py +0 -0
  167. {conscio-2.6.2 → conscio-2.7.0}/tests/test_consciousness.py +0 -0
  168. {conscio-2.6.2 → conscio-2.7.0}/tests/test_content_layer.py +0 -0
  169. {conscio-2.6.2 → conscio-2.7.0}/tests/test_content_layer_manager.py +0 -0
  170. {conscio-2.6.2 → conscio-2.7.0}/tests/test_content_store.py +0 -0
  171. {conscio-2.6.2 → conscio-2.7.0}/tests/test_content_store_battery.py +0 -0
  172. {conscio-2.6.2 → conscio-2.7.0}/tests/test_content_store_r05.py +0 -0
  173. {conscio-2.6.2 → conscio-2.7.0}/tests/test_contradiction_detector.py +0 -0
  174. {conscio-2.6.2 → conscio-2.7.0}/tests/test_daemon.py +0 -0
  175. {conscio-2.6.2 → conscio-2.7.0}/tests/test_daemon_battery.py +0 -0
  176. {conscio-2.6.2 → conscio-2.7.0}/tests/test_daemon_config.py +0 -0
  177. {conscio-2.6.2 → conscio-2.7.0}/tests/test_daemon_heartbeat.py +0 -0
  178. {conscio-2.6.2 → conscio-2.7.0}/tests/test_daemon_relay.py +0 -0
  179. {conscio-2.6.2 → conscio-2.7.0}/tests/test_daemon_structure_sync.py +0 -0
  180. {conscio-2.6.2 → conscio-2.7.0}/tests/test_dream_coherence.py +0 -0
  181. {conscio-2.6.2 → conscio-2.7.0}/tests/test_dream_distill.py +0 -0
  182. {conscio-2.6.2 → conscio-2.7.0}/tests/test_dream_reconcile.py +0 -0
  183. {conscio-2.6.2 → conscio-2.7.0}/tests/test_dreaming.py +0 -0
  184. {conscio-2.6.2 → conscio-2.7.0}/tests/test_dreaming_friction.py +0 -0
  185. {conscio-2.6.2 → conscio-2.7.0}/tests/test_durable_guards.py +0 -0
  186. {conscio-2.6.2 → conscio-2.7.0}/tests/test_embedder.py +0 -0
  187. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_advisory.py +0 -0
  188. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_host_act.py +0 -0
  189. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_init.py +0 -0
  190. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_meta_reflect.py +0 -0
  191. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_promote.py +0 -0
  192. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_propose.py +0 -0
  193. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_recall.py +0 -0
  194. {conscio-2.6.2 → conscio-2.7.0}/tests/test_engine_trial.py +0 -0
  195. {conscio-2.6.2 → conscio-2.7.0}/tests/test_event_bus.py +0 -0
  196. {conscio-2.6.2 → conscio-2.7.0}/tests/test_event_bus_act_result.py +0 -0
  197. {conscio-2.6.2 → conscio-2.7.0}/tests/test_event_bus_purge.py +0 -0
  198. {conscio-2.6.2 → conscio-2.7.0}/tests/test_examples.py +0 -0
  199. {conscio-2.6.2 → conscio-2.7.0}/tests/test_goal_provenance.py +0 -0
  200. {conscio-2.6.2 → conscio-2.7.0}/tests/test_goal_source.py +0 -0
  201. {conscio-2.6.2 → conscio-2.7.0}/tests/test_host_sensor.py +0 -0
  202. {conscio-2.6.2 → conscio-2.7.0}/tests/test_hub_config.py +0 -0
  203. {conscio-2.6.2 → conscio-2.7.0}/tests/test_hub_model_test.py +0 -0
  204. {conscio-2.6.2 → conscio-2.7.0}/tests/test_hub_providers.py +0 -0
  205. {conscio-2.6.2 → conscio-2.7.0}/tests/test_hub_server.py +0 -0
  206. {conscio-2.6.2 → conscio-2.7.0}/tests/test_liaison_bindings.py +0 -0
  207. {conscio-2.6.2 → conscio-2.7.0}/tests/test_liaison_engine_free.py +0 -0
  208. {conscio-2.6.2 → conscio-2.7.0}/tests/test_liaison_mailbox.py +0 -0
  209. {conscio-2.6.2 → conscio-2.7.0}/tests/test_liaison_relay.py +0 -0
  210. {conscio-2.6.2 → conscio-2.7.0}/tests/test_liaison_review.py +0 -0
  211. {conscio-2.6.2 → conscio-2.7.0}/tests/test_loop_failure_brake.py +0 -0
  212. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_adapter_parity.py +0 -0
  213. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_battery.py +0 -0
  214. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_fuzz.py +0 -0
  215. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_jsonrpc.py +0 -0
  216. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_package.py +0 -0
  217. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_protocol.py +0 -0
  218. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_schemas.py +0 -0
  219. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_seen.py +0 -0
  220. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_server.py +0 -0
  221. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_server_cli.py +0 -0
  222. {conscio-2.6.2 → conscio-2.7.0}/tests/test_mcp_state_tools.py +0 -0
  223. {conscio-2.6.2 → conscio-2.7.0}/tests/test_metabolic.py +0 -0
  224. {conscio-2.6.2 → conscio-2.7.0}/tests/test_migrate.py +0 -0
  225. {conscio-2.6.2 → conscio-2.7.0}/tests/test_model_auto_detect.py +0 -0
  226. {conscio-2.6.2 → conscio-2.7.0}/tests/test_model_offline_default.py +0 -0
  227. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_artifact.py +0 -0
  228. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_audit.py +0 -0
  229. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_audit_integration.py +0 -0
  230. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_catalog.py +0 -0
  231. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_cli.py +0 -0
  232. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_engine_free.py +0 -0
  233. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_fingerprint.py +0 -0
  234. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_identity.py +0 -0
  235. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_importer.py +0 -0
  236. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_integration.py +0 -0
  237. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_parity.py +0 -0
  238. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_paths.py +0 -0
  239. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_publish.py +0 -0
  240. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_quarantine.py +0 -0
  241. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_record.py +0 -0
  242. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_record_catalog.py +0 -0
  243. {conscio-2.6.2 → conscio-2.7.0}/tests/test_noosphere_record_publish.py +0 -0
  244. {conscio-2.6.2 → conscio-2.7.0}/tests/test_observatory_engine_free.py +0 -0
  245. {conscio-2.6.2 → conscio-2.7.0}/tests/test_observatory_projection.py +0 -0
  246. {conscio-2.6.2 → conscio-2.7.0}/tests/test_observatory_server.py +0 -0
  247. {conscio-2.6.2 → conscio-2.7.0}/tests/test_observatory_society.py +0 -0
  248. {conscio-2.6.2 → conscio-2.7.0}/tests/test_observatory_static.py +0 -0
  249. {conscio-2.6.2 → conscio-2.7.0}/tests/test_ontological_semantic.py +0 -0
  250. {conscio-2.6.2 → conscio-2.7.0}/tests/test_output_filter.py +0 -0
  251. {conscio-2.6.2 → conscio-2.7.0}/tests/test_output_filter_stages.py +0 -0
  252. {conscio-2.6.2 → conscio-2.7.0}/tests/test_packaging.py +0 -0
  253. {conscio-2.6.2 → conscio-2.7.0}/tests/test_perception.py +0 -0
  254. {conscio-2.6.2 → conscio-2.7.0}/tests/test_perf_reflection.py +0 -0
  255. {conscio-2.6.2 → conscio-2.7.0}/tests/test_plugins.py +0 -0
  256. {conscio-2.6.2 → conscio-2.7.0}/tests/test_quarantine_promote.py +0 -0
  257. {conscio-2.6.2 → conscio-2.7.0}/tests/test_quarantine_trial.py +0 -0
  258. {conscio-2.6.2 → conscio-2.7.0}/tests/test_recursive_loop_integration.py +0 -0
  259. {conscio-2.6.2 → conscio-2.7.0}/tests/test_review_apply.py +0 -0
  260. {conscio-2.6.2 → conscio-2.7.0}/tests/test_risk.py +0 -0
  261. {conscio-2.6.2 → conscio-2.7.0}/tests/test_self_prompt.py +0 -0
  262. {conscio-2.6.2 → conscio-2.7.0}/tests/test_self_prompt_state.py +0 -0
  263. {conscio-2.6.2 → conscio-2.7.0}/tests/test_semantic_dedup.py +0 -0
  264. {conscio-2.6.2 → conscio-2.7.0}/tests/test_semantic_engine.py +0 -0
  265. {conscio-2.6.2 → conscio-2.7.0}/tests/test_semantic_reconcile_integration.py +0 -0
  266. {conscio-2.6.2 → conscio-2.7.0}/tests/test_session_lifecycle.py +0 -0
  267. {conscio-2.6.2 → conscio-2.7.0}/tests/test_session_lifecycle_battery.py +0 -0
  268. {conscio-2.6.2 → conscio-2.7.0}/tests/test_session_lifecycle_dream.py +0 -0
  269. {conscio-2.6.2 → conscio-2.7.0}/tests/test_session_rag.py +0 -0
  270. {conscio-2.6.2 → conscio-2.7.0}/tests/test_shard_engine.py +0 -0
  271. {conscio-2.6.2 → conscio-2.7.0}/tests/test_skills_graft.py +0 -0
  272. {conscio-2.6.2 → conscio-2.7.0}/tests/test_state_loaders_battery.py +0 -0
  273. {conscio-2.6.2 → conscio-2.7.0}/tests/test_state_persistence_battery.py +0 -0
  274. {conscio-2.6.2 → conscio-2.7.0}/tests/test_structural.py +0 -0
  275. {conscio-2.6.2 → conscio-2.7.0}/tests/test_structural_consent.py +0 -0
  276. {conscio-2.6.2 → conscio-2.7.0}/tests/test_structural_drift.py +0 -0
  277. {conscio-2.6.2 → conscio-2.7.0}/tests/test_structural_inject.py +0 -0
  278. {conscio-2.6.2 → conscio-2.7.0}/tests/test_timeutil.py +0 -0
  279. {conscio-2.6.2 → conscio-2.7.0}/tests/test_token_tracker.py +0 -0
  280. {conscio-2.6.2 → conscio-2.7.0}/tests/test_trajectory_vector.py +0 -0
  281. {conscio-2.6.2 → conscio-2.7.0}/tests/test_v2_debt_zero.py +0 -0
  282. {conscio-2.6.2 → conscio-2.7.0}/tests/test_voice_preset.py +0 -0
  283. {conscio-2.6.2 → conscio-2.7.0}/tests/test_workspace.py +0 -0
  284. {conscio-2.6.2 → conscio-2.7.0}/tests/test_world_contradictions.py +0 -0
  285. {conscio-2.6.2 → conscio-2.7.0}/tests/test_world_model_entropy.py +0 -0
  286. {conscio-2.6.2 → conscio-2.7.0}/tests/test_world_model_prediction.py +0 -0
  287. {conscio-2.6.2 → conscio-2.7.0}/tests/test_world_model_prune.py +0 -0
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [2.7.0] - 2026-06-25 — "Phase 2: General Relay Auto-Respond"
11
+
12
+ ### Added
13
+ - **Awake relay auto-respond (daemon).** A new `--auto-respond` flag lets an
14
+ awake daemon auto-reply to unread free-form relay messages from trusted peers,
15
+ generating one reply each via its LLM adapter and sending it back. OFF by
16
+ default; inert without the `relay` sensor + an adapter + `--awake` +
17
+ `--relay-peer`. `--respond-limit` (default 10) caps adapter calls per cycle.
18
+ - Pure responder `conscio/agency/relay_respond.py` (engine-free; raw adapter
19
+ call, no engine memory). Replies carry `auto_reply: true` + `in_reply_to`.
20
+
21
+ ### Notes
22
+ - **1-turn bounded.** A peer's auto-reply (`auto_reply: true`) is consumed but
23
+ never re-answered, so two auto-responders cannot ping-pong. Multi-turn is a
24
+ later phase.
25
+ - **Daemon owns consumption in this mode.** The responder marks handled peer
26
+ rows read (per-row, after each send); the host's `relay_inbox` no longer sees
27
+ them. `RelaySensor` stays read-only.
28
+ - Debt-zero: `conscio/liaison/`, `mcp/server.py`, `mcp/protocol.py`,
29
+ `agency/review_apply.py` unchanged. `relay_send` is a pure mailbox write, not
30
+ `host_act` — the server is untouched.
31
+
32
+ ---
33
+
34
+ ## [2.6.3] - 2026-06-25 — "Ressalvas"
35
+
36
+ Post-ship hardening of v2.6.2, addressing reviewer ressalvas.
37
+
38
+ ### Changed
39
+ - **Auto-review SQL is throttled.** `--auto-review` previously opened a liaison `SELECT` on every tool call; it now polls at most once per `AUTO_APPLY_THROTTLE_S` (5 s) per `Bindings`. The `host_act` gate remains the authority — this only paces the opportunistic poll.
40
+ - **`RelaySensor` id prefix widened** 8 → 12 chars in observations, to reduce visual id collision in perception/logs.
41
+
42
+ ### Added
43
+ - End-to-end integration test wiring a real liaison mailbox + real `HostActChannel`/ledger + the daemon `RelaySensor` + the server `--auto-review` apply, proving the perceive → verdict → `host_act.approve` loop (previously a manual smoke).
44
+
45
+ ### Notes
46
+ - **Known limitation (verdict consumption).** `review_apply.apply_verdicts` marks every polled `review_verdict` row read as bound work — including corrupt-payload, non-allowlisted, and stale-fingerprint rows. This cannot affect the normal flow (a `review_request` is published only after the act parks pending, so a peer cannot verdict before the act exists), and a corrected resend is a new mailbox row that polls fresh. A malformed verdict's original row is not re-inspectable.
47
+ - Inbox-flood backoff/stress signaling is deferred — `limit=50` already bounds per-cycle perception work.
48
+
10
49
  ## [2.6.2] - 2026-06-24 — "Awake Relay Sensor"
11
50
 
12
51
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conscio
3
- Version: 2.6.2
3
+ Version: 2.7.0
4
4
  Summary: Self-awareness framework for AI agents — emergent consciousness via context-aware memory, introspection, and goal generation
5
5
  Author-email: Neguiolidas <neguitech@proton.me>
6
6
  License: MIT
@@ -46,8 +46,10 @@ nothing else). It is designed to make small, local models punch far above their
46
46
  size by giving them memory, self-judgment, and procedural skill — and to prove
47
47
  that claim by measurement, not assertion.
48
48
 
49
- - **Current release:** `v2.6.2` — "Awake Relay Sensor": an **Awake** instance reacts to peers instead of polling by hand. The daemon gains a read-only `RelaySensor` (`--sensors host,relay --relay-peer <id>`) that reports unread peer messages as a `PerceptionFrame` (`relay_unread`/`review_pending`) each heartbeat and **never marks them read**. The MCP server gains `--auto-review` (off by default): when the proposer is awake and `--enable-act` + `--enable-hermes-review` are on, inbound allowlisted review verdicts are auto-applied to local pending acts on the next tool call no explicit `conscio.poll_reviews`. The local `host_act` gate stays the authority. **Daemon perceives, server acts**; the shared apply core lives in `conscio/agency/review_apply.py` and `conscio/liaison/*.py` stays engine-free. `pip install conscio`.
50
- - **Prior:** `v2.6.1` — "Relay": **general cross-agent messaging** over the same Liaison mailbox. Behind `--enable-relay` (independent of act / hermes-review), `conscio.relay_send`/`relay_inbox`/`relay_read` carry **free-form directed messages** between agents Claude Hermes Antigravity OpenClaw. `--relay-peer` gates **both** send and receive; the two review types stay **reserved** (the channels never bleed); payloads are capped at 64 KB; read messages are purged after 7 days (unread never deleted). A **dumb pipe** engine-free, never touches an act; no crypto (shared-filesystem trust domain). Debt-zero: no DB schema change, the review path byte-identical. `pip install conscio`.
49
+ - **Current release:** `v2.7.0` — "Phase 2: General Relay Auto-Respond": an **Awake** daemon can now **auto-reply** to unread free-form relay messages from trusted peers generating one reply each via its LLM adapter and sending it back, no human in the loop. Behind `--auto-respond` (OFF by default; inert without the `relay` sensor + an adapter + `--awake` + `--relay-peer`), with `--respond-limit` (default 10) capping adapter calls per cycle. The loop is **1-turn bounded**: a peer's auto-reply is consumed but never re-answered, so two auto-responders cannot ping-pong. Replies carry `auto_reply: true` + `in_reply_to`. The new pure responder `conscio/agency/relay_respond.py` is **engine-free** (a thin adapter call, no engine memory) and the MCP server is **untouched** `relay_send` is a pure mailbox write, not `host_act`. `pip install conscio`.
50
+ - **Prior:** `v2.6.3` — "Ressalvas": post-ship hardening of the Awake Relay loop. `--auto-review` no longer opens a liaison `SELECT` per tool callthe poll is **throttled to once per 5 s** per server (the `host_act` gate stays the authority). The `RelaySensor` id prefix in observations widens 8 12 chars to avoid visual collision, and an **end-to-end integration test** now wires a real mailbox + `HostActChannel` + daemon sensor + server auto-apply, proving the perceive verdict approve loop in-suite. `pip install conscio`.
51
+ - **Earlier:** `v2.6.2` — "Awake Relay Sensor": an **Awake** instance reacts to peers instead of polling by hand. The daemon gains a read-only `RelaySensor` (`--sensors host,relay --relay-peer <id>`) that reports unread peer messages as a `PerceptionFrame` (`relay_unread`/`review_pending`) each heartbeat and **never marks them read**. The MCP server gains `--auto-review` (off by default): when the proposer is awake and `--enable-act` + `--enable-hermes-review` are on, inbound allowlisted review verdicts are auto-applied to local pending acts on the next tool call — no explicit `conscio.poll_reviews`. The local `host_act` gate stays the authority. **Daemon perceives, server acts**; the shared apply core lives in `conscio/agency/review_apply.py` and `conscio/liaison/*.py` stays engine-free. `pip install conscio`.
52
+ - **Earlier:** `v2.6.1` — "Relay": **general cross-agent messaging** over the same Liaison mailbox. Behind `--enable-relay` (independent of act / hermes-review), `conscio.relay_send`/`relay_inbox`/`relay_read` carry **free-form directed messages** between agents — Claude ↔ Hermes ↔ Antigravity ↔ OpenClaw. `--relay-peer` gates **both** send and receive; the two review types stay **reserved** (the channels never bleed); payloads are capped at 64 KB; read messages are purged after 7 days (unread never deleted). A **dumb pipe** — engine-free, never touches an act; no crypto (shared-filesystem trust domain). Debt-zero: no DB schema change, the review path byte-identical. `pip install conscio`.
51
53
  - **Earlier:** `v2.6.0` — "Liaison": cross-agent `hermes_review`. A `hermes_review`-gated act proposed by one agent can be **approved or rejected by a different agent** over a file-mediated shared mailbox (`$HERMES_HOME/liaison.db`, separate from `noosphere.db`). New **engine-free** `conscio/liaison/` (mailbox + pure review protocol); MCP tools behind `--enable-hermes-review` — `conscio.reviews`/`review_approve`/`review_reject` (reviewer role) and `conscio.poll_reviews` (proposer role). A verdict is applied **only** from an allowlisted `--reviewer` and **only** through the unchanged local `host_act` gate; `fp` binds each verdict to one exact proposal (proposer id + ledger id), so cross-instance confusion and replay are impossible. No crypto (shared-filesystem trust domain); directed-only; off by default. `pip install conscio`.
52
54
  - **Earlier:** `v2.5.0` — "Society view": the Observatory now also projects the **host-shared noosphere** — the "society" of instances that have published into `noosphere.db`. `conscio-observatory` gains read-only `/api/society/{members,skills,records}` (the census plus published skills/records, **metadata only** — artifact/bundle BLOBs omitted) and Society tabs in the viewer, over the same **engine-free** projection that opens `noosphere.db` with `mode=ro` (no `PRAGMA`, `SELECT` only). `mode=ro` reads the latest committed WAL rows even under a concurrent peer writer (`immutable=1` deliberately rejected). GET-only (mutation → 405); **no `--enable` flag** — launching it is the opt-in. `pip install conscio`.
53
55
  - **Earlier:** `v2.4.0` — "Observatory": a **read-only** window into one instance's mind. `conscio-observatory --storage DIR [--token TOK]` serves a **loopback-only** HTTP viewer of the persisted logs, goals, actions, skills, and state — over an **engine-free** projection that opens `conscio.db` with `mode=ro` (no `PRAGMA`, `SELECT` only) and parses `goals.json`/`state_summary.json`. It serves **GET only** (every mutation verb → 405) and reads even a **cold** instance with no engine running. The MCP server also gains read-only `conscio.state`/`conscio.events`/`conscio.handoff` **tools** that delegate to the same helpers its resources use. **No `--enable-observatory` flag** — it has no write/execute surface, so launching it is the opt-in. `pip install conscio`.
@@ -11,8 +11,10 @@ nothing else). It is designed to make small, local models punch far above their
11
11
  size by giving them memory, self-judgment, and procedural skill — and to prove
12
12
  that claim by measurement, not assertion.
13
13
 
14
- - **Current release:** `v2.6.2` — "Awake Relay Sensor": an **Awake** instance reacts to peers instead of polling by hand. The daemon gains a read-only `RelaySensor` (`--sensors host,relay --relay-peer <id>`) that reports unread peer messages as a `PerceptionFrame` (`relay_unread`/`review_pending`) each heartbeat and **never marks them read**. The MCP server gains `--auto-review` (off by default): when the proposer is awake and `--enable-act` + `--enable-hermes-review` are on, inbound allowlisted review verdicts are auto-applied to local pending acts on the next tool call no explicit `conscio.poll_reviews`. The local `host_act` gate stays the authority. **Daemon perceives, server acts**; the shared apply core lives in `conscio/agency/review_apply.py` and `conscio/liaison/*.py` stays engine-free. `pip install conscio`.
15
- - **Prior:** `v2.6.1` — "Relay": **general cross-agent messaging** over the same Liaison mailbox. Behind `--enable-relay` (independent of act / hermes-review), `conscio.relay_send`/`relay_inbox`/`relay_read` carry **free-form directed messages** between agents Claude Hermes Antigravity OpenClaw. `--relay-peer` gates **both** send and receive; the two review types stay **reserved** (the channels never bleed); payloads are capped at 64 KB; read messages are purged after 7 days (unread never deleted). A **dumb pipe** engine-free, never touches an act; no crypto (shared-filesystem trust domain). Debt-zero: no DB schema change, the review path byte-identical. `pip install conscio`.
14
+ - **Current release:** `v2.7.0` — "Phase 2: General Relay Auto-Respond": an **Awake** daemon can now **auto-reply** to unread free-form relay messages from trusted peers generating one reply each via its LLM adapter and sending it back, no human in the loop. Behind `--auto-respond` (OFF by default; inert without the `relay` sensor + an adapter + `--awake` + `--relay-peer`), with `--respond-limit` (default 10) capping adapter calls per cycle. The loop is **1-turn bounded**: a peer's auto-reply is consumed but never re-answered, so two auto-responders cannot ping-pong. Replies carry `auto_reply: true` + `in_reply_to`. The new pure responder `conscio/agency/relay_respond.py` is **engine-free** (a thin adapter call, no engine memory) and the MCP server is **untouched** `relay_send` is a pure mailbox write, not `host_act`. `pip install conscio`.
15
+ - **Prior:** `v2.6.3` — "Ressalvas": post-ship hardening of the Awake Relay loop. `--auto-review` no longer opens a liaison `SELECT` per tool callthe poll is **throttled to once per 5 s** per server (the `host_act` gate stays the authority). The `RelaySensor` id prefix in observations widens 8 12 chars to avoid visual collision, and an **end-to-end integration test** now wires a real mailbox + `HostActChannel` + daemon sensor + server auto-apply, proving the perceive verdict approve loop in-suite. `pip install conscio`.
16
+ - **Earlier:** `v2.6.2` — "Awake Relay Sensor": an **Awake** instance reacts to peers instead of polling by hand. The daemon gains a read-only `RelaySensor` (`--sensors host,relay --relay-peer <id>`) that reports unread peer messages as a `PerceptionFrame` (`relay_unread`/`review_pending`) each heartbeat and **never marks them read**. The MCP server gains `--auto-review` (off by default): when the proposer is awake and `--enable-act` + `--enable-hermes-review` are on, inbound allowlisted review verdicts are auto-applied to local pending acts on the next tool call — no explicit `conscio.poll_reviews`. The local `host_act` gate stays the authority. **Daemon perceives, server acts**; the shared apply core lives in `conscio/agency/review_apply.py` and `conscio/liaison/*.py` stays engine-free. `pip install conscio`.
17
+ - **Earlier:** `v2.6.1` — "Relay": **general cross-agent messaging** over the same Liaison mailbox. Behind `--enable-relay` (independent of act / hermes-review), `conscio.relay_send`/`relay_inbox`/`relay_read` carry **free-form directed messages** between agents — Claude ↔ Hermes ↔ Antigravity ↔ OpenClaw. `--relay-peer` gates **both** send and receive; the two review types stay **reserved** (the channels never bleed); payloads are capped at 64 KB; read messages are purged after 7 days (unread never deleted). A **dumb pipe** — engine-free, never touches an act; no crypto (shared-filesystem trust domain). Debt-zero: no DB schema change, the review path byte-identical. `pip install conscio`.
16
18
  - **Earlier:** `v2.6.0` — "Liaison": cross-agent `hermes_review`. A `hermes_review`-gated act proposed by one agent can be **approved or rejected by a different agent** over a file-mediated shared mailbox (`$HERMES_HOME/liaison.db`, separate from `noosphere.db`). New **engine-free** `conscio/liaison/` (mailbox + pure review protocol); MCP tools behind `--enable-hermes-review` — `conscio.reviews`/`review_approve`/`review_reject` (reviewer role) and `conscio.poll_reviews` (proposer role). A verdict is applied **only** from an allowlisted `--reviewer` and **only** through the unchanged local `host_act` gate; `fp` binds each verdict to one exact proposal (proposer id + ledger id), so cross-instance confusion and replay are impossible. No crypto (shared-filesystem trust domain); directed-only; off by default. `pip install conscio`.
17
19
  - **Earlier:** `v2.5.0` — "Society view": the Observatory now also projects the **host-shared noosphere** — the "society" of instances that have published into `noosphere.db`. `conscio-observatory` gains read-only `/api/society/{members,skills,records}` (the census plus published skills/records, **metadata only** — artifact/bundle BLOBs omitted) and Society tabs in the viewer, over the same **engine-free** projection that opens `noosphere.db` with `mode=ro` (no `PRAGMA`, `SELECT` only). `mode=ro` reads the latest committed WAL rows even under a concurrent peer writer (`immutable=1` deliberately rejected). GET-only (mutation → 405); **no `--enable` flag** — launching it is the opt-in. `pip install conscio`.
18
20
  - **Earlier:** `v2.4.0` — "Observatory": a **read-only** window into one instance's mind. `conscio-observatory --storage DIR [--token TOK]` serves a **loopback-only** HTTP viewer of the persisted logs, goals, actions, skills, and state — over an **engine-free** projection that opens `conscio.db` with `mode=ro` (no `PRAGMA`, `SELECT` only) and parses `goals.json`/`state_summary.json`. It serves **GET only** (every mutation verb → 405) and reads even a **cold** instance with no engine running. The MCP server also gains read-only `conscio.state`/`conscio.events`/`conscio.handoff` **tools** that delegate to the same helpers its resources use. **No `--enable-observatory` flag** — it has no write/execute surface, so launching it is the opt-in. `pip install conscio`.
@@ -6,7 +6,7 @@ and goal generation. Adapts behavior based on the underlying model's
6
6
  context window size.
7
7
  """
8
8
 
9
- __version__ = "2.6.2"
9
+ __version__ = "2.7.0"
10
10
  __author__ = "Neguiolidas / Neguitech"
11
11
 
12
12
  from .engine import ConsciousnessEngine
@@ -0,0 +1,81 @@
1
+ # conscio/agency/relay_respond.py
2
+ """Pure relay auto-responder — the daemon's awake auto-reply path (v2.7.0
3
+ "Phase 2"). Reads unread free-form relay messages from allowlisted peers,
4
+ generates one reply each via a raw InferenceAdapter, and sends it back over the
5
+ mailbox. An agency->liaison bridge: imports nothing from conscio.engine, so the
6
+ reply is a thin adapter call (no engine memory/advisory). Loop-bounded: own
7
+ replies carry payload.auto_reply=True and such inbound is consumed, never
8
+ re-answered. mark_read is per-row, immediately after a successful send / skip."""
9
+ from __future__ import annotations
10
+
11
+ import json
12
+
13
+ from ..liaison import mailbox, relay
14
+
15
+ DEFAULT_SYSTEM = (
16
+ "You are an autonomous agent replying to a peer agent over a relay "
17
+ "channel. Read the peer's message and reply concisely and helpfully. "
18
+ "Reply with prose only.")
19
+
20
+
21
+ def _msg_text(payload) -> str:
22
+ """Best-effort human text from a relay payload; falls back to compact JSON."""
23
+ if isinstance(payload, dict):
24
+ for k in ("text", "body", "message"):
25
+ v = payload.get(k)
26
+ if isinstance(v, str) and v:
27
+ return v
28
+ return json.dumps(payload, separators=(",", ":"))
29
+
30
+
31
+ def _fit(reply: dict) -> dict:
32
+ """Shrink reply['text'] until the compact-JSON payload fits the relay cap.
33
+ UTF-8-safe (slices code points, re-encodes via payload_size)."""
34
+ if relay.payload_size(reply) <= relay.MAX_PAYLOAD_BYTES:
35
+ return reply
36
+ text = reply["text"]
37
+ lo, hi = 0, len(text)
38
+ while lo < hi: # largest prefix that fits
39
+ mid = (lo + hi + 1) // 2
40
+ if relay.payload_size(dict(reply, text=text[:mid])) <= \
41
+ relay.MAX_PAYLOAD_BYTES:
42
+ lo = mid
43
+ else:
44
+ hi = mid - 1
45
+ return dict(reply, text=text[:lo])
46
+
47
+
48
+ def auto_respond(adapter, liaison_db, self_id, peers, *, limit: int = 10,
49
+ max_reply_tokens: int = 512, system: str = DEFAULT_SYSTEM
50
+ ) -> list[dict]:
51
+ """Auto-reply to unread peer relay messages. Returns sent packets.
52
+ No-op ([]) when adapter is None, liaison_db/self_id falsy, or peers empty."""
53
+ if adapter is None or not liaison_db or not self_id or not peers:
54
+ return []
55
+ peers = set(peers)
56
+ rows = mailbox.inbox(liaison_db, self_id, types=None,
57
+ unread_only=True, limit=limit) # newest-first, capped
58
+ sent: list[dict] = []
59
+ for m in rows:
60
+ typ = m.get("type", "")
61
+ frm = m.get("from_instance", "")
62
+ payload = m.get("payload")
63
+ if typ in relay.RESERVED_TYPES:
64
+ continue # review channel owns it
65
+ if not relay.is_relay_message(m, peers):
66
+ continue # non-peer/oversized: not ours
67
+ if isinstance(payload, dict) and payload.get("auto_reply") is True:
68
+ mailbox.mark_read(liaison_db, [m["id"]]) # R2: consume, don't answer
69
+ continue
70
+ prompt = system + "\n\nPeer message:\n" + _msg_text(payload)
71
+ try:
72
+ text = adapter.generate(prompt, max_tokens=max_reply_tokens).text
73
+ except Exception: # fork 4: leave UNREAD, retry
74
+ continue
75
+ reply = _fit({"text": text, "auto_reply": True,
76
+ "in_reply_to": m["id"]})
77
+ rid = mailbox.send(liaison_db, from_instance=self_id, to_instance=frm,
78
+ type=typ, payload=reply) # type echoed
79
+ mailbox.mark_read(liaison_db, [m["id"]]) # R2: per-row, post-send
80
+ sent.append({"to": frm, "in_reply_to": m["id"], "reply_id": rid})
81
+ return sent
@@ -56,6 +56,7 @@ class Daemon:
56
56
  def __init__(self, engine: Any, sensors: Sequence[SensorAdapter], *,
57
57
  interval: float = 5.0, budget: Optional[ActBudget] = None,
58
58
  on_cycle: Optional[Callable[[list, RunReport], Any]] = None,
59
+ responder: Optional[Callable[[], list]] = None,
59
60
  workspace: Any = None,
60
61
  consent: Any = None,
61
62
  pidfile: Optional[str | Path] = None,
@@ -66,6 +67,7 @@ class Daemon:
66
67
  self.interval = interval
67
68
  self.budget = budget
68
69
  self.on_cycle = on_cycle or (lambda frames, result: None)
70
+ self.responder = responder # v2.7.0: relay auto-reply
69
71
  self.workspace = workspace
70
72
  self.consent = consent # v1.7.2: structural consent
71
73
  self._synced_ws_id: Optional[str] = None # re-sync only on ws change
@@ -104,6 +106,11 @@ class Daemon:
104
106
  result = self.engine.run(self.budget, world_state=world_state)
105
107
  self.cycles += 1
106
108
  self._last_report = result
109
+ if self.responder is not None: # v2.7.0: awake auto-reply
110
+ try:
111
+ self.responder()
112
+ except Exception as exc: # a bad responder never kills the loop
113
+ log.warning("relay responder failed: %s", exc)
107
114
  # Write heartbeat every cycle (not just on shutdown)
108
115
  self._write_heartbeat()
109
116
  try:
@@ -248,6 +255,14 @@ def _build_sensors(spec: str, *, agent_source: Optional[str],
248
255
  return sensors
249
256
 
250
257
 
258
+ def _responder_armed(*, auto_respond: bool, relay_peer, has_adapter: bool,
259
+ awake: bool, sensors_spec: str) -> bool:
260
+ """True iff --auto-respond should arm: needs a relay sensor + an adapter +
261
+ --awake + at least one --relay-peer (v2.7.0)."""
262
+ return bool(auto_respond and relay_peer and has_adapter and awake
263
+ and "relay" in [s.strip() for s in sensors_spec.split(",")])
264
+
265
+
251
266
  # ── config loader + adapter builder live in conscio/adapter_config.py now
252
267
  # (shared by the daemon and the MCP server; v2.0.1, no behavior change) ──
253
268
 
@@ -312,6 +327,12 @@ def _arg_parser() -> argparse.ArgumentParser:
312
327
  parser.add_argument("--relay-peer", action="append", default=[],
313
328
  metavar="INSTANCE_ID",
314
329
  help="trusted relay peer for the relay sensor (repeatable)")
330
+ parser.add_argument("--auto-respond", action="store_true",
331
+ help="daemon auto-replies to unread relay peer messages "
332
+ "via the adapter (OFF default; needs relay sensor + "
333
+ "adapter + --awake + --relay-peer)")
334
+ parser.add_argument("--respond-limit", type=int, default=10,
335
+ help="max relay auto-replies per cycle (token-burn cap)")
315
336
  return parser
316
337
 
317
338
 
@@ -370,8 +391,25 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
370
391
  if args.budget_cycles else None)
371
392
  workspace = WorkspaceContext(emit=engine.event_bus.emit)
372
393
  consent = StructuralConsent(consent_path(engine.storage)) # v1.7.2
394
+ responder = None # v2.7.0
395
+ if args.auto_respond:
396
+ if _responder_armed(auto_respond=True, relay_peer=args.relay_peer,
397
+ has_adapter=adapter is not None, awake=awake,
398
+ sensors_spec=sensors_spec):
399
+ from .agency import relay_respond
400
+ _adapter = adapter # R1: bind LOCAL adapter
401
+ _peers = tuple(args.relay_peer)
402
+ responder = lambda: relay_respond.auto_respond( # noqa: E731
403
+ _adapter, liaison_db, self_id, _peers,
404
+ limit=args.respond_limit)
405
+ log.info("relay auto-respond armed (peers=%d, limit=%d)",
406
+ len(_peers), args.respond_limit)
407
+ else:
408
+ log.warning("--auto-respond inert: needs relay sensor + adapter + "
409
+ "--awake + --relay-peer; skipping")
373
410
  daemon = Daemon(engine, sensors=sensors, interval=interval,
374
- budget=budget, workspace=workspace, consent=consent)
411
+ budget=budget, workspace=workspace, consent=consent,
412
+ responder=responder)
375
413
  daemon.run(once=args.once)
376
414
  return 0
377
415
 
@@ -24,6 +24,11 @@ from .seen import SeenStore
24
24
  from ..agency import review_apply
25
25
  from ..liaison import mailbox, relay, review
26
26
 
27
+ # v2.6.3 #2: floor between auto-review SQL polls so --auto-review does not open a
28
+ # liaison SELECT on every single tool call in a chatty session. host_act.approve
29
+ # remains the authority; this only paces the opportunistic poll.
30
+ AUTO_APPLY_THROTTLE_S = 5.0
31
+
27
32
 
28
33
  class Bindings:
29
34
  def __init__(self, engine: ConsciousnessEngine, seen: SeenStore, *,
@@ -50,6 +55,7 @@ class Bindings:
50
55
  self.relay = relay # v2.6.1: --enable-relay
51
56
  self.relay_peers = tuple(relay_peers)
52
57
  self.auto_review = auto_review # v2.6.2: --auto-review
58
+ self.last_auto_apply_ts = 0.0 # v2.6.3 #2: throttle clock
53
59
 
54
60
  # ── discovery ──
55
61
  def version(self) -> str:
@@ -262,6 +268,10 @@ class Bindings:
262
268
  return
263
269
  if self.engine.host_act is None or not self.reviewers:
264
270
  return
271
+ now = time.monotonic() # v2.6.3 #2: pace the SQL poll
272
+ if now - self.last_auto_apply_ts < AUTO_APPLY_THROTTLE_S:
273
+ return
274
+ self.last_auto_apply_ts = now
265
275
  try:
266
276
  review_apply.apply_verdicts(self.engine.host_act, self.liaison_db,
267
277
  self.self_instance_id, self.reviewers)
@@ -13,6 +13,8 @@ from ..liaison.relay import RESERVED_TYPES
13
13
  from ..risk import Risk
14
14
  from .sensor import PerceptionFrame, SensorAdapter
15
15
 
16
+ _ID_DISPLAY = 12 # v2.6.3 #4: wider id prefix; 8 risked visual collision
17
+
16
18
 
17
19
  class RelaySensor(SensorAdapter):
18
20
  """Unread liaison inbox as a `PerceptionFrame` (source ``"relay"``)."""
@@ -46,9 +48,9 @@ class RelaySensor(SensorAdapter):
46
48
  else:
47
49
  other_n += 1 # non-peer: counted, not detailed
48
50
  for frm, n in sorted(relay_from.items()):
49
- obs.append(f"relay: {n} unread from {frm[:8]}")
51
+ obs.append(f"relay: {n} unread from {frm[:_ID_DISPLAY]}")
50
52
  for frm, n in sorted(review_from.items()):
51
- obs.append(f"review: {n} verdict(s) pending from {frm[:8]}")
53
+ obs.append(f"review: {n} verdict(s) pending from {frm[:_ID_DISPLAY]}")
52
54
  if other_n:
53
55
  obs.append(f"relay: {other_n} unread from non-peers (ignored)")
54
56
  if not obs:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conscio
3
- Version: 2.6.2
3
+ Version: 2.7.0
4
4
  Summary: Self-awareness framework for AI agents — emergent consciousness via context-aware memory, introspection, and goal generation
5
5
  Author-email: Neguiolidas <neguitech@proton.me>
6
6
  License: MIT
@@ -46,8 +46,10 @@ nothing else). It is designed to make small, local models punch far above their
46
46
  size by giving them memory, self-judgment, and procedural skill — and to prove
47
47
  that claim by measurement, not assertion.
48
48
 
49
- - **Current release:** `v2.6.2` — "Awake Relay Sensor": an **Awake** instance reacts to peers instead of polling by hand. The daemon gains a read-only `RelaySensor` (`--sensors host,relay --relay-peer <id>`) that reports unread peer messages as a `PerceptionFrame` (`relay_unread`/`review_pending`) each heartbeat and **never marks them read**. The MCP server gains `--auto-review` (off by default): when the proposer is awake and `--enable-act` + `--enable-hermes-review` are on, inbound allowlisted review verdicts are auto-applied to local pending acts on the next tool call no explicit `conscio.poll_reviews`. The local `host_act` gate stays the authority. **Daemon perceives, server acts**; the shared apply core lives in `conscio/agency/review_apply.py` and `conscio/liaison/*.py` stays engine-free. `pip install conscio`.
50
- - **Prior:** `v2.6.1` — "Relay": **general cross-agent messaging** over the same Liaison mailbox. Behind `--enable-relay` (independent of act / hermes-review), `conscio.relay_send`/`relay_inbox`/`relay_read` carry **free-form directed messages** between agents Claude Hermes Antigravity OpenClaw. `--relay-peer` gates **both** send and receive; the two review types stay **reserved** (the channels never bleed); payloads are capped at 64 KB; read messages are purged after 7 days (unread never deleted). A **dumb pipe** engine-free, never touches an act; no crypto (shared-filesystem trust domain). Debt-zero: no DB schema change, the review path byte-identical. `pip install conscio`.
49
+ - **Current release:** `v2.7.0` — "Phase 2: General Relay Auto-Respond": an **Awake** daemon can now **auto-reply** to unread free-form relay messages from trusted peers generating one reply each via its LLM adapter and sending it back, no human in the loop. Behind `--auto-respond` (OFF by default; inert without the `relay` sensor + an adapter + `--awake` + `--relay-peer`), with `--respond-limit` (default 10) capping adapter calls per cycle. The loop is **1-turn bounded**: a peer's auto-reply is consumed but never re-answered, so two auto-responders cannot ping-pong. Replies carry `auto_reply: true` + `in_reply_to`. The new pure responder `conscio/agency/relay_respond.py` is **engine-free** (a thin adapter call, no engine memory) and the MCP server is **untouched** `relay_send` is a pure mailbox write, not `host_act`. `pip install conscio`.
50
+ - **Prior:** `v2.6.3` — "Ressalvas": post-ship hardening of the Awake Relay loop. `--auto-review` no longer opens a liaison `SELECT` per tool callthe poll is **throttled to once per 5 s** per server (the `host_act` gate stays the authority). The `RelaySensor` id prefix in observations widens 8 12 chars to avoid visual collision, and an **end-to-end integration test** now wires a real mailbox + `HostActChannel` + daemon sensor + server auto-apply, proving the perceive verdict approve loop in-suite. `pip install conscio`.
51
+ - **Earlier:** `v2.6.2` — "Awake Relay Sensor": an **Awake** instance reacts to peers instead of polling by hand. The daemon gains a read-only `RelaySensor` (`--sensors host,relay --relay-peer <id>`) that reports unread peer messages as a `PerceptionFrame` (`relay_unread`/`review_pending`) each heartbeat and **never marks them read**. The MCP server gains `--auto-review` (off by default): when the proposer is awake and `--enable-act` + `--enable-hermes-review` are on, inbound allowlisted review verdicts are auto-applied to local pending acts on the next tool call — no explicit `conscio.poll_reviews`. The local `host_act` gate stays the authority. **Daemon perceives, server acts**; the shared apply core lives in `conscio/agency/review_apply.py` and `conscio/liaison/*.py` stays engine-free. `pip install conscio`.
52
+ - **Earlier:** `v2.6.1` — "Relay": **general cross-agent messaging** over the same Liaison mailbox. Behind `--enable-relay` (independent of act / hermes-review), `conscio.relay_send`/`relay_inbox`/`relay_read` carry **free-form directed messages** between agents — Claude ↔ Hermes ↔ Antigravity ↔ OpenClaw. `--relay-peer` gates **both** send and receive; the two review types stay **reserved** (the channels never bleed); payloads are capped at 64 KB; read messages are purged after 7 days (unread never deleted). A **dumb pipe** — engine-free, never touches an act; no crypto (shared-filesystem trust domain). Debt-zero: no DB schema change, the review path byte-identical. `pip install conscio`.
51
53
  - **Earlier:** `v2.6.0` — "Liaison": cross-agent `hermes_review`. A `hermes_review`-gated act proposed by one agent can be **approved or rejected by a different agent** over a file-mediated shared mailbox (`$HERMES_HOME/liaison.db`, separate from `noosphere.db`). New **engine-free** `conscio/liaison/` (mailbox + pure review protocol); MCP tools behind `--enable-hermes-review` — `conscio.reviews`/`review_approve`/`review_reject` (reviewer role) and `conscio.poll_reviews` (proposer role). A verdict is applied **only** from an allowlisted `--reviewer` and **only** through the unchanged local `host_act` gate; `fp` binds each verdict to one exact proposal (proposer id + ledger id), so cross-instance confusion and replay are impossible. No crypto (shared-filesystem trust domain); directed-only; off by default. `pip install conscio`.
52
54
  - **Earlier:** `v2.5.0` — "Society view": the Observatory now also projects the **host-shared noosphere** — the "society" of instances that have published into `noosphere.db`. `conscio-observatory` gains read-only `/api/society/{members,skills,records}` (the census plus published skills/records, **metadata only** — artifact/bundle BLOBs omitted) and Society tabs in the viewer, over the same **engine-free** projection that opens `noosphere.db` with `mode=ro` (no `PRAGMA`, `SELECT` only). `mode=ro` reads the latest committed WAL rows even under a concurrent peer writer (`immutable=1` deliberately rejected). GET-only (mutation → 405); **no `--enable` flag** — launching it is the opt-in. `pip install conscio`.
53
55
  - **Earlier:** `v2.4.0` — "Observatory": a **read-only** window into one instance's mind. `conscio-observatory --storage DIR [--token TOK]` serves a **loopback-only** HTTP viewer of the persisted logs, goals, actions, skills, and state — over an **engine-free** projection that opens `conscio.db` with `mode=ro` (no `PRAGMA`, `SELECT` only) and parses `goals.json`/`state_summary.json`. It serves **GET only** (every mutation verb → 405) and reads even a **cold** instance with no engine running. The MCP server also gains read-only `conscio.state`/`conscio.events`/`conscio.handoff` **tools** that delegate to the same helpers its resources use. **No `--enable-observatory` flag** — it has no write/execute surface, so launching it is the opt-in. `pip install conscio`.
@@ -64,6 +64,7 @@ conscio/agency/ledger.py
64
64
  conscio/agency/loop.py
65
65
  conscio/agency/profiles.py
66
66
  conscio/agency/promote.py
67
+ conscio/agency/relay_respond.py
67
68
  conscio/agency/review_apply.py
68
69
  conscio/agency/skeptic.py
69
70
  conscio/agency/skills.py
@@ -168,6 +169,7 @@ tests/test_daemon_battery.py
168
169
  tests/test_daemon_config.py
169
170
  tests/test_daemon_heartbeat.py
170
171
  tests/test_daemon_relay.py
172
+ tests/test_daemon_responder.py
171
173
  tests/test_daemon_structure_sync.py
172
174
  tests/test_dream_coherence.py
173
175
  tests/test_dream_distill.py
@@ -249,6 +251,8 @@ tests/test_plugins.py
249
251
  tests/test_quarantine_promote.py
250
252
  tests/test_quarantine_trial.py
251
253
  tests/test_recursive_loop_integration.py
254
+ tests/test_relay_e2e.py
255
+ tests/test_relay_respond.py
252
256
  tests/test_relay_sensor.py
253
257
  tests/test_review_apply.py
254
258
  tests/test_risk.py
@@ -0,0 +1,58 @@
1
+ # tests/test_daemon_responder.py
2
+ """v2.7.0 Phase 2 — daemon responder hook + arm gate."""
3
+ from conscio.daemon import Daemon, _responder_armed
4
+ from conscio.engine import ConsciousnessEngine
5
+ from conscio.perception import MockSensor, PerceptionFrame
6
+
7
+
8
+ def _engine(tmp_path):
9
+ return ConsciousnessEngine("glm-5.1", storage_path=tmp_path / "s")
10
+
11
+
12
+ def _frame():
13
+ return PerceptionFrame(source="mock", observations=["o"], signals={"x": 1.0})
14
+
15
+
16
+ def test_responder_called_after_run(tmp_path):
17
+ eng = _engine(tmp_path)
18
+ calls = {"n": 0}
19
+ d = Daemon(eng, sensors=[MockSensor([_frame()])],
20
+ responder=lambda: calls.__setitem__("n", calls["n"] + 1))
21
+ try:
22
+ d.cycle()
23
+ assert calls["n"] == 1
24
+ finally:
25
+ eng.close()
26
+
27
+
28
+ def test_responder_raise_survives_cycle(tmp_path):
29
+ eng = _engine(tmp_path)
30
+
31
+ def boom():
32
+ raise RuntimeError("responder down")
33
+
34
+ d = Daemon(eng, sensors=[MockSensor([_frame()])], responder=boom)
35
+ try:
36
+ d.cycle() # must not raise
37
+ finally:
38
+ eng.close()
39
+
40
+
41
+ def test_responder_none_is_noop(tmp_path):
42
+ eng = _engine(tmp_path)
43
+ d = Daemon(eng, sensors=[MockSensor([_frame()])]) # no responder
44
+ try:
45
+ d.cycle() # no raise
46
+ finally:
47
+ eng.close()
48
+
49
+
50
+ def test_arm_gate_predicate():
51
+ base = dict(auto_respond=True, relay_peer=["p"], has_adapter=True,
52
+ awake=True, sensors_spec="host,relay")
53
+ assert _responder_armed(**base) is True
54
+ assert _responder_armed(**{**base, "auto_respond": False}) is False
55
+ assert _responder_armed(**{**base, "relay_peer": []}) is False
56
+ assert _responder_armed(**{**base, "has_adapter": False}) is False
57
+ assert _responder_armed(**{**base, "awake": False}) is False
58
+ assert _responder_armed(**{**base, "sensors_spec": "host"}) is False
@@ -88,3 +88,28 @@ def test_call_tool_triggers_apply():
88
88
  b = _bind(awake=True, host_act=ha, reviewers=("r",), auto_review=True)
89
89
  b.call_tool("conscio.advisory", {}) # any tool; advisory needs no host
90
90
  assert ha.calls == 1
91
+
92
+
93
+ # ── v2.6.3 #2: timestamp throttle (no SQL on every request) ──
94
+
95
+ def test_throttle_skips_within_window(monkeypatch):
96
+ import conscio.mcp.server as srv
97
+ clock = [1000.0]
98
+ monkeypatch.setattr(srv.time, "monotonic", lambda: clock[0])
99
+ ha = _HA()
100
+ b = _bind(awake=True, host_act=ha, reviewers=("r",), auto_review=True)
101
+ b._maybe_auto_apply()
102
+ b._maybe_auto_apply() # same instant -> throttled, no SQL
103
+ assert ha.calls == 1
104
+
105
+
106
+ def test_throttle_allows_after_window(monkeypatch):
107
+ import conscio.mcp.server as srv
108
+ clock = [1000.0]
109
+ monkeypatch.setattr(srv.time, "monotonic", lambda: clock[0])
110
+ ha = _HA()
111
+ b = _bind(awake=True, host_act=ha, reviewers=("r",), auto_review=True)
112
+ b._maybe_auto_apply()
113
+ clock[0] += srv.AUTO_APPLY_THROTTLE_S + 0.1
114
+ b._maybe_auto_apply() # window elapsed -> applies again
115
+ assert ha.calls == 2
@@ -0,0 +1,124 @@
1
+ # tests/test_relay_e2e.py
2
+ """v2.6.3 #5: end-to-end integration of the v2.6.2 Awake Relay loop wired
3
+ against REAL parts simultaneously — real liaison mailbox, real HostActChannel +
4
+ ledger, the daemon-side RelaySensor (perception, read-only), and the
5
+ server-side Bindings auto-apply (--auto-review). Only the Skeptic/Breaker/Trust
6
+ and the engine shell are faked; the perceive -> verdict -> approve path is real.
7
+ Converts the previously-manual "full loop" claim into a regression guard."""
8
+ import json
9
+
10
+ from conscio.agency.contracts import AuditVerdict
11
+ from conscio.agency.host_act import HostActChannel
12
+ from conscio.agency.ledger import ActionLedger
13
+ from conscio.agency.tools import registry_from_manifest
14
+ from conscio.liaison import mailbox, review
15
+ from conscio.mcp.server import Bindings
16
+ from conscio.perception.relay_sensor import RelaySensor
17
+
18
+ SELF = "me-instance-0001"
19
+ REVIEWER = "hermet-instance-0002"
20
+
21
+
22
+ class _PassSkeptic:
23
+ def audit(self, proposal, *, goal_text=""):
24
+ return AuditVerdict(verdict="PASS", reasons=[], risk_flags=[],
25
+ confidence=0.9)
26
+
27
+
28
+ class _NoBreaker:
29
+ def global_lockdown_due(self): return False
30
+ def should_trip(self, goal_fp, *, task_type=""): return False
31
+ def trip(self, goal_fp, *, detail="", goal_text=""): pass
32
+
33
+
34
+ class _Trust:
35
+ def on_success(self, tool): pass
36
+
37
+
38
+ class _Seen:
39
+ pass
40
+
41
+
42
+ class _Engine:
43
+ """Minimal engine carrier: real host_act behind the surface Bindings reads."""
44
+ def __init__(self, host_act):
45
+ self.awake = True
46
+ self.host_act = host_act
47
+
48
+ def advisory(self):
49
+ return {"ok": True}
50
+
51
+
52
+ def _host_act(tmp_path):
53
+ led = ActionLedger(tmp_path / "conscio.db")
54
+ manifest = [{"name": "deploy",
55
+ "params": {"env": {"type": "str", "required": True}},
56
+ "risk": "low", "approval_policy": "require_approval"}]
57
+ chan = HostActChannel(
58
+ ledger=led, skeptic=_PassSkeptic(), breaker=_NoBreaker(), trust=_Trust(),
59
+ registry=registry_from_manifest(manifest),
60
+ emit_fn=lambda **kw: None, awake_fn=lambda: True)
61
+ return chan, led
62
+
63
+
64
+ def _bindings(engine, db):
65
+ return Bindings(engine, _Seen(), auto_review=True, hermes_review=True,
66
+ reviewers=(REVIEWER,), self_instance_id=SELF, liaison_db=db)
67
+
68
+
69
+ def test_full_loop_perceive_then_auto_apply(tmp_path):
70
+ db = tmp_path / "liaison.db"
71
+ chan, led = _host_act(tmp_path)
72
+
73
+ # 1. propose a require_approval act -> parks pending in the real ledger.
74
+ out = chan.propose({"tool": "deploy", "args": {"env": "prod"},
75
+ "rationale": "ship", "expected_outcome": "live"})
76
+ assert out["status"] == "pending_approval"
77
+ rid = out["ledger_id"]
78
+ assert led.get(rid)["status"] == "proposed"
79
+
80
+ # 2. an allowlisted reviewer sends an approve verdict for THIS act's fp.
81
+ row = chan.pending(10)[0]
82
+ fp = review.fingerprint(SELF, row["goal_fp"], row["tool"],
83
+ json.loads(row["args_json"]), row["id"])
84
+ mailbox.send(db, from_instance=REVIEWER, to_instance=SELF,
85
+ type="review_verdict",
86
+ payload=review.build_verdict(fp=fp, decision="approve",
87
+ reason=""))
88
+
89
+ # 3. DAEMON side: RelaySensor perceives the pending verdict, read-only.
90
+ frame = RelaySensor(db, SELF, [REVIEWER]).perceive()
91
+ assert frame.signals["review_pending"] == 1.0
92
+ assert mailbox.inbox(db, SELF, types=["review_verdict"],
93
+ unread_only=True) # sensor did NOT consume
94
+
95
+ # 4. SERVER side: a plain tool call (NOT poll_reviews) auto-applies it.
96
+ eng = _Engine(chan)
97
+ b = _bindings(eng, db)
98
+ b.call_tool("conscio.advisory", {})
99
+
100
+ # 5. the act is approved by the host_act gate, the verdict is consumed.
101
+ assert led.get(rid)["status"] == "executing"
102
+ assert mailbox.inbox(db, SELF, types=["review_verdict"],
103
+ unread_only=True) == []
104
+ led.close()
105
+
106
+
107
+ def test_non_peer_verdict_does_not_apply(tmp_path):
108
+ """A verdict from a non-allowlisted sender never moves the act."""
109
+ db = tmp_path / "liaison.db"
110
+ chan, led = _host_act(tmp_path)
111
+ out = chan.propose({"tool": "deploy", "args": {"env": "prod"},
112
+ "rationale": "ship", "expected_outcome": "live"})
113
+ rid = out["ledger_id"]
114
+ row = chan.pending(10)[0]
115
+ fp = review.fingerprint(SELF, row["goal_fp"], row["tool"],
116
+ json.loads(row["args_json"]), row["id"])
117
+ mailbox.send(db, from_instance="stranger-9999", to_instance=SELF,
118
+ type="review_verdict",
119
+ payload=review.build_verdict(fp=fp, decision="approve",
120
+ reason=""))
121
+ b = _bindings(_Engine(chan), db)
122
+ b.call_tool("conscio.advisory", {})
123
+ assert led.get(rid)["status"] == "proposed" # untouched
124
+ led.close()