# Experiment Loop — Structure Domain

> Base framework: `../shared/experiment-loop-base.md`

## Reasoning Checklist

Before making any structural change, answer these 8 questions. If you can't answer 3-6 concretely, analyze more before moving code.

1. **Smell**: What structural issue? (god module, circular dependency, misplaced entity, feature envy, dead code)
2. **Measurable?** Can you quantify the improvement? (import time, coupling count, test runtime, circular dep count)
3. **Affinity gap?** What's the entity's affinity to current module vs suggested module? How large is the gap?
4. **Callers?** How many import sites need updating? Higher count = higher risk.
5. **Public API?** Is this entity part of the package's documented public interface? Moving it may be a breaking change.
6. **Mechanism**: HOW does this move improve the codebase? Be specific (reduces coupling, breaks circular dep, improves import time, co-locates related logic).
7. **Safe?** Could this create a new circular dependency or break dynamic references?
8. **Verify cheaply**: Can you confirm the improvement with a quick metric (import time, grep for circular imports) before the full test run?

## Metrics

Structure optimization uses different metrics than runtime optimization. Measure before and after each move:

- **Import time**: `$RUNNER -X importtime -c "import mypackage" 2>&1 | head -30` — measures cold import cost
- **Circular dependencies**: count of import cycles (use grep or trace imports)
- **Coupling score**: number of cross-module calls (from the call matrix diagonal vs off-diagonal)
- **Test runtime**: full test suite time — structural changes can affect import overhead and fixture setup
- **God module fan-in**: number of modules importing the target module

Record the primary metric for each experiment in results.tsv.

## Domain-Specific Loop Steps

**Step 1 — Choose target** sources:
- **Call matrix**: Highest off-diagonal coupling, god modules with highest fan-in.
- **Affinity analysis**: Entities with largest gap between home affinity and best-fit module.
- **Circular dependency graph**: Cycles that could be broken by extracting shared entities.

Print: `[experiment N] Target: <description> (<smell>, <est. impact>)`

**Step 3 — Measure baseline metric.** Print `[experiment N] Baseline: <metric>=<value>`.

**Step 4 — Implement the move.** Print `[experiment N] Moving: <entity> from <source> to <target>`. Follow the safe refactoring protocol in `analysis-methodology.md`.

**Step 5 — Run tests.** Print `[experiment N] Running tests...`. All tests must pass after each move.

**Step 6 — Measure result.** Print `[experiment N] <metric>: <before> -> <after>`.

**Step 8 — E2E benchmark (after KEEP)**: If `codeflash compare` is available (check `.codeflash/setup.md`), run `$RUNNER -m codeflash compare <pre-opt-sha> HEAD` for authoritative isolated timing measurement alongside structural metrics. See `../shared/e2e-benchmarks.md`.

**Step 10 — Re-assess call matrix** (every 3-5 keeps): Rebuild the module connection matrix to see how the overall picture has changed. At milestones, run `$RUNNER -m codeflash compare <baseline-sha> HEAD` for cumulative e2e measurement. Print `[milestone] vN — <total kept>/<total experiments>. Cross-module calls: <before> -> <after>`.

## Keep/Discard Thresholds

```
Tests passed?
+-- NO -> Fix or revert immediately
+-- YES -> Metric improved?
    +-- YES (measurable improvement) -> KEEP
    +-- NO (neutral) -> KEEP only if it breaks a circular dep or reduces god module fan-in
    +-- WORSE -> DISCARD
```

## Strategy Rotation

If 3+ consecutive discards on the same type of move, switch strategy:
- Entity moves -> Circular dependency breaking -> God module decomposition -> Dead code removal

## Plateau Detection — Domain-Specific

3+ consecutive discards across all strategies = check if remaining issues are:
- External dependencies (can't restructure third-party code)
- Already well-organized modules
- Moves that would break public API

If top 3 candidates are all non-actionable, **stop and report to user** with the current state and what's left.

## Logging Format

Tab-separated `.codeflash/results.tsv`, 10 columns:

```
commit	target	metric_name	baseline	result	delta	tests_passed	tests_failed	status	description
```

- `target`: entity moved (e.g., `normalize_text: utils -> pipeline.text`)
- `metric_name`: what was measured (e.g., `cross_module_calls`, `import_time_s`, `circular_deps`)
- `baseline`: metric value before move
- `result`: metric value after move
- `delta`: change (e.g., `-3`, `-0.2s`)
- `status`: `keep`, `discard`, or `revert`
