Take one FSM transition
stepAdvance a load-testing pipeline stage by stage by executing one action at a time with required inputs, validating each transition to keep the workflow on track.
Instructions
Advance the FSM by one transition.
Args:
action: Name of the action to run. Must be in the
current valid-next set; otherwise the call returns
an ``invalid_transition`` error with the list of
actions actually allowed right now.
inputs: Keyword inputs to the action. Each action
declares its own required + optional inputs;
consult ``theodosia://next`` and the action's docstring
to see what's expected. Object is the canonical
form. A JSON-encoded string is also accepted (some
clients serialize nested object arguments that way)
and is parsed into an object before dispatch.Actions (entry: select_mode):
select_mode: Start a run. Pass
intentfor natural-language mode, or justrepo_path/reffor diff mode.repo_pathis also where openapi.json is read from;splunk_indexis the index holding the target's server-side telemetry.read_diff: Read
git diff <ref>..HEADfrom the repo.extract_endpoints: Pull changed routes from the diff and load the sibling openapi.json.
parse_intent: Score OpenAPI operations against the natural-language intent and pick the top matches.
doc_lookup: Consult the k6 MCP documentation for the constructs kassi emits (HTTP requests, thresholds, checks, scenarios) and record version-grounded citations. Non-blocking: degrades to no references when the docs are unavailable.
scaffold: Compose a deterministic, self-contained k6 scaffold from the OpenAPI spec (no model): per-endpoint requests with sample bodies, the baked base URL, and load options. This is the runnable baseline the next step builds on.
generate_script: Author the final k6 script on top of the scaffold, using k6's own
generate_scriptMCP prompt and best-practices to guide the model. Falls back to the scaffold when the model or guidance is unavailable; validation failures are repaired by the fix_script phase.validate_script: Validate the script via the k6 MCP
validate_scripttool (1 VU, 1 iteration).fix_script: Repair the k6 script using the error the k6 MCP
validate_scripttool returned (real stderr + issues + suggestions), then loop back to validation. The correction loop is an explicit edge in the state machine; on a model failure it falls back to the scaffold.run_test: Execute the load test via the k6 MCP
run_scripttool (passing VUs + duration, which the tool needs since it ignores the script's own options) and parse the metrics from the summary. Bounded by a timeout: if the authored script wedges k6 so the call never returns, fall back to running the deterministic scaffold once, so the pipeline never hangs.splunk_preflight: Before correlating, verify the target Splunk index exists and capture its event count, sourcetypes, and the Splunk version via the Splunk MCP
splunk_get_info/splunk_get_index_info/splunk_get_metadatatools. Non-blocking: correlate still runs if a probe fails.correlate: Read the target's server-side telemetry over the exact test window via the Splunk MCP
splunk_run_querytool: an overview rollup, a per-second timeline (when it degraded), a by-endpoint breakdown (which route degraded), and the dominant server-side error (why). Synthesize the actionable findings. Passsplunk_splto override the rollup query.detect_anomalies: Run Splunk's own ML over the test window via the Splunk MCP
splunk_run_querytool: the AI Toolkit'sStateSpaceForecastprojects the latency band (falling back to the corepredictcommand when the toolkit is unavailable), andanomalydetectionflags statistically outlying buckets. This is the saturation onset found statistically, independent of the fixed error thresholds. Non-blocking: degrades to no anomalies when Splunk is unavailable.analyze: The writer phase (Granite 4.1): turn the correlated facts into a cited analysis (cause,
screen: The auditor phase (Granite Guardian): an independent model judges whether the analysis is
report: Assemble the final report from the analyzed and screened state and have the model narrate
Transitions:
select_mode -> read_diff (when: stage == 'selected' and mode == 'diff')
select_mode -> parse_intent (when: stage == 'selected' and mode == 'intent')
read_diff -> analyze (when: stage == 'failed')
read_diff -> extract_endpoints (when: stage == 'diffed')
extract_endpoints -> doc_lookup (when: stage == 'scoped')
parse_intent -> analyze (when: stage == 'failed')
parse_intent -> doc_lookup (when: stage == 'scoped')
doc_lookup -> scaffold (when: stage == 'documented')
scaffold -> analyze (when: stage == 'failed')
scaffold -> generate_script (when: stage == 'scaffolded')
generate_script -> validate_script (when: stage == 'generated')
validate_script -> fix_script (when: stage == 'needs_fix')
fix_script -> validate_script (when: stage == 'generated')
validate_script -> run_test (when: stage == 'validated')
validate_script -> analyze (when: stage == 'failed_validation')
run_test -> splunk_preflight (when: stage == 'ran' and splunk_enabled)
run_test -> analyze (when: stage == 'ran' and not splunk_enabled)
run_test -> analyze (when: stage == 'failed')
splunk_preflight -> correlate (when: stage == 'preflighted')
correlate -> detect_anomalies (when: stage == 'correlated')
detect_anomalies -> analyze (when: stage == 'detected')
analyze -> screen (when: stage == 'analyzed')
screen -> report (when: stage == 'screened')
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Name of the action to run. Must be one of the listed values; calling an out-of-state value returns an invalid_transition error with the current valid set. | |
| inputs | No | Keyword inputs to the action. Each action declares its own required + optional inputs; consult ``theodosia://next`` and the action's docstring to see what's expected. Object is the canonical form. A JSON-encoded string is also accepted (some clients serialize nested object arguments that way) and is parsed into an object before dispatch. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| error | No | Refusal discriminator. When set, the response carries the matching refusal payload's fields. | |
| state | No | Public Application state after the step. | |
| action | No | Name of the action that ran. | |
| app_id | No | Application uid. | |
| chunks | No | Streamed chunk count (when streamed is true). | |
| reason | No | Validation failure reason (validation_failed only). | |
| result | No | Action's structured return value. | |
| details | No | Validation failure details (validation_failed only). | |
| message | No | Human-readable message (unknown_action, invalid_transition, action_timeout). | |
| streamed | No | True when the action was a streaming action. | |
| next_hint | No | Directional steering string appended after every step and refusal: cites what just happened and the reachable actions now. Present on success and on every refusal. | |
| requested | No | Name the client passed; present on every refusal. | |
| error_type | No | Exception class name of the underlying error (action_error only). | |
| error_message | No | Stringified exception (action_error only). | |
| known_actions | No | All action names in the FSM (unknown_action only). | |
| timeout_seconds | No | Configured timeout (action_timeout only). | |
| tracker_project | No | LocalTrackingClient project name if attached. | |
| valid_next_actions | No | Actions reachable from the current state. Present on success and on every refusal so the agent can self-correct. | |
| next_external_tools | No | Present only when the server was mounted with external_tools. Maps each currently-reachable action to the tools (on other connected MCP servers) relevant before taking it. Call those tools, then step() to record findings and advance. |