a64687f2a2
CI / lint (push) Successful in 14s
CI / typecheck (push) Successful in 28s
CI / security (push) Successful in 21s
CI / quality (push) Successful in 15s
CI / integration_tests (push) Successful in 4m25s
CI / build (push) Successful in 15s
CI / unit_tests (push) Successful in 9m8s
CI / docker (push) Successful in 8s
CI / coverage (push) Successful in 6m51s
421 lines
18 KiB
Markdown
421 lines
18 KiB
Markdown
# Database Schema Reference
|
|
|
|
This document describes the spec-aligned database tables created by the
|
|
A5.alpha migrations (`a5_003_spec_aligned_actions` and `a5_004_spec_aligned_plans`).
|
|
|
|
These tables replace the legacy `actions_v3` and `lifecycle_plans` tables with
|
|
a normalized schema using namespaced names as action identity and child tables
|
|
for arguments, invariants, and project links.
|
|
|
|
## Migration Chain
|
|
|
|
| Revision | Description |
|
|
|---|---|
|
|
| `a5_003_spec_aligned_actions` | Drops `lifecycle_plans` and `actions_v3`; creates `actions`, `action_invariants`, `action_arguments` |
|
|
| `a5_004_spec_aligned_plans` | Creates `v3_plans`, `plan_projects`, `plan_arguments`, `plan_invariants` |
|
|
|
|
---
|
|
|
|
## Table: `actions`
|
|
|
|
The primary action definition table. Each row represents a reusable action
|
|
template identified by its namespaced name.
|
|
|
|
**Primary Key:** `namespaced_name`
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `namespaced_name` | String(255) | No | -- | PK. Full namespaced name (e.g. `local/code-review`) |
|
|
| `namespace` | String(100) | No | -- | Extracted namespace component |
|
|
| `name` | String(150) | No | -- | Extracted short name component |
|
|
| `description` | Text | No | -- | Short description |
|
|
| `long_description` | Text | Yes | NULL | Detailed description |
|
|
| `definition_of_done` | Text | No | -- | Explicit testable completion criteria |
|
|
| `strategy_actor` | String(255) | No | -- | Actor for Strategize phase |
|
|
| `execution_actor` | String(255) | No | -- | Actor for Execute phase |
|
|
| `review_actor` | String(255) | Yes | NULL | Actor for reviewing results |
|
|
| `apply_actor` | String(255) | Yes | NULL | Actor for Apply phase |
|
|
| `estimation_actor` | String(255) | Yes | NULL | Actor for cost estimation |
|
|
| `invariant_actor` | String(255) | Yes | NULL | Actor for invariant reconciliation |
|
|
| `automation_profile` | String(255) | Yes | NULL | Default automation profile name |
|
|
| `reusable` | Boolean | No | `1` | Whether action persists after use |
|
|
| `read_only` | Boolean | No | `0` | Read-only mode |
|
|
| `inputs_schema_json` | Text | Yes | NULL | JSON Schema dict for input validation |
|
|
| `state` | String(20) | No | `'available'` | `available` or `archived` |
|
|
| `created_by` | String(255) | Yes | NULL | Creator identifier |
|
|
| `tags_json` | Text | No | `'[]'` | JSON array of tag strings |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 creation timestamp |
|
|
| `updated_at` | String(30) | No | -- | ISO-8601 last-update timestamp |
|
|
|
|
**Check Constraints:**
|
|
- `ck_actions_state`: `state IN ('available', 'archived')`
|
|
|
|
**Indexes:**
|
|
- `ix_actions_namespace` on `namespace`
|
|
- `ix_actions_state` on `state`
|
|
- `ix_actions_name` on `name`
|
|
|
|
---
|
|
|
|
## Table: `action_invariants`
|
|
|
|
Ordered invariant constraints attached to an action. Cascades on action delete.
|
|
|
|
**Primary Key:** `id` (auto-increment)
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `id` | Integer | No | auto | Surrogate PK |
|
|
| `action_name` | String(255) | No | -- | FK to `actions.namespaced_name` (CASCADE) |
|
|
| `invariant_text` | Text | No | -- | The invariant constraint text |
|
|
| `position` | Integer | No | -- | Display ordering |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 timestamp |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_action_invariants_action`: `action_name` -> `actions.namespaced_name` ON DELETE CASCADE
|
|
|
|
**Indexes:**
|
|
- `ix_action_invariants_action` on `action_name`
|
|
- `ix_action_invariants_position` on `(action_name, position)`
|
|
|
|
---
|
|
|
|
## Table: `action_arguments`
|
|
|
|
Typed argument definitions for an action. Cascades on action delete.
|
|
|
|
**Primary Key:** `id` (auto-increment)
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `id` | Integer | No | auto | Surrogate PK |
|
|
| `action_name` | String(255) | No | -- | FK to `actions.namespaced_name` (CASCADE) |
|
|
| `name` | String(100) | No | -- | Argument identifier |
|
|
| `arg_type` | String(20) | No | `'string'` | `string`, `integer`, `float`, `boolean`, `list` |
|
|
| `requirement` | String(20) | No | `'required'` | `required` or `optional` |
|
|
| `description` | Text | Yes | NULL | Human-readable description |
|
|
| `default_value_json` | Text | Yes | NULL | JSON-encoded default value |
|
|
| `min_value` | Float | Yes | NULL | Min bound for numeric types |
|
|
| `max_value` | Float | Yes | NULL | Max bound for numeric types |
|
|
| `validation_pattern` | String(500) | Yes | NULL | Regex pattern for string validation |
|
|
| `position` | Integer | No | -- | Display ordering |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_action_arguments_action`: `action_name` -> `actions.namespaced_name` ON DELETE CASCADE
|
|
|
|
**Unique Constraints:**
|
|
- `uq_action_arguments_name` on `(action_name, name)`
|
|
|
|
**Check Constraints:**
|
|
- `ck_action_arguments_type`: `arg_type IN ('string', 'integer', 'float', 'boolean', 'list')`
|
|
- `ck_action_arguments_requirement`: `requirement IN ('required', 'optional')`
|
|
|
|
**Indexes:**
|
|
- `ix_action_arguments_action` on `action_name`
|
|
- `ix_action_arguments_position` on `(action_name, position)`
|
|
|
|
---
|
|
|
|
## Table: `v3_plans`
|
|
|
|
The primary plan table. Each row is a plan instance created from an action,
|
|
identified by a ULID. Plans reference actions by namespaced name and support
|
|
hierarchical subplan trees via self-referencing foreign keys.
|
|
|
|
**Primary Key:** `plan_id` (ULID, String(26))
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `plan_id` | String(26) | No | -- | ULID primary key |
|
|
| `parent_plan_id` | String(26) | Yes | NULL | FK to `v3_plans.plan_id` (SET NULL) |
|
|
| `root_plan_id` | String(26) | Yes | NULL | FK to `v3_plans.plan_id` (SET NULL) |
|
|
| `action_name` | String(255) | No | -- | FK to `actions.namespaced_name` (RESTRICT) |
|
|
| `namespaced_name` | String(255) | No | -- | Plan's own namespaced name |
|
|
| `namespace` | String(100) | No | -- | Extracted namespace |
|
|
| `phase` | String(20) | No | `'strategize'` | Current lifecycle phase |
|
|
| `processing_state` | String(20) | No | `'queued'` | Current processing state |
|
|
| `attempt` | Integer | No | `1` | Retry attempt counter |
|
|
| `description` | Text | No | -- | Rendered description (from action template + args) |
|
|
| `definition_of_done` | Text | Yes | NULL | Rendered completion criteria |
|
|
| `strategy_actor` | String(255) | Yes | NULL | Strategize phase actor |
|
|
| `execution_actor` | String(255) | Yes | NULL | Execute phase actor |
|
|
| `review_actor` | String(255) | Yes | NULL | Review actor |
|
|
| `apply_actor` | String(255) | Yes | NULL | Apply phase actor |
|
|
| `estimation_actor` | String(255) | Yes | NULL | Estimation actor |
|
|
| `invariant_actor` | String(255) | Yes | NULL | Invariant reconciliation actor |
|
|
| `automation_profile` | String(255) | Yes | NULL | Resolved automation profile name |
|
|
| `automation_level` | String(30) | No | `'manual'` | `manual`, `review_before_apply`, `full_automation` |
|
|
| `reusable` | Boolean | No | `1` | Copied from action |
|
|
| `read_only` | Boolean | No | `0` | Copied from action |
|
|
| `inputs_schema_json` | Text | Yes | NULL | JSON Schema dict (copied from action) |
|
|
| `changeset_id` | String(26) | Yes | NULL | Changeset ULID from Execute phase |
|
|
| `sandbox_refs_json` | Text | Yes | NULL | JSON sandbox references |
|
|
| `validation_summary_json` | Text | Yes | NULL | JSON validation summary |
|
|
| `decision_root_id` | String(26) | Yes | NULL | Root decision tree ULID |
|
|
| `error_message` | Text | Yes | NULL | Error message if errored |
|
|
| `error_details_json` | Text | Yes | NULL | JSON error details dict |
|
|
| `cost_estimate_usd` | Float | Yes | NULL | Estimated cost in USD |
|
|
| `cost_actual_usd` | Float | Yes | NULL | Actual cost in USD |
|
|
| `token_count_input` | Integer | Yes | `0` | Input token count |
|
|
| `token_count_output` | Integer | Yes | `0` | Output token count |
|
|
| `created_by` | String(255) | Yes | NULL | Creator identifier |
|
|
| `tags_json` | Text | No | `'[]'` | JSON array of tag strings |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 creation timestamp |
|
|
| `updated_at` | String(30) | No | -- | ISO-8601 last-update timestamp |
|
|
| `completed_at` | String(30) | Yes | NULL | ISO-8601 completion timestamp |
|
|
| `strategize_started_at` | String(30) | Yes | NULL | Strategize phase start |
|
|
| `strategize_completed_at` | String(30) | Yes | NULL | Strategize phase end |
|
|
| `execute_started_at` | String(30) | Yes | NULL | Execute phase start |
|
|
| `execute_completed_at` | String(30) | Yes | NULL | Execute phase end |
|
|
| `apply_started_at` | String(30) | Yes | NULL | Apply phase start |
|
|
| `applied_at` | String(30) | Yes | NULL | Terminal apply timestamp |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_v3_plans_parent`: `parent_plan_id` -> `v3_plans.plan_id` ON DELETE SET NULL
|
|
- `fk_v3_plans_root`: `root_plan_id` -> `v3_plans.plan_id` ON DELETE SET NULL
|
|
- `fk_v3_plans_action`: `action_name` -> `actions.namespaced_name` ON DELETE RESTRICT
|
|
|
|
**Check Constraints:**
|
|
- `ck_v3_plans_phase`: `phase IN ('action', 'strategize', 'execute', 'apply')`
|
|
- `ck_v3_plans_state`: `processing_state IN ('queued', 'processing', 'errored', 'complete', 'cancelled', 'applied', 'constrained')`
|
|
- `ck_v3_plans_automation`: `automation_level IN ('manual', 'review_before_apply', 'full_automation')`
|
|
|
|
**Indexes:**
|
|
- `ix_v3_plans_phase` on `phase`
|
|
- `ix_v3_plans_state` on `processing_state`
|
|
- `ix_v3_plans_parent` on `parent_plan_id`
|
|
- `ix_v3_plans_root` on `root_plan_id`
|
|
- `ix_v3_plans_created` on `created_at`
|
|
- `ix_v3_plans_action` on `action_name`
|
|
- `ix_v3_plans_namespace` on `namespace`
|
|
- `ix_v3_plans_phase_state` on `(phase, processing_state)` (composite)
|
|
|
|
---
|
|
|
|
## Table: `plan_projects`
|
|
|
|
Links plans to target projects. Composite primary key. Cascades on plan delete.
|
|
|
|
**Primary Key:** `(plan_id, project_name)`
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `plan_id` | String(26) | No | -- | FK to `v3_plans.plan_id` (CASCADE) |
|
|
| `project_name` | String(255) | No | -- | Target project namespaced name |
|
|
| `alias` | String(100) | Yes | NULL | Short alias for plan context |
|
|
| `read_only` | Boolean | No | `0` | Whether project is read-only for this plan |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 timestamp |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_plan_projects_plan`: `plan_id` -> `v3_plans.plan_id` ON DELETE CASCADE
|
|
|
|
**Indexes:**
|
|
- `ix_plan_projects_project` on `project_name`
|
|
|
|
---
|
|
|
|
## Table: `plan_arguments`
|
|
|
|
Resolved argument values for a plan instance. Cascades on plan delete.
|
|
|
|
**Primary Key:** `id` (auto-increment)
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `id` | Integer | No | auto | Surrogate PK |
|
|
| `plan_id` | String(26) | No | -- | FK to `v3_plans.plan_id` (CASCADE) |
|
|
| `name` | String(100) | No | -- | Argument name |
|
|
| `value_json` | Text | Yes | NULL | JSON-encoded argument value |
|
|
| `value_type` | String(20) | No | `'string'` | Value type hint |
|
|
| `position` | Integer | No | -- | Display ordering |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_plan_arguments_plan`: `plan_id` -> `v3_plans.plan_id` ON DELETE CASCADE
|
|
|
|
**Unique Constraints:**
|
|
- `uq_plan_arguments_name` on `(plan_id, name)`
|
|
|
|
**Indexes:**
|
|
- `ix_plan_arguments_plan` on `plan_id`
|
|
- `ix_plan_arguments_position` on `(plan_id, position)`
|
|
|
|
---
|
|
|
|
## Table: `plan_invariants`
|
|
|
|
Plan-level invariant constraints with scope provenance. Cascades on plan delete.
|
|
|
|
**Primary Key:** `id` (auto-increment)
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `id` | Integer | No | auto | Surrogate PK |
|
|
| `plan_id` | String(26) | No | -- | FK to `v3_plans.plan_id` (CASCADE) |
|
|
| `invariant_text` | Text | No | -- | The invariant constraint text |
|
|
| `source_scope` | String(20) | No | `'plan'` | Origin scope: `global`, `project`, `action`, `plan` |
|
|
| `source_name` | String(255) | Yes | NULL | Name of the source entity |
|
|
| `position` | Integer | No | -- | Display ordering |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 timestamp |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_plan_invariants_plan`: `plan_id` -> `v3_plans.plan_id` ON DELETE CASCADE
|
|
|
|
**Unique Constraints:**
|
|
- `uq_plan_invariants_text` on `(plan_id, invariant_text)`
|
|
|
|
**Check Constraints:**
|
|
- `ck_plan_invariants_scope`: `source_scope IN ('global', 'project', 'action', 'plan')`
|
|
|
|
**Indexes:**
|
|
- `ix_plan_invariants_plan` on `plan_id`
|
|
- `ix_plan_invariants_position` on `(plan_id, position)`
|
|
|
|
---
|
|
|
|
---
|
|
|
|
## Table: `resource_types`
|
|
|
|
Schema-level definitions that constrain categories of resources. Built-in types
|
|
(e.g. `builtin/git-checkout`) are registered at startup; custom types are loaded
|
|
from YAML configuration files.
|
|
|
|
**Primary Key:** `name`
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `name` | String(255) | No | -- | PK. Namespaced type name (e.g. `builtin/git-checkout`) |
|
|
| `namespace` | String(100) | No | -- | Extracted namespace component |
|
|
| `description` | Text | Yes | NULL | Human-readable description |
|
|
| `resource_kind` | String(20) | No | -- | `physical` or `virtual` |
|
|
| `sandbox_strategy` | String(50) | Yes | NULL | Default sandbox strategy for instances |
|
|
| `user_addable` | Boolean | No | `0` | Whether users can add instances via CLI |
|
|
| `handler_ref` | String(500) | Yes | NULL | Handler implementation reference |
|
|
| `args_schema_json` | Text | Yes | NULL | JSON: CLI argument definitions |
|
|
| `allowed_parent_types_json` | Text | Yes | NULL | JSON: allowed parent type names |
|
|
| `allowed_child_types_json` | Text | Yes | NULL | JSON: allowed child type definitions |
|
|
| `auto_discover_json` | Text | Yes | NULL | JSON: auto-discovery configuration |
|
|
| `capabilities_json` | Text | Yes | NULL | JSON: capability flags |
|
|
| `equivalence_json` | Text | Yes | NULL | JSON: equivalence criteria (virtual types) |
|
|
| `source` | String(500) | Yes | NULL | `builtin` or path to YAML config |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 creation timestamp |
|
|
| `updated_at` | String(30) | No | -- | ISO-8601 last-update timestamp |
|
|
|
|
**Check Constraints:**
|
|
- `ck_resource_types_kind`: `resource_kind IN ('physical', 'virtual')`
|
|
|
|
**Indexes:**
|
|
- `ix_resource_types_namespace` on `namespace`
|
|
- `ix_resource_types_kind` on `resource_kind`
|
|
- `ix_resource_types_user_addable` on `user_addable`
|
|
|
|
---
|
|
|
|
## Table: `resources`
|
|
|
|
Independently registered resources representing anything that can be read,
|
|
written, or queried. Each resource has a ULID primary key and an optional
|
|
namespaced name (auto-discovered children have no name).
|
|
|
|
**Primary Key:** `resource_id` (ULID, String(26))
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `resource_id` | String(26) | No | -- | ULID primary key |
|
|
| `namespaced_name` | String(255) | Yes | NULL | Optional namespaced name (unique when non-null) |
|
|
| `namespace` | String(100) | Yes | NULL | Extracted namespace component |
|
|
| `type_name` | String(255) | No | -- | FK to `resource_types.name` (RESTRICT) |
|
|
| `resource_kind` | String(20) | No | -- | `physical` or `virtual` (denormalized from type) |
|
|
| `location` | Text | Yes | NULL | Physical location (path, URL, etc.) |
|
|
| `description` | Text | Yes | NULL | Human-readable description |
|
|
| `read_only` | Boolean | No | `0` | Read-only flag |
|
|
| `auto_discovered` | Boolean | No | `0` | Whether auto-discovered (not user-registered) |
|
|
| `sandbox_strategy` | String(50) | Yes | NULL | Per-resource sandbox strategy override |
|
|
| `content_hash` | String(128) | Yes | NULL | Content hash for equivalence tracking |
|
|
| `properties_json` | Text | Yes | NULL | JSON: type-specific properties |
|
|
| `metadata_json` | Text | Yes | NULL | JSON: type-specific metadata |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 creation timestamp |
|
|
| `updated_at` | String(30) | No | -- | ISO-8601 last-update timestamp |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_resources_type`: `type_name` -> `resource_types.name` ON DELETE RESTRICT
|
|
|
|
**Check Constraints:**
|
|
- `ck_resources_kind`: `resource_kind IN ('physical', 'virtual')`
|
|
|
|
**Indexes:**
|
|
- `ix_resources_name` on `namespaced_name` (unique, partial - non-null only)
|
|
- `ix_resources_namespace` on `namespace`
|
|
- `ix_resources_type` on `type_name`
|
|
- `ix_resources_kind` on `resource_kind`
|
|
- `ix_resources_content_hash` on `content_hash`
|
|
|
|
---
|
|
|
|
## Table: `resource_edges`
|
|
|
|
DAG edges representing parent-child relationships between resources. A resource
|
|
can have multiple parents and multiple children, subject to type constraints.
|
|
|
|
**Primary Key:** `(parent_id, child_id)` (composite)
|
|
|
|
| Column | Type | Nullable | Default | Description |
|
|
|---|---|---|---|---|
|
|
| `parent_id` | String(26) | No | -- | FK to `resources.resource_id` (CASCADE) |
|
|
| `child_id` | String(26) | No | -- | FK to `resources.resource_id` (CASCADE) |
|
|
| `link_type` | String(30) | No | `'contains'` | `contains`, `references`, or `derived_from` |
|
|
| `auto_discovered` | Boolean | No | `0` | Whether auto-discovered (vs manually linked) |
|
|
| `created_at` | String(30) | No | -- | ISO-8601 timestamp |
|
|
|
|
**Foreign Keys:**
|
|
- `fk_resource_edges_parent`: `parent_id` -> `resources.resource_id` ON DELETE CASCADE
|
|
- `fk_resource_edges_child`: `child_id` -> `resources.resource_id` ON DELETE CASCADE
|
|
|
|
**Check Constraints:**
|
|
- `ck_resource_edges_no_self_loop`: `parent_id != child_id`
|
|
- `ck_resource_edges_link_type`: `link_type IN ('contains', 'references', 'derived_from')`
|
|
|
|
**Indexes:**
|
|
- `ix_resource_edges_child` on `child_id`
|
|
- `ix_resource_edges_link_type` on `link_type`
|
|
|
|
---
|
|
|
|
## Entity Relationship Diagram
|
|
|
|
```
|
|
actions (PK: namespaced_name)
|
|
|-- 1:N --> action_invariants (FK: action_name)
|
|
|-- 1:N --> action_arguments (FK: action_name)
|
|
|-- 1:N --> v3_plans (FK: action_name, RESTRICT)
|
|
|
|
v3_plans (PK: plan_id)
|
|
|-- self --> parent_plan_id (SET NULL)
|
|
|-- self --> root_plan_id (SET NULL)
|
|
|-- 1:N --> plan_projects (FK: plan_id, CASCADE)
|
|
|-- 1:N --> plan_arguments (FK: plan_id, CASCADE)
|
|
|-- 1:N --> plan_invariants (FK: plan_id, CASCADE)
|
|
|
|
resource_types (PK: name)
|
|
|-- 1:N --> resources (FK: type_name, RESTRICT)
|
|
|
|
resources (PK: resource_id)
|
|
|-- N:M --> resource_edges (FK: parent_id/child_id, CASCADE)
|
|
```
|
|
|
|
## Migration Chain
|
|
|
|
| Revision | Description |
|
|
|---|---|
|
|
| `a5_003_spec_aligned_actions` | Drops `lifecycle_plans` and `actions_v3`; creates `actions`, `action_invariants`, `action_arguments` |
|
|
| `a5_004_spec_aligned_plans` | Creates `v3_plans`, `plan_projects`, `plan_arguments`, `plan_invariants` |
|
|
| `b1_001_resource_registry` | Creates `resource_types`, `resources`, `resource_edges` |
|
|
|
|
## Source Location
|
|
|
|
- Migration (actions): `alembic/versions/a5_003_spec_aligned_actions.py`
|
|
- Migration (plans): `alembic/versions/a5_004_spec_aligned_plans.py`
|
|
- Migration (resources): `alembic/versions/b1_001_resource_registry_tables.py`
|
|
- ORM models: `src/cleveragents/infrastructure/database/models.py`
|
|
- Repositories: `src/cleveragents/infrastructure/database/repositories.py`
|