Skip to content

REQ-C-003: Mutating Commands Declare effect Field

Tier: Command Contract | Priority: P0

Source: §12 Idempotency & Safe Retries

Addresses: Severity: Critical / Token Spend: High / Time: High / Context: Medium


Description

Every command with danger_level of mutating or destructive MUST include an effect field in its success response. The effect value MUST be one of: "created", "updated", "deleted", "noop". Command authors MUST determine and set the correct value based on what actually occurred. The framework MUST validate that the effect field is present and has a valid value for all non-safe commands. A passthrough command (REQ-C-031) is exempt, because the framework cannot know what the delegated tool changed: its data is {"exit_code": n}, and only a deduplicated replay adds effect: "noop". A streaming command (REQ-O-004) reports what it did per event instead: each item line carries its own effect, and the summary line's effects counts the events per effect value.

Acceptance Criteria

  • A mutating command response always includes "effect" at the top level of the envelope
  • effect: "noop" is returned when the operation was a no-op (e.g., already at desired state)
  • effect: "created" vs effect: "updated" is accurate (not always one or the other)
  • The framework raises a registration or runtime error if a mutating command omits effect
  • A streaming mutating command puts a valid effect on every item line, and its summary line's effects counts sum to the number of item lines

Schema

Types: response-envelope.md

The effect field is required at the top level of the response envelope data for all non-safe commands. Allowed values: "created" · "updated" · "deleted" · "noop".

{
  "effect": {
    "type": "string",
    "enum": ["created", "updated", "deleted", "noop"],
    "description": "Describes what the command actually did; present on all mutating and destructive command responses"
  }
}

Wire Format

$ tool create-order --amount 100 --idempotency-key abc123
{
  "ok": true,
  "data": {
    "effect": "created",
    "id": 42,
    "amount": 100
  },
  "error": null,
  "warnings": [],
  "meta": { "exit_code": 0, "duration_ms": 84 }
}

Second call with same key:

{
  "ok": true,
  "data": {
    "effect": "noop",
    "id": 42,
    "amount": 100
  },
  "error": null,
  "warnings": [],
  "meta": { "exit_code": 0, "duration_ms": 12 }
}

Example

A mutating command sets effect based on what actually occurred at runtime. The command author determines the correct value.

register command "deploy":
  danger_level: mutating
  exit_codes:
    SUCCESS(0): description: "Deployment completed", retryable: false, side_effects: complete

  execute(args):
    current = get_current_version(args.target)
    if current == args.version:
      return response(effect="noop", current_version=current)
    deploy(args.target, args.version)
    return response(effect="updated", previous=current, current=args.version)

Requirement Tier Relationship
REQ-C-002 C Provides: danger_level: mutating/destructive triggers effect field obligation
REQ-C-007 C Composes: effect: "noop" is the canonical response for a deduplicated idempotency-key hit
REQ-C-004 C Extends: dry-run responses use would_* effect prefixes, not the values defined here
REQ-F-004 F Wraps: effect is carried inside the ResponseEnvelope
REQ-C-031 C Specializes: a passthrough command's data carries exit_code, not effect
REQ-O-004 O Specializes: a mutating stream carries effect on each event and counts them on the summary line