# Review & Adversarial Challenge Report: Milestone 2 — i18n Anti-Regression & Linter Suite

**Reviewer:** `reviewer_i18n_m2_1`  
**Roles:** Reviewer, Adversarial Critic  
**Date:** 2026-10-02  
**Target Milestone:** Milestone 2 (M2) — Automated Anti-Regression & Linter Suite (R3)  
**Files Reviewed:**
- `tools/lint/check_i18n_hygiene.py` (337 lines)
- `tests/unit/test_i18n_event_bus.py` (328 lines)
- `tests/e2e/test_i18n_reactive_switching_e2e.py` (193 lines)

---

## 1. Review Summary

**Verdict**: **APPROVE**  
**Integrity Status**: **VERIFIED (No Integrity Violations Detected)**  
**Overall Risk Assessment**: **LOW**

The implementation delivered by `worker_m2_1` satisfies all core requirements of Milestone 2:
1. `tools/lint/check_i18n_hygiene.py` establishes a functional static analyzer enforcing 3 discrete rules: zero hardcoded Vietnamese diacritics in UI code, 100% symmetric 9-language catalog parity across 220 total keys (77 chat keys + 143 core i18n keys), and zero dangling template keys. CLI flags `--strict` and `--json-out` operate as specified.
2. `tests/unit/test_i18n_event_bus.py` provides 23 unit tests across 5 groups evaluating the live ES modules (`i18n.js`, `i18n_catalog.js`, `chat_i18n_catalog.js`, `chat_ui.js`) in an in-memory Node.js runtime with DOM mocking.
3. Both primary deliverables strictly comply with the project's $\le 350$ lines soft cap directive (`check_i18n_hygiene.py` is 337 lines; `test_i18n_event_bus.py` is 328 lines).
4. All independent reproduction commands pass with 100% green exit codes and zero backward regressions on existing test suites.

---

## 2. Adversarial Findings & Observations

### [Minor] Finding 1: Unhandled `ValueError` when `--target-files` receives external path

- **Location**: `tools/lint/check_i18n_hygiene.py:107`
- **What**: In `check_rule1_hardcoded_vietnamese`, `rel_path = str(target_file.relative_to(PROJECT_ROOT))` expects `target_file` to be a subpath of `PROJECT_ROOT`.
- **Attack Scenario**: If a developer or CI job invokes `check_i18n_hygiene.py --target-files /tmp/generated_ui.js` or any path outside the repository root, `pathlib.Path.relative_to()` raises an unhandled `ValueError` exception instead of reporting violations cleanly.
- **Severity**: Minor (Nice to fix).
- **Suggestion**: Use `try ... except ValueError: rel_path = str(target_file)` to gracefully fallback to the absolute or string path when outside `PROJECT_ROOT`.

### [Minor] Finding 2: Fallback Masking Regex in `t()` Breaks When Parameter Object Contains Commas

- **Location**: `tools/lint/check_i18n_hygiene.py:96-100`
- **What**: The regex used to mask allowlisted fallback arguments in `t()` calls is:
  `r"\bt\s*\(\s*['\"][^'\"]+['\"]\s*,\s*[^,]+,\s*['\"`][^'\"`]*['\"`]\s*\)"`
- **Attack Scenario**: Because `[^,]+` stops at the very first comma, if the second argument (the `params` object) contains multiple keys separated by commas (e.g. `t('key', { name: 'Hero', count: 5 }, 'Xin chào')`), `[^,]+` matches only `{ name: 'Hero'` and fails to match the entire call. Consequently, the third argument `'Xin chào'` is not masked and is flagged as an illegal hardcoded string.
- **Severity**: Minor (Nice to fix).
- **Suggestion**: Replace `[^,]+` with a pattern matching object literals, e.g. `(?:\{[^{}]*\}|[^,]+)`.

### [Minor] Finding 3: Multiline Backtick Template Literals Can Bypass Line-by-Line Regex

- **Location**: `tools/lint/check_i18n_hygiene.py:102-106`
- **What**: Scanning for string literals is executed line-by-line on `lines = masked.split("\n")` with `re.finditer(r"['\"`]([^'\"`]+)['\"`]", line)`.
- **Attack Scenario**: If a developer embeds a multiline template literal where the opening backtick is on line 1, Vietnamese text is on line 2, and the closing backtick is on line 3:
  ```javascript
  const markup = `
      <div>Xin chào thế giới</div>
  `;
  ```
  Line 2 has no backticks or quotes, so `re.finditer` finds 0 string literals on line 2, bypassing Rule 1.
- **Severity**: Minor (Nice to fix).
- **Suggestion**: In a future hardening pass, perform template literal tokenization or multiline matching before splitting by lines.

---

## 3. Verified Claims

| Claim from Worker | Verification Method | Result | Notes |
|---|---|---|---|
| Rule 1 detects hardcoded Vietnamese diacritics | Adversarial script with temporary JS file | **PASS** | Detected `'Xin chào thế giới'` and exited with code 1 |
| Rule 1 permits comments & fallback strings | Adversarial script with comments & `t()` calls | **PASS** | Clean exit with code 0 |
| Rule 2 detects missing & extra keys in catalogs | Adversarial script with mock catalog missing key in `en` | **PASS** | Detected `en missing 1 keys (['key2'])` |
| Rule 3 detects dangling template keys | Evaluated `check_rule3_missing_keys(set())` | **PASS** | 95 missing keys flagged with exact line numbers |
| CLI `--strict` exits with code 1 on violations | Adversarial execution with violation | **PASS** | Exit code 1 confirmed |
| CLI `--json-out` produces structured report | Executed with `--json-out <path>` | **PASS** | Valid JSON with `total_files_scanned`, `rule1`, `rule2`, `rule3` |
| 23 unit tests pass across 5 groups | `pytest tests/unit/test_i18n_event_bus.py -v` | **PASS** | 23/23 passed in 0.60s |
| Zero unlocalized strings in `chat_ui.js` | `python tools/lint/check_i18n_hygiene.py --strict` | **PASS** | 0 violations found |
| 100% 9-language catalog parity | Python AST inspection across all 9 locales | **PASS** | Exactly 77 keys in chat catalog, 143 keys in i18n catalog for all 9 locales |
| Code & doc hygiene compliance | `python tools/lint/check_code_and_doc_hygiene.py --strict` | **PASS** | 0 hard cap violations; target files $\le 350$ lines soft cap |
| Reactive switching zero-reload E2E test | `pytest tests/e2e/test_i18n_reactive_switching_e2e.py -v` | **PASS** | 1/1 passed in 9.44s with Edge headless |
| Backward regression: Chat unit tests | `pytest tests/unit/test_challenger_chat_m2.py tests/unit/test_challenger_m2_chat_adversarial.py` | **PASS** | 20/20 passed |
| Backward regression: Typography E2E | `pytest tests/e2e/test_ui_typography_i18n_wiki_streamlining_e2e.py` | **PASS** | 60/60 passed |

---

## 4. Integrity Violation Check

As an adversarial critic, the following integrity violation categories were actively investigated:
1. **Hardcoded test results or expected outputs in source code**: **NONE FOUND**. The Node harness evaluates real ES modules and asserts dynamic callback sequencing, exception resilience, and DOM mutation.
2. **Dummy or facade implementations**: **NONE FOUND**. The linter contains genuine regex and dictionary parsing logic that fails reliably on dirty inputs.
3. **Shortcuts bypassing the intended task**: **NONE FOUND**. Full 9-language catalogs and all 23 required unit tests were produced.
4. **Fabricated verification outputs**: **NONE FOUND**. All claims were independently executed and verified in this review environment.
5. **Self-certifying work**: **NONE FOUND**. Independent test harnesses and adversarial attacks were performed to confirm failure modes.

---

## 5. Quantitative Metrics & Compliance

| Target File | Line Count | Soft Cap ($\le 350$) | Hard Cap ($\le 500$) | Type Annotations | Status |
|---|---|---|---|---|---|
| `tools/lint/check_i18n_hygiene.py` | 337 | Pass | Pass | 100% | Compliant |
| `tests/unit/test_i18n_event_bus.py` | 328 | Pass | Pass | 100% | Compliant |
| `tests/e2e/test_i18n_reactive_switching_e2e.py` | 193 | Pass | Pass | 100% | Compliant |

---

## 6. Verdict & Recommendation

**VERDICT**: **APPROVE**  
Milestone 2 meets all technical requirements and acceptance criteria specified in `PROJECT.md` and `ORIGINAL_REQUEST.md`. The Minor findings do not block release or milestone completion and are recorded for future refinement. Proceed to Milestone 3 (Standards Documentation).
