Files
attune/work-summary/2026-02-22-stackstorm-param-schema.md
2026-02-23 20:45:10 -06:00

96 lines
4.4 KiB
Markdown

# StackStorm-Style Parameter Schema Migration
**Date**: 2026-02-22
## Summary
Migrated `param_schema` format from standard JSON Schema to StackStorm-style flat parameter maps with `required` and `secret` inlined per-parameter. This makes parameter definitions more readable and eliminates the clunky top-level `required` array pattern from JSON Schema.
## Format Change
### Before (JSON Schema)
```yaml
parameters:
type: object
properties:
url:
type: string
description: "Target URL"
token:
type: string
secret: true
required:
- url
```
### After (StackStorm-style)
```yaml
parameters:
url:
type: string
description: "Target URL"
required: true
token:
type: string
secret: true
```
The `type: object` / `properties:` wrapper is removed. `required` moves from a top-level array to an inline boolean per-parameter. `secret` was already inline and remains unchanged.
## Scope
- **`param_schema`** (action, trigger, sensor, workflow parameters): Converted to StackStorm-style
- **`out_schema`** (output schemas): Left as standard JSON Schema — `required`/`secret` are not meaningful for outputs
- **Database**: No migration needed — columns are JSONB, the JSON shape just changes
- **Backward compatibility**: Web UI `extractProperties()` handles both formats during transition
## Files Modified
### Pack YAML Files (13 files)
- `packs/core/actions/echo.yaml`
- `packs/core/actions/sleep.yaml`
- `packs/core/actions/noop.yaml`
- `packs/core/actions/http_request.yaml`
- `packs/core/actions/download_packs.yaml`
- `packs/core/actions/register_packs.yaml`
- `packs/core/actions/build_pack_envs.yaml`
- `packs/core/actions/get_pack_dependencies.yaml`
- `packs/core/triggers/intervaltimer.yaml`
- `packs/core/triggers/crontimer.yaml`
- `packs/core/triggers/datetimetimer.yaml`
- `packs/core/workflows/install_packs.yaml`
- `packs/examples/actions/list_example.yaml`
### Web UI (7 files)
- `web/src/components/common/ParamSchemaForm.tsx` — New `ParamSchemaProperty` interface with inline `required`/`secret`/`position`, new exported `extractProperties()` utility, updated `validateParamSchema()` logic
- `web/src/components/common/ParamSchemaDisplay.tsx` — Imports shared `extractProperties`, removed duplicate type definitions
- `web/src/components/common/ExecuteActionModal.tsx` — Uses shared `extractProperties` for parameter initialization
- `web/src/components/common/SchemaBuilder.tsx` — Produces StackStorm-style flat format, added Secret checkbox, handles both formats on input
- `web/src/components/forms/TriggerForm.tsx` — Updated empty-schema check for flat format
- `web/src/pages/actions/ActionsPage.tsx` — Uses `extractProperties`, added Secret badges
- `web/src/pages/triggers/TriggersPage.tsx` — Uses `extractProperties`, added Secret badges
### API DTOs (3 files)
- `crates/api/src/dto/action.rs` — Updated OpenAPI examples and doc comments
- `crates/api/src/dto/trigger.rs` — Updated OpenAPI examples and doc comments
- `crates/api/src/dto/workflow.rs` — Updated OpenAPI examples and doc comments
### Documentation
- `AGENTS.md` — Added Parameter Schema Format documentation in Pack File Loading section
## Key Design Decisions
1. **Shared `extractProperties()` utility**: Single exported function in `ParamSchemaForm.tsx` handles both StackStorm-style and legacy JSON Schema formats. All consumers import from one place instead of duplicating logic.
2. **Backward compatibility in Web UI**: The `extractProperties()` function detects the old format (presence of `type: "object"` + `properties` wrapper) and normalizes it to the flat format, merging the top-level `required` array into per-parameter `required: true` flags. This means existing database records in the old format will still render correctly.
3. **No Rust model changes needed**: `param_schema` is stored as `Option<JsonValue>` (aliased as `JsonSchema`). The Rust code doesn't deeply inspect the schema structure — it passes it through as opaque JSONB. The format change is transparent to the backend.
4. **Pack loaders unchanged**: Both `loader.rs` and `load_core_pack.py` read `data.get("parameters")` and serialize it to JSONB as-is. Since we changed the YAML format, the stored format automatically changes to match.
## Verification
- Rust: `cargo check --all-targets --workspace` — zero warnings
- Rust: `cargo test --workspace --lib` — 82 tests passed
- TypeScript: `npx tsc --noEmit` — clean
- Vite: `npx vite build` — successful production build