# Sync Placeholder Validation Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Make `tt sync` reset translations with invalid placeholder expressions to `MISSING_TRANSLATION`, while sharing the same placeholder validation logic used by `tt translate`.

**Architecture:** Extract placeholder parsing and compatibility checks from `src/autolang/cli/translate.py` into a shared CLI module, then reuse that module from both `translate` and `sync`. Extend sync's reconciliation loop to downgrade invalid existing translations to `MISSING_TRANSLATION` and report a dedicated reset count.

**Tech Stack:** Python 3.12, `pytest`, existing CLI modules under `src/autolang/cli/`

---

### Task 1: Extract shared placeholder validation module

**Files:**
- Create: `src/autolang/cli/placeholders.py`
- Modify: `src/autolang/cli/translate.py`
- Test: `tests/test_cli.py`

**Step 1: Write the failing test**

Add a focused test in `tests/test_cli.py` that exercises the shared validator entry point after extraction. Use two assertions:

```python
from autolang.cli.placeholders import validate_translated_text


def test_shared_validate_translated_text_rejects_incompatible_wrapper():
    with pytest.raises(RuntimeError, match="placeholder"):
        validate_translated_text("Price: {price}", "价格：{fmt.date(price)}")


def test_shared_validate_translated_text_allows_fmt_currency_wrapper():
    validate_translated_text(
        "Price: {price}",
        '价格：{fmt.currency(price, "USD")}',
    )
```

**Step 2: Run test to verify it fails**

Run: `uv run pytest tests/test_cli.py -q -k "shared_validate_translated_text"`

Expected: FAIL because `autolang.cli.placeholders` does not exist yet.

**Step 3: Write minimal implementation**

Create `src/autolang/cli/placeholders.py` and move only the placeholder-specific items from `src/autolang/cli/translate.py`:

- `PlaceholderSpec`
- `validate_translated_text`
- `find_matching_placeholder_index`
- `placeholder_matches`
- `build_placeholder_spec`
- `is_allowed_wrapper_for_source`
- all helper functions and constants they depend on

Update `src/autolang/cli/translate.py` to import and use the shared functions without changing translate behavior.

**Step 4: Run test to verify it passes**

Run: `uv run pytest tests/test_cli.py -q -k "shared_validate_translated_text or validate_translated_text_allows_fmt_wrappers or tt_translate_rejects_invalid_placeholders"`

Expected: PASS

**Step 5: Commit**

```bash
git add src/autolang/cli/placeholders.py src/autolang/cli/translate.py tests/test_cli.py
git commit -m "Extract shared placeholder validation"
```

### Task 2: Make sync reset invalid placeholder translations

**Files:**
- Modify: `src/autolang/cli/sync.py`
- Test: `tests/test_cli.py`

**Step 1: Write the failing test**

Add a CLI regression test that sets up:

- source template `Price: {price}`
- an existing locale translation such as `Precio: {fmt.date(price)}`
- a valid source cue generated by sync

Assert that after `tt sync`:

- the locale entry becomes `MISSING_TRANSLATION`
- the summary output includes `reset 1 invalid placeholder translation(s)`
- a valid sibling translation remains unchanged

Use `capsys` to capture the sync output.

**Step 2: Run test to verify it fails**

Run: `uv run pytest tests/test_cli.py -q -k "tt_sync_resets_invalid_placeholder_translation"`

Expected: FAIL because sync currently preserves the invalid translation and does not report reset counts.

**Step 3: Write minimal implementation**

In `src/autolang/cli/sync.py`:

- import `validate_translated_text` from `autolang.cli.placeholders`
- add an `invalid_placeholder_resets` counter
- when an existing translation is present and not equal to `MISSING_TRANSLATION`, validate it against the source template
- on `RuntimeError`, replace the value with `MISSING_TRANSLATION` and increment the reset counter
- update the printed summary string to include the reset count

Do not make invalid placeholders fatal for sync.

**Step 4: Run test to verify it passes**

Run: `uv run pytest tests/test_cli.py -q -k "tt_sync_resets_invalid_placeholder_translation or tt_sync_updates_all_locale_files_and_cues"`

Expected: PASS

**Step 5: Commit**

```bash
git add src/autolang/cli/sync.py tests/test_cli.py
git commit -m "Reset invalid placeholder translations during sync"
```

### Task 3: Verify no behavior drift in translate

**Files:**
- Modify: `tests/test_cli.py` if needed
- Verify: `src/autolang/cli/translate.py`

**Step 1: Write the failing test**

If the moved validator changed import paths or helper exposure, add one more targeted test that imports from the new shared module and confirms translate still rejects a renamed placeholder:

```python
def test_shared_validate_translated_text_rejects_renamed_placeholder():
    with pytest.raises(RuntimeError, match="placeholder"):
        validate_translated_text("Hello {name}", "Hola {other}")
```

Only add this test if the existing translate-focused regression coverage is not enough after extraction.

**Step 2: Run test to verify it fails**

Run: `uv run pytest tests/test_cli.py -q -k "renamed_placeholder"`

Expected: FAIL only if the extra test was added.

**Step 3: Write minimal implementation**

Keep the shared module and translate imports aligned until both the new shared-module tests and the existing translate placeholder tests pass without duplicating logic.

**Step 4: Run test to verify it passes**

Run: `uv run pytest tests/test_cli.py -q -k "validate_translated_text or invalid_placeholder or tt_sync_resets_invalid_placeholder_translation"`

Expected: PASS

**Step 5: Commit**

```bash
git add src/autolang/cli/placeholders.py src/autolang/cli/translate.py tests/test_cli.py
git commit -m "Cover shared placeholder validation regressions"
```

### Task 4: Run full verification

**Files:**
- Verify: `tests/test_cli.py`
- Verify: `tests/test_static_analysis.py`
- Verify: `src/autolang/cli/placeholders.py`
- Verify: `src/autolang/cli/sync.py`
- Verify: `src/autolang/cli/translate.py`

**Step 1: Run the targeted CLI suite**

Run: `uv run pytest tests/test_cli.py -q`

Expected: PASS

**Step 2: Run the full test suite**

Run: `uv run pytest -q`

Expected: PASS

**Step 3: Run style and type verification if the project uses them in this area**

Run: `uv run ruff`

Expected: PASS

Run: `uv run basedpyright --pythonpath /workspace/autolang/.venv-docker/bin/python`

Expected: PASS

**Step 4: Commit verification-ready state**

```bash
git add src/autolang/cli/placeholders.py src/autolang/cli/sync.py src/autolang/cli/translate.py tests/test_cli.py
git commit -m "Finalize sync placeholder validation"
```
