microcoreos 0.4.2__tar.gz → 0.4.4__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.
- {microcoreos-0.4.2 → microcoreos-0.4.4}/AI_CONTEXT.md +1 -1
- {microcoreos-0.4.2 → microcoreos-0.4.4}/PKG-INFO +3 -2
- {microcoreos-0.4.2 → microcoreos-0.4.4}/README.md +2 -1
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/CLI.md +11 -1
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_logs_stream_plugin.py +8 -2
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/cli.py +2 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/pipeline.py +37 -5
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/plan/__init__.py +11 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/plan/rules.py +7 -1
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/plan/scan.py +26 -14
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/plan/schema.py +45 -3
- microcoreos-0.4.4/microcoreos_dev/plan/sync.py +140 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/pyproject.toml +1 -1
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/dev/test_pipeline.py +46 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/dev/test_plan_validator.py +242 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/http_server/test_http_server_tool.py +3 -2
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/logger/test_logger_tool.py +26 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/logger/logger_tool.py +19 -3
- {microcoreos-0.4.2 → microcoreos-0.4.4}/uv.lock +1 -1
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/skills/microcoreos-architecture/SKILL.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/skills/microcoreos-architecture/agent.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/workflows/feature-plan.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/workflows/multi-domain-plan.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/workflows/new-domain.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/workflows/new-tool.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.agent/workflows/solo-build.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.claude/settings.local.json +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.dockerignore +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.env.example +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.github/workflows/ci.yml +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.github/workflows/release.yml +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.gitignore +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.mutmut-cache +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/.python-version +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/AGENTS.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/Dockerfile +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/INSTRUCTIONS_FOR_AI.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/LICENSE +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/ROADMAP.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/cli.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/conftest.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/dev_infra/cache_probe.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/dev_infra/docker-compose.yml +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/CORE_INFRASTRUCTURE.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/ELASTIC_DEPLOYMENT.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/EVENT_BUS.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/HTTP_SERVER.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/INDEX.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/OBSERVABILITY.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/OBSERVABILITY_API.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/PARALLEL_DEVELOPMENT.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/docs/translations/es/README.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/lint/plugin_sources.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/discovery_naming_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/domain_isolation_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/event_contract_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/event_schemas_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/field_divergence_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/route_collision_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/table_ownership_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/devtools/plugins/tool_doc_drift_linter_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/event_delivery_monitor_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_events_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_events_stream_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_metrics_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_status_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_traces_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/system_traces_stream_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/domains/system/plugins/tool_health_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/chaos/plugins/blocking_boot_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/chaos/plugins/chaos_control_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/chaos/plugins/failing_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/chaos/plugins/stress_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/ping/plugins/ping_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/scheduler/migrations/001_scheduler_one_shots.sql +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/scheduler/models/scheduler_one_shot.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/scheduler/plugins/durable_one_shots_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/migrations/001_create_users.sql +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/models/user.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/create_user_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/delete_user_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/get_me_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/get_user_by_id_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/get_users_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/login_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/logout_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/update_user_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_domains/users/plugins/welcome_service_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/auth/auth_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/auth/tests/auth_tool_test.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/chaos/chaos_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/kafka/kafka_driver.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/postgresql/postgresql_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/postgresql/tests/postgresql_describe_schema_test.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/postgresql/tests/postgresql_tool_test.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/rabbitmq/rabbitmq_driver.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/redis_state/redis_state_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/s3/__init__.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/s3/s3_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/s3/tests/s3_tool_test.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/scheduler/scheduler_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/scheduler/tests/scheduler_singleton_test.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/extras/available_tools/scheduler/tests/scheduler_tool_test.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/hatch_build.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/main.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/__init__.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/base_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/base_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/catalog.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/cli.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/container.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/context.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/kernel.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/project.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/project_readme.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/registry.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/scaffold.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos/upgrade.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/__init__.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/fuzzer.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/microcoreos_dev/probe.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/plans/README.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/plans/active_plan.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/plans/active_plan.yaml +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_core.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_core_purity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_kernel.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_no_retry.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_plugin_di_fixtures.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_registry_collisions.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/core/test_tool_proxy.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/dev/corpus/README.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/dev/corpus/qwen_twitter_plan.yaml +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/ping/test_ping_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_create_user_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_delete_user_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_get_me_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_get_user_by_id_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_get_users_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_login_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_logout_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_update_user_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/domains/users/test_welcome_service_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/helpers/active_db.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/helpers/async_wait.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/helpers/mock_db.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/helpers/trace_chains.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_discovery_naming_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_domain_isolation_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_event_contract_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_field_divergence_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_route_collision_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_table_ownership_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/linters/test_tool_doc_drift_linter.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_catalog.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_chaos_control.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_chaos_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_cli.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_durable_one_shots.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_event_schemas_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_scaffold.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_system_events_stats.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_system_traces_plugin.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_trace_chain_helper.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/system/test_upgrade.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/config/test_config_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/context/test_context_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/db/test_db_parity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/event_bus/test_event_bus_broker_parity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/event_bus/test_event_bus_groups.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/event_bus/test_event_bus_kafka_parity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/event_bus/test_event_bus_rabbitmq_parity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/event_bus/test_event_bus_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/event_bus/test_redis_streams_driver.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/http_server/test_http_params_hardening.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/http_server/test_http_pipeline.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/http_server/test_security_hardening.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/registry/test_registry_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/s3/test_s3_parity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/sqlite/test_sqlite_concurrency.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/sqlite/test_sqlite_describe_schema.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/sqlite/test_sqlite_driver.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/sqlite/test_sqlite_migrations.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/sqlite/test_sqlite_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/state/test_state_parity.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/state/test_state_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tests/tools/telemetry/test_telemetry_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/config/config_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/context/authoring_guide.md +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/context/context_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/context/renderers.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/context/scanners.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/event_bus/drivers.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/event_bus/envelope.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/event_bus/event_bus_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/event_bus/redis_streams_driver.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/event_bus/sqlite_driver.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/http_server/context.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/http_server/http_server_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/http_server/pipeline.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/http_server/types.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/sqlite/errors.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/sqlite/migrations.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/sqlite/sqlite_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/sqlite/transaction.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/state/state_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/system/registry_tool.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/telemetry/__init__.py +0 -0
- {microcoreos-0.4.2 → microcoreos-0.4.4}/tools/telemetry/telemetry_tool.py +0 -0
|
@@ -321,7 +321,7 @@ Async SQLite Persistence Tool (sqlite):
|
|
|
321
321
|
- **Events emitted**: none
|
|
322
322
|
- **Events consumed**: none
|
|
323
323
|
- **Dependencies**: container, http, logger
|
|
324
|
-
- **Plugins**: devtools.DiscoveryNamingLinterPlugin, devtools.
|
|
324
|
+
- **Plugins**: devtools.DiscoveryNamingLinterPlugin, devtools.DomainIsolationLinterPlugin, devtools.EventContractLinterPlugin, devtools.EventSchemasPlugin, devtools.FieldDivergenceLinterPlugin, devtools.RouteCollisionLinterPlugin, devtools.TableOwnershipLinterPlugin, devtools.ToolDocDriftLinterPlugin
|
|
325
325
|
|
|
326
326
|
### `system`
|
|
327
327
|
- **Tables**: none
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: microcoreos
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: Atomic Microkernel Architecture optimized for AI-Driven Development
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -124,7 +124,8 @@ Use that rather than `uv add 'microcoreos[auth]'`. The extra is only the **depen
|
|
|
124
124
|
| Command | Purpose |
|
|
125
125
|
|---|---|
|
|
126
126
|
| `microcoreos status` | Reports active plan progress and `AI_CONTEXT.md` freshness |
|
|
127
|
-
| `microcoreos plan validate` | Validates active plan YAML (`plans/active_plan.yaml`) offline against
|
|
127
|
+
| `microcoreos plan validate` | Validates active plan YAML (`plans/active_plan.yaml`) offline against 19 rules (`--fix` to sync checklist first) |
|
|
128
|
+
| `microcoreos plan sync` | Generates or updates execution checklist (`plans/active_plan.md`) preserving progress |
|
|
128
129
|
| `microcoreos migrate` | Applies SQL migrations AND regenerates `AI_CONTEXT.md` (the AI context manifest) |
|
|
129
130
|
| `microcoreos schema` | Inspects live database schema and normalized tables |
|
|
130
131
|
|
|
@@ -83,7 +83,8 @@ Use that rather than `uv add 'microcoreos[auth]'`. The extra is only the **depen
|
|
|
83
83
|
| Command | Purpose |
|
|
84
84
|
|---|---|
|
|
85
85
|
| `microcoreos status` | Reports active plan progress and `AI_CONTEXT.md` freshness |
|
|
86
|
-
| `microcoreos plan validate` | Validates active plan YAML (`plans/active_plan.yaml`) offline against
|
|
86
|
+
| `microcoreos plan validate` | Validates active plan YAML (`plans/active_plan.yaml`) offline against 19 rules (`--fix` to sync checklist first) |
|
|
87
|
+
| `microcoreos plan sync` | Generates or updates execution checklist (`plans/active_plan.md`) preserving progress |
|
|
87
88
|
| `microcoreos migrate` | Applies SQL migrations AND regenerates `AI_CONTEXT.md` (the AI context manifest) |
|
|
88
89
|
| `microcoreos schema` | Inspects live database schema and normalized tables |
|
|
89
90
|
|
|
@@ -11,12 +11,14 @@ microcoreos [run] [--boot-tool <tool>] Boot the Kernel
|
|
|
11
11
|
microcoreos dev Boot with auto-reload
|
|
12
12
|
|
|
13
13
|
microcoreos status Active plan, progress, manifest age
|
|
14
|
-
microcoreos plan validate [path]
|
|
14
|
+
microcoreos plan validate [path] [--fix] The 18 plan rules, offline
|
|
15
|
+
microcoreos plan sync [path] Sync execution checklist from plan
|
|
15
16
|
microcoreos plan probe [path] What each feature actually touches
|
|
16
17
|
microcoreos migrate Migrations + regenerate AI_CONTEXT.md
|
|
17
18
|
microcoreos schema The live tables and columns
|
|
18
19
|
```
|
|
19
20
|
|
|
21
|
+
|
|
20
22
|
**Every example below needs a `uv run` prefix** (or an activated venv): the
|
|
21
23
|
console script lives in `.venv/bin`, so a bare `microcoreos` is "command not
|
|
22
24
|
found". And `<angle brackets>` mark a placeholder — type the value, not the
|
|
@@ -203,6 +205,8 @@ observed failing.
|
|
|
203
205
|
```bash
|
|
204
206
|
microcoreos status # before anything else
|
|
205
207
|
microcoreos plan validate # defaults to plans/active_plan.yaml
|
|
208
|
+
microcoreos plan validate --fix # sync checklist then validate
|
|
209
|
+
microcoreos plan sync # generate / sync plans/active_plan.md from plan
|
|
206
210
|
microcoreos plan validate draft.yaml # or any path
|
|
207
211
|
microcoreos migrate # after writing phase 0
|
|
208
212
|
microcoreos schema # verify what landed in the database
|
|
@@ -216,6 +220,12 @@ and any loose `.py` in the project root — every deliverable has a declared hom
|
|
|
216
220
|
under `domains/`, `tools/` or `tests/`, so one at the root is an agent's
|
|
217
221
|
scratch file left behind. Reported, never deleted.
|
|
218
222
|
|
|
223
|
+
**`plan sync`** — generates or updates `plans/active_plan.md` directly from
|
|
224
|
+
`plans/active_plan.yaml`, preserving existing checkmarks `[x]` while generating
|
|
225
|
+
exact task paths for Phase 0, Phase 2 and Phase 3. Eliminates manual checklist
|
|
226
|
+
authoring and Rule 15 mismatches.
|
|
227
|
+
|
|
228
|
+
|
|
219
229
|
**`plan probe`** — the other half of the question. `validate` asks whether the
|
|
220
230
|
PLAN is well formed; this drives every feature with recording stand-ins for its
|
|
221
231
|
tools and prints every call it makes.
|
|
@@ -22,10 +22,16 @@ class SystemLogsStreamPlugin(BasePlugin):
|
|
|
22
22
|
tags=["System"],
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
def _on_log(self, level: str, message: str, timestamp: str, identity: str):
|
|
25
|
+
def _on_log(self, level: str, message: str, timestamp: str, identity: str, trace_id: str = None):
|
|
26
26
|
if not self._queues:
|
|
27
27
|
return
|
|
28
|
-
record = {
|
|
28
|
+
record = {
|
|
29
|
+
"level": level,
|
|
30
|
+
"message": message,
|
|
31
|
+
"timestamp": timestamp,
|
|
32
|
+
"identity": identity,
|
|
33
|
+
"trace_id": trace_id,
|
|
34
|
+
}
|
|
29
35
|
try:
|
|
30
36
|
loop = asyncio.get_running_loop()
|
|
31
37
|
for q in list(self._queues):
|
|
@@ -34,6 +34,7 @@ USAGE = """MicroCoreOS — development tooling
|
|
|
34
34
|
Usage:
|
|
35
35
|
microcoreos-dev status Active plan, progress, manifest age
|
|
36
36
|
microcoreos-dev plan validate [path] Validate the plan offline (no server)
|
|
37
|
+
microcoreos-dev plan sync [path] Sync execution checklist from plan
|
|
37
38
|
microcoreos-dev plan probe [path] Drive each feature, report what it touches
|
|
38
39
|
microcoreos-dev migrate Apply migrations + regenerate AI_CONTEXT.md
|
|
39
40
|
microcoreos-dev schema Print the live tables and columns
|
|
@@ -44,6 +45,7 @@ project (the directory holding tools/, domains/ and plans/).
|
|
|
44
45
|
"""
|
|
45
46
|
|
|
46
47
|
|
|
48
|
+
|
|
47
49
|
def dispatch(name: str, argv: list[str]) -> int:
|
|
48
50
|
"""Run one pipeline command by name — the seam `microcoreos` calls.
|
|
49
51
|
|
|
@@ -285,27 +285,59 @@ def schema(argv: list[str]) -> int:
|
|
|
285
285
|
|
|
286
286
|
# ── plan validate ────────────────────────────────────────────────────────────
|
|
287
287
|
|
|
288
|
-
PLAN_USAGE = """Usage: microcoreos plan <validate|probe> [path]
|
|
288
|
+
PLAN_USAGE = """Usage: microcoreos plan <validate|probe|sync> [path] [--fix]
|
|
289
289
|
|
|
290
|
-
validate the 19 rules, offline — is the PLAN well formed
|
|
290
|
+
validate the 19 rules, offline — is the PLAN well formed (--fix to sync checklist first)
|
|
291
291
|
probe drive each feature and record what it touches — does the CODE
|
|
292
292
|
match the plan it was written from
|
|
293
|
+
sync generate or sync plans/active_plan.md from the active plan
|
|
293
294
|
|
|
294
295
|
path defaults to plans/active_plan.yaml
|
|
295
296
|
"""
|
|
296
297
|
|
|
297
298
|
|
|
298
299
|
def plan(argv: list[str]) -> int:
|
|
299
|
-
if not argv or argv[0] not in ("validate", "probe"):
|
|
300
|
+
if not argv or argv[0] not in ("validate", "probe", "sync"):
|
|
300
301
|
print(PLAN_USAGE)
|
|
301
302
|
return 2
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
cmd = argv[0]
|
|
304
|
+
rest = argv[1:]
|
|
305
|
+
fix = "--fix" in rest
|
|
306
|
+
args = [a for a in rest if a != "--fix"]
|
|
307
|
+
path = args[0] if args else PLAN_PATH
|
|
308
|
+
|
|
309
|
+
if cmd == "sync":
|
|
310
|
+
return _plan_sync(path)
|
|
311
|
+
elif cmd == "validate":
|
|
312
|
+
if fix:
|
|
313
|
+
sync_res = _plan_sync(path)
|
|
314
|
+
if sync_res != 0:
|
|
315
|
+
return sync_res
|
|
316
|
+
return _plan_validate(path)
|
|
317
|
+
else: # probe
|
|
318
|
+
return _run_probe(path)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _plan_sync(path: str) -> int:
|
|
322
|
+
"""Generate or update plans/active_plan.md from the plan file."""
|
|
323
|
+
root = ensure_project_on_path()
|
|
324
|
+
if not require_project(root):
|
|
325
|
+
return 2
|
|
326
|
+
|
|
327
|
+
from microcoreos_dev.plan.sync import sync_checklist
|
|
328
|
+
|
|
329
|
+
success, msg = sync_checklist(path, CHECKLIST_PATH)
|
|
330
|
+
if not success:
|
|
331
|
+
print(f"\n❌ {msg}\n")
|
|
332
|
+
return 1
|
|
333
|
+
print(f"✅ {msg}")
|
|
334
|
+
return 0
|
|
304
335
|
|
|
305
336
|
|
|
306
337
|
def _plan_validate(path: str) -> int:
|
|
307
338
|
"""Run the 16 plan rules offline — no server, no jq, no curl.
|
|
308
339
|
|
|
340
|
+
|
|
309
341
|
The validator was already pure (a Plan plus a LiveSnapshot in, violations
|
|
310
342
|
out); only the snapshot needed the running system, and everything in it
|
|
311
343
|
except live subscribers can be read straight off the disk. So the gate
|
|
@@ -19,8 +19,10 @@ from microcoreos_dev.plan.schema import (
|
|
|
19
19
|
PlanLanguage,
|
|
20
20
|
PlanLink,
|
|
21
21
|
PlanMigration,
|
|
22
|
+
PlanPhase0,
|
|
22
23
|
PlanPublish,
|
|
23
24
|
PlanRoute,
|
|
25
|
+
PlanTool,
|
|
24
26
|
PlanViolation,
|
|
25
27
|
ValidatePlanData,
|
|
26
28
|
unknown_plan_keys,
|
|
@@ -40,6 +42,10 @@ from microcoreos_dev.plan.rules import (
|
|
|
40
42
|
run_validation,
|
|
41
43
|
validate_yaml,
|
|
42
44
|
)
|
|
45
|
+
from microcoreos_dev.plan.sync import (
|
|
46
|
+
generate_checklist,
|
|
47
|
+
sync_checklist,
|
|
48
|
+
)
|
|
43
49
|
|
|
44
50
|
__all__ = [
|
|
45
51
|
"DURABLE_DRIVERS",
|
|
@@ -51,11 +57,14 @@ __all__ = [
|
|
|
51
57
|
"PlanLanguage",
|
|
52
58
|
"PlanLink",
|
|
53
59
|
"PlanMigration",
|
|
60
|
+
"PlanPhase0",
|
|
54
61
|
"PlanPublish",
|
|
55
62
|
"PlanRoute",
|
|
63
|
+
"PlanTool",
|
|
56
64
|
"PlanValidator",
|
|
57
65
|
"PlanViolation",
|
|
58
66
|
"ValidatePlanData",
|
|
67
|
+
"generate_checklist",
|
|
59
68
|
"offline_snapshot",
|
|
60
69
|
"parse_plan_yaml",
|
|
61
70
|
"run_validation",
|
|
@@ -63,6 +72,8 @@ __all__ = [
|
|
|
63
72
|
"scan_live_events",
|
|
64
73
|
"scan_live_routes",
|
|
65
74
|
"scan_live_tables",
|
|
75
|
+
"sync_checklist",
|
|
66
76
|
"unknown_plan_keys",
|
|
67
77
|
"validate_yaml",
|
|
68
78
|
]
|
|
79
|
+
|
|
@@ -19,6 +19,7 @@ from microcoreos_dev.plan.schema import (
|
|
|
19
19
|
Plan,
|
|
20
20
|
PlanFeature,
|
|
21
21
|
PlanLanguage,
|
|
22
|
+
PlanTool,
|
|
22
23
|
PlanViolation,
|
|
23
24
|
ValidatePlanData,
|
|
24
25
|
unknown_plan_keys,
|
|
@@ -388,8 +389,13 @@ class PlanValidator:
|
|
|
388
389
|
declared.append((flow.name, path))
|
|
389
390
|
for migration in self.plan.phase_0.migrations:
|
|
390
391
|
declared.append((migration.file, migration.file))
|
|
391
|
-
for path in self.plan.phase_0.models
|
|
392
|
+
for path in self.plan.phase_0.models:
|
|
392
393
|
declared.append((path, path))
|
|
394
|
+
for tool in self.plan.phase_0.tools:
|
|
395
|
+
if isinstance(tool, PlanTool):
|
|
396
|
+
declared.append((tool.name, tool.file))
|
|
397
|
+
else:
|
|
398
|
+
declared.append((tool, tool))
|
|
393
399
|
|
|
394
400
|
def covered(path: str) -> bool:
|
|
395
401
|
# substring match, path or basename — no coupling to the
|
|
@@ -208,25 +208,37 @@ def scan_live_events(domains_dir: str = "domains") -> tuple[set[str], dict[str,
|
|
|
208
208
|
tree = ast.parse(f.read())
|
|
209
209
|
except Exception:
|
|
210
210
|
continue
|
|
211
|
+
|
|
212
|
+
# First pass: map each node to its enclosing ClassDef name if any
|
|
213
|
+
class_map = {}
|
|
211
214
|
for klass in [n for n in ast.walk(tree) if isinstance(n, ast.ClassDef)]:
|
|
212
|
-
for
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
215
|
+
for child in ast.walk(klass):
|
|
216
|
+
class_map[child] = klass.name
|
|
217
|
+
|
|
218
|
+
for node in ast.walk(tree):
|
|
219
|
+
if not (isinstance(node, ast.Call)
|
|
220
|
+
and isinstance(node.func, ast.Attribute)):
|
|
221
|
+
continue
|
|
222
|
+
event = None
|
|
223
|
+
if node.args and isinstance(node.args[0], ast.Constant) and isinstance(node.args[0].value, str):
|
|
219
224
|
event = node.args[0].value
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
for kw in node.keywords:
|
|
226
|
+
if kw.arg in ("event", "topic") and isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str):
|
|
227
|
+
event = kw.value.value
|
|
228
|
+
if not event:
|
|
229
|
+
continue
|
|
230
|
+
if node.func.attr == "publish":
|
|
231
|
+
published.add(event)
|
|
232
|
+
elif node.func.attr == "subscribe":
|
|
233
|
+
handler = "handler"
|
|
234
|
+
if len(node.args) > 1 and isinstance(node.args[1], ast.Attribute):
|
|
235
|
+
handler = node.args[1].attr
|
|
236
|
+
owner = class_map.get(node, filename[:-3])
|
|
237
|
+
subscribers.setdefault(event, []).append(f"{owner}.{handler}")
|
|
227
238
|
return published, subscribers
|
|
228
239
|
|
|
229
240
|
|
|
241
|
+
|
|
230
242
|
def offline_snapshot(domains_dir: str = "domains") -> LiveSnapshot:
|
|
231
243
|
"""What the repo on disk already occupies, with no system running."""
|
|
232
244
|
tables = scan_live_tables(domains_dir)
|
|
@@ -4,8 +4,15 @@ Vocabulary only: what a plan may say, and which keys no field claims. The rules
|
|
|
4
4
|
that judge a plan live in `rules.py`; what the repo on disk already occupies
|
|
5
5
|
lives in `scan.py`.
|
|
6
6
|
"""
|
|
7
|
-
|
|
8
|
-
from
|
|
7
|
+
import re
|
|
8
|
+
from typing import Optional, Literal, Union, get_args
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def payload_model_name(event: str) -> str:
|
|
13
|
+
"""'order.paid' -> 'OrderPaidPayload' (AGENTS.md rule 10's spelling)."""
|
|
14
|
+
parts = [p for p in re.split(r"[^0-9A-Za-z]+", event) if p]
|
|
15
|
+
return ("".join(p[:1].upper() + p[1:] for p in parts) + "Payload") if parts else "EventPayload"
|
|
9
16
|
|
|
10
17
|
|
|
11
18
|
class PlanRoute(BaseModel):
|
|
@@ -21,10 +28,17 @@ class PlanMigration(BaseModel):
|
|
|
21
28
|
columns: dict[str, dict[str, str]] = {}
|
|
22
29
|
|
|
23
30
|
|
|
31
|
+
class PlanTool(BaseModel):
|
|
32
|
+
name: str
|
|
33
|
+
file: str
|
|
34
|
+
contract: list[str] = []
|
|
35
|
+
infra_errors: bool = False
|
|
36
|
+
|
|
37
|
+
|
|
24
38
|
class PlanPhase0(BaseModel):
|
|
25
39
|
migrations: list[PlanMigration] = []
|
|
26
40
|
models: list[str] = []
|
|
27
|
-
tools: list[str] = []
|
|
41
|
+
tools: list[Union[PlanTool, str]] = []
|
|
28
42
|
|
|
29
43
|
|
|
30
44
|
class PlanDbContract(BaseModel):
|
|
@@ -37,11 +51,29 @@ class PlanPublish(BaseModel):
|
|
|
37
51
|
model: Optional[str] = None
|
|
38
52
|
payload: dict = {}
|
|
39
53
|
|
|
54
|
+
@model_validator(mode="before")
|
|
55
|
+
@classmethod
|
|
56
|
+
def _coerce_str(cls, data):
|
|
57
|
+
if isinstance(data, str):
|
|
58
|
+
return {
|
|
59
|
+
"event": data,
|
|
60
|
+
"model": payload_model_name(data),
|
|
61
|
+
"payload": {},
|
|
62
|
+
}
|
|
63
|
+
return data
|
|
64
|
+
|
|
40
65
|
|
|
41
66
|
class PlanConsume(BaseModel):
|
|
42
67
|
event: str
|
|
43
68
|
requires: list[str] = []
|
|
44
69
|
|
|
70
|
+
@model_validator(mode="before")
|
|
71
|
+
@classmethod
|
|
72
|
+
def _coerce_str(cls, data):
|
|
73
|
+
if isinstance(data, str):
|
|
74
|
+
return {"event": data, "requires": []}
|
|
75
|
+
return data
|
|
76
|
+
|
|
45
77
|
|
|
46
78
|
class PlanFeature(BaseModel):
|
|
47
79
|
plugin: str
|
|
@@ -64,6 +96,16 @@ class PlanFeature(BaseModel):
|
|
|
64
96
|
|
|
65
97
|
model_config = ConfigDict(populate_by_name=True)
|
|
66
98
|
|
|
99
|
+
@field_validator("publishes", "consumes", mode="before")
|
|
100
|
+
@classmethod
|
|
101
|
+
def _ensure_list(cls, data):
|
|
102
|
+
if data is None:
|
|
103
|
+
return []
|
|
104
|
+
if isinstance(data, (str, dict)):
|
|
105
|
+
return [data]
|
|
106
|
+
return data
|
|
107
|
+
|
|
108
|
+
|
|
67
109
|
|
|
68
110
|
class PlanLink(BaseModel):
|
|
69
111
|
consumes: str
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Checklist generator & synchronizer for MicroCoreOS execution plans.
|
|
2
|
+
|
|
3
|
+
Reads a Plan object (from `plans/active_plan.yaml`) and generates or updates
|
|
4
|
+
the markdown execution checklist at `plans/active_plan.md`.
|
|
5
|
+
|
|
6
|
+
Preserves existing `[x]` / `[X]` progress so synchronizing a plan does not
|
|
7
|
+
reset completed tasks, while ensuring 100% path coverage for Rule 15 and
|
|
8
|
+
eliminating the template marker so Rule 0 passes.
|
|
9
|
+
"""
|
|
10
|
+
import os
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
from microcoreos_dev.plan.schema import Plan, PlanTool
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def generate_checklist(plan: Plan, existing_checklist: Optional[str] = None) -> str:
|
|
17
|
+
"""Generate or update the markdown checklist from a Plan instance.
|
|
18
|
+
|
|
19
|
+
Every file:, test:, migration, model and tool path is generated with a checkbox.
|
|
20
|
+
If existing_checklist contains checked boxes (`- [x]` or `- [X]`) for a path,
|
|
21
|
+
that checkmark is preserved in the updated output.
|
|
22
|
+
"""
|
|
23
|
+
done_paths = set()
|
|
24
|
+
if existing_checklist:
|
|
25
|
+
for line in existing_checklist.splitlines():
|
|
26
|
+
stripped = line.strip()
|
|
27
|
+
if stripped.startswith(("- [x]", "- [X]", "* [x]", "* [X]")):
|
|
28
|
+
for token in line.split():
|
|
29
|
+
clean = token.strip("`(),*[]\"'")
|
|
30
|
+
if "/" in clean or clean.endswith((".py", ".sql")) or clean.startswith("microcoreos"):
|
|
31
|
+
done_paths.add(clean)
|
|
32
|
+
done_paths.add(os.path.basename(clean))
|
|
33
|
+
|
|
34
|
+
def mark(path: str) -> str:
|
|
35
|
+
if path in done_paths or os.path.basename(path) in done_paths:
|
|
36
|
+
return "- [x]"
|
|
37
|
+
return "- [ ]"
|
|
38
|
+
|
|
39
|
+
lines = [
|
|
40
|
+
"# Active Integration Plan — Execution Checklist",
|
|
41
|
+
"",
|
|
42
|
+
"> This file is the checklist / state machine for orchestrating subagents.",
|
|
43
|
+
"> The formal contract (routes, columns, events, flows) lives in `plans/active_plan.yaml`.",
|
|
44
|
+
"> The coordinator agent updates the task status as features are verified.",
|
|
45
|
+
"",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
# Phase 0: Foundation
|
|
49
|
+
p0 = plan.phase_0
|
|
50
|
+
has_p0 = bool(p0.tools or p0.migrations or p0.models)
|
|
51
|
+
if has_p0:
|
|
52
|
+
lines.append("## 🛠️ Phase 0: Foundation (Serial — built 1:1 from the plan's `phase_0`)")
|
|
53
|
+
for tool in p0.tools:
|
|
54
|
+
name = tool.name if isinstance(tool, PlanTool) else str(tool)
|
|
55
|
+
file_path = tool.file if isinstance(tool, PlanTool) else str(tool)
|
|
56
|
+
lines.append(f"{mark(file_path)} Task T_{name}: Tool `{name}` (`{file_path}`)")
|
|
57
|
+
for migration in p0.migrations:
|
|
58
|
+
lines.append(f"{mark(migration.file)} Task M_{os.path.basename(migration.file)}: SQL Migration (`{migration.file}`)")
|
|
59
|
+
if migration.tables:
|
|
60
|
+
lines.append(f" * **Tables owned**: `{migration.tables}`")
|
|
61
|
+
for model in p0.models:
|
|
62
|
+
lines.append(f"{mark(model)} Task D_{os.path.basename(model)}: Model (`{model}`)")
|
|
63
|
+
migrate_cmd = "microcoreos migrate"
|
|
64
|
+
lines.append(f"{mark(migrate_cmd)} Task P0_Migrate: Apply migrations (`{migrate_cmd}`)")
|
|
65
|
+
lines.append("")
|
|
66
|
+
|
|
67
|
+
# Phase 2: Plugins & Features
|
|
68
|
+
if plan.features:
|
|
69
|
+
lines.append("## 💻 Phase 2: Plugins & Features (Parallel)")
|
|
70
|
+
for idx, feat in enumerate(plan.features, 1):
|
|
71
|
+
lines.append(f"{mark(feat.file)} Task P{idx}: Feature Plugin `{feat.plugin}` (`{feat.file}`)")
|
|
72
|
+
details = []
|
|
73
|
+
if feat.route:
|
|
74
|
+
details.append(f"**Route**: `{feat.route.method.upper()} {feat.route.path}`")
|
|
75
|
+
if feat.publishes:
|
|
76
|
+
events = [p.event for p in feat.publishes]
|
|
77
|
+
details.append(f"**Publishes**: `{events}`")
|
|
78
|
+
if feat.consumes:
|
|
79
|
+
events = [c.event for c in feat.consumes]
|
|
80
|
+
details.append(f"**Consumes**: `{events}`")
|
|
81
|
+
if feat.tools:
|
|
82
|
+
details.append(f"**Tools**: `{feat.tools}`")
|
|
83
|
+
for d in details:
|
|
84
|
+
lines.append(f" * {d}")
|
|
85
|
+
if feat.test:
|
|
86
|
+
lines.append(f"{mark(feat.test)} Task P{idx}_Test: Unit Test (`{feat.test}`)")
|
|
87
|
+
lines.append("")
|
|
88
|
+
|
|
89
|
+
# Phase 3: Integration & Flow Verification
|
|
90
|
+
if plan.flows:
|
|
91
|
+
lines.append("## 🚦 Phase 3: Integration & Flow Verification (End-to-End)")
|
|
92
|
+
for idx, flow in enumerate(plan.flows, 1):
|
|
93
|
+
if flow.e2e_test:
|
|
94
|
+
lines.append(f"{mark(flow.e2e_test)} Task F{idx}_E2E: Flow `{flow.name}` E2E test (`{flow.e2e_test}`)")
|
|
95
|
+
if flow.sad_path_test:
|
|
96
|
+
lines.append(f"{mark(flow.sad_path_test)} Task F{idx}_Sad: Flow `{flow.name}` Sad-path test (`{flow.sad_path_test}`)")
|
|
97
|
+
for link in flow.links:
|
|
98
|
+
if link.idempotency_test:
|
|
99
|
+
lines.append(f"{mark(link.idempotency_test)} Task F{idx}_Idempotent: `{link.consumes} → {link.consumer}` (`{link.idempotency_test}`)")
|
|
100
|
+
lines.append("")
|
|
101
|
+
|
|
102
|
+
return "\n".join(lines).rstrip() + "\n"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def sync_checklist(plan_path: str = os.path.join("plans", "active_plan.yaml"),
|
|
106
|
+
checklist_path: str = os.path.join("plans", "active_plan.md")) -> tuple[bool, str]:
|
|
107
|
+
"""Read plan_path, update checklist_path, and return (success, message)."""
|
|
108
|
+
if not os.path.isfile(plan_path):
|
|
109
|
+
return False, f"No plan file found at {plan_path}"
|
|
110
|
+
|
|
111
|
+
from microcoreos_dev.plan.rules import parse_plan_yaml
|
|
112
|
+
|
|
113
|
+
with open(plan_path, "r", encoding="utf-8") as f:
|
|
114
|
+
content = f.read()
|
|
115
|
+
|
|
116
|
+
plan_dict, err = parse_plan_yaml(content)
|
|
117
|
+
if err:
|
|
118
|
+
return False, f"Could not parse plan: {err}"
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
plan = Plan(**plan_dict)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
return False, f"Plan schema error: {e}"
|
|
124
|
+
|
|
125
|
+
existing = None
|
|
126
|
+
if os.path.isfile(checklist_path):
|
|
127
|
+
with open(checklist_path, "r", encoding="utf-8") as f:
|
|
128
|
+
existing = f.read()
|
|
129
|
+
|
|
130
|
+
generated = generate_checklist(plan, existing)
|
|
131
|
+
|
|
132
|
+
# Ensure parent dir exists
|
|
133
|
+
parent = os.path.dirname(checklist_path)
|
|
134
|
+
if parent:
|
|
135
|
+
os.makedirs(parent, exist_ok=True)
|
|
136
|
+
|
|
137
|
+
with open(checklist_path, "w", encoding="utf-8") as f:
|
|
138
|
+
f.write(generated)
|
|
139
|
+
|
|
140
|
+
return True, f"Synchronized {checklist_path} from {plan_path}"
|
|
@@ -676,3 +676,49 @@ def test_probe_accepts_the_route_and_events_the_plan_declares(tmp_path, monkeypa
|
|
|
676
676
|
monkeypatch.chdir(_route_project(tmp_path))
|
|
677
677
|
|
|
678
678
|
assert cli.main(["plan", "probe"]) == 0
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
def test_plan_sync_cli_generates_active_plan_md(tmp_path, monkeypatch, capsys):
|
|
682
|
+
project = _probe_project(tmp_path)
|
|
683
|
+
monkeypatch.chdir(project)
|
|
684
|
+
|
|
685
|
+
checklist_file = project / "plans" / "active_plan.md"
|
|
686
|
+
assert not checklist_file.exists()
|
|
687
|
+
|
|
688
|
+
code = cli.main(["plan", "sync"])
|
|
689
|
+
assert code == 0
|
|
690
|
+
assert checklist_file.exists()
|
|
691
|
+
|
|
692
|
+
content = checklist_file.read_text(encoding="utf-8")
|
|
693
|
+
assert "CounterPlugin" in content
|
|
694
|
+
assert "domains/shop/plugins/counter_plugin.py" in content
|
|
695
|
+
assert "tests/test_counter_plugin.py" in content
|
|
696
|
+
assert "<!-- template: true -->" not in content
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
def test_plan_validate_fix_cli_syncs_checklist(tmp_path, monkeypatch, capsys):
|
|
700
|
+
valid_plan_yaml = """
|
|
701
|
+
plan:
|
|
702
|
+
domain: shop
|
|
703
|
+
features:
|
|
704
|
+
- plugin: CounterPlugin
|
|
705
|
+
file: domains/shop/plugins/counter_plugin.py
|
|
706
|
+
publishes: ["order.counted"]
|
|
707
|
+
tools: [event_bus]
|
|
708
|
+
test: tests/test_counter_plugin.py
|
|
709
|
+
"""
|
|
710
|
+
project = _probe_project(tmp_path, plan=valid_plan_yaml)
|
|
711
|
+
monkeypatch.chdir(project)
|
|
712
|
+
|
|
713
|
+
# Place a template checklist
|
|
714
|
+
checklist_file = project / "plans" / "active_plan.md"
|
|
715
|
+
checklist_file.write_text("<!-- template: true -->\n- [ ] dummy", encoding="utf-8")
|
|
716
|
+
|
|
717
|
+
code = cli.main(["plan", "validate", "--fix"])
|
|
718
|
+
# Validation will pass because --fix updated the checklist with the real tasks
|
|
719
|
+
assert code == 0
|
|
720
|
+
content = checklist_file.read_text(encoding="utf-8")
|
|
721
|
+
assert "<!-- template: true -->" not in content
|
|
722
|
+
assert "counter_plugin.py" in content
|
|
723
|
+
|
|
724
|
+
|