# MDAP/MAKER Framework

Implementation of the **MAKER** framework from "Solving a Million-Step LLM Task with Zero Errors" (Meyerson et al., arXiv:2511.09030) integrated into Synqed.

## Overview

The MAKER framework enables LLM-based systems to solve tasks with millions of steps with zero errors through three key components:

1. **Maximal Agentic Decomposition (MAD)**: Tasks are decomposed into minimal subtasks (m=1 step per agent call).
2. **First-to-ahead-by-k Voting**: Error correction at each step through statistical voting.
3. **Red-flagging**: Discard risky outputs (too long, misformatted) instead of trying to fix them.

## Architecture

```
synqed/mdap/
├── __init__.py           # public api
├── types.py              # core data structures (stepinput, stepoutput, configs)
├── red_flags.py          # output validation and rejection logic
├── voting.py             # first-to-ahead-by-k voting implementation
├── calibration.py        # cost estimation and model selection
├── execution.py          # main executor orchestrating the pipeline
├── step_runner.py        # integration with synqed agents / llm calls
└── README.md             # this file
```

## Key Concepts

### Maximal Agentic Decomposition (MAD)

Instead of having one agent solve an entire task, MAD decomposes the task into the smallest possible subtasks (ideally 1 logical decision per agent call). This:
- Reduces context burden on each agent.
- Enables effective error correction at each step.
- Allows use of smaller, cheaper models.

### First-to-ahead-by-k Voting

For each step, we sample multiple candidate outputs and accept the first candidate whose votes exceed the runner-up by at least k. This provides:
- Exponentially increasing success probability as k grows.
- Theoretical guarantees from eq. 9 in the paper: `p_success = 1 / (1 + ((1-p)/p)^k)`.
- Log-linear cost scaling with task size.

### Red-flagging

Instead of trying to repair malformed outputs, we discard them as red flags:
- **Too long**: Outputs exceeding token threshold (e.g. 750 tokens).
- **Misformatted**: Outputs missing required fields or with parse errors.

This increases the per-step success rate p and reduces correlated errors.

## Usage

### Basic Example

```python
from synqed.mdap import (
    MdapExecutor,
    MdapConfig,
    ModelConfig,
    RedFlagger,
    SynqedStepRunner,
    Voter,
)

# configure model
model_config = ModelConfig(
    provider="openai",
    model="gpt-4o-mini",
    api_key="...",
    temperature=0.1,
    max_output_tokens=750,
)

# setup red-flagger
red_flagger = RedFlagger(
    max_output_tokens=750,
    required_fields=["action", "next_state"],
    strict_format=True,
)

# setup step runner
step_runner = SynqedStepRunner(
    model_config=model_config,
    red_flagger=red_flagger,
    prompt_builder=build_prompt_fn,
    response_parser=parse_response_fn,
    system_prompt="...",
)

# setup voter
voter = Voter(
    step_runner=step_runner,
    red_flagger=red_flagger,
    k=3,
)

# setup executor
executor = MdapExecutor(
    mdap_config=MdapConfig(k=3),
    voter=voter,
)

# run task
result = executor.run_task(
    initial_state=initial_state,
    num_steps=1_048_575,  # 20 disks hanoi
)

print(f"Success: {result.success}")
print(f"Total samples: {result.total_samples}")
print(f"Valid samples: {result.total_valid_samples}")
```

### Calibration

Before running a million-step task, calibrate to estimate p, k, and cost:

```python
from synqed.mdap.calibration import estimate_p_and_cost

report = estimate_p_and_cost(
    model_config=model_config,
    task_sampler=sample_random_step,
    ground_truth_fn=compute_correct_action,
    step_runner=step_runner,
    num_samples=1000,
    target_success_prob=0.95,
    total_steps=1_048_575,
)

print(f"Estimated p: {report.p_estimate:.4f}")
print(f"Recommended k: {report.k_min}")
print(f"Projected cost: ${report.projected_cost:.2f}")
```

## Scaling Laws

From the paper (section 3.2):

- **k_min** (eq. 14): `k_min = ceil(ln(t^(-m/s) - 1) / ln((1-p)/p))`
- **Expected cost** (eq. 18, MAD): `E[cost] = Θ(c * s * ln(s) / p)`

Where:
- `t`: target success probability
- `s`: total steps
- `m`: steps per subtask (usually 1 for MAD)
- `p`: per-step success probability
- `c`: cost per sample
- `k`: vote margin

The key insight: cost scales **log-linearly** with s, not exponentially, making million-step tasks feasible.

## Examples

### Towers of Hanoi (20 disks, ≈1M steps)

See `synqed-samples/api/examples/maker_hanoi_20_disks.py`:

```bash
# calibration
python maker_hanoi_20_disks.py --calibrate --num-disks 10

# run 10 disks (1,023 steps)
python maker_hanoi_20_disks.py --num-disks 10 --k 3

# run 20 disks (1,048,575 steps)
python maker_hanoi_20_disks.py --num-disks 20 --k 3
```

## Testing

```bash
# unit tests
pytest tests/test_mdap_voting.py
pytest tests/test_mdap_red_flags.py

# integration tests
pytest tests/test_mdap_hanoi_small.py
```

## Integration with Synqed

The MDAP framework is designed to integrate cleanly with Synqed's existing agent system:

- **StepRunnerInterface**: Abstract interface that can be implemented using Synqed agents.
- **SynqedStepRunner**: Default implementation that calls LLMs directly.
- **Future**: Integrate with Synqed's WorkspaceManager for persistent long-running tasks.

## References

- Paper: Meyerson et al., "Solving a Million-Step LLM Task with Zero Errors", arXiv:2511.09030, 2025.
- Key algorithms: Algorithm 1 (generate_solution), Algorithm 2 (do_voting), Algorithm 3 (get_vote).
- Key equations: Eq. 9 (vote success prob), Eq. 13 (full task success), Eq. 14 (k_min), Eq. 18 (expected cost).

## Design Principles

1. **Additive, not invasive**: MDAP is a separate module that doesn't break existing Synqed APIs.
2. **Composable**: Each component (voter, red_flagger, step_runner) can be used independently.
3. **Minimal abstractions**: No over-generalization; focus on the core MAKER framework.
4. **Testable**: Extensive unit and integration tests with mock runners.
5. **Production-ready**: Structured logging, cost estimation, configurable thresholds.

## Future Extensions

- **Model diversity**: Use different models for different votes to decorrelate errors.
- **Adaptive k**: Adjust k per step based on difficulty.
- **Parallel voting**: Parallelize k votes across multiple processes.
- **Integration with Synqed workspaces**: Long-running tasks with persistent state.
- **Beyond execution**: Extend to handle insight generation (decomposition, composition).

