Cross-Language Replication Check
Level 1 of the verification hierarchy: same specification → same estimate across languages. If two independent implementations disagree, at least one has a bug.
Output Path
Per rules/review-artefact-routing.md (auto-loads in research projects (path-scoped to paper-*/ and paper/)):
- Source slug:
cross-language-check
- Write reports to:
reviews/<scope>/cross-language-check/<YYYY-MM-DD-HHMM>.md inside the project, where <scope> is the paper slug (e.g., paper-jtp) for paper-level checks or _project for project-level checks. Path is relative to the research project root, not the Task-Management repo.
- Never at project root (
./CRITIC-REPORT.md-style filenames are forbidden — pre-rule layout).
- Idempotency: if today's file exists, append a same-day descriptor (
{date}-revision.md, {date}-r2.md, {date}-pre-submission.md) — never overwrite.
- Index update: if
reviews/INDEX.md exists, write a one-line entry under "Latest per source" pointing at the new file. Otherwise review-recap will rebuild the index next time it runs.
- Infrastructure repos (Task-Management, atlas-workspace, etc.): this section does not apply — the path-scoped rule won't load there.
When to Use
- Before submitting a paper with quantitative results
- When you suspect a subtle bug in estimation code
- After refactoring analysis scripts
- As a robustness check that reviewers increasingly expect
- When switching languages for a collaborator
When NOT to Use
- Pure simulation code with no statistical estimation →
computational-experiments
- The analysis is trivial (descriptive stats only) — not worth the overhead
- The source script uses language-specific packages with no equivalent (e.g., bespoke Bayesian MCMC)
Workflow
Phase 1: Parse Source Script
- Read the source script — identify language, packages, estimation calls
- Extract the specification:
- Data loading and cleaning steps
- Variable construction and transformations
- Estimation command(s) with exact formula/model specification
- Standard error clustering, weights, fixed effects
- Sample restrictions and filters
- Identify key outputs — point estimates, standard errors, p-values, confidence intervals, N
- Flag untranslatable elements — language-specific features that may need adaptation (e.g., R formula syntax, Stata factor variables, Python sklearn pipelines)
Phase 2: Choose Target Language
If --target is specified, use that. Otherwise:
| Source |
Default target |
Rationale |
| R |
Python |
Widest package overlap |
| Python |
R |
Strongest econometrics ecosystem |
| Stata |
R |
Both strong on panel/causal methods |
| Julia |
Python |
Closest syntax mapping |
Ask the user to confirm if the default seems wrong for the specific analysis.
Phase 3: Translate
Write the replication script to code/replication/ (or src/replication/):
code/replication/{original_name}_{target_lang}.{ext}
Translation rules:
- Mirror the specification exactly — same formula, same controls, same sample restrictions
- Use equivalent packages (see
shared/multi-language-conventions.md for mappings)
- Match output format — both scripts should produce a CSV with columns:
estimate, se, pvalue, ci_lower, ci_upper, n, model_label
- Document every adaptation — comment blocks explaining where the translation required judgment calls
- Use the same data file — both scripts read from the same cleaned dataset
Phase 4: Run Both & Compare
- Run the source script, capture output CSV
- Run the replication script, capture output CSV
- Comparison thresholds:
| Metric |
Threshold |
Verdict |
| Point estimates |
Differ by < 0.1% |
PASS |
| Point estimates |
Differ by 0.1–1% |
WARN — likely rounding or optimizer differences |
| Point estimates |
Differ by > 1% |
FAIL — investigate |
| Standard errors |
Differ by < 1% |
PASS |
| Standard errors |
Differ by 1–5% |
WARN — check SE type (robust, clustered, HC1 vs HC3) |
| Standard errors |
Differ by > 5% |
FAIL — likely different SE computation |
| Sample size N |
Must be identical |
FAIL if different — data filtering diverged |
- Generate comparison table saved to
code/replication/comparison.md:
| Model | Estimate (source) | Estimate (replica) | Diff (%) | SE (source) | SE (replica) | Diff (%) | N match | Verdict |
Phase 5: Diagnose Discrepancies
If any FAIL or WARN:
- Check N first — if sample sizes differ, the data pipeline diverged (most common source of bugs)
- Check SE type — HC1 vs HC3 vs clustered vs bootstrap defaults differ across languages
- Check optimizer — MLE/GLM may converge to different optima with different starting values
- Check missing value handling —
NA dropping rules differ (R drops per-variable, Stata drops listwise, Python varies)
- Check factor variable encoding — reference category defaults differ across languages
Report the root cause, not just the symptom.
Phase 6: Report
Save to code/replication/cross-language-report.md:
# Cross-Language Replication Report
**Source:** {source_path} ({source_language})
**Replica:** {replica_path} ({target_language})
**Date:** {date}
## Summary
- Models checked: N
- PASS: N | WARN: N | FAIL: N
## Comparison Table
[from Phase 4]
## Discrepancies
[from Phase 5, if any]
## Verdict
[REPLICATED | REPLICATED WITH NOTES | FAILED — action required]
Common Package Mappings
| Task |
R |
Python |
Stata |
Julia |
| OLS + FE |
fixest::feols |
linearmodels.PanelOLS |
reghdfe |
FixedEffectModels.reg |
| IV |
fixest::feols (iv syntax) |
linearmodels.IV2SLS |
ivregress 2sls |
FixedEffectModels.reg |
| DiD |
did::att_gt |
differences |
csdid |
— |
| Clustered SE |
vcov = ~cluster |
cov_type='clustered' |
vce(cluster var) |
Vcov.cluster(:var) |
| Logit/Probit |
glm(family=binomial) |
statsmodels.Logit |
logit |
GLM.jl |
Log to REVIEW-STATE.md (final step)
Write the comparison report to reviews/<scope>/cross-language-check/<YYYY-MM-DD-HHMM>.md (where <scope> is the paper slug for paper-level checks or _project for project-level checks; mkdir -p reviews/<scope>/cross-language-check/ first). Then append a row to the project's REVIEW-STATE.md:
bash <skills-root>/_shared/review-state-log.sh \
--check cross-language-check \
--paper "<paper-{venue} dir, or — for project-level cross-language checks>" \
--verdict "<MATCH|DIVERGENCE>" \
--score "<pass-count>/<total-comparisons>" \
--open-issues "<fail-count>/<total-comparisons>" \
--report "reviews/<scope>/cross-language-check/<YYYY-MM-DD-HHMM>.md" \
--notes "<one-line: e.g. 'all match within tol'; or 'IV SE differs in §4'>" \
[--trigger "pre-submission-report|review-cluster"]
- Verdict: MATCH if every comparison passes (within tolerance); DIVERGENCE if any FAIL.
- Score: PASS count / total comparisons.
- Open issues: FAIL count / total at run time.
- Trigger: pass orchestrator name only if invoked as a sub-agent. Otherwise omit.
Schema: the installed shared resource shared/review-state-schema.md.
Cross-References
| Resource |
When read |
shared/multi-language-conventions.md |
Phase 3 (language-specific style) |
multi-perspective/references/computational-many-analysts.md |
Context (verification hierarchy) |
the code-review agent |
Phase 6 (optionally review both scripts) |
replication-package skill |
After (include both scripts in replication materials) |
1---2name: cross-language-check3description: "Replicate a quantitative analysis in a second language (R↔Python↔Stata↔Julia) and compare outputs for implementation errors. Use when an existing empirical result needs independent cross-language verification. Not for reviewing one implementation in place; use $code-suite."4allowed-tools: Bash(uv*, Rscript*, stata*, julia*, diff*, mkdir*, ls*, cp*), Read, Write, Edit, Glob, Grep, Agent5argument-hint: "<script-path> [--target r|python|stata|julia]"6---78# Cross-Language Replication Check910> Level 1 of the verification hierarchy: same specification → same estimate across languages. If two independent implementations disagree, at least one has a bug.1112## Output Path1314Per `rules/review-artefact-routing.md` (auto-loads in research projects (path-scoped to `paper-*/` and `paper/`)):1516- **Source slug:** `cross-language-check`17- **Write reports to:** `reviews/<scope>/cross-language-check/<YYYY-MM-DD-HHMM>.md` inside the project, where `<scope>` is the paper slug (e.g., `paper-jtp`) for paper-level checks or `_project` for project-level checks. Path is relative to the research project root, not the Task-Management repo.18- **Never** at project root (`./CRITIC-REPORT.md`-style filenames are forbidden — pre-rule layout).19- **Idempotency:** if today's file exists, append a same-day descriptor (`{date}-revision.md`, `{date}-r2.md`, `{date}-pre-submission.md`) — never overwrite.20- **Index update:** if `reviews/INDEX.md` exists, write a one-line entry under "Latest per source" pointing at the new file. Otherwise `review-recap` will rebuild the index next time it runs.21- **Infrastructure repos** (Task-Management, atlas-workspace, etc.): this section does not apply — the path-scoped rule won't load there.222324## When to Use2526- Before submitting a paper with quantitative results27- When you suspect a subtle bug in estimation code28- After refactoring analysis scripts29- As a robustness check that reviewers increasingly expect30- When switching languages for a collaborator3132## When NOT to Use3334- Pure simulation code with no statistical estimation → `computational-experiments`35- The analysis is trivial (descriptive stats only) — not worth the overhead36- The source script uses language-specific packages with no equivalent (e.g., bespoke Bayesian MCMC)3738## Workflow3940### Phase 1: Parse Source Script41421. **Read the source script** — identify language, packages, estimation calls432. **Extract the specification:**44 - Data loading and cleaning steps45 - Variable construction and transformations46 - Estimation command(s) with exact formula/model specification47 - Standard error clustering, weights, fixed effects48 - Sample restrictions and filters493. **Identify key outputs** — point estimates, standard errors, p-values, confidence intervals, N504. **Flag untranslatable elements** — language-specific features that may need adaptation (e.g., R formula syntax, Stata factor variables, Python sklearn pipelines)5152### Phase 2: Choose Target Language5354If `--target` is specified, use that. Otherwise:5556| Source | Default target | Rationale |57|--------|---------------|-----------|58| R | Python | Widest package overlap |59| Python | R | Strongest econometrics ecosystem |60| Stata | R | Both strong on panel/causal methods |61| Julia | Python | Closest syntax mapping |6263Ask the user to confirm if the default seems wrong for the specific analysis.6465### Phase 3: Translate6667Write the replication script to `code/replication/` (or `src/replication/`):6869```70code/replication/{original_name}_{target_lang}.{ext}71```7273Translation rules:741. **Mirror the specification exactly** — same formula, same controls, same sample restrictions752. **Use equivalent packages** (see `shared/multi-language-conventions.md` for mappings)763. **Match output format** — both scripts should produce a CSV with columns: `estimate`, `se`, `pvalue`, `ci_lower`, `ci_upper`, `n`, `model_label`774. **Document every adaptation** — comment blocks explaining where the translation required judgment calls785. **Use the same data file** — both scripts read from the same cleaned dataset7980### Phase 4: Run Both & Compare81821. Run the source script, capture output CSV832. Run the replication script, capture output CSV843. **Comparison thresholds:**8586| Metric | Threshold | Verdict |87|--------|-----------|---------|88| Point estimates | Differ by < 0.1% | PASS |89| Point estimates | Differ by 0.1–1% | WARN — likely rounding or optimizer differences |90| Point estimates | Differ by > 1% | FAIL — investigate |91| Standard errors | Differ by < 1% | PASS |92| Standard errors | Differ by 1–5% | WARN — check SE type (robust, clustered, HC1 vs HC3) |93| Standard errors | Differ by > 5% | FAIL — likely different SE computation |94| Sample size N | Must be identical | FAIL if different — data filtering diverged |95964. **Generate comparison table** saved to `code/replication/comparison.md`:9798```markdown99| Model | Estimate (source) | Estimate (replica) | Diff (%) | SE (source) | SE (replica) | Diff (%) | N match | Verdict |100```101102### Phase 5: Diagnose Discrepancies103104If any FAIL or WARN:1051061. **Check N first** — if sample sizes differ, the data pipeline diverged (most common source of bugs)1072. **Check SE type** — HC1 vs HC3 vs clustered vs bootstrap defaults differ across languages1083. **Check optimizer** — MLE/GLM may converge to different optima with different starting values1094. **Check missing value handling** — `NA` dropping rules differ (R drops per-variable, Stata drops listwise, Python varies)1105. **Check factor variable encoding** — reference category defaults differ across languages111112Report the root cause, not just the symptom.113114### Phase 6: Report115116Save to `code/replication/cross-language-report.md`:117118```markdown119# Cross-Language Replication Report120121**Source:** {source_path} ({source_language})122**Replica:** {replica_path} ({target_language})123**Date:** {date}124125## Summary126- Models checked: N127- PASS: N | WARN: N | FAIL: N128129## Comparison Table130[from Phase 4]131132## Discrepancies133[from Phase 5, if any]134135## Verdict136[REPLICATED | REPLICATED WITH NOTES | FAILED — action required]137```138139## Common Package Mappings140141| Task | R | Python | Stata | Julia |142|------|---|--------|-------|-------|143| OLS + FE | `fixest::feols` | `linearmodels.PanelOLS` | `reghdfe` | `FixedEffectModels.reg` |144| IV | `fixest::feols` (iv syntax) | `linearmodels.IV2SLS` | `ivregress 2sls` | `FixedEffectModels.reg` |145| DiD | `did::att_gt` | `differences` | `csdid` | — |146| Clustered SE | `vcov = ~cluster` | `cov_type='clustered'` | `vce(cluster var)` | `Vcov.cluster(:var)` |147| Logit/Probit | `glm(family=binomial)` | `statsmodels.Logit` | `logit` | `GLM.jl` |148149## Log to REVIEW-STATE.md (final step)150151Write the comparison report to `reviews/<scope>/cross-language-check/<YYYY-MM-DD-HHMM>.md` (where `<scope>` is the paper slug for paper-level checks or `_project` for project-level checks; `mkdir -p reviews/<scope>/cross-language-check/` first). Then append a row to the project's `REVIEW-STATE.md`:152153```bash154bash <skills-root>/_shared/review-state-log.sh \155 --check cross-language-check \156 --paper "<paper-{venue} dir, or — for project-level cross-language checks>" \157 --verdict "<MATCH|DIVERGENCE>" \158 --score "<pass-count>/<total-comparisons>" \159 --open-issues "<fail-count>/<total-comparisons>" \160 --report "reviews/<scope>/cross-language-check/<YYYY-MM-DD-HHMM>.md" \161 --notes "<one-line: e.g. 'all match within tol'; or 'IV SE differs in §4'>" \162 [--trigger "pre-submission-report|review-cluster"]163```164165- Verdict: MATCH if every comparison passes (within tolerance); DIVERGENCE if any FAIL.166- Score: PASS count / total comparisons.167- Open issues: FAIL count / total at run time.168- Trigger: pass orchestrator name only if invoked as a sub-agent. Otherwise omit.169170Schema: the installed shared resource `shared/review-state-schema.md`.171172## Cross-References173174| Resource | When read |175|----------|-----------|176| `shared/multi-language-conventions.md` | Phase 3 (language-specific style) |177| `multi-perspective/references/computational-many-analysts.md` | Context (verification hierarchy) |178| the `code-review` agent | Phase 6 (optionally review both scripts) |179| `replication-package` skill | After (include both scripts in replication materials) |