Files
attune/work-summary/2026-02-13-runtime-type-removal-and-yaml-loading.md

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:

  1. Runtime YAML files were never loaded into the database. PackComponentLoader::load_all() loaded triggers, actions, and sensors but completely ignored the runtimes/ directory. Files like packs/core/runtimes/python.yaml were dead weight.

  2. load_core_pack.py only created Shell + Sensor Builtin runtimes via hardcoded ensure_shell_runtime() and ensure_sensor_runtime() methods instead of reading from YAML files.

  3. 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.

  4. Runtime ref naming mismatch. The Python YAML uses ref: core.python, but resolve_runtime_id("python") only looked for core.action.python and python — 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_config has 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 by runtime_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:

  1. Runtimes (no dependencies)
  2. Triggers (no dependencies)
  3. Actions (depend on runtimes)
  4. 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_test database)