Skip to content

Stage-2 cleanup: tighten runnerKind from string to enum union #13

@byeagerOIT

Description

@byeagerOIT

Background

`runnerKind` is currently typed as plain `string` across the dispatcher:

  • `types.ts` AttemptRecord, RunSpec → `runnerKind: string`
  • `schema.sql` attempts.runner_kind → TEXT (no CHECK)
  • `idempotency.ts` payload format includes runnerKind unconstrained

Surfaced by Grok 4 batch review of Week 1 Foundations: this is a locked-in API decision that Tasks 11+ (RunnerInterface, ClaudeRunner, CodexRunner) will inherit. A typo or stale literal silently produces a wrong sha256 idempotency key with no compile-time protection.

Proposed fix

After Task 11 ships RunnerInterface, refactor:

```typescript
export type RunnerKind = "claude" | "codex" | "concurrency-gate";

export interface RunSpec {
runnerKind: RunnerKind;
}
```

Plus a CHECK constraint on `schema.sql attempts.runner_kind`:

```sql
runner_kind TEXT NOT NULL CHECK (runner_kind IN ('claude','codex','concurrency-gate'))
```

Migration: existing rows are already in the union (only "claude" + "concurrency-gate" used in Week 1), so a CHECK ADD is non-breaking.

When

After Task 11 (RunnerInterface) defines the canonical runner kind set. Don't do this earlier — risk of premature enum lock-in.

Reference

  • Branch: `oit/dispatcher-stage-1`
  • Source: `src/adapters/oit/dispatcher/types.ts`, `src/adapters/oit/dispatcher/state/schema.sql`, `src/adapters/oit/dispatcher/idempotency.ts`

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions