{
  "version": "order-intent-chaser.workflow.v1",
  "fixtures": [
    {
      "name": "chaser_dry_run_buy_candidate_respects_limit_and_filters",
      "intent": "A buy entry intent produces a bounded dry-run child candidate without live exchange writes.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "config": { "mode": "dry-run", "postOnly": true },
        "parentIntent": {
          "id": "intent-buy-1",
          "quantity": "0.010",
          "priceLimit": "100.00",
          "maxSlippageBps": 5,
          "riskApproved": true
        },
        "filters": { "tickSize": "0.10", "stepSize": "0.001", "minNotional": "5" },
        "marketData": { "bestBid": "99.90", "bestAsk": "100.10", "fresh": true }
      },
      "steps": [{ "type": "start" }, { "type": "place_attempt" }],
      "expect": {
        "state": "dry_run_planned",
        "actions": [
          {
            "type": "dry_run_child_candidate",
            "side": "BUY",
            "price": "99.90",
            "quantity": "0.010",
            "wouldSubmit": false
          }
        ],
        "blocks": []
      },
      "forbid": ["exchange_submit_called", "price_above_buy_limit"]
    },
    {
      "name": "chaser_dry_run_sell_exit_preserves_reduce_or_close_semantics",
      "intent": "A sell exit intent keeps reduce-only or close-only semantics where the selected exchange supports them.",
      "scope": {
        "exchange": "generic",
        "product": "perpetual",
        "symbol": "ASSETQUOTE",
        "side": "SELL",
        "role": "EXIT"
      },
      "initial": {
        "config": { "mode": "dry-run" },
        "parentIntent": {
          "id": "intent-exit-1",
          "quantity": "0.020",
          "priceLimit": "99.50",
          "riskApproved": true,
          "reduceOnly": true
        },
        "filters": { "tickSize": "0.10", "stepSize": "0.001", "minNotional": "5" },
        "marketData": { "bestBid": "99.70", "bestAsk": "99.90", "fresh": true }
      },
      "steps": [{ "type": "start" }, { "type": "place_attempt" }],
      "expect": {
        "state": "dry_run_planned",
        "actions": [
          {
            "type": "dry_run_child_candidate",
            "side": "SELL",
            "reduceOnly": true,
            "price": "99.90"
          }
        ]
      },
      "forbid": ["exposure_increasing_exit", "price_below_sell_limit"]
    },
    {
      "name": "chaser_rest_acceptance_does_not_confirm_child_order_state",
      "intent": "REST acceptance creates pending evidence only and does not confirm active child-order state.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "config": { "mode": "demo" },
        "parentIntent": { "id": "intent-buy-2", "quantity": "0.010", "riskApproved": true },
        "marketData": { "fresh": true },
        "filters": { "tickSize": "0.10", "stepSize": "0.001" }
      },
      "steps": [
        {
          "type": "place_attempt",
          "payload": {
            "childOrderId": "oid-ch-0002",
            "parentIntentId": "intent-buy-2",
            "generation": 1
          }
        },
        { "type": "rest_accept", "payload": { "childOrderId": "oid-ch-0002" } },
        { "type": "replace_tick" }
      ],
      "expect": {
        "state": "pending_child_confirmation",
        "childOrderTrust": { "known": false, "source": "pending_rest_acceptance" },
        "pendingConfirmations": [
          { "childOrderId": "oid-ch-0002", "parentIntentId": "intent-buy-2", "generation": 1 }
        ],
        "blocks": [{ "reason": "child_order_confirmation_pending" }]
      },
      "forbid": ["duplicate_place_before_confirmation", "rest_accept_marked_active"]
    },
    {
      "name": "chaser_private_fill_before_rest_acceptance_updates_remaining_quantity_once",
      "intent": "A private fill that arrives before REST acceptance updates remaining quantity once and is not double-counted when REST settles.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "parentIntent": { "id": "intent-buy-3", "quantity": "0.100", "riskApproved": true },
        "marketData": { "fresh": true },
        "filters": { "tickSize": "0.10", "stepSize": "0.001" }
      },
      "steps": [
        {
          "type": "place_attempt",
          "payload": {
            "childOrderId": "oid-ch-0003",
            "parentIntentId": "intent-buy-3",
            "generation": 1
          }
        },
        {
          "type": "private_event",
          "payload": {
            "childOrderId": "oid-ch-0003",
            "status": "PARTIALLY_FILLED",
            "filled": "0.040"
          }
        },
        { "type": "rest_accept", "payload": { "childOrderId": "oid-ch-0003" } }
      ],
      "expect": {
        "remainingQuantity": "0.060",
        "childOrderTrust": { "known": true, "status": "PARTIALLY_FILLED" },
        "logs": [{ "event": "partial_fill_applied_once" }]
      },
      "forbid": ["fill_double_counted"]
    },
    {
      "name": "chaser_cancel_replace_waits_for_terminal_or_recovered_child_state",
      "intent": "Cancel-replace cannot submit the next generation while the previous child order state is unknown.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "parentIntent": { "id": "intent-buy-4", "quantity": "0.050", "riskApproved": true },
        "childOrders": [
          {
            "childOrderId": "oid-ch-0004",
            "parentIntentId": "intent-buy-4",
            "generation": 1,
            "status": "CANCEL_PENDING"
          }
        ]
      },
      "steps": [{ "type": "replace_tick" }],
      "expect": {
        "state": "waiting_child_state",
        "blocks": [{ "reason": "previous_child_state_unknown" }],
        "actions": []
      },
      "forbid": ["replacement_submitted_before_cancel_terminal"]
    },
    {
      "name": "chaser_stale_market_data_blocks_place_and_replace",
      "intent": "Stale top-of-book or sequence-gapped market data blocks both new place and replace decisions.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "parentIntent": { "id": "intent-buy-5", "quantity": "0.020", "riskApproved": true },
        "marketData": { "fresh": false, "reason": "sequence_gap" }
      },
      "steps": [{ "type": "place_attempt" }, { "type": "replace_tick" }],
      "expect": {
        "marketDataTrust": { "known": false, "reason": "sequence_gap" },
        "blocks": [{ "reason": "market_data_not_trusted" }],
        "actions": []
      },
      "forbid": ["place_from_stale_market_data", "replace_from_stale_market_data"]
    },
    {
      "name": "chaser_reconnect_requires_market_resync_before_replace",
      "intent": "Reconnect clears market-data trust and requires resync before replacement decisions.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "SELL",
        "role": "EXIT"
      },
      "initial": {
        "parentIntent": { "id": "intent-exit-2", "quantity": "0.030", "riskApproved": true },
        "marketData": { "fresh": true },
        "childOrders": [
          {
            "childOrderId": "oid-ch-0005",
            "parentIntentId": "intent-exit-2",
            "generation": 1,
            "status": "NEW"
          }
        ]
      },
      "steps": [
        { "type": "reconnect" },
        { "type": "replace_tick" },
        { "type": "market_data", "payload": { "fresh": true, "resynced": true } }
      ],
      "expect": {
        "marketDataTrust": { "known": true, "resyncedAfterReconnect": true },
        "blocks": [{ "reason": "market_resync_required" }]
      },
      "forbid": ["replace_before_market_resync"]
    },
    {
      "name": "chaser_partial_fill_below_minimum_abandons_or_pauses_by_policy",
      "intent": "A partial fill that leaves a remainder below exchange filters stops by explicit policy rather than sending an invalid replacement.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "parentIntent": { "id": "intent-buy-6", "quantity": "0.010", "riskApproved": true },
        "filters": { "minQty": "0.005", "minNotional": "5" }
      },
      "steps": [
        {
          "type": "private_event",
          "payload": {
            "childOrderId": "oid-ch-0006",
            "status": "PARTIALLY_FILLED",
            "filled": "0.008"
          }
        },
        { "type": "replace_tick" }
      ],
      "expect": {
        "remainingQuantity": "0.002",
        "state": "paused",
        "blocks": [{ "reason": "remaining_quantity_below_minimum" }]
      },
      "forbid": ["below_minimum_replacement_submitted"]
    },
    {
      "name": "chaser_duplicate_child_generation_is_blocked_before_exchange_call",
      "intent": "Submitter-level idempotency blocks duplicate child generation before any exchange call.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "parentIntent": { "id": "intent-buy-7", "quantity": "0.010", "riskApproved": true },
        "pendingConfirmations": [
          { "childOrderId": "oid-ch-0007", "parentIntentId": "intent-buy-7", "generation": 1 }
        ]
      },
      "steps": [
        { "type": "place_attempt", "payload": { "generation": 1 } },
        { "type": "place_attempt", "payload": { "generation": 1 } }
      ],
      "expect": {
        "blocks": [{ "reason": "duplicate_child_generation_pending" }],
        "actions": []
      },
      "forbid": ["duplicate_exchange_call"]
    },
    {
      "name": "chaser_active_app_child_without_parent_context_refuses_mutation",
      "intent": "An active app-owned child without durable parent context refuses mutation unless an explicit adoption path exists and is tested.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "SELL",
        "role": "EXIT"
      },
      "initial": {
        "parentIntent": null,
        "childOrders": [{ "childOrderId": "orphan-1", "owned": true, "status": "NEW" }]
      },
      "steps": [{ "type": "replace_tick" }],
      "expect": {
        "state": "paused",
        "blocks": [{ "reason": "missing_parent_context" }],
        "actions": []
      },
      "forbid": ["orphan_child_amended", "orphan_child_cancelled_without_policy"]
    },
    {
      "name": "chaser_timeout_cleanup_follows_explicit_policy",
      "intent": "Timeout behavior follows configured cleanup policy and logs final parent state.",
      "scope": {
        "exchange": "generic",
        "product": "spot",
        "symbol": "ASSETQUOTE",
        "side": "BUY",
        "role": "ENTRY"
      },
      "initial": {
        "config": { "timeoutPolicy": "cancel_app_child" },
        "parentIntent": { "id": "intent-buy-8", "quantity": "0.010", "riskApproved": true },
        "childOrders": [
          {
            "childOrderId": "oid-ch-0008",
            "parentIntentId": "intent-buy-8",
            "generation": 1,
            "owned": true,
            "status": "NEW"
          }
        ]
      },
      "steps": [{ "type": "timer", "payload": { "elapsedMs": 60000 } }],
      "expect": {
        "state": "abandoned",
        "actions": [{ "type": "cancel", "childOrderId": "oid-ch-0008" }],
        "logs": [{ "event": "parent_intent_abandoned", "reason": "timeout" }]
      },
      "forbid": ["unowned_order_cancelled", "timeout_policy_implicit"]
    }
  ]
}
