Skip to content
Back to skills

State Machines

ASecurity

Transition RunState and PhaseState only through the explicit functions in src/domain/state.ts — never mutate state-bearing fields directly.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
developmenttypescriptgo

Security analysis

A100/100

Scanned October 19, 2026

npx -y skills add lbdremy/phax --skill state-machines --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of State Machines?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for State Machines
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lbdremy-state-machines/badge)](https://www.skillsdirectory.com/skills/lbdremy-state-machines)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: state-machines
description: Transition RunState and PhaseState only through the explicit functions in src/domain/state.ts — never mutate state-bearing fields directly.
---

# State machines

## The rule

**`RunState` and `PhaseState` transitions must go through the explicit
transition functions in `src/domain/state.ts`.** Direct assignment or mutation
of state-bearing fields outside that module is a violation.

## State shapes

```typescript
// src/domain/state.ts
type RunState =
  | "created"
  | "running"
  | "failed"
  | "review_open"
  | "completed"
  | "stopped"
  | "archived"
  | "interrupted";

type PhaseState =
  | "pending"
  | "setting_up_worktree"
  | "running"
  | "gates_failed"
  | "fixing"
  | "failed"
  | "passed"
  | "committed"
  | "cleaning_up"
  | "cleaned_up"
  | "review_open"
  | "handoff_failed"
  | "skipped";
```

## Transition functions

Each transition function takes the current state and returns
`Either<NewState, InvalidTransitionError>`. Call-sites must handle the `Left`
(invalid transition) case.

```typescript
import { startRun, failRun, openRunReview } from "../domain/state.js";
import { Either } from "effect";

const next = startRun(currentState);
if (Either.isLeft(next)) {
  // surface InvalidTransitionError — never silently swallow it
}
```

## Why

Direct string assignment bypasses the transition guard. This means illegal
state sequences (e.g., `archived → running`) become possible, which corrupts
`registry.json` and `run-status.json` in ways that are hard to detect.

The `Either`-returning pattern forces callers to handle illegal transitions
explicitly rather than producing silent corrupt state.

## How to fix a violation

1. Find the direct state field assignment (e.g., `status.runState = "running"`).
2. Replace with the appropriate transition function from `src/domain/state.ts`.
3. Handle the `Left` case and surface the `InvalidTransitionError`.

## Audit rule

`PHAX_STATE_001` — direct assignment to a state-bearing type field detected
outside `domain/state.ts`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.