---
wave: 1
depends_on: []
files_modified:
  - tests/eval_gsd_lite/README.md
  - tests/eval_gsd_lite/data/input.csv
  - tests/eval_gsd_lite/src/__init__.py
  - tests/eval_gsd_lite/src/pipeline.py
  - tests/eval_gsd_lite/src/etl/__init__.py
  - tests/eval_gsd_lite/src/etl/extract.py
  - tests/eval_gsd_lite/src/etl/transform.py
  - tests/eval_gsd_lite/src/etl/load.py
  - tests/eval_gsd_lite/tests/__init__.py
  - tests/eval_gsd_lite/tests/test_transform.py
autonomous: true
---

# Plan 01.5-01: Simulation Sandbox Setup

**Goal**: Create a dependency-free, standard-library Python ETL pipeline in `tests/eval_gsd_lite` to serve as the "Subject Under Test" for GSD-lite evaluation.

## Tasks

### 1. Create Simulation Structure
<task>
<description>Create the directory structure for the simulated environment.</description>
<command>mkdir -p tests/eval_gsd_lite/data tests/eval_gsd_lite/src/etl tests/eval_gsd_lite/tests</command>
<verification>ls -R tests/eval_gsd_lite</verification>
</task>

### 2. Create Data Source
<task>
<description>Create a simple CSV data source with some currency fields for transformation.</description>
<file>tests/eval_gsd_lite/data/input.csv</file>
<content>
id,date,description,amount,category
1,2026-01-01,Server Cost,$1200.50,Infrastructure
2,2026-01-02,Consulting,-$500.00,Income
3,2026-01-03,Software Lic,$99.99,Tools
4,2026-01-04,Coffee,$4.50,Misc
</content>
<verification>cat tests/eval_gsd_lite/data/input.csv</verification>
</task>

### 3. Create Source Modules (ETL)
<task>
<description>Create the `extract.py` module to read CSV data.</description>
<file>tests/eval_gsd_lite/src/etl/extract.py</file>
<content>
import csv

def read_csv(file_path):
    """
    Reads a CSV file and returns a list of dictionaries.
    """
    data = []
    try:
        with open(file_path, mode='r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for row in reader:
                data.append(row)
    except FileNotFoundError:
        print(f"Error: File not found at {file_path}")
        return []
    return data
</content>
</task>

<task>
<description>Create the `transform.py` module with simple logic (and potential for bugs/expansion).</description>
<file>tests/eval_gsd_lite/src/etl/transform.py</file>
<content>
def clean_currency(value_str):
    """
    Converts currency string '$1,200.50' to float 1200.50.
    Handles negative values '-$500.00'.
    """
    if not value_str:
        return 0.0
    
    clean_str = value_str.replace('$', '').replace(',', '')
    try:
        return float(clean_str)
    except ValueError:
        return 0.0

def process_transactions(raw_data):
    """
    Transforms raw CSV data into clean records.
    """
    processed = []
    for row in raw_data:
        record = {
            'id': int(row['id']),
            'date': row['date'],
            'description': row['description'].title(),
            'amount': clean_currency(row['amount']),
            'category': row['category']
        }
        processed.append(record)
    return processed
</content>
</task>

<task>
<description>Create the `load.py` module to write to SQLite.</description>
<file>tests/eval_gsd_lite/src/etl/load.py</file>
<content>
import sqlite3

def init_db(db_path):
    """
    Initializes the SQLite database with the transactions table.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS transactions (
            id INTEGER PRIMARY KEY,
            date TEXT,
            description TEXT,
            amount REAL,
            category TEXT
        )
    ''')
    conn.commit()
    conn.close()

def save_to_db(data, db_path):
    """
    Saves processed data to SQLite.
    """
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    
    # Clear existing data for idempotency in this simple simulation
    cursor.execute('DELETE FROM transactions')
    
    for row in data:
        cursor.execute('''
            INSERT INTO transactions (id, date, description, amount, category)
            VALUES (?, ?, ?, ?, ?)
        ''', (row['id'], row['date'], row['description'], row['amount'], row['category']))
    
    conn.commit()
    print(f"Loaded {len(data)} records into {db_path}")
    conn.close()
</content>
</task>

<task>
<description>Create empty __init__.py files to make it a package.</description>
<command>touch tests/eval_gsd_lite/src/__init__.py tests/eval_gsd_lite/src/etl/__init__.py tests/eval_gsd_lite/tests/__init__.py</command>
<verification>ls tests/eval_gsd_lite/src/etl/__init__.py</verification>
</task>

### 4. Create Pipeline Orchestrator
<task>
<description>Create the `pipeline.py` script to run the full ETL process.</description>
<file>tests/eval_gsd_lite/src/pipeline.py</file>
<content>
import sys
import os

# Ensure we can import from src
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.etl import extract, transform, load

def main():
    base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    input_file = os.path.join(base_dir, 'data', 'input.csv')
    db_file = os.path.join(base_dir, 'transactions.db')
    
    print("Starting ETL Pipeline...")
    
    # Extract
    print(f"Reading from {input_file}...")
    raw_data = extract.read_csv(input_file)
    if not raw_data:
        print("No data found. Exiting.")
        return

    # Transform
    print(f"Transforming {len(raw_data)} records...")
    clean_data = transform.process_transactions(raw_data)
    
    # Load
    print(f"Loading to {db_file}...")
    load.init_db(db_file)
    load.save_to_db(clean_data, db_file)
    
    print("Pipeline Complete.")

if __name__ == '__main__':
    main()
</content>
<verification>python3 tests/eval_gsd_lite/src/pipeline.py</verification>
</task>

### 5. Create Unit Test
<task>
<description>Create a basic unit test for the transformation logic.</description>
<file>tests/eval_gsd_lite/tests/test_transform.py</file>
<content>
import unittest
import sys
import os

# Ensure we can import from src
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.etl.transform import clean_currency

class TestTransform(unittest.TestCase):
    def test_clean_currency_standard(self):
        self.assertEqual(clean_currency('$1,200.50'), 1200.50)
        
    def test_clean_currency_negative(self):
        self.assertEqual(clean_currency('-$500.00'), -500.00)
        
    def test_clean_currency_empty(self):
        self.assertEqual(clean_currency(''), 0.0)
        
    def test_clean_currency_no_symbol(self):
        self.assertEqual(clean_currency('100.00'), 100.00)

if __name__ == '__main__':
    unittest.main()
</content>
<verification>python3 tests/eval_gsd_lite/tests/test_transform.py</verification>
</task>

### 6. Create Context README
<task>
<description>Create the README for the simulation environment to orient the agent.</description>
<file>tests/eval_gsd_lite/README.md</file>
<content>
# Simulated Data Pipeline for Evaluation

This is a **simulated** data engineering project used to evaluate GSD-lite agents.
It is a simple ETL pipeline that reads CSV, cleans data, and loads to SQLite.

## Structure
- `data/`: Input files
- `src/etl/`: Logic for Extract, Transform, Load
- `src/pipeline.py`: Main entry point
- `tests/`: Unit tests

## Usage
Run the pipeline:
```bash
python3 src/pipeline.py
```

Run tests:
```bash
python3 -m unittest discover tests
```

## Constraints
- Use **Standard Library only** (no pandas, no numpy, no external deps).
- Keep logic simple but correct.
- Verify changes with tests.
</content>
<verification>cat tests/eval_gsd_lite/README.md</verification>
</task>

## Verification
- [ ] Pipeline runs successfully: `python3 tests/eval_gsd_lite/src/pipeline.py`
- [ ] Database is created: `ls tests/eval_gsd_lite/transactions.db`
- [ ] Tests pass: `python3 tests/eval_gsd_lite/tests/test_transform.py`

## Must Haves
- Zero external dependencies (standard library only)
- Working end-to-end pipeline (CSV -> SQLite)
- Basic test coverage
