# How to Debug Quota Eligibility Failures in LoopX: A Step-by-Step Diagnostic Guide

> Debug LoopX quota eligibility failures by tracing envelope construction, signature verification, and disposition logic. Follow our step-by-step diagnostic guide to resolve issues.

- Repository: [huangruiteng/loopx](https://github.com/huangruiteng/loopx)
- Tags: how-to-guide
- Published: 2026-09-04

---

**LoopX determines whether an agent turn proceeds through the quota-should-run subsystem, and debugging failures requires tracing the envelope construction, signature verification, and disposition logic across three core stages.**

When an agent turn fails to execute in the huangruiteng/loopx repository, the root cause often lies in the quota eligibility check. This subsystem evaluates whether sufficient resources exist and whether gates permit execution. Understanding how to debug quota eligibility failures in LoopX involves tracing the flow from the CLI command through envelope construction to the final disposition decision.

## How Quota Eligibility Works in LoopX

The quota decision flow consists of three interconnected stages defined in `loopx/control_plane/quota/`. A failure typically originates when any stage returns `should_run = False` or fails to validate the envelope signature.

### Stage 1: Building the Turn Envelope

Located in [`loopx/control_plane/quota/turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/turn_envelope.py), the `build_turn_envelope()` function assembles a **turn envelope** that travels with the turn receipt. This envelope encapsulates the quota decision, the **effective_action** (such as `run`, `quiet-noop`, or `terminal-no-follow-up`), and the turn metadata. The envelope serves as the canonical record of why a turn was permitted or blocked.

### Stage 2: Interpreting the Quota Packet

The `interpret_quota_should_run_packet()` function in [`loopx/control_plane/quota/effect_program.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/effect_program.py) decodes the JSON output from the CLI command `loopx quota should-run`. It creates a **QuotaDecision** object containing the boolean `should_run`, the `effective_action` string, and the `signature` block. This stage transforms the raw provider response into a typed structure that downstream logic consumes.

### Stage 3: Deciding Loop Disposition

Also in [`loopx/control_plane/quota/turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/turn_envelope.py), the `decide_loop_disposition()` function combines the turn receipt with the quota envelope to determine if the loop will **spend quota**, **wait**, **re-plan**, or **terminate**. This final stage checks for signature mismatches, stale `source_hash` values, and propagation errors in `turn_key` or `selected_todo_id`.

## Step-by-Step Debugging Checklist

### 1. Run the Quota Command with Full Details

Execute the CLI command to see the raw provider decision:

```bash
loopx quota should-run \
    --goal-id <your-goal-id> \
    --include-detail scheduler \
    --format json

```

Examine the JSON payload for the `should_run` field. If this value is `false`, the failure originates from the quota provider itself—indicating limits, missing resources, or explicit gating. The `effective_action` field reveals whether the system intends to `run_now`, `stop_until_explicit_resume`, or execute a `quiet-noop`.

### 2. Inspect the Signature Block

The `signature` object proves that the quota decision matches the current goal state. Check the `source_hash` against the goal's latest state stored in the **goal ledger** (`loopx/state/`). A stale or mismatched hash causes the envelope to be rejected later in the pipeline even if `should_run` is `true`.

### 3. Trace the Turn Envelope Construction

Verify that `build_turn_envelope()` receives the correct arguments:

```python
from loopx.control_plane.quota.turn_envelope import build_turn_envelope

envelope = build_turn_envelope(
    quota_decision=quota_decision,  # Must match CLI output

    turn_key=receipt.turn_key,      # Must match the turn receipt

    selected_todo_id=None,          # Propagate correctly if present

)

```

Mismatched keys cause the envelope to be ignored during disposition. Ensure the `quota_decision` argument matches the CLI JSON exactly, including the `signature` block.

### 4. Check the Disposition Logic

The disposition function determines whether quota is actually consumed:

```python
from loopx.control_plane.quota.turn_envelope import decide_loop_disposition

disposition = decide_loop_disposition(
    turn_receipt=receipt,
    quota_decision=envelope,
)

```

The `disposition["spends_quota"]` field should be `True` when `should_run` is `True`. If it is `False`, inspect the envelope for flags such as `quiet_noop_allowed`, `replan_required`, or a failed signature verification.

### 5. Enable Debug Logging

Set the environment variable to capture detailed trace logs:

```bash
export LOOPX_LOG_LEVEL=debug

```

The logs emit messages from critical functions including `quota_action_signature_document` (signature creation), `interpret_quota_should_run_packet` (payload parsing), and `decide_loop_disposition` (final decision).

### 6. Validate the Quota Provider

Provider implementations reside in `loopx/control_plane/quota/provider/`. The ecosystem includes:

- **Static gates** defined in test fixtures (see [`tests/test_summary_all.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_summary_all.py))
- **Dynamic quota services** consulted via HTTP in [`quota_service.py`](https://github.com/huangruiteng/loopx/blob/main/quota_service.py)

If using a custom provider, ensure it returns a JSON object with the strict schema: `should_run`, `effective_action`, and `signature`. Missing fields cause parsing failures in [`effect_program.py`](https://github.com/huangruiteng/loopx/blob/main/effect_program.py).

### 7. Run the Relevant Unit Tests

Isolate failures using the dedicated test suites:

```bash
pytest tests/test_turn_envelope.py -v
pytest tests/test_turn_loop_disposition.py::test_quota_failure -v

```

These tests validate envelope construction, signature handling, and disposition logic for both success and failure scenarios.

## Practical Code Examples

### Inspecting a Quota Packet Manually

Simulate CLI output to debug parsing logic without running the full agent:

```python
import json
from loopx.control_plane.quota.effect_program import interpret_quota_should_run_packet

raw = """
{
  "should_run": false,
  "effective_action": "stop_until_explicit_resume",
  "signature": {
    "source_hash": "sha256:abc123",
    "gate_id": "explicit-quota-gate"
  }
}
"""
packet = json.loads(raw)
decision = interpret_quota_should_run_packet(packet)

assert decision.should_run is False
assert decision.effective_action == "stop_until_explicit_resume"

```

*Source:* [`loopx/control_plane/quota/effect_program.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/effect_program.py)

### Building a Turn Envelope and Deciding Disposition

Programmatically replicate the envelope flow to verify integration:

```python
from loopx.control_plane.quota.turn_envelope import (
    build_turn_envelope,
    decide_loop_disposition,
)
from loopx.control_plane.quota.effect_program import interpret_quota_should_run_packet

# Assume receipt from a previous turn

receipt = ...  # TurnReceipt object

quota_payload = {
    "should_run": True,
    "effective_action": "run_now",
    "signature": {"source_hash": "sha256:def456", "gate_id": "default"}
}
quota_decision = interpret_quota_should_run_packet(quota_payload)

envelope = build_turn_envelope(
    quota_decision=quota_decision,
    turn_key=receipt.turn_key,
    selected_todo_id=None,
)

disposition = decide_loop_disposition(
    turn_receipt=receipt,
    quota_decision=envelope
)
print(disposition["spends_quota"])  # Expected: True when eligible

```

*Source:* [`loopx/control_plane/quota/turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/turn_envelope.py)

### CLI Diagnostic Output

Generate full diagnostic data including scheduler internals:

```bash
loopx quota should-run \
    --goal-id my-goal \
    --include-detail scheduler \
    --format json

```

The output includes a `"scheduler"` block indicating whether execution occurs immediately or is deferred, which distinguishes between hard gate failures and scheduling waits.

*Source:* [`loopx/control_plane/quota/cli.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/cli.py)

## Key Source Files

- [`loopx/control_plane/quota/turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/turn_envelope.py) — Builds the turn envelope and decides loop disposition via `build_turn_envelope()` and `decide_loop_disposition()`
- [`loopx/control_plane/quota/effect_program.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/effect_program.py) — Parses JSON packets from `quota should-run` via `interpret_quota_should_run_packet()`
- [`loopx/control_plane/quota/task_orchestration.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/control_plane/quota/task_orchestration.py) — Orchestrates quota checks for a goal and integrates with the scheduler
- `loopx/control_plane/quota/provider/` — Contains static gates and dynamic HTTP quota service implementations
- [`tests/test_turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_turn_envelope.py) — Unit tests for envelope creation and signature validation
- [`tests/test_turn_loop_disposition.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_turn_loop_disposition.py) — Tests covering decision-making across all quota outcomes

## Summary

- **Trace the CLI output** to verify the raw `should_run` and `effective_action` values using `loopx quota should-run --include-detail scheduler --format json`
- **Verify signatures** by ensuring `source_hash` matches the current goal ledger state to prevent stale envelope rejections
- **Inspect envelope construction** in `build_turn_envelope()` to confirm correct propagation of `quota_decision`, `turn_key`, and `selected_todo_id`
- **Check disposition logic** to ensure `decide_loop_disposition()` returns `spends_quota=True` when execution is expected, and watch for `quiet_noop_allowed` or `replan_required` flags
- **Enable debug logging** with `LOOPX_LOG_LEVEL=debug` to capture detailed traces from `quota_action_signature_document`, `interpret_quota_should_run_packet`, and `decide_loop_disposition`
- **Run unit tests** in [`tests/test_turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_turn_envelope.py) and [`tests/test_turn_loop_disposition.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_turn_loop_disposition.py) to isolate component-level failures

## Frequently Asked Questions

### What causes a quota eligibility failure in LoopX?

A failure occurs when the quota provider returns `should_run: false` due to resource limits, explicit gates, or missing prerequisites. Failures also happen when the envelope's `signature` contains a stale `source_hash` that does not match the goal ledger, causing `decide_loop_disposition()` to reject the envelope even if the provider initially approved execution.

### How do I check if the quota signature is valid?

Compare the `source_hash` field in the quota decision's signature block against the latest hash stored in the goal ledger (`loopx/state/`). The `quota_action_signature_document` function generates this hash during envelope construction; if the ledger has advanced since the quota check, the hash mismatch triggers a rejection.

### Where are quota provider implementations located?

Providers reside in `loopx/control_plane/quota/provider/`. The repository includes static gates for testing (defined in [`tests/test_summary_all.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_summary_all.py)) and dynamic services that query external HTTP endpoints ([`quota_service.py`](https://github.com/huangruiteng/loopx/blob/main/quota_service.py)). Custom providers must return JSON with `should_run`, `effective_action`, and `signature` fields to be compatible with [`effect_program.py`](https://github.com/huangruiteng/loopx/blob/main/effect_program.py).

### Can I test quota logic without running the full agent?

Yes. Use the unit tests in [`tests/test_turn_envelope.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_turn_envelope.py) to validate envelope construction and signature handling, and [`tests/test_turn_loop_disposition.py`](https://github.com/huangruiteng/loopx/blob/main/tests/test_turn_loop_disposition.py) to verify disposition decisions against mock quota decisions. You can also manually call `interpret_quota_should_run_packet()` with JSON payloads to simulate provider responses without invoking the CLI.