microcoreos 0.3.0__tar.gz → 0.3.2__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 (210) hide show
  1. {microcoreos-0.3.0 → microcoreos-0.3.2}/.agent/skills/microcoreos-architecture/SKILL.md +5 -5
  2. {microcoreos-0.3.0 → microcoreos-0.3.2}/.agent/skills/microcoreos-architecture/agent.md +1 -1
  3. {microcoreos-0.3.0 → microcoreos-0.3.2}/.agent/workflows/feature-plan.md +14 -5
  4. {microcoreos-0.3.0 → microcoreos-0.3.2}/.agent/workflows/multi-domain-plan.md +5 -5
  5. {microcoreos-0.3.0 → microcoreos-0.3.2}/.agent/workflows/new-domain.md +70 -32
  6. {microcoreos-0.3.0 → microcoreos-0.3.2}/.agent/workflows/new-tool.md +21 -8
  7. {microcoreos-0.3.0 → microcoreos-0.3.2}/.claude/settings.local.json +2 -1
  8. {microcoreos-0.3.0 → microcoreos-0.3.2}/.github/workflows/ci.yml +8 -4
  9. {microcoreos-0.3.0 → microcoreos-0.3.2}/.gitignore +7 -0
  10. {microcoreos-0.3.0 → microcoreos-0.3.2}/AGENTS.md +34 -4
  11. {microcoreos-0.3.0 → microcoreos-0.3.2}/AI_CONTEXT.md +17 -8
  12. {microcoreos-0.3.0 → microcoreos-0.3.2}/INSTRUCTIONS_FOR_AI.md +15 -11
  13. {microcoreos-0.3.0 → microcoreos-0.3.2}/PKG-INFO +21 -4
  14. {microcoreos-0.3.0 → microcoreos-0.3.2}/README.md +20 -3
  15. {microcoreos-0.3.0 → microcoreos-0.3.2}/ROADMAP.md +11 -11
  16. {microcoreos-0.3.0/tests → microcoreos-0.3.2}/conftest.py +8 -3
  17. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/CORE_INFRASTRUCTURE.md +1 -1
  18. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/ELASTIC_DEPLOYMENT.md +1 -1
  19. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/EVENT_BUS.md +1 -1
  20. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/INDEX.md +1 -0
  21. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/OBSERVABILITY.md +4 -2
  22. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/PARALLEL_DEVELOPMENT.md +18 -2
  23. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/discovery_naming_linter_plugin.py +29 -0
  24. microcoreos-0.3.2/domains/devtools/plugins/doc_path_linter_plugin.py +193 -0
  25. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/event_contract_linter_plugin.py +2 -0
  26. microcoreos-0.3.0/tests/test_auth_tool.py → microcoreos-0.3.2/extras/available_tools/auth/tests/auth_tool_test.py +16 -22
  27. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/postgresql/postgresql_tool.py +1 -1
  28. microcoreos-0.3.0/tests/test_postgresql_describe_schema.py → microcoreos-0.3.2/extras/available_tools/postgresql/tests/postgresql_describe_schema_test.py +36 -28
  29. microcoreos-0.3.0/tests/test_postgresql_tool.py → microcoreos-0.3.2/extras/available_tools/postgresql/tests/postgresql_tool_test.py +15 -11
  30. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/rabbitmq/rabbitmq_driver.py +7 -6
  31. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/s3/s3_tool.py +28 -13
  32. microcoreos-0.3.0/tests/test_s3_tool.py → microcoreos-0.3.2/extras/available_tools/s3/tests/s3_tool_test.py +67 -8
  33. microcoreos-0.3.0/tests/test_scheduler_singleton.py → microcoreos-0.3.2/extras/available_tools/scheduler/tests/scheduler_singleton_test.py +13 -8
  34. microcoreos-0.3.0/tests/test_scheduler_tool.py → microcoreos-0.3.2/extras/available_tools/scheduler/tests/scheduler_tool_test.py +12 -23
  35. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/cli.py +1 -1
  36. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/scaffold.py +126 -37
  37. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/__init__.py +2 -2
  38. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/cli.py +1 -1
  39. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/fuzzer.py +1 -1
  40. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/plan/rules.py +1 -1
  41. {microcoreos-0.3.0 → microcoreos-0.3.2}/pyproject.toml +14 -2
  42. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/core}/test_core.py +137 -0
  43. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/core}/test_core_purity.py +4 -4
  44. microcoreos-0.3.2/tests/core/test_kernel.py +348 -0
  45. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/core}/test_plugin_di_fixtures.py +1 -1
  46. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/core}/test_tool_proxy.py +12 -1
  47. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/dev/test_plan_validator.py +3 -3
  48. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/helpers/active_db.py +1 -1
  49. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_discovery_naming_linter.py +29 -0
  50. microcoreos-0.3.2/tests/linters/test_doc_path_linter.py +128 -0
  51. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_catalog.py +1 -1
  52. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_cli.py +1 -1
  53. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_scaffold.py +17 -9
  54. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_upgrade.py +4 -3
  55. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/context}/test_context_tool.py +78 -3
  56. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/event_bus}/test_event_bus_broker_parity.py +1 -1
  57. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/event_bus}/test_event_bus_kafka_parity.py +1 -1
  58. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/event_bus}/test_event_bus_rabbitmq_parity.py +1 -1
  59. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/event_bus}/test_event_bus_tool.py +60 -0
  60. microcoreos-0.3.2/tests/tools/http_server/test_http_pipeline.py +222 -0
  61. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/http_server}/test_http_server_tool.py +56 -3
  62. microcoreos-0.3.2/tests/tools/registry/test_registry_tool.py +52 -0
  63. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/state}/test_state_parity.py +1 -1
  64. microcoreos-0.3.2/tests/tools/telemetry/test_telemetry_tool.py +390 -0
  65. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/event_bus/event_bus_tool.py +1 -1
  66. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/event_bus/sqlite_driver.py +1 -1
  67. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/http_server/http_server_tool.py +1 -1
  68. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/sqlite/sqlite_tool.py +27 -12
  69. microcoreos-0.3.2/tools/telemetry/__init__.py +0 -0
  70. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/telemetry/telemetry_tool.py +102 -8
  71. {microcoreos-0.3.0 → microcoreos-0.3.2}/uv.lock +424 -1
  72. microcoreos-0.3.0/tests/test_kernel.py +0 -131
  73. {microcoreos-0.3.0 → microcoreos-0.3.2}/.dockerignore +0 -0
  74. {microcoreos-0.3.0 → microcoreos-0.3.2}/.env.example +0 -0
  75. {microcoreos-0.3.0 → microcoreos-0.3.2}/.github/workflows/release.yml +0 -0
  76. /microcoreos-0.3.0/extras/available_tools/s3/__init__.py → /microcoreos-0.3.2/.mutmut-cache +0 -0
  77. {microcoreos-0.3.0 → microcoreos-0.3.2}/.python-version +0 -0
  78. {microcoreos-0.3.0 → microcoreos-0.3.2}/Dockerfile +0 -0
  79. {microcoreos-0.3.0 → microcoreos-0.3.2}/LICENSE +0 -0
  80. {microcoreos-0.3.0 → microcoreos-0.3.2}/cli.py +0 -0
  81. {microcoreos-0.3.0 → microcoreos-0.3.2}/dev_infra/cache_probe.py +0 -0
  82. {microcoreos-0.3.0 → microcoreos-0.3.2}/dev_infra/docker-compose.yml +0 -0
  83. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/CLI.md +0 -0
  84. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/HTTP_SERVER.md +0 -0
  85. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/OBSERVABILITY_API.md +0 -0
  86. {microcoreos-0.3.0 → microcoreos-0.3.2}/docs/translations/es/README.md +0 -0
  87. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/lint/plugin_sources.py +0 -0
  88. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/domain_isolation_linter_plugin.py +0 -0
  89. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/event_schemas_plugin.py +0 -0
  90. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/field_divergence_linter_plugin.py +0 -0
  91. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/route_collision_linter_plugin.py +0 -0
  92. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/table_ownership_linter_plugin.py +0 -0
  93. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/devtools/plugins/tool_doc_drift_linter_plugin.py +0 -0
  94. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/event_delivery_monitor_plugin.py +0 -0
  95. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_events_plugin.py +0 -0
  96. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_events_stream_plugin.py +0 -0
  97. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_logs_stream_plugin.py +0 -0
  98. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_metrics_plugin.py +0 -0
  99. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_status_plugin.py +0 -0
  100. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_traces_plugin.py +0 -0
  101. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/system_traces_stream_plugin.py +0 -0
  102. {microcoreos-0.3.0 → microcoreos-0.3.2}/domains/system/plugins/tool_health_plugin.py +0 -0
  103. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/chaos/plugins/blocking_boot_plugin.py +0 -0
  104. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/chaos/plugins/chaos_control_plugin.py +0 -0
  105. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/chaos/plugins/failing_plugin.py +0 -0
  106. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/chaos/plugins/stress_plugin.py +0 -0
  107. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/ping/plugins/ping_plugin.py +0 -0
  108. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/scheduler/migrations/001_scheduler_one_shots.sql +0 -0
  109. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/scheduler/models/scheduler_one_shot.py +0 -0
  110. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/scheduler/plugins/durable_one_shots_plugin.py +0 -0
  111. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/migrations/001_create_users.sql +0 -0
  112. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/models/user.py +0 -0
  113. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/create_user_plugin.py +0 -0
  114. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/delete_user_plugin.py +0 -0
  115. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/get_me_plugin.py +0 -0
  116. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/get_user_by_id_plugin.py +0 -0
  117. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/get_users_plugin.py +0 -0
  118. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/login_plugin.py +0 -0
  119. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/logout_plugin.py +0 -0
  120. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/update_user_plugin.py +0 -0
  121. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_domains/users/plugins/welcome_service_plugin.py +0 -0
  122. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/auth/auth_tool.py +0 -0
  123. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/chaos/chaos_tool.py +0 -0
  124. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/kafka/kafka_driver.py +0 -0
  125. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/redis_state/redis_state_tool.py +0 -0
  126. {microcoreos-0.3.0/tools/telemetry → microcoreos-0.3.2/extras/available_tools/s3}/__init__.py +0 -0
  127. {microcoreos-0.3.0 → microcoreos-0.3.2}/extras/available_tools/scheduler/scheduler_tool.py +0 -0
  128. {microcoreos-0.3.0 → microcoreos-0.3.2}/hatch_build.py +0 -0
  129. {microcoreos-0.3.0 → microcoreos-0.3.2}/main.py +0 -0
  130. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/__init__.py +0 -0
  131. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/base_plugin.py +0 -0
  132. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/base_tool.py +0 -0
  133. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/catalog.py +0 -0
  134. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/container.py +0 -0
  135. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/context.py +0 -0
  136. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/kernel.py +0 -0
  137. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/project.py +0 -0
  138. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/project_readme.md +0 -0
  139. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/registry.py +0 -0
  140. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos/upgrade.py +0 -0
  141. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/pipeline.py +0 -0
  142. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/plan/__init__.py +0 -0
  143. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/plan/scan.py +0 -0
  144. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/plan/schema.py +0 -0
  145. {microcoreos-0.3.0 → microcoreos-0.3.2}/microcoreos_dev/probe.py +0 -0
  146. {microcoreos-0.3.0 → microcoreos-0.3.2}/plans/README.md +0 -0
  147. {microcoreos-0.3.0 → microcoreos-0.3.2}/plans/active_plan.md +0 -0
  148. {microcoreos-0.3.0 → microcoreos-0.3.2}/plans/active_plan.yaml +0 -0
  149. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/core}/test_no_retry.py +0 -0
  150. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/core}/test_registry_collisions.py +0 -0
  151. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/dev/corpus/README.md +0 -0
  152. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/dev/corpus/qwen_twitter_plan.yaml +0 -0
  153. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/dev/test_pipeline.py +0 -0
  154. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/ping/test_ping_plugin.py +0 -0
  155. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_create_user_plugin.py +0 -0
  156. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_delete_user_plugin.py +0 -0
  157. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_get_me_plugin.py +0 -0
  158. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_get_user_by_id_plugin.py +0 -0
  159. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_get_users_plugin.py +0 -0
  160. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_login_plugin.py +0 -0
  161. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_logout_plugin.py +0 -0
  162. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_update_user_plugin.py +0 -0
  163. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/domains/users/test_welcome_service_plugin.py +0 -0
  164. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/helpers/async_wait.py +0 -0
  165. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/helpers/mock_db.py +0 -0
  166. {microcoreos-0.3.0 → microcoreos-0.3.2}/tests/helpers/trace_chains.py +0 -0
  167. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_domain_isolation_linter.py +0 -0
  168. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_event_contract_linter.py +0 -0
  169. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_field_divergence_linter.py +0 -0
  170. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_route_collision_linter.py +0 -0
  171. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_table_ownership_linter.py +0 -0
  172. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/linters}/test_tool_doc_drift_linter.py +0 -0
  173. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_chaos_control.py +0 -0
  174. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_chaos_tool.py +0 -0
  175. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_durable_one_shots.py +0 -0
  176. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_event_schemas_plugin.py +0 -0
  177. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_system_events_stats.py +0 -0
  178. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_system_traces_plugin.py +0 -0
  179. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/system}/test_trace_chain_helper.py +0 -0
  180. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/config}/test_config_tool.py +0 -0
  181. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/db}/test_db_parity.py +0 -0
  182. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/event_bus}/test_event_bus_groups.py +0 -0
  183. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/event_bus}/test_redis_streams_driver.py +0 -0
  184. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/http_server}/test_http_params_hardening.py +0 -0
  185. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/http_server}/test_security_hardening.py +0 -0
  186. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/logger}/test_logger_tool.py +0 -0
  187. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/s3}/test_s3_parity.py +0 -0
  188. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/sqlite}/test_sqlite_concurrency.py +0 -0
  189. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/sqlite}/test_sqlite_describe_schema.py +0 -0
  190. {microcoreos-0.3.0/tests/tools → microcoreos-0.3.2/tests/tools/sqlite}/test_sqlite_driver.py +0 -0
  191. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/sqlite}/test_sqlite_migrations.py +0 -0
  192. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/sqlite}/test_sqlite_tool.py +0 -0
  193. {microcoreos-0.3.0/tests → microcoreos-0.3.2/tests/tools/state}/test_state_tool.py +0 -0
  194. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/config/config_tool.py +0 -0
  195. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/context/authoring_guide.md +0 -0
  196. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/context/context_tool.py +0 -0
  197. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/context/renderers.py +0 -0
  198. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/context/scanners.py +0 -0
  199. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/event_bus/drivers.py +0 -0
  200. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/event_bus/envelope.py +0 -0
  201. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/event_bus/redis_streams_driver.py +0 -0
  202. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/http_server/context.py +0 -0
  203. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/http_server/pipeline.py +0 -0
  204. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/http_server/types.py +0 -0
  205. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/logger/logger_tool.py +0 -0
  206. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/sqlite/errors.py +0 -0
  207. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/sqlite/migrations.py +0 -0
  208. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/sqlite/transaction.py +0 -0
  209. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/state/state_tool.py +0 -0
  210. {microcoreos-0.3.0 → microcoreos-0.3.2}/tools/system/registry_tool.py +0 -0
@@ -11,14 +11,14 @@ open — a Planner that also loads the plugin templates spends ~3,000 tokens on
11
11
  code it will never write.
12
12
 
13
13
  This file deliberately holds no rules, no reading path and no checklist of its
14
- own. It used to hold all three, and all three had drifted: its reading path
15
- sent plugin authors to `INSTRUCTIONS_FOR_AI.md` for templates that live in the
16
- generated manifest, and its checklist was a fifth partial copy of the 13
17
- Non-Negotiable Rules — one that never mentioned typed event payloads.
14
+ own. It is a routing table and nothing else: every row points at the one place
15
+ that owns its subject. Add a rule, a path or a checklist here and it becomes a
16
+ rival copy of something canonical — which is the one failure this file exists
17
+ to prevent.
18
18
 
19
19
  | You need | It is in |
20
20
  |---|---|
21
- | The rules | `AGENTS.md` § Non-Negotiable Rules (13, canonical) |
21
+ | The rules | `AGENTS.md` § Non-Negotiable Rules (canonical) |
22
22
  | Kernel/tool/event-bus laws | `AGENTS.md` § Core Architectural Laws |
23
23
  | The plugin template | `AI_CONTEXT.md` § Plugin Authoring Guide (regenerated every boot) |
24
24
  | What exists right now | `AI_CONTEXT.md` § Available Tools / § Domains |
@@ -10,7 +10,7 @@ You are a **Systems Architect** specialized in high-performance, resilient micro
10
10
  ## Decision Framework
11
11
  - **Core First**: Is this change affecting the Core? If yes, look for an alternative in Plugins/Tools.
12
12
  - **Tool Isolation**: Does this Tool import another Tool? If so, REJECT the design and move the logic to a Plugin (Bridge).
13
- - **Rules Review**: Before implementing, check the 13 Non-Negotiable Rules in `AGENTS.md`. (This line used to cite "Three Golden Rules in SKILL.md" — a document that never existed.)
13
+ - **Rules Review**: Before implementing, check the Non-Negotiable Rules in `AGENTS.md`.
14
14
  - **Resilience**: Will a failure here crash the entire system?
15
15
  - **Observability**: Can this be monitored via the `registry`?
16
16
 
@@ -30,8 +30,8 @@ existing vocabulary implies, put it in the YAML, and flag it in a comment.
30
30
 
31
31
  `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 holds the rules behind the format.
32
32
  Read it when a validator error is unclear, not before — and never reach for
33
- plugin source under `domains/`, `tools/` or `extras/` to infer the shape. A
34
- planner that did produced a plan with every field renamed.
33
+ plugin source under `domains/`, `tools/` or `extras/` to infer the shape:
34
+ reading an implementation to infer the format renames every field in your plan.
35
35
 
36
36
  ## Prerequisites
37
37
 
@@ -127,10 +127,19 @@ assert_chain(build_tree(bus.get_trace_history()), ["order.cancelled", "order.ref
127
127
  ### 5. Close
128
128
 
129
129
  ```bash
130
- // turbo
131
- uv run main.py # or: microcoreos (if you installed the package)
130
+ microcoreos migrate # the boot that ends: applies migrations, regenerates AI_CONTEXT.md
132
131
  ```
133
132
 
134
- - `GET /system/lint` → no warnings, no `UNTYPED_PAYLOAD` for your events.
135
133
  - Regenerated `AI_CONTEXT.md` matches the plan (routes, events, keys).
136
134
  **The feature is done when AI_CONTEXT == plan.**
135
+
136
+ Then, for the lint only — the one boot this workflow sanctions (`AGENTS.md`
137
+ § reading route). This boot **serves forever**: foreground, read, Ctrl-C.
138
+ Never background it; a process holding port 5000 makes the next
139
+ `microcoreos migrate` refuse to run.
140
+
141
+ ```bash
142
+ microcoreos # or: uv run main.py (identical) — Ctrl-C when done
143
+ ```
144
+
145
+ - `GET /system/lint` → no warnings, no `UNTYPED_PAYLOAD` for your events.
@@ -35,8 +35,8 @@ existing vocabulary implies, put it in the YAML, and flag it in a comment.
35
35
 
36
36
  `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 holds the rules behind the format.
37
37
  Read it when a validator error is unclear, not before — and never reach for
38
- plugin source under `domains/`, `tools/` or `extras/` to infer the shape. A
39
- planner that did produced a plan with every field renamed.
38
+ plugin source under `domains/`, `tools/` or `extras/` to infer the shape:
39
+ reading an implementation to infer the format renames every field in your plan.
40
40
 
41
41
  ## Phase 1 — The full plan (the contract, authored FIRST)
42
42
 
@@ -73,14 +73,14 @@ never patch it in code.
73
73
  ## Phases 0, 2 and 3
74
74
 
75
75
  Identical to any other plan — `docs/PARALLEL_DEVELOPMENT.md` owns them, and
76
- restating them here is how this file once kept prescribing a boot command that
77
- had stopped regenerating the manifest.
76
+ nothing about them is restated here. A second copy of a phase is a second
77
+ command to keep in step, and only one of the two gets updated.
78
78
 
79
79
  Two things are specific to multi-domain work and are the only reason this
80
80
  section exists:
81
81
 
82
82
  - **Migration ordering across domains.** One author for the numbering, and
83
- `-- depends: other_domain/001_file.sql` wherever a table in one domain must
83
+ `-- depends: other_domain/001_file.sql` wherever a table in one domain must <!-- lint:no-path -->
84
84
  exist before another's. The db tool resolves the order and prints each file
85
85
  as it applies it.
86
86
  - **Never assign two agents to the same feature**, and never let one agent
@@ -32,13 +32,13 @@ existing vocabulary implies, put it in the YAML, and flag it in a comment.
32
32
 
33
33
  `docs/PARALLEL_DEVELOPMENT.md` § Phase 1 holds the rules behind the format.
34
34
  Read it when a validator error is unclear, not before — and never reach for
35
- plugin source under `domains/`, `tools/` or `extras/` to infer the shape. A
36
- planner that did produced a plan with every field renamed.
35
+ plugin source under `domains/`, `tools/` or `extras/` to infer the shape:
36
+ reading an implementation to infer the format renames every field in your plan.
37
37
 
38
38
  ## Prerequisites
39
39
 
40
40
  Both files above. Nothing else: the plugin template lives in `AI_CONTEXT.md`
41
- § Plugin Authoring Guide, generated on every boot, and the rules are the 13
41
+ § Plugin Authoring Guide, generated on every boot, and the rules are the
42
42
  Non-Negotiable Rules in `AGENTS.md`.
43
43
 
44
44
  ## Steps
@@ -65,7 +65,6 @@ lines of YAML, one pass.
65
65
  ### 1. Create the domain folder structure
66
66
 
67
67
  ```bash
68
- // turbo
69
68
  mkdir -p domains/{name}/models domains/{name}/migrations domains/{name}/plugins
70
69
  ```
71
70
 
@@ -93,13 +92,24 @@ class {Name}Entity(BaseModel):
93
92
 
94
93
  File: `domains/{name}/migrations/001_create_{name}_table.sql`
95
94
 
96
- Write raw SQL that creates the table. Use `$1, $2...` placeholders in queries (PostgreSQL-style, auto-converted for SQLite).
95
+ Write raw SQL that creates the table. Queries use `$1, $2...` placeholders
96
+ (PostgreSQL-style, auto-converted for SQLite) — but **migration SQL is never
97
+ translated: it runs verbatim on the active engine** (Non-Negotiable Rule 8).
98
+ The default engine is SQLite, which has neither `SERIAL` nor `NOW()`.
99
+
100
+ Write portable SQL — `CURRENT_TIMESTAMP`, not `NOW()` — so the PostgreSQL swap
101
+ stays free. The auto-increment PK is the one thing with no spelling common to
102
+ both: write it the SQLite way and carry the swap note in the file. The
103
+ reference is `extras/available_domains/users/migrations/001_create_users.sql`:
97
104
 
98
105
  ```sql
106
+ -- Portable SQL except the auto-increment PK. On a PostgreSQL swap, change
107
+ -- "INTEGER PRIMARY KEY" to "INTEGER PRIMARY KEY GENERATED BY DEFAULT AS
108
+ -- IDENTITY" (see docs/ELASTIC_DEPLOYMENT.md, Stage 1 review).
99
109
  CREATE TABLE IF NOT EXISTS {name}s (
100
- id SERIAL PRIMARY KEY,
101
- -- columns matching the entity model
102
- created_at TIMESTAMP DEFAULT NOW()
110
+ id INTEGER PRIMARY KEY,
111
+ -- columns matching the entity model, with the plan's types
112
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
103
113
  );
104
114
  ```
105
115
 
@@ -108,7 +118,8 @@ CREATE TABLE IF NOT EXISTS {name}s (
108
118
  One plugin file per operation in `domains/{name}/plugins/`. The template — with
109
119
  request, response and event-payload schemas inline, and the rules that go with
110
120
  them — is `AI_CONTEXT.md` § **Plugin Authoring Guide**, regenerated on every
111
- boot and already inside every executor prompt. A fourth copy lived here.
121
+ boot and already inside every executor prompt. Never copy it into this file
122
+ or into a plan — the copy is what goes stale.
112
123
 
113
124
  The one thing that is this workflow's own decision: which operations exist.
114
125
  A CRUD domain is create / get_all / get_by_id / update / delete, one file each,
@@ -116,54 +127,81 @@ each declared in the plan before any of them is written.
116
127
 
117
128
  ### 5. Verify
118
129
 
130
+ Most of the checklist needs no server. Start with the boot that ends:
131
+
132
+ ```bash
133
+ microcoreos migrate # applies migrations AND regenerates AI_CONTEXT.md
134
+ ```
135
+
119
136
  ```bash
120
- // turbo
121
- uv run main.py # or: microcoreos (if you installed the package)
137
+ microcoreos schema # the live tables and columns
122
138
  ```
123
139
 
124
140
  Check that:
125
- - Migration ran successfully (look for `[Migration] ✅` in logs)
141
+ - Migrations applied (look for `[Migration] ✅`) and `microcoreos schema` shows
142
+ the new tables with the columns the plan declared
143
+ - `AI_CONTEXT.md` was regenerated with the new domain — **done when it matches
144
+ the plan**
145
+
146
+ Only the lint endpoints need a live system, and this is the one place in this
147
+ workflow sanctioned to boot one (`AGENTS.md` § reading route). This boot
148
+ **serves forever**: run it in the foreground, read the endpoints, Ctrl-C.
149
+ Never background it — a process left holding port 5000 makes the next
150
+ `microcoreos migrate` refuse to run.
151
+
152
+ ```bash
153
+ microcoreos # or: uv run main.py (identical) — Ctrl-C when done
154
+ ```
155
+
126
156
  - Endpoints appear in the Swagger UI at `http://localhost:5000/docs`
127
157
  - `GET /system/lint` has no warnings and no `UNTYPED_PAYLOAD` for your events
128
158
  - `GET /system/events/schemas` lists every event the plan declared
129
- - `AI_CONTEXT.md` was regenerated with the new domain — **done when it matches the plan**
130
- - `microcoreos schema` shows the new tables with the columns the plan declared
131
159
 
132
160
  ### 6. Generate tests
133
161
 
134
162
  Create `tests/test_{name}_plugin.py` with one test per plugin. Mock exactly
135
163
  the tools the plan's `tools:` field lists; run the rest as real in-memory
136
- instances (`INSTRUCTIONS_FOR_AI.md` § Testing). Example with everything
137
- mocked (`tools: [http, db, event_bus, logger]`):
164
+ instances (`INSTRUCTIONS_FOR_AI.md` § Testing).
165
+
166
+ **Configure the method, not the mock.** A plugin awaits `self.db.execute(...)`,
167
+ never `self.db(...)` — so `AsyncMock(return_value=1)` and
168
+ `AsyncMock(side_effect=...)` configure a call that never happens. Set them on
169
+ the method: `db.execute.return_value = 1`, `db.execute.side_effect = ...`.
138
170
 
139
171
  ```python
140
172
  import pytest
141
173
  from unittest.mock import MagicMock, AsyncMock
142
174
  from domains.{name}.plugins.create_{name}_plugin import Create{Name}Plugin
143
175
 
144
- @pytest.mark.anyio
145
- async def test_create_{name}_success():
146
- plugin = Create{Name}Plugin(
147
- http=MagicMock(),
148
- db=AsyncMock(return_value=1),
149
- event_bus=AsyncMock(),
150
- logger=MagicMock(),
176
+ pytestmark = pytest.mark.anyio
177
+
178
+
179
+ def make_plugin(db):
180
+ return Create{Name}Plugin(
181
+ http=MagicMock(), db=db, event_bus=AsyncMock(), logger=MagicMock()
151
182
  )
152
- result = await plugin.execute({"field1": "value", "field2": 42})
183
+
184
+
185
+ async def test_create_{name}_success():
186
+ db = AsyncMock()
187
+ db.execute.return_value = 1 # the METHOD the plugin awaits
188
+ result = await make_plugin(db).execute({"field1": "value", "field2": 42})
153
189
  assert result["success"] is True
154
190
  assert result["data"]["id"] == 1
155
191
 
156
- @pytest.mark.anyio
192
+
157
193
  async def test_create_{name}_db_error():
158
- plugin = Create{Name}Plugin(
159
- http=MagicMock(),
160
- db=AsyncMock(side_effect=Exception("DB down")),
161
- event_bus=AsyncMock(),
162
- logger=MagicMock(),
163
- )
164
- result = await plugin.execute({"field1": "value", "field2": 42})
194
+ db = AsyncMock()
195
+ db.execute.side_effect = Exception("DB down")
196
+ result = await make_plugin(db).execute({"field1": "value", "field2": 42})
165
197
  assert result["success"] is False
166
198
  assert "DB down" not in result["error"] # Safe Errors: technical detail never reaches the client
167
199
  ```
168
200
 
201
+ `pytest.mark.anyio` needs an `anyio_backend` fixture; the generated
202
+ the generated root `conftest.py` already ships one, along with `mock_logger` and
203
+ `mock_state`. The richer alternative — the real db tool with this domain's
204
+ migrations applied, asserting on rows instead of on mock calls — is the
205
+ black-box style of `tests/domains/users/test_create_user_plugin.py`.
206
+
169
207
  Run with `uv run -m pytest tests/test_{name}_plugin.py`.
@@ -20,16 +20,29 @@ else about them exists so they can be swapped without touching a single plugin.
20
20
  1. **Location**: `tools/{name}/{name}_tool.py` — or `extras/available_tools/{name}/`
21
21
  if it should not be active by default (a replacement ALWAYS starts in
22
22
  extras/: two tools with the same `name` silently overwrite each other).
23
- 2. **The `name` property is the contract** — it is the DI injection key.
24
- 3. **A tool never uses other tools.** If a capability needs `db` + `event_bus`
23
+ **The tool's own tests go in `{that folder}/tests/`**, so they travel with
24
+ the tool when `microcoreos add` moves it. Import the tool the way those
25
+ tests do — `tools.{name}` first, `extras.available_tools.{name}` as the
26
+ fallback — or the import dies the moment the folder moves. Parity suites
27
+ are the exception: they import two implementations at once, so they stay in
28
+ `tests/tools/{name}/`.
29
+ 2. **Name those tests `{name}_tool_test.py`, never `test_{name}_tool.py`.**
30
+ The Kernel imports every `*_tool.py` under `tools/`, and `test_s3_tool.py`
31
+ ends in exactly that: boot would import the test, and with it pytest, which
32
+ a deployed install does not have. pytest collects `*_test.py` by default,
33
+ so the safe name costs nothing. `DiscoveryNamingLinterPlugin` fails on the
34
+ unsafe one — this is the only place in the repo where `*_test.py` is the
35
+ required form.
36
+ 3. **The `name` property is the contract** — it is the DI injection key.
37
+ 4. **A tool never uses other tools.** If a capability needs `db` + `event_bus`
25
38
  + `scheduler`, it is not a tool: compose it in the plugin layer
26
39
  (precedents: DurableOneShotsPlugin, the deferred Outbox — Issue 28).
27
- 4. **Self-documented**: every public method appears in
40
+ 5. **Self-documented**: every public method appears in
28
41
  `get_interface_description()` — the anti-drift linter warns on discrepancies.
29
- 5. **Config via `os.getenv()`** inside the tool (the `config` tool is for plugins).
30
- 6. **Header spec**: the tool's docstring/header documents its replacement
42
+ 6. **Config via `os.getenv()`** inside the tool (the `config` tool is for plugins).
43
+ 7. **Header spec**: the tool's docstring/header documents its replacement
31
44
  contract — the exact API and semantics a substitute must honor.
32
- 7. **External backend?** Make its connection-error class inherit
45
+ 8. **External backend?** Make its connection-error class inherit
33
46
  `ToolUnavailableError` so ToolProxy marks it DEAD on the first
34
47
  infrastructure failure. In-memory/local tools skip this.
35
48
 
@@ -52,8 +65,8 @@ No imports from other tools, no plugin imports, stateless where possible.
52
65
 
53
66
  The same test battery runs against the reference implementation AND yours:
54
67
 
55
- - Canonical examples: `tests/tools/test_state_parity.py`,
56
- `tests/tools/test_event_bus_broker_parity.py` (parameterized over transports).
68
+ - Canonical examples: `tests/tools/state/test_state_parity.py`,
69
+ `tests/tools/event_bus/test_event_bus_broker_parity.py` (parameterized over transports).
57
70
  - If the backend needs a server, the suite skips itself when unavailable and
58
71
  the server is added to CI services (`dev_infra/docker-compose.yml`).
59
72
  - **A replacement that does not pass the reference's parity suite is not a
@@ -5,7 +5,8 @@
5
5
  "Bash(cp AI_CONTEXT.md /tmp/ai_context_antes.md)",
6
6
  "Read(//tmp/**)",
7
7
  "Bash(timeout 15 uv run main.py)",
8
- "Bash(echo \"EXIT:$?\")"
8
+ "Bash(echo \"EXIT:$?\")",
9
+ "Bash(.venv/bin/python *)"
9
10
  ]
10
11
  }
11
12
  }
@@ -35,7 +35,7 @@ jobs:
35
35
  --health-timeout 5s
36
36
  --health-retries 5
37
37
 
38
- # Real Redis so the state parity suite (tests/tools/test_state_parity.py)
38
+ # Real Redis so the state parity suite (tests/tools/state/test_state_parity.py)
39
39
  # runs against actual infrastructure instead of skipping itself.
40
40
  redis:
41
41
  image: redis:7-alpine
@@ -48,7 +48,7 @@ jobs:
48
48
  --health-retries 5
49
49
 
50
50
  # Real RabbitMQ so the broker parity suite
51
- # (tests/tools/test_event_bus_rabbitmq_parity.py) runs instead of skipping.
51
+ # (tests/tools/event_bus/test_event_bus_rabbitmq_parity.py) runs instead of skipping.
52
52
  rabbitmq:
53
53
  image: rabbitmq:3.13-alpine
54
54
  ports:
@@ -103,7 +103,11 @@ jobs:
103
103
  uv run python -c "from microcoreos import BaseTool; print('✅ BaseTool OK')"
104
104
 
105
105
  - name: Run Core Tests
106
- run: uv run -m pytest tests/ -v --tb=short
106
+ # No path argument: `testpaths` in pyproject.toml owns the set, and it
107
+ # is wider than tests/ — a tool's own tests live inside the tool's
108
+ # folder so they travel with it when `microcoreos add` moves it.
109
+ # Passing `tests/` here would silently drop every one of them.
110
+ run: uv run -m pytest -v --tb=short
107
111
 
108
112
  # Boots the REAL system against REAL infrastructure (MinIO as S3, SQLite on
109
113
  # disk) and asserts that every tool is OK and every plugin is READY. This is
@@ -373,7 +377,7 @@ jobs:
373
377
  # The filesystem-facing suites. The rest of tests/ needs Postgres, Redis
374
378
  # and RabbitMQ, which is what the Linux matrix is for.
375
379
  - name: Path and packaging suites
376
- run: uv run -m pytest tests/test_upgrade.py tests/test_scaffold.py tests/test_catalog.py tests/test_cli.py -q
380
+ run: uv run -m pytest tests/system/test_upgrade.py tests/system/test_scaffold.py tests/system/test_catalog.py tests/system/test_cli.py -q
377
381
 
378
382
  - name: Build the wheel
379
383
  run: uv build --wheel -o dist
@@ -55,3 +55,10 @@ package-lock.json
55
55
  # as a submodule with no .gitmodules, and every checkout since failed its
56
56
  # cleanup step with exit 128.
57
57
  .claude/worktrees/
58
+
59
+ # Test Coverage & Mutation Testing
60
+ .coverage
61
+ htmlcov/
62
+ .mutmut-cache/
63
+ mutants/
64
+
@@ -27,12 +27,42 @@ Four roles do the work, and **each needs a different slice**. Reading outside
27
27
  your slice is not thoroughness, it is budget: the Planner that also loads the
28
28
  plugin templates spends ~3,000 tokens on code it will never write.
29
29
 
30
+ They are phases, not people. Doing all of them yourself is the fifth row — the
31
+ common case for one or two features — and it means playing the four in order,
32
+ taking each slice as you enter it, not reading everything up front.
33
+
30
34
  | You are… | Read exactly this | **Write exactly this** | Not this |
31
35
  |---|---|---|---|
32
36
  | **Planner** — turning a request into a plan | **1.** `plans/active_plan.yaml` — the file you are about to overwrite. It ships as a worked example of all three feature shapes, and it is the cheapest, densest statement of the format there is. **2.** `AI_CONTEXT.md` **down to `## 🧩 Plugin Authoring Guide`** (existing tools, tables, models, routes, events). **3.** `docs/PARALLEL_DEVELOPMENT.md` **§ Phase 1** for the rules behind it | **`plans/active_plan.yaml` + `plans/active_plan.md`, overwriting them.** Never a new filename — `plans/twitter_plan.yaml` is a plan nothing will execute | The Authoring Guide, Phases 2-3, `domains/`, `tools/`, `tests/`, `extras/` |
33
37
  | **Phase 0 Builder** — migrations, models, tools | `plans/active_plan.yaml` **§ phase_0** only | Exactly the files `phase_0` names: its migrations, its models, its tools | Everything else. The plan already decided every column |
34
38
  | **Executor** — one plugin + its test | **Nothing.** Your prompt already contains `AI_CONTEXT.md` + the plan + your one task line | Exactly two files: the `file:` and `test:` your task declares | Any file at all — opening one only invites guessed paths |
35
39
  | **Coordinator** — dispatch, verify, reconstruct | `plans/active_plan.md` (the checklist/state machine) + `docs/PARALLEL_DEVELOPMENT.md` **§ Phases 2-3** | Only the checkboxes in `plans/active_plan.md` | The plan's internals; the checklist is the state |
40
+ | **Solo** — one agent, every phase, in sequence | The row above you, as you reach it — the Planner's slice first, and nothing else until you are past planning | Everything the four rows write, in their order | Skipping the plan because it is "only two features". See below |
41
+
42
+ **If you are the Solo row**, exactly two things differ from the four above.
43
+ You may read the code **you** wrote — the black box rule is about not seeing
44
+ *another agent's* implementation, and it does not apply to your own
45
+ (`docs/PARALLEL_DEVELOPMENT.md` § Features are black boxes). And you run the
46
+ union of the command rows below, each in its own phase.
47
+
48
+ What does **not** differ is the plan. `plans/active_plan.yaml` is still the
49
+ first file you write, for one feature as much as for twelve. Three reasons,
50
+ none of which are about coordinating anybody:
51
+
52
+ - **The shipped plan is a valid plan.** Leave it untouched and `microcoreos
53
+ status` reports the *example* domain as the active work — to you now, and to
54
+ whoever opens the project next.
55
+ - **`microcoreos plan validate` is the only pre-code check there is.** Route
56
+ collisions, consumed events that nothing publishes, tables owned by another
57
+ domain, the sad-path checklist. It runs offline, in a second, before a line
58
+ of code commits you to any of it.
59
+ - **It is what survives you.** A context that gets compacted, a session that
60
+ dies at feature two of three — the plan is the only record of what "done"
61
+ meant. Prose in a reply is not.
62
+
63
+ The cost is the honest objection, and it is small: one feature on an existing
64
+ domain is ~10-15 lines of YAML, no `phase_0`, and no `flows` at all unless it
65
+ publishes or consumes events (`.agent/workflows/feature-plan.md`).
36
66
 
37
67
  If you are the Planner, the first thing you write is `plans/active_plan.yaml`
38
68
  itself — not a draft under another name that someone copies later. The copy
@@ -54,6 +84,7 @@ reviews a real file rather than a description of one.
54
84
  | Phase 0 Builder | `microcoreos migrate`, `microcoreos schema` |
55
85
  | Executor | none — write your two files and stop |
56
86
  | Coordinator | `uv run -m pytest`, `microcoreos status`, and `microcoreos` (the real boot) for the final lint |
87
+ | Solo | All of the above — but each in its phase, and the real boot only at the end |
57
88
 
58
89
  **Never `microcoreos run` / `uv run main.py` outside that last row.** It serves
59
90
  forever: in the foreground it hangs your session, in the background it leaves a
@@ -157,10 +188,9 @@ The Kernel (ToolProxy & Container) is infrastructure-blind:
157
188
  ## 🔄 The pipeline, in five lines
158
189
 
159
190
  The methodology, the phase numbering and the executor-prompt mechanics live in
160
- `docs/PARALLEL_DEVELOPMENT.md` — **canonically, and only there**. This used to
161
- be a second copy of it, which is precisely how the copy drifted: it prescribed
162
- `--boot-tool db` for phase 0 long after that stopped regenerating the manifest,
163
- and no one compares two documents to notice.
191
+ `docs/PARALLEL_DEVELOPMENT.md` — **canonically, and only there**. What follows
192
+ is a five-line index, not a second copy: nobody diffs two documents, so a copy
193
+ here would keep prescribing a stale command with every test still green.
164
194
 
165
195
  | Phase | Command | Gate |
166
196
  |---|---|---|
@@ -87,22 +87,31 @@ Configuration Tool (config):
87
87
  ### 🔧 Tool: `telemetry` (Status: ✅)
88
88
  ```text
89
89
  Telemetry Tool (telemetry):
90
- - PURPOSE: OpenTelemetry distributed tracing. Auto-instruments all tool calls via ToolProxy.
91
- No changes needed in plugins or existing tools to get basic spans.
90
+ - PURPOSE: OpenTelemetry distributed tracing AND metrics. Auto-instruments all tool
91
+ calls via ToolProxy. No changes needed in plugins or existing tools to get basic
92
+ spans or metrics.
92
93
  - ACTIVATION: Set OTEL_ENABLED=true. Degrades gracefully if disabled or packages missing.
93
94
  - ENV VARS:
94
95
  - OTEL_ENABLED: "true" to activate (default: "false").
95
- - OTEL_SERVICE_NAME: Service name in traces (default: "microcoreos").
96
- - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP/gRPC endpoint (e.g. "http://jaeger:4317").
97
- If not set, traces are printed to console (development mode).
96
+ - OTEL_SERVICE_NAME: Service name in traces/metrics (default: "microcoreos").
97
+ - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP/gRPC endpoint (e.g. "http://otel-collector:4317").
98
+ If not set, traces and metrics are printed to console (development mode).
98
99
  - CAPABILITIES:
99
100
  - get_tracer(scope: str) -> Tracer: Named tracer for custom spans inside a plugin.
100
101
  Usage: tracer = self.telemetry.get_tracer("my_plugin")
101
102
  with tracer.start_as_current_span("my_operation"): ...
102
103
  Returns a no-op tracer if OTel is disabled — safe to use unconditionally.
104
+ - get_meter(scope: str) -> Meter: Named meter for custom metrics inside a plugin.
105
+ Usage: meter = self.telemetry.get_meter("my_plugin")
106
+ counter = meter.create_counter("orders_created")
107
+ counter.add(1)
108
+ Returns a no-op meter if OTel is disabled — safe to use unconditionally.
103
109
  - AUTO-INSTRUMENTATION (zero config):
104
110
  Every tool call (db.execute, event_bus.publish, auth.create_token, etc.)
105
- gets a span automatically via ToolProxy. No plugin changes needed.
111
+ gets a span automatically via ToolProxy, AND is recorded as an OTel histogram
112
+ (tool_call_duration_ms) and counter (tool_call_total) with tool/method/success
113
+ attributes — the same record already exposed at registry.get_metrics() / GET
114
+ /system/metrics, now also exported over OTLP. No plugin changes needed.
106
115
  - DRIVER-LEVEL INSTRUMENTATION (optional, per tool):
107
116
  Tools can implement on_instrument(tracer_provider) in BaseTool to add
108
117
  framework-specific spans (SQL query text, HTTP route, etc.).
@@ -304,11 +313,11 @@ Async SQLite Persistence Tool (sqlite):
304
313
  - `GET /system/events/schemas`
305
314
  - **res**: EventSchemasData(schemas: dict)
306
315
  - `GET /system/lint`
307
- - **res**: SystemLintData(arch_violations: list[str], drift_warnings: list[str], event_contract_violations: list[LintFinding(code: str, severity: str, event: Optional[str], publisher: Optional[str], consumer: Optional[str], detail: str)], route_collisions: list[str], table_ownership_warnings: list[str], field_divergence_warnings: list[str])
316
+ - **res**: SystemLintData(arch_violations: list[str], drift_warnings: list[str], event_contract_violations: list[LintFinding(code: str, severity: str, event: Optional[str], publisher: Optional[str], consumer: Optional[str], detail: str)], route_collisions: list[str], table_ownership_warnings: list[str], field_divergence_warnings: list[str], dead_path_warnings: list[str])
308
317
  - **Events emitted**: none
309
318
  - **Events consumed**: none
310
319
  - **Dependencies**: container, http, logger
311
- - **Plugins**: devtools.DiscoveryNamingLinterPlugin, devtools.DomainIsolationLinterPlugin, devtools.EventContractLinterPlugin, devtools.EventSchemasPlugin, devtools.FieldDivergenceLinterPlugin, devtools.RouteCollisionLinterPlugin, devtools.TableOwnershipLinterPlugin, devtools.ToolDocDriftLinterPlugin
320
+ - **Plugins**: devtools.DiscoveryNamingLinterPlugin, devtools.DocPathLinterPlugin, devtools.DomainIsolationLinterPlugin, devtools.EventContractLinterPlugin, devtools.EventSchemasPlugin, devtools.FieldDivergenceLinterPlugin, devtools.RouteCollisionLinterPlugin, devtools.TableOwnershipLinterPlugin, devtools.ToolDocDriftLinterPlugin
312
321
 
313
322
  ### `system`
314
323
  - **Tables**: none
@@ -27,9 +27,10 @@ These are the most frequent errors. Check these first before writing any code.
27
27
 
28
28
  ## ⚠️ The rules
29
29
 
30
- The 13 **Non-Negotiable Rules** in `AGENTS.md`, there and nowhere else. This
31
- section held a rival list of eleven that had never heard of "schemas inline" or
32
- typed event payloads — an agent's constitution depended on which file it opened.
30
+ The **Non-Negotiable Rules** in `AGENTS.md`, there and nowhere else. Never
31
+ restate them here, and never cite them with a count: a rival copy, or a number
32
+ that another file has to keep in step, is one more thing that can disagree with
33
+ the list an agent is standing in front of.
33
34
 
34
35
  Event bus capabilities (`ttl`, `retries`, `backoff`, DLQ) are in `AI_CONTEXT.md`
35
36
  § Tool: `event_bus`, generated from the tool itself so they cannot drift.
@@ -63,7 +64,8 @@ domains/{name}/
63
64
 
64
65
  `AI_CONTEXT.md` § **Plugin Authoring Guide** — one complete template per
65
66
  deliverable type, regenerated on every boot from `tools/context/authoring_guide.md` and
66
- already inside every executor prompt. A third copy lived here and had drifted.
67
+ already inside every executor prompt. Never copy it here: the generated one
68
+ is the only one that tracks the code.
67
69
 
68
70
  If you are writing a plugin you are an executor: nothing in this file is for you.
69
71
 
@@ -120,7 +122,9 @@ Rules of the pattern:
120
122
 
121
123
  ## 🔧 New Tool
122
124
 
123
- **Location**: `tools/{name}/{name}_tool.py`
125
+ **Location**: `tools/{name}/{name}_tool.py`, with its own tests in
126
+ `tools/{name}/tests/`, named `{name}_tool_test.py` — NEVER `test_{name}_tool.py`,
127
+ which the Kernel would import at boot. They travel with the tool when it is installed or swapped.
124
128
  **Rule**: Stateless, isolated, self-documented. Use `EventBusDriver` pattern for new transport layers.
125
129
 
126
130
  ### The Parity Rule (Contract over Implementation)
@@ -130,9 +134,9 @@ replaces. This ensures that plugins remain infrastructure-blind and behavior
130
134
  is consistent across backends.
131
135
 
132
136
  **Canonical examples:**
133
- - `tests/tools/test_state_parity.py`: Verifies that `RedisStateTool` behaves
137
+ - `tests/tools/state/test_state_parity.py`: Verifies that `RedisStateTool` behaves
134
138
  exactly like the default in-memory `StateTool`.
135
- - `tests/tools/test_event_bus_broker_parity.py`: Parametrized suite that
139
+ - `tests/tools/event_bus/test_event_bus_broker_parity.py`: Parametrized suite that
136
140
  runs against both the local driver and `RedisStreamsDriver`.
137
141
 
138
142
  **Health contract (optional, only for tools with an external backend)**:
@@ -261,15 +265,15 @@ plugin against a contract the test itself declares, so if a tool's real API
261
265
  drifts the mock keeps passing. That gap is closed elsewhere, not by your test:
262
266
  the `ToolDocDriftLinter` (boot + `/system/lint`) compares each tool's
263
267
  documented interface against its implementation, and the parity suites
264
- (`tests/tools/test_state_parity.py`,
265
- `tests/tools/test_event_bus_broker_parity.py`) hold swappable tools to one
268
+ (`tests/tools/state/test_state_parity.py`,
269
+ `tests/tools/event_bus/test_event_bus_broker_parity.py`) hold swappable tools to one
266
270
  behaviour. Do not re-verify that in a plugin test.
267
271
 
268
272
  ### Ask for tools the way the plugin does
269
273
 
270
274
  A plugin never builds a tool: it names one in `__init__` and the Kernel hands
271
275
  it over. pytest injects by parameter name too, so **a test uses the same
272
- vocabulary** — `tests/conftest.py` publishes one fixture per Kernel injection
276
+ vocabulary** — `conftest.py` (repo root) publishes one fixture per Kernel injection
273
277
  key (`db`, `event_bus`, `auth`, `state`, `logger`, `config`). No tool imports,
274
278
  no setup/teardown, no hand-built schema:
275
279
 
@@ -285,7 +289,7 @@ async def test_create_user_persists(db, event_bus, auth, logger):
285
289
  assert rows[0]["password_hash"] != "secret123"
286
290
  ```
287
291
 
288
- Worked example: `tests/test_plugin_di_fixtures.py`.
292
+ Worked example: `tests/core/test_plugin_di_fixtures.py`.
289
293
 
290
294
  - `@pytest.mark.migrations("users", "system")` applies those domains' real
291
295
  migration files. **No marker = a real but empty database**, which is what a
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microcoreos
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Atomic Microkernel Architecture optimized for AI-Driven Development
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -184,7 +184,7 @@ That is the code your app depends on, and it is the whole of it: booting loads
184
184
  `kernel`, `container`, `registry`, `context` and the two base classes, and
185
185
  nothing else. The rest of the package — the scaffolder, the extras catalog,
186
186
  `upgrade` — is the `microcoreos` command, build-time work that never executes
187
- inside your application. `tests/test_core_purity.py` enforces both halves of
187
+ inside your application. `tests/core/test_core_purity.py` enforces both halves of
188
188
  that: a third-party import in the kernel fails the suite, and so does the
189
189
  kernel importing the CLI half.
190
190
 
@@ -217,7 +217,7 @@ This pattern works for any infrastructure: swap the event bus backend, the HTTP
217
217
 
218
218
  Additional tools — PostgreSQL, Redis state, auth, S3, the scheduler, chaos — ship in `extras/` and install with `microcoreos add <name>`. If the new tool reuses an existing `name` (e.g. `redis_state` registers as `"state"`), move the tool it replaces out of `tools/` first: only one tool per name may be discovered.
219
219
 
220
- The Redis state swap is verified by a parity suite (`tests/tools/test_state_parity.py`): the same contract battery runs against the in-memory reference and against a real Redis, so the replacement is proven equivalent, not assumed.
220
+ The Redis state swap is verified by a parity suite (`tests/tools/state/test_state_parity.py`): the same contract battery runs against the in-memory reference and against a real Redis, so the replacement is proven equivalent, not assumed.
221
221
 
222
222
  ### Honest Kernel & Smart Infrastructure.
223
223
 
@@ -231,7 +231,7 @@ The Kernel is "logic-free." `ToolProxy` observes and reports health but **never
231
231
 
232
232
  **Tool Call Metrics** — Every tool method call is automatically timed by ToolProxy. Access via `registry.get_metrics()` or attach a real-time sink.
233
233
 
234
- **OpenTelemetry** (optional) — Set `OTEL_ENABLED=true`. Every tool call gets a span. Export to Jaeger, Grafana Tempo, Datadog. Zero changes to plugins.
234
+ **OpenTelemetry** (optional) — Set `OTEL_ENABLED=true`. Every tool call gets a span AND is recorded as a histogram (`tool_call_duration_ms`) + counter (`tool_call_total`). Export to Jaeger, Grafana Tempo, Prometheus, Datadog. Zero changes to plugins.
235
235
 
236
236
  ---
237
237
 
@@ -418,6 +418,23 @@ Two tracks — see [ROADMAP.md](ROADMAP.md) for the full plan and decision log:
418
418
 
419
419
  ---
420
420
 
421
+ ## 💖 Built on the Shoulders of Open-Source Giants
422
+
423
+ MicroCoreOS provides the **Atomic Microkernel Architecture, DI container, orchestration engine, and 1-file decoupling**. Every swappable Tool is a contract wrapper powered by world-class open-source projects created by amazing maintainers:
424
+
425
+ - **FastAPI, Starlette & Uvicorn** — Powers `HttpServerTool` (`http`)
426
+ - **Pydantic** — Powers request/response schema validation
427
+ - **aiosqlite & asyncpg** — Powers `SQLiteTool` and `PostgreSQLTool` (`db`)
428
+ - **redis-py** — Powers `RedisStateTool` and Redis Streams event bus driver
429
+ - **aiokafka & aio-pika** — Powers Kafka and RabbitMQ event bus drivers
430
+ - **APScheduler** — Powers `SchedulerTool` (`scheduler`)
431
+ - **PyJWT & bcrypt** — Powers `AuthTool` (`auth`)
432
+ - **OpenTelemetry** — Powers `TelemetryTool` (`telemetry`)
433
+ - **aioboto3** — Powers `S3Tool` (`s3`)
434
+ - **mutmut & Locust** — Powers mutation blindage and the `MicroCoreBench` laboratory
435
+
436
+ ---
437
+
421
438
  ## License
422
439
 
423
440
  [MIT](LICENSE)