6.1 KiB
Runtime Type Removal, YAML Loading & Ref Format Cleanup
Date: 2026-02-13
Problem
Running a Python action failed with:
Runtime not found: No runtime found for action: python_example.hello (available: shell)
The worker only had the Shell runtime registered. Investigation revealed four interrelated bugs:
-
Runtime YAML files were never loaded into the database.
PackComponentLoader::load_all()loaded triggers, actions, and sensors but completely ignored theruntimes/directory. Files likepacks/core/runtimes/python.yamlwere dead weight. -
load_core_pack.pyonly created Shell + Sensor Builtin runtimes via hardcodedensure_shell_runtime()andensure_sensor_runtime()methods instead of reading from YAML files. -
The worker filtered by
runtime_type == "action", but this distinction (action vs sensor) was meaningless — a Python runtime should be usable for both actions and sensors. -
Runtime ref naming mismatch. The Python YAML uses
ref: core.python, butresolve_runtime_id("python")only looked forcore.action.pythonandpython— neither matched.
Root Cause Analysis: runtime_type Was Meaningless
The runtime_type column (action | sensor) conflated what the runtime is used for with what the runtime is. Analysis of all usages showed:
- Worker filter: Only behavioral use — could be replaced by checking if
execution_confighas an interpreter configured. RuntimeRepository::find_by_type/find_action_runtimes: Never called anywhere in the codebase. Tests for them were already commented out.runtime_detection.rs: Was filtering by ref pattern (NOT LIKE '%.sensor.builtin'), not byruntime_type.DependencyManager::runtime_type(): Completely unrelated concept (returns "python"/"nodejs" for language identification).
The real distinction is whether a runtime has an execution_config with an interpreter — data that already exists. The column was redundant.
Changes
Column Removal: runtime_type
| File | Change |
|---|---|
migrations/20250101000002_pack_system.sql |
Removed runtime_type column, its CHECK constraint, and its index |
crates/common/src/models.rs |
Removed runtime_type field from Runtime struct |
crates/common/src/repositories/runtime.rs |
Removed runtime_type from CreateRuntimeInput, UpdateRuntimeInput, all SELECT/INSERT/UPDATE queries; removed find_by_type() and find_action_runtimes() |
crates/worker/src/service.rs |
Replaced runtime_type filter with execution_config check (skip runtimes with empty config) |
crates/worker/src/executor.rs |
Removed runtime_type from runtime SELECT query |
crates/common/src/pack_environment.rs |
Removed runtime_type from runtime SELECT query |
crates/common/src/runtime_detection.rs |
Removed runtime_type from runtime SELECT query |
crates/common/tests/helpers.rs |
Removed runtime_type from RuntimeFixture |
crates/common/tests/repository_runtime_tests.rs |
Removed runtime_type from test fixtures |
crates/common/tests/repository_worker_tests.rs |
Removed runtime_type from test fixture |
crates/common/tests/migration_tests.rs |
Removed stale runtime_type_enum from expected enums list |
crates/executor/tests/fifo_ordering_integration_test.rs |
Removed runtime_type from test fixture |
crates/executor/tests/policy_enforcer_tests.rs |
Removed runtime_type from test fixture |
scripts/load_core_pack.py |
Removed runtime_type from INSERT/UPDATE queries |
Runtime Ref Format Cleanup
Runtime refs now use a clean 2-part {pack_ref}.{name} format (e.g., core.python, core.shell, core.builtin). The old 3-part format with action or sensor segments (e.g., core.action.shell, core.sensor.builtin) is eliminated.
| File | Change |
|---|---|
packs/core/runtimes/sensor_builtin.yaml |
Renamed ref from core.sensor.builtin to core.builtin |
crates/common/src/schema.rs |
Updated validate_runtime_ref to enforce 2-part pack.name format; updated tests |
crates/common/src/runtime_detection.rs |
Removed WHERE ref NOT LIKE '%.sensor.builtin' filter — no ref-based filtering needed |
crates/common/src/pack_registry/loader.rs |
Updated hardcoded sensor runtime ref to core.builtin; cleaned resolve_runtime_id() to use only core.{name} patterns (removed legacy core.action.* fallbacks) |
scripts/load_core_pack.py |
Updated core.sensor.builtin references to core.builtin |
crates/common/tests/repository_runtime_tests.rs |
Updated test refs from 3-part to 2-part format |
crates/common/tests/repository_worker_tests.rs |
Updated test ref from 3-part to 2-part format |
Runtime YAML Loading
| File | Change |
|---|---|
crates/common/src/pack_registry/loader.rs |
Added load_runtimes() method to read runtimes/*.yaml and insert into DB; added runtimes_loaded/runtimes_skipped to PackLoadResult |
crates/api/src/routes/packs.rs |
Updated log message to include runtime count |
scripts/load_core_pack.py |
Replaced hardcoded ensure_shell_runtime()/ensure_sensor_runtime() with upsert_runtimes() that reads all YAML files from runtimes/ directory; added resolve_action_runtime() for smart runtime resolution |
Error Reporting Improvement
| File | Change |
|---|---|
crates/worker/src/executor.rs |
handle_execution_failure now accepts an error_message parameter. Actual error messages from prepare_execution_context and execute_action failures are stored in the execution result instead of the generic "Execution failed during preparation". |
Component Loading Order
PackComponentLoader::load_all() now loads in dependency order:
- Runtimes (no dependencies)
- Triggers (no dependencies)
- Actions (depend on runtimes)
- Sensors (depend on triggers and runtimes)
Deployment
Requires database reset (docker compose down -v && docker compose up -d) since the migration changed (column removed).
Validation
- Zero compiler errors, zero warnings
- All 76 unit tests pass
- Integration test failures are pre-existing (missing
attune_testdatabase)