Skip to content

Commit fa818c4

Browse files
authored
Document that version_constraint decides an action's output path shape (#34)
* Document that version_constraint decides an action's output path shape Adding a version_constraint to an existing workflow without shortening its ${data['...']} references produces YAML that imports cleanly and then fails at release. Nothing in the skill documentation said so, and the two forms are mutually exclusive rather than aliases: unpinned, a reference carries the action's namespace as in ${data['DeviceQuery.Device.query.devices']}, while pinned at ~1 the same field is ${data['DeviceQuery.devices']}. The schema and best-practices references now describe the pin and the path rewrite as a single two-part edit, and the authoring skill gains a counter-rationalization row for the half-applied case. Verified against a live tenant for Device Query, Get device details, and Event Query: with ~1 the short form resolves and the long form is rejected at release with `property "..." contains unknown variable`; without the pin, the long form resolves. Two smaller corrections came out of the same check. Only class-based actions strictly require a version_constraint at import, since a non-class action such as Device Query imports and releases without one, so that claim is now scoped accordingly. And the workflows copies of both references had drifted from the authoring copies, still saying to always use ~1 and claiming every CrowdStrike action sits at major version 1, which is wrong for the 0.x actions such as Charlotte AI. Both are now in line. * Leave authoring SKILL.md at its token budget The counter-rationalization row added in the previous commit pushed authoring/SKILL.md from 5491 to 5570 tokens, over its 5500 budget, and CI's size check failed. The file had 35 characters of headroom, so the row cannot fit without evicting unrelated guidance, and merging it into the adjacent version_constraint row still lands 10 tokens over. Reverting that hunk. The guidance lives in the schema and best-practices references, which is where the detail belongs anyway. Deciding what to evict from SKILL.md to make room is a separate change.
1 parent feb3f91 commit fa818c4

5 files changed

Lines changed: 123 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
1919
### Fixed
2020

2121
- Three authoring-doc corrections from a Fusion engineer's tech review. `version_constraint` is no longer framed as class-specific — nearly every action carries one whether or not it declares a `class`, so include it on every action node. The event-trigger and system-level variables (`Trigger.CID`, `Workflow.Execution.ID`, `Workflow.Definition.Name`, etc.) are now shown in the `${data['...']}` form and are documented as living in the `data` namespace like any other field rather than as an exception. And the action `name:` field is described as a relabelable display label — renaming it does not break references, which resolve by node key and action `id`.
22+
- **`version_constraint` decides the shape of an action's output paths, and that was undocumented.** Unpinned, a reference carries the action's namespace (`${data['DeviceQuery.Device.query.devices']}`); pinned at `~1` the same field is `${data['DeviceQuery.devices']}`. The two forms are mutually exclusive, so adding a `version_constraint` to an existing workflow without shortening its `${data['...']}` references produces YAML that imports cleanly and then fails at release with `property "..." contains unknown variable`. The schema and best-practices references now document this as a single two-part edit. Verified against a live tenant for Device Query, Get device details, and Event Query. The `workflows` copies of both references were also brought in line with the `authoring` copies, which had drifted: they still said to "always use `~1`" and claimed all CrowdStrike actions sit at major version 1, which is wrong for the 0.x actions such as Charlotte AI.
23+
- Clarified that only class-based actions strictly *require* a `version_constraint` at import. A non-class action such as Device Query imports and releases without one; it just keeps the older, longer output paths.
2224

2325
## [1.0.1] - 2026-08-07
2426

skills/authoring/references/best-practices.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,28 @@ Import validation fails with an error like:
100100
version constraint required for activity class 'CreateVariable'
101101
```
102102

103+
That failure is specific to class-based actions. A non-class action such as Device
104+
Query imports and releases fine without a `version_constraint` — but read the next
105+
section before you decide to leave it off.
106+
107+
### It also decides the shape of the action's output paths
108+
Pinning a version changes how you reference that action's output, and the two
109+
forms are mutually exclusive:
110+
111+
| `version_constraint` | Reference form |
112+
|---|---|
113+
| omitted | `${data['DeviceQuery.Device.query.devices']}` — carries the action's namespace |
114+
| `~1` | `${data['DeviceQuery.devices']}` — node label plus field |
115+
116+
The middle segment is the action's `Namespace` from `action_search.py --details`.
117+
Pin `~1` and keep the long path, and release fails with
118+
`property "..." contains unknown variable "DeviceQuery.Device.query.devices"`.
119+
120+
**So adding a `version_constraint` to an existing workflow is a two-part edit:**
121+
add the pin *and* shorten every `${data['...']}` reference to that action. Doing
122+
only the first produces YAML that imports and then fails at release. Confirmed
123+
against a live tenant for Device Query, Get device details, and Event Query.
124+
103125
---
104126

105127
## YAML authoring gotchas

skills/authoring/references/yaml-schema.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,42 @@ output_fields:
437437

438438
## version_constraint
439439

440-
Required for class-based actions (CreateVariable, UpdateVariable) and every other
441-
action as well. The value is the tilde range for the major component of the
440+
Required for class-based actions (CreateVariable, UpdateVariable), and wanted on
441+
every other action too. The value is the tilde range for the major component of the
442442
action's `semantic_version` (`~0` when it declares none), so read it from
443443
`action_search.py --details` rather than assuming `~1`:
444444

445445
```yaml
446446
version_constraint: ~1 # semantic_version 1.x.y; use ~0 for 0.x.y, ~2 for 2.x.y
447447
```
448448

449-
Omitting this on actions that require it causes import validation failures.
449+
Omitting this on a class-based action causes import validation failures. On a
450+
non-class action, import and release both succeed without it, but the action's
451+
output paths keep their older, longer form — see below.
452+
453+
### It also decides the shape of the action's output paths
454+
455+
Pinning a version is not only a compatibility guard. It changes how you reference
456+
that action's output, and the two forms are mutually exclusive:
457+
458+
| `version_constraint` | Reference form |
459+
|---|---|
460+
| omitted | `${data['DeviceQuery.Device.query.devices']}` — carries the action's namespace |
461+
| `~1` | `${data['DeviceQuery.devices']}` — node label plus field |
462+
463+
That middle segment is the action's `Namespace` as reported by
464+
`action_search.py --details` (`device.query` for Device Query,
465+
`device.get_details` for Get device details, `logscale.query_event` for Event
466+
Query). Pin `~1`, leave the long path in place, and **release fails**:
467+
468+
```
469+
property "Script" contains unknown variable "DeviceQuery.Device.query.devices"
470+
```
471+
472+
So when you add a `version_constraint` to an existing workflow, shorten every
473+
`${data['...']}` reference to that action in the same edit. Adding the pin alone
474+
produces YAML that imports and then fails at release.
475+
476+
Confirmed against a live tenant for Device Query, Get device details, and Event
477+
Query: with `~1` the short form resolves and the long form is rejected at
478+
release; without it, the long form resolves.

skills/workflows/references/best-practices.md

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,49 @@ per item. Include the input value (e.g., `device_id`) so callers can correlate r
7777
### When to use it
7878
- **Always** on `CreateVariable` and `UpdateVariable` (class-based actions)
7979
- **Always** when the action response from `action_search.py --details` includes `class`
80-
- **Sometimes** on catalog actions that have been versioned (check API response)
80+
- **Every** other action needs one too — it just isn't gated on having a `class`
8181

8282
### The correct value
83+
The value is the tilde range for the major component of the action's declared
84+
`semantic_version`, and `~0` when the action declares none:
85+
8386
```yaml
84-
version_constraint: ~1
87+
version_constraint: ~1 # action's semantic_version is 1.x.y
8588
```
86-
This means "compatible with major version 1" (semver tilde range). All current
87-
CrowdStrike actions use major version 1.
89+
90+
So an action at `1.0.4` takes `~1`, one at `0.0.100` (Charlotte AI, most Store
91+
plugins) takes `~0`, and one at `2.3.0` takes `~2`. Do not assume `~1`
92+
everywhere — plenty of actions sit at major version 0. Read the
93+
`semantic_version` from `action_search.py --details` and take its major component.
8894

8995
### What happens without it
9096
Import validation fails with an error like:
9197
```
9298
version constraint required for activity class 'CreateVariable'
9399
```
94100

101+
That failure is specific to class-based actions. A non-class action such as Device
102+
Query imports and releases fine without a `version_constraint` — but read the next
103+
section before you decide to leave it off.
104+
105+
### It also decides the shape of the action's output paths
106+
Pinning a version changes how you reference that action's output, and the two
107+
forms are mutually exclusive:
108+
109+
| `version_constraint` | Reference form |
110+
|---|---|
111+
| omitted | `${data['DeviceQuery.Device.query.devices']}` — carries the action's namespace |
112+
| `~1` | `${data['DeviceQuery.devices']}` — node label plus field |
113+
114+
The middle segment is the action's `Namespace` from `action_search.py --details`.
115+
Pin `~1` and keep the long path, and release fails with
116+
`property "..." contains unknown variable "DeviceQuery.Device.query.devices"`.
117+
118+
**So adding a `version_constraint` to an existing workflow is a two-part edit:**
119+
add the pin *and* shorten every `${data['...']}` reference to that action. Doing
120+
only the first produces YAML that imports and then fails at release. Confirmed
121+
against a live tenant for Device Query, Get device details, and Event Query.
122+
95123
---
96124

97125
## YAML authoring gotchas

skills/workflows/references/yaml-schema.md

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -441,11 +441,42 @@ output_fields:
441441

442442
## version_constraint
443443

444-
Required for class-based actions (CreateVariable, UpdateVariable) and some catalog actions.
445-
Always use `~1` (semver compatible with major version 1).
444+
Required for class-based actions (CreateVariable, UpdateVariable), and wanted on
445+
every other action too. The value is the tilde range for the major component of the
446+
action's `semantic_version` (`~0` when it declares none), so read it from
447+
`action_search.py --details` rather than assuming `~1`:
446448

447449
```yaml
448-
version_constraint: ~1
450+
version_constraint: ~1 # semantic_version 1.x.y; use ~0 for 0.x.y, ~2 for 2.x.y
449451
```
450452

451-
Omitting this on actions that require it causes import validation failures.
453+
Omitting this on a class-based action causes import validation failures. On a
454+
non-class action, import and release both succeed without it, but the action's
455+
output paths keep their older, longer form — see below.
456+
457+
### It also decides the shape of the action's output paths
458+
459+
Pinning a version is not only a compatibility guard. It changes how you reference
460+
that action's output, and the two forms are mutually exclusive:
461+
462+
| `version_constraint` | Reference form |
463+
|---|---|
464+
| omitted | `${data['DeviceQuery.Device.query.devices']}` — carries the action's namespace |
465+
| `~1` | `${data['DeviceQuery.devices']}` — node label plus field |
466+
467+
That middle segment is the action's `Namespace` as reported by
468+
`action_search.py --details` (`device.query` for Device Query,
469+
`device.get_details` for Get device details, `logscale.query_event` for Event
470+
Query). Pin `~1`, leave the long path in place, and **release fails**:
471+
472+
```
473+
property "Script" contains unknown variable "DeviceQuery.Device.query.devices"
474+
```
475+
476+
So when you add a `version_constraint` to an existing workflow, shorten every
477+
`${data['...']}` reference to that action in the same edit. Adding the pin alone
478+
produces YAML that imports and then fails at release.
479+
480+
Confirmed against a live tenant for Device Query, Get device details, and Event
481+
Query: with `~1` the short form resolves and the long form is rejected at
482+
release; without it, the long form resolves.

0 commit comments

Comments
 (0)