{"id":"466e97ce-c128-45f0-82a8-f49b58824138","entityType":"agent","slug":"clawhub-suifei-lang-migration","name":"编程语言迁移","canonicalUrl":"https://www.xpersona.co/agent/clawhub-suifei-lang-migration","canonicalPath":"/agent/clawhub-suifei-lang-migration","generatedAt":"2026-10-11T16:01:20.177Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T13:08:01.714Z","emptyReason":null},"description":"AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua... Skill: 编程语言迁移 Owner: suifei Summary: AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua... Tags: latest:1.3.1 Version history: v1.3.1 | 2026-05-18T02:32:46.759Z | user v1.3 — Bug Triage Protocol + Real-World Validation Every P5 test failure now goes through a mandatory 3-step triage before any fix is attempted.","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17cwv8cyfy64wkqte2x67hesn86s5rq:lang-migration","sourceUrl":"https://clawhub.ai/suifei/lang-migration","homepage":"https://clawhub.ai/suifei/skills/lang-migration","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/suifei/lang-migration","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/suifei/skills/lang-migration","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:08:01.714Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:08:01.714Z","emptyReason":null},"stars":null,"forks":null,"downloads":1060,"packageName":null,"latestVersion":"1.3.1","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:08:01.642Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T13:08:01.714Z","lastCrawledAt":"2026-10-11T13:08:01.642Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T13:08:01.642Z","lastVerifiedAt":null,"highlights":[{"version":"1.3.1","createdAt":"2026-05-18T02:32:46.759Z","changelog":"v1.3 — Bug Triage Protocol + Real-World Validation Every P5 test failure now goes through a mandatory 3-step triage before any fix is attempted. Only 1 of 5 verdicts leads to modifying the translated function. Four new root cause categories. Validated against a real Python→Go migration (GenericAgent → go-GenericAgent). Learn more → https://github.com/suifei/lang-migration-skill#bug-triage-protocol-classify-before-fix","fileCount":37,"zipByteSize":154634},{"version":"1.2.1","createdAt":"2026-05-15T15:35:23.365Z","changelog":"lang-migration 1.2.1 - Added detailed author attribution and contact section to SKILL.md. - Introduced stricter evidence requirements: mandatory TDD Retrospective protocol at every fix, checklist output, and full suite reruns. - Phase Gate Review (PGR) mechanism integrated: each phase now requires a completed audit report before being marked DONE; added session-start PGR check. - New reference files supporting audit and retrospective protocols: phase-0-bootstrap.md, phase-gate-review.md, tdd-retrospective.md. - Added templates/retrospective-checklist.yaml for structured incident tracking. - Added multilingual documentation (README.zh-CN.md). - Expanded documentation of process, anti-cheating policies, and progress-reporting protocols.","fileCount":36,"zipByteSize":135675},{"version":"1.0.0","createdAt":"2026-05-15T04:24:13.418Z","changelog":"lang-migration 1.0.0 - Initial release: systematic multi-phase workflow for AI-driven, full-project language migration. - Enforces 1:1 structural equivalence, full asset coverage, persistent YAML state, and strict no-mock verification. - Introduces anti-cheating protocols: evidence required at every step, with robust task verification and blocking if human input is needed. - Supports multiple environments (Claude/OpenCode/Editor) with session protocols and detailed pipeline from asset scan to verification. - Includes blocking and gap report protocols for transparent and auditable migration progress.","fileCount":30,"zipByteSize":90821}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cwv8cyfy64wkqte2x67hesn86s5rq:lang-migration","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T16:01:20.170Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-suifei-lang-migration/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T13:08:01.714Z","emptyReason":null},"readme":"Skill: 编程语言迁移\n\nOwner: suifei\n\nSummary: AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua...\n\nTags: latest:1.3.1\n\nVersion history:\n\nv1.3.1 | 2026-05-18T02:32:46.759Z | user\n\nv1.3 — Bug Triage Protocol + Real-World Validation Every P5 test failure now goes through a mandatory 3-step triage before any fix is attempted. Only 1 of 5 verdicts leads to modifying the translated function. Four new root cause categories. Validated against a real Python→Go migration (GenericAgent → go-GenericAgent). \nLearn more → https://github.com/suifei/lang-migration-skill#bug-triage-protocol-classify-before-fix\n\nv1.2.1 | 2026-05-15T15:35:23.365Z | user\n\nlang-migration 1.2.1\n\n- Added detailed author attribution and contact section to SKILL.md.\n- Introduced stricter evidence requirements: mandatory TDD Retrospective protocol at every fix, checklist output, and full suite reruns.\n- Phase Gate Review (PGR) mechanism integrated: each phase now requires a completed audit report before being marked DONE; added session-start PGR check.\n- New reference files supporting audit and retrospective protocols: phase-0-bootstrap.md, phase-gate-review.md, tdd-retrospective.md.\n- Added templates/retrospective-checklist.yaml for structured incident tracking.\n- Added multilingual documentation (README.zh-CN.md).\n- Expanded documentation of process, anti-cheating policies, and progress-reporting protocols.\n\nv1.0.0 | 2026-05-15T04:24:13.418Z | user\n\nlang-migration 1.0.0\n\n- Initial release: systematic multi-phase workflow for AI-driven, full-project language migration.\n- Enforces 1:1 structural equivalence, full asset coverage, persistent YAML state, and strict no-mock verification.\n- Introduces anti-cheating protocols: evidence required at every step, with robust task verification and blocking if human input is needed.\n- Supports multiple environments (Claude/OpenCode/Editor) with session protocols and detailed pipeline from asset scan to verification.\n- Includes blocking and gap report protocols for transparent and auditable migration progress.\n\nArchive index:\n\nArchive v1.3.1: 37 files, 154634 bytes\n\nFiles: README.md (38606b), README.zh-CN.md (36248b), references/lang-pairs/bun-python.md (8589b), references/lang-pairs/c-python.md (10351b), references/lang-pairs/cpp-python.md (9906b), references/lang-pairs/go-python.md (9013b), references/lang-pairs/python-bun.md (6887b), references/lang-pairs/python-c.md (5313b), references/lang-pairs/python-cpp.md (6420b), references/lang-pairs/python-go.md (12303b), references/lang-pairs/python-rust.md (10798b), references/lang-pairs/python-typescript.md (7993b), references/lang-pairs/python-zig.md (6917b), references/lang-pairs/rust-python.md (10509b), references/lang-pairs/TEMPLATE.md (2267b), references/lang-pairs/typescript-python.md (9786b), references/lang-pairs/zig-python.md (9690b), references/phase-0-bootstrap.md (4489b), references/phase-1-asset-scan.md (5448b), references/phase-2-ecosystem-map.md (8797b), references/phase-3-ipo-analysis.md (15303b), references/phase-4-translation.md (8936b), references/phase-5-verification.md (16210b), references/phase-6-gap-report.md (7933b), references/phase-gate-review.md (22116b), references/schemas.md (7563b), references/tdd-retrospective.md (13980b), scripts/gap_report.py (22904b), scripts/scan_assets.py (8891b), skill-card.md (2722b), SKILL.md (19991b), templates/asset-inventory.yaml (1660b), templates/ecosystem-map.yaml (2563b), templates/ipo-registry.yaml (2679b), templates/migration-state.yaml (2653b), templates/retrospective-checklist.yaml (2221b), _meta.json (133b)\n\nFile v1.3.1:SKILL.md\n\n---\r\nname: lang-migration\r\ndescription: >\r\n  AI-driven full-project language migration skill. Use this skill whenever the user wants to\r\n  port, translate, or rewrite a codebase from one programming language to another — including\r\n  Python→Rust, Python→Go, Python→C, Python→C++, Python→Zig, Python→Bun/TS, or any other pair.\r\n  Also trigger when user mentions \"精确复刻\", \"语言迁移\", \"port project\", \"translate codebase\",\r\n  \"1:1 rewrite\", or \"language conversion\". This skill enforces structural equivalence first,\r\n  full asset coverage (no file skipped), persistent YAML state across sessions, and a strict\r\n  no-mock verification policy with human-gated blocking.\r\nlicense: MIT\r\n---\r\n\r\n## Author & Attribution\r\n\r\n**Original Author**: flynn  \r\n**Contact**: https://github.com/suifei/lang-migration-skill  \r\n**Role**: Architect, Developer, Documenter  \r\n**Expertise**: Software engineering, programming languages, AI workflow design  \r\n**Contributions**: Designed the multi-phase pipeline, defined YAML schemas, implemented blocking protocol, and wrote comprehensive documentation for the skill.\r\n\r\n---\r\n\r\n# Language Migration Skill\r\n\r\nA systematic, multi-session, AI-executable workflow for migrating any open-source project\r\nfrom one programming language to another with 1:1 structural fidelity.\r\n\r\n## Core Principles\r\n\r\n1. **No file is useless** — every file in the source project is analyzed and assigned a migration strategy\r\n2. **Structural equivalence first** — algorithm steps, loop structure, and control flow must mirror the source; behavioral equivalence is only used when the ecosystem gap makes structural impossible\r\n3. **No mock, ever** — tests must use real implementations and real test data\r\n4. **Block, don't skip** — when a decision cannot be made autonomously, stop and ask the human; never label-and-continue\r\n5. **State persists across sessions** — all state lives in YAML files in the workspace, readable by any AI agent or human\r\n6. **Evidence before completion** — every unit of work must produce verifiable evidence of execution before being marked done\r\n\r\n---\r\n\r\n## Global Anti-Cheating Policy\r\n\r\nThis skill operates under the assumption that an AI agent may attempt to mark tasks complete\r\nwithout actually doing the work. Every phase has mechanisms to detect and prevent this.\r\n\r\n**The Three Forms of AI Task Fraud (all prohibited):**\r\n\r\n| Form | Example | Detection |\r\n|---|---|---|\r\n| Batch fabrication | Scripts generate IPO content without reading source | source_lines field will be wrong/empty |\r\n| Silent bulk-confirm | NEEDS_REVIEW → CONFIRMED without evidence | confirmation_evidence field empty |\r\n| Premature phase advance | Marking P3 DONE when entries have empty fields | Self-verification checks fail |\r\n\r\n**Evidence Requirements by Phase:**\r\n\r\n| Phase | Required Evidence |\r\n|---|---|\r\n| P2 | `confirmation_evidence` block per CONFIRMED entry |\r\n| P3 | `READ_EVIDENCE` + `BEHAVIOR_PROOF` per function; `source_lines` in every step; `source_line` on every magic number |\r\n| P4 | Compilation succeeds; IPO entry updated with `target_lines`; **every fix triggers TDD Retrospective** |\r\n| P5 | **TEST OUTPUT EVIDENCE** (actual runner output, not just \"tests pass\"); **every fix triggers TDD Retrospective**; **full suite re-run after each fix**; **Checklist Summary at phase end** |\r\n| Fix | `retrospective-checklist.yaml` entry with RCA → scope_scan_query (defined BEFORE scan) → scope scan results → consistent fix (see `tdd-retrospective.md`) |\r\n| **PGR** | **Full audit report output in response** listing every item checked; each FINDING citing exact artifact (file path, field, value); each FIXED citing same artifact after change; `findings_count: 0` proven by enumerated item list; `phase_gates.PGR_N.passed_at` timestamp set only after zero-findings pass |\r\n\r\n**TDD Retrospective Integration**\r\n\r\nThe **Retrospective Protocol** is mandatory at every fix point:\r\n- **Trigger**: Compilation error, vet failure, structural deviation, test failure\r\n- **Steps**: RCA (root cause analysis) → Checklist rule → Scope scan → Consistent fix\r\n- **Output**: Entry in `retrospective-checklist.yaml` with root cause category and generalized rule\r\n- **Scope scan constraint**: `scope_scan_query` MUST be written before scanning (prevents post-hoc bias)\r\n- **Impact**: After each fix, full test suite is re-run; new failures each trigger independent retrospectives\r\n\r\nSee [Retrospective Protocol](#retrospective-protocol) below and `references/tdd-retrospective.md`.\r\n\r\n**Self-Verification is not optional.** Each phase that has a Self-Verification Protocol\r\nmust run it and output the report before advancing. The report must appear in the AI's\r\nresponse — not silently written to a file.\r\n\r\n**The AI must never say \"done\" without evidence.** \"I have completed X\" is not a valid\r\ncompletion statement without accompanying evidence artifacts.\r\n\r\n---\r\n\r\n## Environment Detection\r\n\r\nThis skill runs in Claude Code, Cursor, OpenCode, or GitHub Copilot. At session start, detect the environment:\r\n\r\n```\r\nIF bash tool is available AND can write files → full_mode (Claude Code / OpenCode)\r\nIF only file editing available → editor_mode (Cursor / Copilot)\r\n```\r\n\r\nIn **full_mode**: use bash scripts for scanning, run `scan_assets.py` directly.\r\nIn **editor_mode**: generate file lists manually by reading directory structure; instruct user to run scripts manually if needed.\r\n\r\n**Workspace location**: Always at the project root, in a directory called `migration_workspace/`.\r\n\r\n```\r\n<project-root>/\r\n├── <source_code>/          ← original project (read-only, never modify)\r\n├── <target_code>/          ← translated output (created by this skill)\r\n└── migration_workspace/\r\n    ├── migration-state.yaml      ← SESSION ENTRY POINT: read this first every session\r\n    ├── asset-inventory.yaml\r\n    ├── ecosystem-map.yaml\r\n    └── ipo-registry.yaml\r\n```\r\n\r\n---\r\n\r\n## Session Start Protocol\r\n\r\n**Every time you start a new session, do this first — no exceptions:**\r\n\r\n1. Check if `migration_workspace/migration-state.yaml` exists\r\n   - YES → read it, understand current phase and `current_task`, resume from there\r\n   - NO → this is a new project, run **P0 Bootstrap**\r\n\r\n2. Read `current_task` block. If `status: BLOCKED`, present the block to the user immediately and wait for their input before doing anything else.\r\n\r\n2b. **Check phase gate consistency**: For every phase marked `DONE` in the `phases` block, verify the corresponding `phase_gates.PGR_N.passed_at` is non-empty. If a phase is `DONE` but `passed_at` is empty, the PGR was not completed. Re-run PGR-N for that phase before advancing to the next phase. Load `references/phase-gate-review.md` for the audit criteria.\r\n\r\n3. **Check if the user's opening message is a status/gap question:**\r\n   - Triggers: \"还差什么\", \"进度怎样\", \"gap report\", \"show status\", \"还有哪些\", \"差多少\", \"完成了多少\"\r\n   - If YES → run P6 Gap Report immediately, output the summary to the user, then ask how to proceed\r\n   - If NO → continue to step 4\r\n\r\n4. Load the language pair module: `references/lang-pairs/<source>-<target>.md`\r\n\r\n5. Proceed with the current phase.\r\n\r\n---\r\n\r\n## Five-Phase Pipeline\r\n\r\n```\r\nP0 Bootstrap          → Initialize workspace, detect language pair, load lang-pair module\r\nP1 Asset Scan         → Inventory every file, assign migration strategy\r\nP2 Ecosystem Mapping  → Map all imports/types/stdlib to target equivalents, identify gaps\r\nP3 IPO Analysis       → Document every function: Inputs, Process (incl. magic numbers), Outputs\r\nP4 Translation        → Translate function by function using IPO registry + ecosystem map\r\nP5 Verification       → Structural review + real-data behavioral tests (no mock)\r\nP6 Gap Report         → Multi-dimensional completeness audit (invoke at any time)\r\n```\r\n\r\nEach phase has a detailed reference file. Load it when entering that phase:\r\n\r\n| Phase | Reference File |\r\n|-------|----------------|\r\n| P0    | `references/phase-0-bootstrap.md` |\r\n| P1    | `references/phase-1-asset-scan.md` |\r\n| P2    | `references/phase-2-ecosystem-map.md` |\r\n| P3    | `references/phase-3-ipo-analysis.md` |\r\n| P4    | `references/phase-4-translation.md` |\r\n| P5    | `references/phase-5-verification.md` |\r\n| P6    | `references/phase-6-gap-report.md` |\r\n| **Fix** | **`references/tdd-retrospective.md` ← mandatory on every fix in P4/P5** |\r\n| **PGR** | **`references/phase-gate-review.md` ← mandatory between every phase transition** |\r\n\r\n---\r\n\r\n## Phase Gate Review Protocol (PGR)\r\n\r\n**A phase is not complete when the AI says it is complete. A phase is complete when PGR-N passes with zero findings.**\r\n\r\nAfter every phase finishes, the AI enters an autonomous self-auditing loop before advancing to the next phase. This loop requires no human involvement.\r\n\r\n### Updated Pipeline with PGR Gates\r\n\r\n```\r\nP0 Bootstrap → [PGR-0] → P1 Asset Scan → [PGR-1] → P2 Ecosystem Map → [PGR-2]\r\n    → P3 IPO Analysis → [PGR-3] → P4 Translation → [PGR-4] → P5 Verification → [PGR-5] → DONE\r\n```\r\n\r\n### How PGR Works\r\n\r\nEach PGR-N runs an **enumerate → audit → fix → re-audit** loop:\r\n\r\n1. **Enumerate** — list every expected output of the completed phase\r\n2. **Audit** — check each output against phase-specific criteria; record any FINDING with artifact evidence\r\n3. **Tally** — if `findings_count == 0`, advance; if `findings_count > 0`, proceed to Fix\r\n4. **Fix** — fix each FINDING autonomously; record artifact evidence of each fix\r\n5. **Re-audit** — return to Step 1 (full re-enumeration required after every fix pass)\r\n6. **Pass** — when zero findings: set `phase_gates.PGR_N.status: PASSED`; only then set `phases.PN_xxx: DONE`\r\n\r\n### Core Rule\r\n\r\nThe phase status `DONE` in `migration-state.yaml` must NEVER be set directly at the end of a phase.\r\nIt is only set by PGR-N as the final action of a passed audit. Any session that finds a phase marked\r\n`DONE` without a corresponding `phase_gates.PGR_N.passed_at` timestamp must re-run PGR-N before\r\nadvancing (see Session Start Protocol).\r\n\r\n### PGR Reference\r\n\r\n| Gate | Triggered After | Reference |\r\n|------|----------------|-----------|\r\n| PGR-0 | P0 Bootstrap | `references/phase-gate-review.md#pgr-0` |\r\n| PGR-1 | P1 Asset Scan | `references/phase-gate-review.md#pgr-1` |\r\n| PGR-2 | P2 Ecosystem Map | `references/phase-gate-review.md#pgr-2` |\r\n| PGR-3 | P3 IPO Analysis | `references/phase-gate-review.md#pgr-3` |\r\n| PGR-4 | P4 Translation | `references/phase-gate-review.md#pgr-4` |\r\n| PGR-5 | P5 Verification | `references/phase-gate-review.md#pgr-5` |\r\n\r\nFor the full protocol including per-phase audit criteria, finding formats, and anti-cheating rules,\r\nsee: `references/phase-gate-review.md`\r\n\r\n---\r\n\r\n## P0 Bootstrap (New Project)\r\n\r\nWhen `migration-state.yaml` does not exist:\r\n\r\n1. Ask the user:\r\n   - Source language and directory path\r\n   - Target language\r\n   - Any known constraints or priorities\r\n\r\n2. Determine language pair key (e.g., `python-rust`). If the file `references/lang-pairs/<pair>.md` does not exist, load `references/lang-pairs/TEMPLATE.md` and tell the user this pair needs a new module — offer to draft one before continuing.\r\n\r\n3. Copy all five template files from `templates/` into `migration_workspace/`:\r\n   - `migration-state.yaml` → fill in meta block\r\n   - `asset-inventory.yaml` → empty, ready for P1\r\n   - `ecosystem-map.yaml` → empty, ready for P2\r\n   - `ipo-registry.yaml` → empty, ready for P3\r\n   - `retrospective-checklist.yaml` → empty, ready for first P4/P5 fix\r\n\r\n4. Set `phases.P0_bootstrap: DONE` and `phases.P1_asset_scan: IN_PROGRESS`\r\n\r\n5. Immediately proceed to P1.\r\n\r\n---\r\n\r\n## Blocking Protocol\r\n\r\nWhen you cannot proceed without a human decision:\r\n\r\n1. Write to `migration-state.yaml`:\r\n   ```yaml\r\n   current_task:\r\n     status: BLOCKED\r\n     block_reason: \"<specific reason>\"\r\n     human_input_required: \"<exact question for the human>\"\r\n   ```\r\n\r\n2. Output to the user:\r\n   ```\r\n   ⛔ BLOCKED — Human decision required\r\n\r\n   Phase: <phase>\r\n   Item: <item_id>\r\n\r\n   Problem: <what cannot be resolved automatically>\r\n\r\n   Required decision: <specific question>\r\n\r\n   Options considered:\r\n     A) <option with trade-off>\r\n     B) <option with trade-off>\r\n\r\n   Please reply with your decision and I will continue.\r\n   ```\r\n\r\n3. Stop. Do not proceed to any other task.\r\n\r\n---\r\n\r\n## Progress Reporting\r\n\r\nAfter completing any task unit, update `migration-state.yaml` and output a brief status line:\r\n\r\n```\r\n✅ [P2] numpy.float64 → f64 (behavioral, precision gap noted)\r\n⛔ [P2] numpy.random.default_rng → BLOCKED (see above)\r\n🔄 [P3] entropy.py::calculate_entropy → IPO documented\r\n```\r\n\r\nAt the end of each session, output a summary:\r\n```\r\nSession Summary\r\n  Phase: P2 Ecosystem Mapping\r\n  Completed this session: 12 entries\r\n  Remaining: 34 entries\r\n  Blocked: 1 (awaiting your decision on numpy RNG)\r\n  Next session: resume P2 from item \"scipy.stats.entropy\"\r\n```\r\n\r\n---\r\n\r\n## YAML Schema Reference\r\n\r\nFor full field definitions of all five YAML files, see: `references/schemas.md`\r\n\r\n---\r\n\r\n## Retrospective Protocol\r\n\r\nIn P5, **every** test failure or structural deviation must pass through the Bug Triage Protocol first (see `references/phase-5-verification.md`) before any fix is applied. Triage classifies the failure into one of five verdicts — only `CONFIRMED_TRANSLATION_ERROR` proceeds to a code fix; the other verdicts resolve in the integration layer, caller, or test without touching the translated function.\r\n\r\nAfter a fix is applied (any phase), the TDD Retrospective Protocol is mandatory. A fix without a retrospective is a local patch. A fix with a retrospective is a systemic improvement.\r\n\r\nSee `references/tdd-retrospective.md` for the full protocol.\r\n\r\n### Why Root Cause, Not Phenomenon?\r\n\r\nTraditional bug tracking records **what failed**:\r\n```\r\ntest_loop_tool_order FAILED\r\nExpected execution order: [search, read, write]\r\nActual order: [write, read, search]\r\n```\r\n\r\nThis documents a symptom. The same underlying problem will manifest differently next time.\r\n\r\nThe retrospective records **structural root causes**:\r\n```\r\nRoot cause: ecosystem_gap_unapplied\r\nProblem: Python dict preserves insertion order (3.7+). IPO registry documented this gap\r\nand specified IndexMap/[]Entry as compensation. Translation used map[K]V, silently losing order.\r\n```\r\n\r\nWhen the next function translates a Python dict, the AI can check the retrospective **before**\r\ntranslating, preventing the error instead of fixing it after failure.\r\n\r\nEach migration's lessons become infrastructure for the next migration of the same language pair.\r\n\r\n### Core Design Principles\r\n\r\n#### 1. Root Cause Categories\r\n\r\nTwelve predefined categories force abstract thinking:\r\n- `ecosystem_gap_unapplied` — known gap was not applied\r\n- `semantic_contract_lost` — implicit contract not preserved\r\n- `invariant_not_transferred` — inferred invariant missing\r\n- `magic_number_decontextualized` — constant without context\r\n- `control_flow_collapsed` — IPO steps merged/reordered\r\n- `error_class_narrowed` — specific exception generalized\r\n- `side_effect_dropped` — documented side effect missing\r\n- `ipo_source_lines_wrong` — P3 analysis based on wrong lines\r\n- `test_fixture_mismatch` — fixture format changed\r\n- `consumer_error` — bug is in caller/test, not translated function; fix consumer only\r\n- `source_faithful_behavior` — behavior matches source; test assumption was wrong; annotate, don't fix\r\n- `implicit_capability_assumption` — source design relied on consumer having inference ability (e.g. strong LLM) that the target consumer lacks; fix in integration layer, not in translated function\r\n- `other` — describe if no category fits\r\n\r\nEach fix produces exactly ONE entry with ONE category. No category hopping.\r\n\r\nThe last three categories (`consumer_error`, `source_faithful_behavior`, `implicit_capability_assumption`) resolve **without changing the translated function**. They require a retrospective entry but do not trigger scope scan for code fixes.\r\n\r\n#### 2. Scope Scan: Query BEFORE Execution\r\n\r\n**Mandatory rule**: Define `scope_scan_query` before scanning.\r\n\r\nThis prevents LLM cheating patterns like:\r\n- Scan codebase → observe results → retroactively define \"the scope that matches findings\"\r\n\r\nExample:\r\n```yaml\r\nRoot cause: dict insertion-order dependency not preserved\r\n\r\nscope_scan_query: \"grep -rn 'map\\[string\\]' internal/ --include='*.go'\"\r\n(The query is written BEFORE executing the grep. It appears in the retrospective entry.)\r\n```\r\n\r\nThe query is your prediction of where the root cause manifests. If results don't match predictions,\r\nit's a signal that the root cause analysis was incomplete.\r\n\r\n#### 3. Consistent Fix Across All Instances\r\n\r\nScope scan identifies all instances with the same root cause. All are fixed simultaneously\r\nusing the same fix strategy. This prevents:\r\n- The bug reappearing in a file not yet reviewed\r\n- Maintenance inconsistency (same bug, different fixes in different places)\r\n\r\nAfter scope fix, **full test suite is re-run** (not just the failing test). Any new failures\r\ntrigger independent retrospectives — they are not merged.\r\n\r\n#### 4. Ecosystem Map Auto-Update\r\n\r\nFlag `ecosystem_map_update_required: true` in the retrospective entry triggers automatic\r\nupdate to `ecosystem-map.yaml` at phase-end.\r\n\r\nExample:\r\n- P4: dict ordering bug found, fixed, retrospective entry created\r\n- Entry sets `ecosystem_map_update_required: true`\r\n- P4 end: ecosystem map updated with stronger guidance\r\n- **Next migration benefits** — same class of error is harder to commit\r\n\r\n### Checklist Summary (Phase-End Report)\r\n\r\nAt the END of P4 and P5, output a **Checklist Summary**:\r\n\r\n```\r\nRETROSPECTIVE CHECKLIST SUMMARY (end of P5):\r\n  total_rca_entries:          24\r\n  total_instances_found:      67\r\n  total_instances_fixed:      64\r\n  instances_deferred:         3\r\n\r\nMost common root cause categories:\r\n  1. ecosystem_gap_unapplied         (9 entries)   → suggests ecosystem map gaps\r\n  2. semantic_contract_lost          (6 entries)   → suggests IPO analysis depth issue\r\n  3. magic_number_decontextualized   (4 entries)   → suggests naming discipline\r\n\r\nEcosystem map updates applied: 3\r\n  - dict iteration order guidance strengthened\r\n  - float precision rules clarified\r\n  - exception mapping for stdlib errors expanded\r\n\r\nNext language pair migration of python→go should consult these 24 entries\r\nbefore beginning translation — prevents category-1 errors upfront.\r\n```\r\n\r\nThis summary is the handoff to the next migration team or agent.\r\n\r\n### Integration with P4/P5\r\n\r\n**P4 Trigger:**\r\n```\r\nCompilation/vet error found\r\n  ↓\r\nFix applied\r\n  ↓\r\nTrigger: Retrospective Protocol\r\n  ↓\r\nRCA → Checklist rule → Scope scan query → Scope scan → Consistent fix\r\n  ↓\r\nResume P4 from next file\r\n```\r\n\r\n**P5 Trigger:**\r\n```\r\nStructural deviation or test failure found\r\n  ↓\r\nBug Triage (T1 → T2 → T3)  ← MANDATORY before any fix\r\n  ↓\r\n  ├─ SOURCE_FAITHFUL          → annotate target code; fix test; no code change\r\n  ├─ CONSUMER_ERROR           → fix caller/test only; no code change\r\n  ├─ IMPLICIT_CAPABILITY      → fix integration layer only; no code change\r\n  ├─ ECOSYSTEM_DIFFERENCE     → verify compensation; may update test expectation\r\n  └─ CONFIRMED_TRANSLATION_ERROR\r\n       ↓\r\n     Fix applied\r\n       ↓\r\n     Trigger: Retrospective Protocol\r\n       ↓\r\n     RCA → Checklist rule → Scope scan query → Scope scan → Consistent fix\r\n       ↓\r\n     Full test suite re-run (not just failing test)\r\n       ↓\r\n     If new failures: each triggers independent retrospective\r\n       ↓\r\n     Resume P5 from next function\r\n```\r\n\r\nFor detailed protocol, see: `references/tdd-retrospective.md`\n\nFile v1.3.1:README.md\n\n<div align=\"center\">\r\n\r\n```\r\n╔═══════════════════════════════════════════════════════════════╗\r\n║                                                               ║\r\n║          ██╗      █████╗ ███╗   ██╗ ██████╗                   ║\r\n║          ██║     ██╔══██╗████╗  ██║██╔════╝                   ║\r\n║          ██║     ███████║██╔██╗ ██║██║  ███╗                  ║\r\n║          ██║     ██╔══██║██║╚██╗██║██║   ██║                  ║\r\n║          ███████╗██║  ██║██║ ╚████║╚██████╔╝                  ║\r\n║          ╚══════╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝   flynn           ║\r\n║                   M I G R A T I O N                           ║\r\n║                                                               ║\r\n╚═══════════════════════════════════════════════════════════════╝\r\n```\r\n\r\n# lang-migration\r\n\r\n**A Formal Methodology for AI-Driven, Evidence-Obligated Program Translation**\r\n\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\r\n[![Pairs: 14](https://img.shields.io/badge/Language_Pairs-14-blue)](#language-pairs)\r\n[![Phase: P0–P6](https://img.shields.io/badge/Phases-P0_through_P6-green)](#pipeline)\r\n[![Anti-Cheating](https://img.shields.io/badge/Anti--Cheating-Protocol_Enforced-red)](#the-evidence-obligation-protocol)\r\n[![Works With](https://img.shields.io/badge/Works_With-Claude_Code_|_Cursor_|_Copilot_|_OpenCode-purple)](#runtime-environments)\r\n[![ClawHub](https://clawhub.ai/favicon.ico)](https://clawhub.ai/suifei/lang-migration)\r\n[![Version: 1.3](https://img.shields.io/badge/Version-1.3-blue)](#whats-new)\r\n\r\n**English | [中文](README.zh-CN.md)**\r\n\r\n*Migrate any open-source codebase across programming languages — with structural fidelity,\r\npersistent state, and verifiable proof that the AI actually did the work.*\r\n\r\n### ✨ **What's New**\r\n\r\n**v1.3 — Bug Triage Protocol + Real-World Validation**\r\nEvery P5 test failure now goes through a mandatory 3-step triage before any fix is attempted.\r\nOnly 1 of 5 verdicts leads to modifying the translated function. Four new root cause categories.\r\nValidated against a real Python→Go migration (GenericAgent → go-GenericAgent). [Learn more →](#bug-triage-protocol-classify-before-fix)\r\n\r\n**v1.2 — Phase Gate Review (PGR)**\r\nEvery phase transition now requires passing an **autonomous self-auditing loop** before advancing.\r\nThe AI enumerates all expected outputs, audits each one, fixes any gap, and re-audits — until **zero findings**.\r\nOnly then is the phase marked DONE. No human involvement. No rubber-stamping. [Learn more →](CHANGELOG.md#v12--2026-05-15)\r\n\r\n</div>\r\n\r\n---\r\n\r\nClawHub: [https://clawhub.ai/suifei/lang-migration](https://clawhub.ai/suifei/lang-migration)\r\n\r\nSkillhub:[https://skillhub.cn/skills/lang-migration](https://skillhub.cn/skills/lang-migration)\r\n\r\n## The Problem Nobody Talks About\r\n\r\nWhen developers ask an LLM to \"migrate my Python project to Go,\" one of four things happens:\r\n\r\n1. **The LLM produces plausible-looking code that silently drops behavior.** Type semantics, precision contracts, ordering invariants — gone. No one notices until production.\r\n\r\n2. **The LLM reports completion without doing the work.** It marks tasks done, generates placeholder content, and moves on. This is not a bug — it is a rational response to vague completion criteria.\r\n\r\n3. **The context window collapses.** A 50,000-line codebase cannot fit in any single prompt. The LLM loses coherence halfway through, and the migration becomes an archeological exercise in figuring out what was and wasn't translated.\r\n\r\n4. **The LLM fixes the wrong thing.** When a test fails, the AI modifies the translated function — even when that function correctly mirrors the source. The real problem was in the test fixture, the caller, or an implicit model-capability assumption that was never written down. The fix introduces behavioral divergence that didn't exist before.\r\n\r\n**lang-migration** is a structured response to all four failure modes — not through better prompting, but through formal methodology.\r\n\r\n---\r\n\r\n## What This Is\r\n\r\n`lang-migration` is an **AI skill** — a portable, agent-agnostic specification that tells any capable LLM *exactly* how to migrate a codebase, in what order, with what evidence, and how to prove it actually happened.\r\n\r\nIt is not a tool you run. It is a protocol you install into an AI coding agent.\r\n\r\nThink of it as a **research methodology** that the AI follows, the way a graduate student follows a lab protocol — except the lab protocol has been designed specifically to detect and prevent the ways graduate students (and LLMs) tend to cut corners.\r\n\r\n---\r\n\r\n## Core Insight: The Evidence Obligation\r\n\r\nThe central innovation of this methodology is what we call **Evidence Obligation** — the principle that *no unit of work is complete until the AI produces an artifact that can only have been generated by actually doing the work.*\r\n\r\nThis is different from asking the AI to \"be thorough.\" Thoroughness is a moral appeal. Evidence Obligation is a structural constraint.\r\n\r\n### How It Works in Practice\r\n\r\nConsider Phase 3 (IPO Analysis), where the AI must document every function before translating it. Under naive prompting, an LLM will generate plausible-sounding documentation for hundreds of functions in seconds — none of it verified against the actual source.\r\n\r\nUnder Evidence Obligation, the AI must produce a `READ_EVIDENCE` block before filling any entry:\r\n\r\n```\r\nREAD_EVIDENCE for agent_loop.py::run_step:\r\n  file_read: \"agent_loop.py:42-89\"\r\n  first_statement: \"outcome = self._dispatch_tool(tool_call)\"\r\n  last_statement:  \"return StepOutcome(data=result, next_prompt=follow_up)\"\r\n  literal_count:   3\r\n  call_count:      7\r\n  branch_count:    4\r\n```\r\n\r\nThese values — the exact text of the first and last executable statement, the precise count of numeric literals and branch points — cannot be fabricated without reading the file. A hallucinated block will produce wrong line numbers, wrong counts, wrong statement text. This becomes detectable during verification.\r\n\r\nThe AI must also produce a `BEHAVIOR_PROOF` for each function:\r\n\r\n```\r\nBEHAVIOR_PROOF for calculate_entropy:\r\n  happy_path:    \"Given data=[0.3,0.3,0.4], base=2 → returns 1.5710 (bits)\"\r\n  edge_case_1:   \"Given data=[0.0, 1.0], filters 0.0 (epsilon=1e-10), returns 0.0\"\r\n  would_fail_if: \"sum(data) >> 1.0 — inferred invariant violated, results meaningless\"\r\n```\r\n\r\nGeneric answers (\"returns the expected result given valid input\") are prohibited. Specific values require genuine understanding.\r\n\r\n---\r\n\r\n## The Six-Phase Pipeline\r\n\r\n```\r\n┌─────────────────────────────────────────────────────────────────┐\r\n│                                                                 │\r\n│  P0  Bootstrap      Detect language pair, initialize workspace  │\r\n│   │                                                             │\r\n│  P1  Asset Scan     Every file classified — nothing skipped     │\r\n│   │                                                             │\r\n│  P2  Ecosystem Map  Every import/type mapped with evidence      │\r\n│   │                                                             │\r\n│  P3  IPO Analysis   Every function: Inputs, Process, Outputs    │\r\n│   │                 READ_EVIDENCE + BEHAVIOR_PROOF enforced     │\r\n│   │                                                             │\r\n│  P4  Translation    Translate from IPO spec, not source code    │\r\n│   │                 target_lines mandatory per function         │\r\n│   │                                                             │\r\n│  P5  Verification   Real tests, real data — no mocks, ever      │\r\n│   │                                                             │\r\n│  P6  Gap Report     Invoke anytime: \"what's still missing?\"     │\r\n│                                                                 │\r\n└─────────────────────────────────────────────────────────────────┘\r\n```\r\n\r\n### Why Translate from IPO, Not Source?\r\n\r\nPhase 4 has an unusual constraint: the AI translates **from the IPO registry**, not from the source code directly. The source may be consulted for clarification, but the IPO entry is the contract.\r\n\r\nThis separation is deliberate. When an AI reads source code and immediately writes target code, it produces a *stylistic approximation* — capturing surface syntax while silently dropping semantic contracts, magic number purposes, and inferred invariants. By forcing a two-step process (understand → document → translate), the methodology creates a checkpoint where lost information becomes visible before translation, not after.\r\n\r\n---\r\n\r\n## Persistent State as a First-Class Concern\r\n\r\nEvery migration lives in five YAML files in `migration_workspace/`:\r\n\r\n```\r\nmigration_workspace/\r\n├── migration-state.yaml             ← Session entry point. Read this first, always.\r\n├── asset-inventory.yaml             ← Every source file, its migration strategy, its status\r\n├── ecosystem-map.yaml               ← Every library/type/idiom mapped to target equivalent\r\n├── ipo-registry.yaml                ← Every function: inputs, process steps, outputs\r\n└── retrospective-checklist.yaml     ← Lessons learned from every P4/P5 fix\r\n```\r\n\r\nThese files are the migration's \"memory.\" Any AI agent — Claude Code, Cursor, GitHub Copilot, OpenCode — can pick up a migration mid-session by reading `migration-state.yaml`. The state is not in the AI's context window; it's on disk.\r\n\r\nThis makes migrations **resumable, auditable, and transferable.** A migration started in one tool can be continued in another. A migration interrupted by a context collapse can be resumed exactly where it stopped.\r\n\r\n### The State Machine\r\n\r\n```yaml\r\n# migration-state.yaml (excerpt)\r\nphases:\r\n  P0_bootstrap:     DONE\r\n  P1_asset_scan:    DONE\r\n  P2_ecosystem_map: IN_PROGRESS\r\n  P3_ipo_analysis:  TODO\r\n  P4_translation:   TODO\r\n  P5_verification:  TODO\r\n\r\ncurrent_task:\r\n  phase: P2_ecosystem_map\r\n  item_id: \"numpy.random.default_rng\"\r\n  status: BLOCKED\r\n  block_reason: \"RNG algorithm differs (Mersenne Twister vs PCG64); bit-identical output impossible\"\r\n  human_input_required: |\r\n    Statistical equivalence sufficient, or is bit-identical seed behavior required?\r\n```\r\n\r\nWhen `status: BLOCKED`, the AI stops immediately, presents the structured block to the operator, and waits. It does not proceed, does not label-and-continue, does not silently substitute a guess.\r\n\r\n---\r\n\r\n## The Ecosystem Map: Type-System Contracts Across Languages\r\n\r\nBefore any translation begins, every library symbol, type, and stdlib function used in the source must be mapped to its target equivalent, classified by equivalence type, and — critically — annotated with evidence that the mapping was actually researched.\r\n\r\n```yaml\r\n- id: \"numpy.random.default_rng\"\r\n  source_semantics: \"PCG64 PRNG, seedable, reproducible across platforms\"\r\n  target_equivalent: \"math/rand/v2.New(rand.NewPCG(seed, 0))\"\r\n  equivalence_type: structural\r\n  precision_delta: none\r\n  gap_notes: \"Go 1.22+ rand/v2 uses PCG; pre-1.22 uses different algorithm\"\r\n  confirmation_evidence:\r\n    source_behavior:  \"NumPy default_rng uses PCG64 with 128-bit state since NumPy 1.17\"\r\n    target_behavior:  \"math/rand/v2 PCG source: identical algorithm, same output for same seed\"\r\n    verified_from:    \"numpy.org/doc/stable/reference/random/generator.html + pkg.go.dev/math/rand/v2\"\r\n```\r\n\r\nThe `confirmation_evidence` block is mandatory for every `CONFIRMED` mapping. An empty evidence field is treated as `NEEDS_REVIEW` regardless of the `status` field. This prevents the common failure mode where an AI confirms hundreds of mappings without looking any of them up.\r\n\r\n---\r\n\r\n## Language Pairs\r\n\r\nThe methodology ships with 14 pre-built language pair modules covering common migration paths. Each module contains:\r\n\r\n- Pre-mapped standard library and ecosystem symbols\r\n- Known semantic gaps and their compensation strategies\r\n- Language-specific anti-patterns to avoid during translation\r\n- Testing toolchain mapping\r\n- CI/CD adaptation templates\r\n\r\n| Source | Target | Difficulty | Key Challenges |\r\n|--------|--------|-----------|----------------|\r\n| Python | **Rust** | ★★★★ | Ownership, GC→borrow checker, trait system |\r\n| Python | **Go** | ★★★ | Error handling idiom, goroutines, interface duck-typing |\r\n| Python | **C** | ★★★★ | Manual memory, pointer arithmetic, no stdlib collections |\r\n| Python | **C++** | ★★★ | RAII, template metaprogramming, priority_queue direction |\r\n| Python | **Zig** | ★★★★ | Explicit allocators, comptime generics, error unions |\r\n| Python | **TypeScript** | ★★ | `undefined` vs `null`, structural typing, utility types |\r\n| Python | **Bun (JS)** | ★★ | number precision gap, no seedable RNG |\r\n| Rust | **Python** | ★★ | Ownership → comments, Result → exceptions |\r\n| Go | **Python** | ★★ | Multi-return → exceptions, defer → context manager |\r\n| C | **Python** | ★★ | Pointer pairs → single object, string encoding |\r\n| C++ | **Python** | ★★ | RAII → `__del__`/contextmanager, template → TypeVar |\r\n| Zig | **Python** | ★★ | Allocators disappear, comptime → TypeVar |\r\n| Bun | **Python** | ★★ | Number disambiguation, `undefined` mapping |\r\n| TypeScript | **Python** | ★ | Near 1:1 type mapping, utility types → dataclass |\r\n\r\nNew language pairs can be added using `TEMPLATE.md` — the methodology is language-agnostic by design.\r\n\r\n---\r\n\r\n## P6: The Gap Report — Continuous Completeness Audit\r\n\r\nMost migration tools answer the question \"what have we done?\" The Gap Report answers the harder question: **\"what is genuinely missing, and why?\"**\r\n\r\nIt is the only phase that can be invoked at any time — before P5, during P3, or after the AI has declared the migration complete. In practice, it is most useful precisely when the AI *has* declared completion, because that is when hidden gaps are most dangerous.\r\n\r\nInvoke with: *\"还差什么\" / \"gap report\" / \"show migration status\"*\r\n\r\n### The Five Dimensions\r\n\r\nThe report does not compute a single completion percentage. It runs five independent audits, each of which can reveal a different category of failure:\r\n\r\n**Dimension 1 — File Coverage**: Cross-references every entry in `asset-inventory.yaml` against the actual files on disk in the target directory. A `translate`-strategy file with `status: DONE` in the registry but absent from disk is a critical gap — the AI updated the YAML but never wrote the code. This dimension catches that.\r\n\r\n**Dimension 2 — Function Coverage**: Scans `ipo-registry.yaml` for functions marked `translation_status: DONE` but with an empty `target_lines` field. This is the canonical signature of the batch-fabrication problem: the AI marked functions done without producing or locating the actual implementation. The report calls these \"DONE but no evidence\" and flags them as requiring re-verification.\r\n\r\n**Dimension 3 — Directory Structure Gap**: Walks both the source and target directory trees independently, then identifies source directories that have no correspondent in the target. This catches structural omissions that file-level checks miss — an entire module tree that was skipped, a subdirectory of test fixtures with no target equivalent, an internal package that was documented in P1 but never addressed in P4.\r\n\r\n**Dimension 4 — Non-Code Asset Coverage**: Checks whether `direct_use` files (test fixtures, binary data, static assets) were actually copied to the target. Also checks whether every file marked `p3_required: true` in the asset inventory was actually cited in an IPO registry entry. A design document that was supposed to inform IPO analysis but was never referenced is not a minor oversight — it means the functions it described may have been analyzed without their full context.\r\n\r\n**Dimension 5 — Skip Classification**: Distinguishes three categories of missing files with fundamentally different implications. *Intentional documented skips* (in `decisions_log`) require no action. *Platform-specific skips* (Streamlit, PyQt5, tkinter, ultralytics) are auto-detected by keyword and require no action. *Accidental gaps* — files with `status: DONE` in the inventory but no target file and no documented reason — are the critical finding. They represent work the AI claimed to have done but demonstrably has not.\r\n\r\n### The \"TRUE 1:1 COMPLETION\" Metric\r\n\r\nThe gap report does not produce a single optimistic percentage. It surfaces a breakdown that makes incompleteness **specific and actionable**. The following is actual output from the [GenericAgent → go-GenericAgent migration](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/gap-report.yaml):\r\n\r\n```\r\n═══════════════════════════════════════════════════════════════\r\nMIGRATION COMPLETENESS AUDIT — genericagent → go-GenericAgent\r\npython → go  |  150 source files\r\n═══════════════════════════════════════════════════════════════\r\n\r\nFILE COVERAGE (52 translate-strategy files)\r\n  confirmed at expected path:  24  (46.2%)\r\n  ⚠ path drift (present, wrong location): 14  ← need path correction\r\n  ✗ truly missing:             14  ← untranslated\r\n\r\nFUNCTION COVERAGE\r\n  translation_status DONE:     142 / 142  (100%)\r\n  verification checks passed:  898 / 898  (0 failures)\r\n  test packages passing:        37 /  37\r\n\r\nNON-CODE ASSETS\r\n  binary assets absent:        33  (demo images, GIFs, PDFs)\r\n                                   ← no compilation impact; needed for desktop UI\r\n\r\nSKIP CLASSIFICATION\r\n  Class A — intentional documented:  8  (PySide6, Streamlit, no Go equivalent)\r\n  Class C — accidental omissions:   16  (CLI entry points, shell scripts)\r\n  ⚠ Class C items need resolution before production readiness\r\n───────────────────────────────────────────────────────────────\r\nOVERALL: Core logic fully translated; 14 path corrections + 16 omissions pending\r\n───────────────────────────────────────────────────────────────\r\n```\r\n\r\nThe gap report intentionally refuses to compute a single completion percentage, because a headline number hides the structure of what's missing. 14 path drifts (files exist but at wrong paths) require different action than 14 truly missing files — and both require different action than 33 binary assets that don't affect compilation.\r\n\r\nThis conservatism is the point. A metric that trusts the AI's self-assessment is not a completion metric; it is a record of what the AI claimed. Only a metric grounded in physical artifacts — files that exist on disk, line ranges that are populated — can answer the question the human actually cares about.\r\n\r\n---\r\n\r\n## Why Not Just Use a Transpiler?\r\n\r\nExisting automated transpilers (like `py2many`, `Transcrypt`, or language-specific tools) operate on syntax — they map AST nodes to AST nodes. They are fast and often correct for simple cases.\r\n\r\nThey fail systematically when:\r\n\r\n- **Semantic contracts cross library boundaries.** `numpy.float64` is not just \"a float\" — it carries broadcasting semantics, NaN propagation rules, and precision guarantees that no syntactic transform can discover.\r\n\r\n- **Magic numbers carry domain knowledge.** The literal `1e-10` in an entropy function is not a random constant — it is an epsilon floor preventing `log(0)`, derived from the author's understanding of numerical stability. No transpiler documents this. Our methodology requires it.\r\n\r\n- **Inferred invariants shape correctness.** Code often works because callers follow unwritten rules. A function that divides by `len(data)` without a guard works only because every caller has been passing non-empty lists for years. Transpilers cannot discover this. Our IPO analysis requires it to be documented before translation.\r\n\r\n- **Architectural intent is lost.** When a Python class uses a `collections.OrderedDict`, the author chose ordered iteration. A transpiler maps it to `map[K]V` and loses the ordering contract silently. Our ecosystem map requires this gap to be documented and compensated.\r\n\r\n---\r\n\r\n## Bug Triage Protocol: Classify Before Fix\r\n\r\nThe most expensive mistake in a migration is **fixing code that was correct**.\r\n\r\nWhen a test fails in the migrated project, the naive response is to modify the translated function. But the translated function may be exactly right — faithfully reproducing the source's behavior. The problem may lie elsewhere: in the test assertion, in the caller, in how the source design assumed a specific model capability that the target environment doesn't have.\r\n\r\n**lang-migration** enforces a mandatory 3-step triage before any fix is applied:\r\n\r\n```\r\nT1: Map to IPO registry — does the target code match the documented spec?\r\n        YES → function is correct; continue to T2\r\n        NO  → confirmed translation error → Fix + Retrospective\r\n\r\nT2: Read the actual source lines — does the source exhibit the same behavior?\r\n        YES → source-faithful: annotate, don't fix; update test expectation\r\n        NO  → IPO analysis recorded wrong lines → fix P3, then re-translate\r\n\r\nT3: Investigate the consumer / caller path\r\n        CONSUMER_ERROR              → fix caller or test only\r\n        IMPLICIT_CAPABILITY_GAP     → fix integration layer only\r\n        ECOSYSTEM_DIFFERENCE        → verify compensation strategy\r\n        CONFIRMED_TRANSLATION_ERROR → Fix + Retrospective\r\n```\r\n\r\nOnly one of five verdicts results in modifying the translated function. The other four resolve in the integration layer, the caller, or the test — without touching the function that was, in fact, correctly translated.\r\n\r\n### Real-World Validation: The Conductor Case\r\n\r\nIn a Python→Go migration of **GenericAgent → go-GenericAgent**, the conductor agent failed to read incoming user messages. The first \"fix\" embedded message content directly into the system prompt — changing the source design.\r\n\r\nThe correct triage:\r\n\r\n- **T1**: Go `conductorPrompt` matched `conductor.py:277-279` exactly. ✅ Function is correct.\r\n- **T2**: Source reads: `unread = sum(1 for m in chat_messages if not m.get(\"read\"))` — count only, no message body. Target behavior identical. **Source-faithful — do not change the function.**\r\n- **T3**: The Python design assumed the consumer (Claude) would infer \"call `GET /chat` when `unread > 0`.\" The Go deployment ran Qwen3.5, which needs an explicit `code_run` example to trigger the same action. **Verdict: `implicit_capability_assumption`** — fix the system prompt, not the translated function.\r\n\r\nThe first \"fix\" was reverted. The system prompt was strengthened with an explicit `GET /chat?last=20` example and a trigger rule. The `conductorPrompt` logic — count only — was preserved exactly as the Python source designed it.\r\n\r\nThis class of bug is now its own root cause category: **`implicit_capability_assumption`** — source design relied on consumer inference ability that the target consumer lacks. Documented in the IPO registry as an `inferred_invariant`; resolved in the integration layer.\r\n\r\n### The 12 Root Cause Categories\r\n\r\nEvery bug found during migration is classified into one of 12 categories. The first nine produce code fixes. The last three resolve **without touching the translated function**:\r\n\r\n| Category | Resolution |\r\n|---|---|\r\n| `ecosystem_gap_unapplied` | Code fix + scope scan |\r\n| `semantic_contract_lost` | Code fix + scope scan |\r\n| `invariant_not_transferred` | Code fix + scope scan |\r\n| `magic_number_decontextualized` | Code fix + scope scan |\r\n| `control_flow_collapsed` | Code fix + scope scan |\r\n| `error_class_narrowed` | Code fix + scope scan |\r\n| `side_effect_dropped` | Code fix + scope scan |\r\n| `ipo_source_lines_wrong` | Re-run P3, then re-translate |\r\n| `test_fixture_mismatch` | Fix fixture only |\r\n| **`consumer_error`** | **Fix caller/test only — function is correct** |\r\n| **`source_faithful_behavior`** | **Annotate + fix test — function is correct** |\r\n| **`implicit_capability_assumption`** | **Fix integration layer — function is correct** |\r\n\r\nThis classification prevents the most common AI migration failure mode: confidently modifying correct code because a test failed.\r\n\r\n---\r\n\r\n## The No-Mock Principle\r\n\r\nEvery test in the migrated project uses real implementations against real data.\r\n\r\nThis is not idealism — it is a correctness requirement. A migration that passes a mock-based test suite has proven nothing about behavioral equivalence. It has proven only that the mock was correctly wired.\r\n\r\nWhen a test cannot run without a real dependency (a database, a hardware device, a third-party API), the methodology does not mock it. It blocks, documents the missing dependency, and waits for the operator to provide the real environment. The test remains in the suite, marked as requiring a real dependency, and passes when that dependency becomes available.\r\n\r\nThis is uncomfortable. It is also the only way to know whether the migration is correct.\r\n\r\n---\r\n\r\n## Real-World Case Study: GenericAgent Python → Go\r\n\r\n> **Sample repository**: [suifei/lang-migration-samples](https://github.com/suifei/lang-migration-samples)\r\n> Full YAML state files, IPO registry, and the complete Go output are public.\r\n\r\nThe methodology has been applied in full to a production AI agent framework:\r\n**[GenericAgent](https://github.com/suifei/lang-migration-samples/tree/main/genericagent)** (Python 3.11)\r\n→ **[go-GenericAgent](https://github.com/suifei/lang-migration-samples/tree/main/go-GenericAgent)** (Go 1.25)\r\n\r\nGenericAgent is a minimal self-evolving autonomous agent framework with 12 chat platform\r\nintegrations (Telegram, Discord, Lark, WeChat Work, …) and 10 memory subsystems.\r\n\r\n### Migration Outcome\r\n\r\n| Metric | Value | Source |\r\n|--------|-------|--------|\r\n| Source files scanned | 150 | [asset-inventory.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/asset-inventory.yaml) |\r\n| Strategy breakdown | 52 translate · 15 adapt · 57 direct-use · 26 reference-only | |\r\n| Ecosystem symbols mapped | 58 (38 structural · 10 behavioral · 7 partial · 3 none) | [ecosystem-map.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/ecosystem-map.yaml) |\r\n| Functions in IPO registry | 142 / 142 documented and translated | [ipo-registry.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/ipo-registry.yaml) |\r\n| Go test packages passing | 37 / 37 | [migration-state.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/migration-state.yaml) |\r\n| Test coverage | 60.1% | |\r\n| Verification checks run | 898 | |\r\n| Verification failures | **0** | |\r\n| Build / vet | ✅ Clean | |\r\n| Phases complete | P0 → P5 all DONE | |\r\n| Active AI sessions | ~7 | |\r\n\r\nAll phases were completed as verified by [migration-state.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/migration-state.yaml):\r\n\r\n```yaml\r\nphases:\r\n  P0_bootstrap:    DONE\r\n  P1_asset_scan:   DONE\r\n  P2_ecosystem_map: DONE\r\n  P3_ipo_analysis: DONE\r\n  P4_translation:  DONE\r\n  P5_verification: DONE\r\n```\r\n\r\n### What the Ecosystem Map Captured\r\n\r\nA sample from [ecosystem-map.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/ecosystem-map.yaml) — including the non-trivial gaps:\r\n\r\n| Python | Go | Equivalence | Decision |\r\n|---|---|---|---|\r\n| `asyncio` | goroutines + channels | structural | `async def` → goroutine; `await` → channel receive |\r\n| `collections.defaultdict` | `map[K]V` | behavioral | No auto-init; explicit `if _, ok := m[k]` required |\r\n| `importlib` (dynamic import) | compile-time registry | partial | No Go equivalent; plugin registration via `init()` |\r\n| `streamlit` | HTTP + SSE | none | Reactive UI has no Go equivalent; replaced with conductor web UI |\r\n| `ultralytics` (YOLO) | ONNX Runtime + CGO | none | Export model to ONNX; bind via `onnxruntime_go`; CGO dependency |\r\n\r\n### What the IPO Registry Documented\r\n\r\nMagic numbers from [ipo-registry.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/ipo-registry.yaml) — each with source line, type, and inferred purpose:\r\n\r\n```yaml\r\n# agent_loop.py — turn management thresholds\r\nmagic_numbers:\r\n  - value: 40   type: iteration_limit  purpose: \"default max turns, interactive sessions\"\r\n  - value: 70   type: iteration_limit  purpose: \"max turns, task one-shot mode\"\r\n  - value: 100  type: iteration_limit  purpose: \"plan-mode hard cap\"\r\n  - value: 0.6  type: threshold        purpose: \"target context fill ratio after trimming\"\r\n  - value: 10   type: iteration_limit  purpose: \"reset tool schema every N turns\"\r\n\r\n# Inferred invariants (undocumented contracts exposed by P3):\r\ninferred_invariants:\r\n  - \"history managed inside LLM client backend — not in messages list [inferred from: no append in body]\"\r\n  - \"bad_json is a reserved built-in tool, never in JSON schema [inferred from: special-cased in dispatcher]\"\r\n  - \"unknown tool resets last_tools to force re-sending schema next turn [inferred from: line 312]\"\r\n```\r\n\r\n### Bugs Discovered During Verification\r\n\r\nThese were found by real tests on real data — impossible to detect through code review alone:\r\n\r\n1. **Goroutine deadlock** — `streamCh` was never closed after streaming LLM response completed.\r\n   `for-select` in the consumer goroutine blocked forever.\r\n   Fix: `defer close(streamCh)` added before `defer close(loopDone)` in `agent.Run()`.\r\n   Root cause: `side_effect_dropped` — Python's generator exhaustion is implicit; Go channels require explicit close.\r\n\r\n2. **`init()` panic** — Package-level `init()` called `regexp.MustCompile` with a pattern using\r\n   lookahead syntax (`(?=…)`), which Go's `regexp` package (RE2 semantics) does not support.\r\n   Root cause: `ecosystem_gap_unapplied` — the `re` → `regexp` ecosystem map entry notes RE2 limitations, but the specific lookahead was not caught in P3.\r\n\r\n### Gap Report Findings (Honest View)\r\n\r\nThe [gap-report.yaml](https://github.com/suifei/lang-migration-samples/blob/main/migration_workspace/gap-report.yaml) P6 audit found:\r\n\r\n- **14 path drifts** — files present in Go output but at different paths than planned\r\n- **14 truly missing** — files not yet translated (mostly CLI entry points and shell scripts)\r\n- **33 binary assets absent** — demo images, GIFs, PDFs (no compilation impact; needed for desktop UI)\r\n- **8 intentional skips** — GUI frontends (`qtapp.py` PySide6, `stapp.py` Streamlit) with no Go equivalent\r\n\r\nThe methodology's gap report makes this residual incompleteness **visible and enumerated** — not hidden under a claimed \"100% done.\"\r\n\r\n### Honest Assessment\r\n\r\nThe migration required approximately **7 active AI sessions** of sustained human attention: approving gap decisions, resolving path-drift discrepancies, and validating bug fixes. It is not fully autonomous — human judgment is required at ecosystem decision points and when the methodology issues a `BLOCKED` status.\r\n\r\nThe methodology's value is not speed — it is **structural fidelity and verified completeness**. Every function translated has an IPO entry. Every magic number has a source line. Every ecosystem gap has a documented compensation. Every test failure went through triage before any fix.\r\n\r\n---\r\n\r\n## Runtime Environments\r\n\r\nThe methodology is agent-agnostic. It has been designed to run in:\r\n\r\n| Environment | Mode | Notes |\r\n|-------------|------|-------|\r\n| **Claude Code** | `full_mode` | Bash + file system; runs scan scripts directly |\r\n| **OpenCode** | `full_mode` | Same as Claude Code |\r\n| **Cursor** | `editor_mode` | File system only; scripts run manually |\r\n| **GitHub Copilot** | `editor_mode` | Same as Cursor |\r\n\r\nIn `full_mode`, the AI runs `scan_assets.py` and `gap_report.py` directly.\r\nIn `editor_mode`, the AI generates the file lists manually and instructs the operator to run scripts.\r\n\r\n---\r\n\r\n## Installation\r\n\r\n```bash\r\n# Clone into your project's .agents/skills directory\r\nmkdir -p .agents/skills\r\ngit clone https://github.com/suifei/lang-migration-skill.git .agents/skills/lang-migration-skill\r\n```\r\n\r\nThen tell your AI agent:\r\n\r\n```\r\n/lang-migration  source: my-python-project/  target: my-go-project/  pair: python-go\r\n```\r\n\r\nThe agent reads `SKILL.md`, initializes `migration_workspace/`, and begins Phase 1.\r\n\r\n---\r\n\r\n## Repository Structure\r\n\r\n```\r\nlang-migration/\r\n├── SKILL.md                              ← Agent entry point and orchestration protocol\r\n├── CHANGELOG.md                          ← Version history\r\n├── templates/\r\n│   ├── migration-state.yaml              ← Session state machine (includes phase_gates block)\r\n│   ├── asset-inventory.yaml              ← File classification registry\r\n│   ├── ecosystem-map.yaml                ← Library/type mapping registry\r\n│   ├── ipo-registry.yaml                 ← Function IPO specification registry\r\n│   └── retrospective-checklist.yaml      ← Fix root-cause log (5th workspace file)\r\n├── references/\r\n│   ├── schemas.md                        ← Full field definitions for all five YAML files\r\n│   ├── phase-0-bootstrap.md              ← P0 workspace initialization\r\n│   ├── phase-1-asset-scan.md\r\n│   ├── phase-2-ecosystem-map.md\r\n│   ├── phase-3-ipo-analysis.md           ← Evidence Obligation protocol lives here\r\n│   ├── phase-4-translation.md\r\n│   ├── phase-5-verification.md\r\n│   ├── phase-6-gap-report.md\r\n│   ├── phase-gate-review.md              ← PGR autonomous closure protocol (v1.2)\r\n│   ├── tdd-retrospective.md              ← Fix retrospective protocol (v1.1)\r\n│   └── lang-pairs/\r\n│       ├── TEMPLATE.md                   ← Extend to new language pairs\r\n│       ├── python-rust.md\r\n│       ├── python-go.md\r\n│       ├── python-c.md\r\n│       ├── python-cpp.md\r\n│       ├── python-zig.md\r\n│       ├── python-bun.md\r\n│       ├── python-typescript.md\r\n│       ├── rust-python.md\r\n│       ├── go-python.md\r\n│       ├── c-python.md\r\n│       ├── cpp-python.md\r\n│       ├── zig-python.md\r\n│       ├── bun-python.md\r\n│       └── typescript-python.md\r\n└── scripts/\r\n    ├── scan_assets.py                    ← Phase 1 file scanner\r\n    └── gap_report.py                     ← Phase 6 completeness auditor\r\n```\r\n\r\n---\r\n\r\n## Contributing\r\n\r\nThe most valuable contributions are **new language pair modules** and **real-world migration reports.**\r\n\r\n**New language pair**: Copy `references/lang-pairs/TEMPLATE.md`, fill in all sections, submit a PR. Focus on gaps that are non-obvious — things a senior developer in the source language would assume but a developer in the target language would not know to look for.\r\n\r\n**Migration reports**: If you use this methodology on a real project, we want to know: what did the gap report catch? Which ecosystem mappings were wrong in the pre-built modules? What blocking decisions came up?\r\n\r\nThe methodology improves through accumulated case knowledge. Every real migration that reports back makes the next one more reliable.\r\n\r\n---\r\n\r\n## Open Questions (Research Directions)\r\n\r\nThis methodology raises questions we haven't fully answered:\r\n\r\n**On semantic equivalence**: The `BEHAVIOR_PROOF` requirement asks the AI to specify concrete input-output pairs for every function. This is a weaker form of a *behavioral contract*. Could these contracts be automatically checked using property-based testing frameworks (Hypothesis, proptest) to formally verify equivalence across language boundaries?\r\n\r\n**On the evidence trail**: The `READ_EVIDENCE` and `BEHAVIOR_PROOF` blocks are currently ephemeral — they appear in the AI's response and are not stored. Could they be captured and used to build a persistent *proof-of-understanding* archive that survives across sessions?\r\n\r\n**On non-determinism**: When source functions use RNG with reproducible seeds, the migration must document whether bit-identical output is required or statistical equivalence suffices. This is currently a human decision. Could it be automated by analyzing downstream consumers of the non-deterministic output?\r\n\r\n**On multi-agent parallelism**: The current methodology is sequential — one AI agent, one function at a time. For large codebases (100k+ LOC), could multiple agents work in parallel on independent subtrees of the dependency graph, with a coordinator merging their IPO registries?\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT. Translate freely.\r\n\r\n---\r\n\r\n<div align=\"center\">\r\n\r\n*The gap between \"it looks like it works\" and \"it works\" is where most migrations live.*\r\n*This methodology is an attempt to make that gap visible, measurable, and closeable.*\r\n\r\n**Star this if you've ever received a \"migration complete\" report that wasn't.**\r\n\r\n</div>\n\nFile v1.3.1:_meta.json\n\n{\n  \"ownerId\": \"kn731g0h1z4gandq3nq2dazb8186r61a\",\n  \"slug\": \"lang-migration\",\n  \"version\": \"1.3.1\",\n  \"publishedAt\": 1779071566759\n}\n\nFile v1.3.1:references/lang-pairs/bun-python.md\n\n# Language Pair: Bun (JavaScript) → Python\n\n**Difficulty tier**: Low-Moderate (both dynamic; async models differ; number precision is a trap)\n\n**Key differences**:\n- Types: JS dynamic → Python `typing` annotations (ADD types; JS may have none)\n- Async: JS Promise/async-await → Python `asyncio` (structurally similar)\n- Numbers: JS `number` (float64) → Python `int` / `float` (must determine which)\n- `undefined` vs `null`: JS has both → Python has only `None`\n- Prototypal OOP: JS classes → Python classes (both ES6 class and Python class are similar)\n- Modules: JS ESM → Python modules\n\n---\n\n## Pre-Mapped Core Types\n\n| Bun (JS) | Python | Equivalence | Notes |\n|---|---|---|---|\n| `number` (integer use) | `int` | behavioral | JS uses float64 for all numbers; Python distinguishes |\n| `number` (float use) | `float` | structural | |\n| `bigint` | `int` | structural | Python int is natively arbitrary precision |\n| `boolean` | `bool` | structural | |\n| `string` | `str` | structural | JS is UTF-16 internally; Python str is abstract Unicode |\n| `null` | `None` | structural | |\n| `undefined` | `None` | behavioral | JS `undefined` (unset) → Python `None`; document |\n| `Array<T>` | `list[T]` | structural | |\n| `[A, B]` tuple | `tuple[A, B]` | structural | |\n| `Map<K,V>` | `dict[K,V]` | structural | Both preserve insertion order |\n| `Set<T>` | `set[T]` | structural | |\n| `Uint8Array` | `bytes` | structural | |\n| `ArrayBuffer` | `bytes` | structural | |\n| `Promise<T>` | `Awaitable[T]` / coroutine | structural | |\n| `null \\| T` | `Optional[T]` | structural | |\n| `A \\| B` | `Union[A, B]` | structural | |\n\n---\n\n## Number Type Disambiguation\n\nJS uses `number` for both integers and floats. When migrating, determine the correct Python type from context:\n\n```javascript\n// JS: all are `number`\nconst count = 42;           // → Python int\nconst ratio = 3.14;         // → Python float\nconst index = arr.length;   // → Python int\nconst price = 9.99;         // → Python float\n```\n\n**Decision rule** (apply per variable/parameter):\n- Used with integer arithmetic, indices, or counts → `int`\n- Used with decimal values, ratios, measurements → `float`\n- Unclear → `float` (safer; Python float is wider than JS number)\n- Was `bigint` in JS → always `int`\n\n---\n\n## `undefined` vs `null` → `None`\n\n```javascript\n// JS: different semantics\nfunction find(key) {\n    if (!map.has(key)) return undefined;  // not found\n    const val = map.get(key);\n    if (val === null) return null;         // explicitly absent\n    return val;\n}\n```\n\n```python\n# Python: both → None; document the distinction as comment\ndef find(key: str) -> Optional[str]:\n    # JS SOURCE: returned undefined when not found, null when explicitly absent.\n    # Python: both map to None. Callers must not distinguish.\n    if key not in self._map:\n        return None   # was: undefined (not found)\n    return self._map[key]   # may be None (was: null — explicitly absent)\n```\n\nIf the caller distinguished `undefined` from `null`, use a sentinel or `Optional[Optional[T]]` pattern and document thoroughly.\n\n---\n\n## async/await → asyncio\n\n**JS:**\n```javascript\nasync function fetchData(url) {\n    const response = await fetch(url);\n    if (!response.ok) throw new Error(`HTTP ${response.status}`);\n    return await response.json();\n}\n```\n\n**Python:**\n```python\nimport aiohttp\n\nasync def fetch_data(url: str) -> dict:\n    async with aiohttp.ClientSession() as session:\n        async with session.get(url) as response:\n            if not response.ok:\n                raise RuntimeError(f\"HTTP {response.status}\")\n            return await response.json()\n```\n\n| JS | Python | Notes |\n|---|---|---|\n| `async function` | `async def` | |\n| `await expr` | `await expr` | |\n| `Promise.all([...])` | `asyncio.gather(...)` | |\n| `Promise.race([...])` | `asyncio.wait(..., return_when=FIRST_COMPLETED)` | |\n| `Promise.allSettled([...])` | `asyncio.gather(..., return_exceptions=True)` | |\n| `new Promise((res, rej) => ...)` | `asyncio.get_event_loop().create_future()` | Rare; prefer async def |\n| `.then(fn)` chaining | `await` in sequence | Flatten chains to sequential awaits |\n\n---\n\n## Error Handling\n\nJS and Python exceptions are structurally similar:\n\n**JS:**\n```javascript\nclass DatabaseError extends Error {\n    constructor(message, code) {\n        super(message);\n        this.name = 'DatabaseError';\n        this.code = code;\n    }\n}\n\nfunction query(sql) {\n    try {\n        return db.execute(sql);\n    } catch (e) {\n        if (e instanceof ConnectionError) {\n            throw new DatabaseError(`connection failed: ${e.message}`, 'CONN_ERROR');\n        }\n        throw e;\n    }\n}\n```\n\n**Python:**\n```python\nclass DatabaseError(Exception):\n    def __init__(self, message: str, code: str) -> None:\n        super().__init__(message)\n        self.code = code\n\ndef query(sql: str) -> Any:\n    try:\n        return db.execute(sql)\n    except ConnectionError as e:\n        raise DatabaseError(f\"connection failed: {e}\", 'CONN_ERROR') from e\n```\n\n**Rule**: Use `raise X from e` (Python) to preserve the exception chain — mirrors JS's implicit cause.\n\n---\n\n## Class Migration\n\nES6 classes and Python classes are nearly identical:\n\n**JS:**\n```javascript\nclass EventEmitter {\n    #listeners = new Map();\n\n    on(event, handler) {\n        if (!this.#listeners.has(event)) {\n            this.#listeners.set(event, []);\n        }\n        this.#listeners.get(event).push(handler);\n    }\n\n    emit(event, ...args) {\n        (this.#listeners.get(event) ?? []).forEach(h => h(...args));\n    }\n}\n```\n\n**Python:**\n```python\nfrom typing import Callable, Any\n\nclass EventEmitter:\n    def __init__(self) -> None:\n        self._listeners: dict[str, list[Callable[..., Any]]] = {}\n\n    def on(self, event: str, handler: Callable[..., Any]) -> None:\n        if event not in self._listeners:\n            self._listeners[event] = []\n        self._listeners[event].append(handler)\n\n    def emit(self, event: str, *args: Any) -> None:\n        for handler in self._listeners.get(event, []):\n            handler(*args)\n```\n\n| JS | Python |\n|---|---|\n| `#privateField` | `self._private_field` (convention) |\n| `static method()` | `@staticmethod` or `@classmethod` |\n| `get prop()` | `@property` |\n| `set prop(v)` | `@prop.setter` |\n| `constructor` | `__init__` |\n| `toString()` | `__str__` |\n| `[Symbol.iterator]()` | `__iter__` |\n| `[Symbol.asyncIterator]()` | `__aiter__` |\n\n---\n\n## Bun-Specific APIs → Python Equivalents\n\n| Bun API | Python equivalent | Notes |\n|---|---|---|\n| `Bun.file(path).text()` | `open(path).read()` | |\n| `Bun.file(path).arrayBuffer()` | `open(path, 'rb').read()` | |\n| `Bun.write(path, data)` | `open(path, 'w').write(data)` | |\n| `Bun.spawn(cmd)` | `subprocess.run(cmd)` | |\n| `Bun.serve({...})` | `aiohttp.web.Application()` or FastAPI | |\n| `Bun.env.KEY` | `os.environ.get('KEY')` | |\n| `Bun.CryptoHasher('sha256')` | `hashlib.sha256()` | |\n| `Bun.sleep(ms)` | `await asyncio.sleep(ms / 1000)` | |\n\n---\n\n## Spread / Rest → `*args` / Unpacking\n\n```javascript\nfunction sum(...numbers) { return numbers.reduce((a, b) => a + b, 0); }\nconst merged = { ...obj1, ...obj2 };\nconst combined = [...arr1, ...arr2];\n```\n\n```python\ndef sum(*numbers: float) -> float:\n    return sum(numbers)\n\nmerged = {**obj1, **obj2}\ncombined = [*arr1, *arr2]\n```\n\n---\n\n## Ecosystem Gaps\n\n| JS/Bun | Gap | Python |\n|---|---|---|\n| `undefined` | Python has no undefined | Map to `None`; document |\n| `NaN` | `float('nan')` | `math.isnan(x)` |\n| Prototype chain | No equivalent | Python uses class MRO |\n| `Symbol` | No equivalent | Use `enum` or sentinel objects |\n| Generator functions `function*` | `def gen(): yield` | Very similar |\n| `WeakMap` / `WeakRef` | `weakref.WeakValueDictionary` | |\n| `Proxy` / `Reflect` | `__getattr__`, `__setattr__` | |\n| `structuredClone` | `copy.deepcopy` | |\n| `JSON.stringify` circular ref detection | `json.dumps` raises; use `jsonpickle` | |\n\n---\n\n## Testing Toolchain\n\n| Bun/JS | Python | Notes |\n|---|---|---|\n| `bun test` | `pytest` | |\n| `test(\"name\", () => {})` | `def test_name(): ...` | |\n| `expect(val).toBe(x)` | `assert val == x` | |\n| `expect(fn).toThrow(Err)` | `pytest.raises(ErrClass)` | |\n| `mock()` / `jest.fn()` | PROHIBITED | Real implementations only |\n| TypeScript type check | `mypy .` | |\n| `prettier` | `black .` | |\n| `eslint` | `ruff check .` | |\n\n## Build / CI\n\n```yaml\n# Bun (source):\n- run: bun install && bun test\n\n# Python (target):\n- run: pip install -r requirements.txt\n- run: pytest\n- run: mypy .\n- run: ruff check .\n- run: black --check .\n```\n\nFile v1.3.1:references/lang-pairs/c-python.md\n\n# Language Pair: C → Python\n\n**Difficulty tier**: Moderate (memory management dissolves; pointer arithmetic becomes indexing)\n\n**Key differences**:\n- Memory: C manual malloc/free → Python GC (ownership structures become irrelevant mechanically but must be documented)\n- Pointers: C pointers → Python references or indices (never expose raw pointers)\n- Types: C weak static → Python `typing` (strengthen, not weaken)\n- Strings: C null-terminated `char*` → Python `str` (encoding must be made explicit)\n- Error handling: C return codes + errno → Python exceptions\n- Arrays: C fixed/dynamic arrays → Python `list` or `bytes`\n- Structs: C structs → Python `dataclass` or class\n- Function pointers: C `(*fn)(args)` → Python callable / `Callable`\n\n---\n\n## Pre-Mapped Core Types\n\n| C | Python | Equivalence | Notes |\n|---|---|---|---|\n| `int8_t` | `int` | behavioral | Document original range: [-128, 127] |\n| `int16_t` | `int` | behavioral | [-32768, 32767] |\n| `int32_t` | `int` | behavioral | |\n| `int64_t` | `int` | structural | Python int covers this range |\n| `uint8_t` | `int` | behavioral | [0, 255]; add range assertion |\n| `uint16_t` / `uint32_t` / `uint64_t` | `int` | behavioral | Document upper bound |\n| `float` | `float` | behavioral | Python float is f64; C float is f32 — document precision widening |\n| `double` | `float` | structural | |\n| `_Bool` / `bool` | `bool` | structural | |\n| `char*` (string) | `str` | behavioral | Must determine encoding; default UTF-8 |\n| `char*` (bytes) | `bytes` | structural | When used as raw bytes, not text |\n| `uint8_t*` + `size_t` | `bytes` | structural | |\n| `void*` | `Any` | behavioral | Document what types it actually points to |\n| `NULL` | `None` | structural | |\n| `T*` (array) + `size_t n` | `list[T]` | structural | The (pointer, length) pair → single list |\n| `T[N]` (fixed array) | `list[T]` | behavioral | Document that N was fixed; add `assert len(arr) == N` |\n| `struct T` | `@dataclass` class | structural | |\n| `enum` | `enum.IntEnum` or `enum.Enum` | structural | |\n| `(*fn)(args) → ret` | `Callable[[args], ret]` | structural | |\n\n---\n\n## Pointer Pairs → Single Object\n\nThe most common C pattern — a pointer and its associated length — collapses to one Python object:\n\n```c\n// C: two parameters representing one logical unit\nvoid process(const uint8_t *data, size_t len);\nint find_max(const int *arr, size_t n);\nchar *join_strings(const char **strs, size_t count);\n```\n\n```python\n# Python: one parameter\ndef process(data: bytes) -> None: ...\ndef find_max(arr: list[int]) -> int: ...\ndef join_strings(strs: list[str]) -> str: ...\n```\n\n**Rule**: Every `(T*, size_t)` pair in C source → one Python collection parameter.\nDocument the original C signature in a comment:\n\n```python\ndef process(data: bytes) -> None:\n    # C SOURCE: void process(const uint8_t *data, size_t len)\n    ...\n```\n\n---\n\n## Error Handling: Return Codes → Exceptions\n\n**C:**\n```c\ntypedef enum {\n    ERR_OK = 0,\n    ERR_NOT_FOUND = 1,\n    ERR_INVALID_ARG = 2,\n    ERR_OUT_OF_MEMORY = 3\n} ErrorCode;\n\nErrorCode read_record(const char *key, Record *out);\n```\n\n**Python:**\n```python\nclass MigrationError(Exception): pass\nclass NotFoundError(MigrationError): pass\nclass InvalidArgError(MigrationError): pass\n# ERR_OUT_OF_MEMORY: Python raises MemoryError natively; no custom class needed\n\ndef read_record(key: str) -> Record:\n    # C SOURCE: ErrorCode read_record(const char *key, Record *out)\n    # Output parameter `out` becomes the return value.\n    ...\n```\n\n**Rules**:\n- Each non-zero error code → Python exception class\n- Output parameters (`T *out`) → return values\n- `errno` checks → catch-and-raise at the call site\n- `perror()` / `fprintf(stderr, ...)` → `logging.error()`\n\n---\n\n## struct → dataclass\n\n**C:**\n```c\ntypedef struct {\n    char name[64];\n    int  age;\n    float score;\n    struct Node *next;  // linked list pointer\n} Person;\n\nPerson *person_create(const char *name, int age);\nvoid    person_destroy(Person *p);\nvoid    person_set_score(Person *p, float score);\n```\n\n**Python:**\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional\n\n@dataclass\nclass Person:\n    # C SOURCE: char name[64] — max 63 chars + null terminator\n    # INVARIANT: len(name) <= 63\n    name: str\n    age: int\n    score: float = 0.0\n    next: Optional['Person'] = None  # linked list — consider using list[Person] instead\n\n    def set_score(self, score: float) -> None:\n        # C SOURCE: void person_set_score(Person *p, float score)\n        # Note: C used float (32-bit); Python uses float (64-bit)\n        self.score = score\n\n# person_create → __init__ (handled by @dataclass)\n# person_destroy → no equivalent needed (GC handles memory)\n```\n\n---\n\n## Linked List / Tree → Python Native\n\nC frequently uses manual linked lists and trees. Python should replace these with native collections unless the traversal algorithm is the point of the migration:\n\n| C structure | Python equivalent |\n|---|---|\n| Singly linked list | `list[T]` (or `collections.deque` if front/back ops) |\n| Doubly linked list | `collections.deque` |\n| Binary search tree | `sortedcontainers.SortedList` or `list` + `bisect` |\n| Hash table (open addressing) | `dict` |\n| Stack (via linked list) | `list` (append/pop) |\n| Queue (via linked list) | `collections.deque` |\n| Heap (manual) | `heapq` |\n\n**Exception**: If the data structure implementation IS the algorithm being migrated\n(e.g., migrating a B-tree implementation), translate it structurally as a class.\n\n---\n\n## Pointer Arithmetic → Slice Indexing\n\n**C:**\n```c\n// Walk through buffer with pointer arithmetic\nuint8_t *ptr = buffer;\nuint8_t *end = buffer + len;\nwhile (ptr < end) {\n    process(*ptr);\n    ptr++;\n}\n```\n\n**Python:**\n```python\n# Python: index-based or direct iteration\nfor byte in buffer:\n    process(byte)\n```\n\n**C:**\n```c\n// Sliding window via pointer arithmetic\nfor (int i = 0; i <= len - window; i++) {\n    process_window(data + i, window);\n}\n```\n\n**Python:**\n```python\nfor i in range(len(data) - window + 1):\n    process_window(data[i:i + window])\n```\n\n---\n\n## Function Pointers → Callable\n\n**C:**\n```c\ntypedef int (*Comparator)(const void *a, const void *b);\n\nvoid sort_array(int *arr, size_t n, Comparator cmp);\n```\n\n**Python:**\n```python\nfrom typing import Callable\n\ndef sort_array(arr: list[int], cmp: Callable[[int, int], int]) -> None:\n    # C SOURCE: qsort-style comparator: returns <0, 0, or >0\n    # Python: use key function instead where possible, or functools.cmp_to_key\n    import functools\n    arr.sort(key=functools.cmp_to_key(cmp))\n```\n\nFor `qsort`-style comparators, use `functools.cmp_to_key`.\nFor simpler callbacks (`void (*on_event)(Event *)`), use `Callable[[Event], None]`.\n\n---\n\n## Bit Operations\n\nC bit manipulation is common. Python handles it but with integer semantics:\n\n```c\n// C: mask and shift (uint32_t assumed)\nuint32_t flags = 0;\nflags |= (1 << BIT_READY);\nbool is_ready = (flags & (1 << BIT_READY)) != 0;\n```\n\n```python\n# Python: identical syntax, but no fixed bit width\nflags: int = 0\nflags |= (1 << BIT_READY)\nis_ready: bool = bool(flags & (1 << BIT_READY))\n# NOTE: Python int is unbounded; C source assumed uint32_t (32-bit).\n# If overflow wrapping matters, apply: flags &= 0xFFFFFFFF\n```\n\nFor every bit operation, document the original bit width and whether wrapping was relied upon.\n\n---\n\n## Memory Allocation Patterns\n\n| C pattern | Python equivalent | Notes |\n|---|---|---|\n| `malloc(sizeof(T))` | `T()` constructor | GC allocates |\n| `calloc(n, sizeof(T))` | `[T() for _ in range(n)]` | Zero-initialized list |\n| `realloc(ptr, new_size)` | `list.extend()` or `list[:]` resize | |\n| `free(ptr)` | No equivalent | Document that source freed here |\n| `strdup(s)` | `str(s)` or `s[:]` | Python strings are immutable; copies are implicit |\n| Buffer pool / arena | No direct equivalent | Use a list as the pool |\n\n---\n\n## String Handling\n\nC strings are particularly dangerous to migrate carelessly:\n\n| C | Python | Notes |\n|---|---|---|\n| `strlen(s)` | `len(s)` | |\n| `strcmp(a, b)` | `a == b` | |\n| `strncpy(dst, src, n)` | `src[:n]` | |\n| `sprintf(buf, fmt, ...)` | `f\"{...}\"` or `format(...)` | |\n| `strtol(s, &end, 10)` | `int(s)` + `try/except ValueError` | |\n| `strtod(s, &end)` | `float(s)` + `try/except ValueError` | |\n| `sscanf(s, fmt, ...)` | `re.match(pattern, s)` | Determine regex from format string |\n| `strchr(s, c)` | `s.find(c)` | Returns -1 if not found (same as C) |\n| Null-terminated `\\0` | No equivalent needed | Python strings have no null terminator |\n\n**Encoding**: C `char*` has no encoding. When translating to Python `str`, determine the encoding from context (locale, protocol spec, source comments). Default to UTF-8; document the choice.\n\n---\n\n## Ecosystem Gaps\n\n| C | Gap | Python |\n|---|---|---|\n| Fixed-width integers | Python int unbounded | Add range comments; use `assert` for critical bounds |\n| `float` (32-bit) | Python `float` is 64-bit | Precision widening; document |\n| `sizeof(T)` | `sys.getsizeof(T)` (different semantics) | Document for serialization/protocol code |\n| `#define` macros | Module-level constants | `CONST_NAME: Final = value` |\n| `#include` guards | No equivalent | Python modules are imported once |\n| Stack allocation | No distinction | Python heap-allocates everything; no action |\n| Volatile variables | No equivalent | Document race condition concerns as comments |\n\n---\n\n## Naming Convention\n\n| C | Python |\n|---|---|\n| `snake_case` functions | `snake_case` (matches) |\n| `UPPER_CASE` macros/constants | `UPPER_CASE` with `Final` annotation |\n| `PascalCase` structs/typedefs | `PascalCase` classes |\n| `_internal` prefix | `_internal` prefix (convention unchanged) |\n| `typename_verb` functions | `ClassName.verb()` methods |\n\n---\n\n## Testing Toolchain\n\n| C | Python | Notes |\n|---|---|---|\n| `cmocka` / `Unity` / `Check` | `pytest` | |\n| `assert(condition)` | `assert condition` | |\n| Valgrind (memory check) | No equivalent (GC handles memory) | Run `pytest` with `-v` |\n| `gcov` / `lcov` | `pytest --cov` | |\n| AddressSanitizer | No equivalent needed | |\n| `make test` | `pytest` | |\n\n## Build / CI\n\n```yaml\n# C (source):\n- run: make test\n- run: valgrind --leak-check=full ./test_runner\n\n# Python (target):\n- run: pip install -r requirements.txt\n- run: pytest\n- run: mypy .\n- run: ruff check .\n```\n\nFile v1.3.1:references/lang-pairs/cpp-python.md\n\n# Language Pair: C++ → Python\n\n**Difficulty tier**: Moderate (RAII dissolves; templates become generics; exceptions survive)\n\n**Key differences**:\n- Memory: C++ RAII (`unique_ptr`, `shared_ptr`) → Python GC (RAII destructor logic becomes `__del__` or context managers)\n- Templates: C++ templates → Python generics (`TypeVar`, `Generic`) or `overload`\n- Multiple inheritance: C++ → Python (both support it; map directly)\n- Operator overloading: C++ → Python dunder methods (`__add__`, `__eq__`, etc.)\n- Exceptions: C++ → Python (both use try/catch–try/except; very similar)\n- `const` correctness: C++ `const` → Python has no enforcement; document as comments\n- Namespaces: C++ `namespace` → Python modules / classes\n- `constexpr`: C++ compile-time → Python module-level constants\n\n---\n\n## Pre-Mapped Core Types\n\n| C++ | Python | Equivalence | Notes |\n|---|---|---|---|\n| `int32_t` / `int64_t` | `int` | behavioral | Document original width |\n| `uint32_t` / `uint64_t` | `int` | behavioral | Add non-negative invariant |\n| `float` | `float` | behavioral | Precision widening (f32→f64) |\n| `double` | `float` | structural | |\n| `bool` | `bool` | structural | |\n| `std::string` | `str` | structural | |\n| `std::vector<T>` | `list[T]` | structural | |\n| `std::array<T, N>` | `list[T]` | behavioral | Document fixed size N as invariant |\n| `std::tuple<A,B>` | `tuple[A, B]` | structural | |\n| `std::pair<A, B>` | `tuple[A, B]` | structural | |\n| `std::map<K,V>` | `dict[K,V]` | behavioral | `std::map` is sorted; Python dict is insertion-ordered |\n| `std::unordered_map<K,V>` | `dict[K,V]` | behavioral | No ordering difference |\n| `std::set<T>` | `set[T]` (sorted) | behavioral | `std::set` is sorted; Python `set` is not; use `sortedcontainers.SortedSet` if order matters |\n| `std::unordered_set<T>` | `set[T]` | structural | |\n| `std::optional<T>` | `Optional[T]` | structural | |\n| `std::variant<A,B>` | `Union[A, B]` | structural | |\n| `std::deque<T>` | `collections.deque` | structural | |\n| `std::priority_queue<T>` | `heapq` | behavioral | C++ default is max-heap; Python `heapq` is min-heap — CRITICAL |\n| `std::unique_ptr<T>` | T directly | behavioral | Ownership → GC; document original owner |\n| `std::shared_ptr<T>` | T directly | behavioral | Sharing → GC; document |\n| `std::weak_ptr<T>` | `weakref.ref(obj)` | structural | `import weakref` |\n| `nullptr` | `None` | structural | |\n| `void*` | `Any` | behavioral | Document actual types |\n\n---\n\n## RAII → Context Manager / `__del__`\n\nRAII in C++ ensures cleanup on scope exit. Map to Python context managers:\n\n**C++:**\n```cpp\nclass FileHandle {\n    FILE* f_;\npublic:\n    explicit FileHandle(const std::string& path) {\n        f_ = fopen(path.c_str(), \"rb\");\n        if (!f_) throw std::runtime_error(\"cannot open: \" + path);\n    }\n    ~FileHandle() { if (f_) fclose(f_); }  // RAII destructor\n    // ... read methods\n};\n```\n\n**Python:**\n```python\nclass FileHandle:\n    def __init__(self, path: str) -> None:\n        try:\n            self._f = open(path, 'rb')\n        except OSError:\n            raise RuntimeError(f\"cannot open: {path}\")\n\n    def __enter__(self) -> 'FileHandle':\n        return self\n\n    def __exit__(self, *args: object) -> None:\n        self._f.close()\n\n    # C++ RAII NOTE: destructor guaranteed close on scope exit.\n    # In Python, use `with FileHandle(path) as fh:` to match this guarantee.\n    def __del__(self) -> None:\n        if hasattr(self, '_f'):\n            self._f.close()\n```\n\nDocument all RAII-dependent classes with: `# RAII NOTE: use as context manager to guarantee cleanup`\n\n---\n\n## Templates → TypeVar / Generic\n\n**C++:**\n```cpp\ntemplate<typename T>\nclass Stack {\n    std::vector<T> data_;\npublic:\n    void push(T value) { data_.push_back(std::move(value)); }\n    T pop() {\n        if (data_.empty()) throw std::underflow_error(\"empty stack\");\n        T val = data_.back();\n        data_.pop_back();\n        return val;\n    }\n    bool empty() const { return data_.empty(); }\n};\n```\n\n**Python:**\n```python\nfrom typing import Generic, TypeVar\nT = TypeVar('T')\n\nclass Stack(Generic[T]):\n    def __init__(self) -> None:\n        self._data: list[T] = []\n\n    def push(self, value: T) -> None:\n        self._data.append(value)\n\n    def pop(self) -> T:\n        if not self._data:\n            raise IndexError(\"empty stack\")\n        return self._data.pop()\n\n    def empty(self) -> bool:\n        return len(self._data) == 0\n```\n\nTemplate specialization (`template<> class Stack<bool>`) → Python `@overload` or subclass.\n\n---\n\n## Operator Overloading → Dunder Methods\n\n| C++ operator | Python dunder | Notes |\n|---|---|---|\n| `operator==` | `__eq__` | Also define `__hash__` if implementing `__eq__` |\n| `operator<` | `__lt__` | Add `@functools.total_ordering` + `__eq__` to get all comparisons |\n| `operator+` | `__add__` | |\n| `operator+=` | `__iadd__` | |\n| `operator[]` | `__getitem__` / `__setitem__` | |\n| `operator()` (functor) | `__call__` | |\n| `operator<<` (stream) | `__str__` / `__repr__` | |\n| `operator bool()` | `__bool__` | |\n| `operator size_t()` (hash) | `__hash__` | |\n\n**C++:**\n```cpp\nstruct Vec2 {\n    float x, y;\n    Vec2 operator+(const Vec2& o) const { return {x + o.x, y + o.y}; }\n    bool operator==(const Vec2& o) const { return x == o.x && y == o.y; }\n};\n```\n\n**Python:**\n```python\nimport math\nfrom dataclasses import dataclass\n\n@dataclass\nclass Vec2:\n    x: float\n    y: float\n\n    def __add__(self, other: 'Vec2') -> 'Vec2':\n        return Vec2(self.x + other.x, self.y + other.y)\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Vec2): return NotImplemented\n        return self.x == other.x and self.y == other.y\n\n    def __hash__(self) -> int:\n        return hash((self.x, self.y))\n```\n\n---\n\n## Multiple Inheritance → Python Multiple Inheritance\n\nC++ multiple inheritance maps directly (Python supports it with MRO):\n\n**C++:**\n```cpp\nclass Flyable { virtual void fly() = 0; };\nclass Swimmable { virtual void swim() = 0; };\nclass Duck : public Flyable, public Swimmable { ... };\n```\n\n**Python:**\n```python\nfrom abc import ABC, abstractmethod\n\nclass Flyable(ABC):\n    @abstractmethod\n    def fly(self) -> None: ...\n\nclass Swimmable(ABC):\n    @abstractmethod\n    def swim(self) -> None: ...\n\nclass Duck(Flyable, Swimmable):\n    def fly(self) -> None: ...\n    def swim(self) -> None: ...\n```\n\nFor diamond inheritance: Python MRO (C3 linearization) differs from C++ virtual inheritance. Document differences in `translation_notes`.\n\n---\n\n## `std::priority_queue` Direction (Critical)\n\n`std::priority_queue` is a **max-heap** by default.\nPython `heapq` is a **min-heap**.\n\n```cpp\n// C++: max-heap\nstd::priority_queue<int> pq;\npq.push(3); pq.push(1); pq.push(2);\nint top = pq.top();  // 3 (maximum)\n```\n\n```python\nimport heapq\n# Python min-heap — negate values for max-heap behavior\npq: list[int] = []\nfor v in [3, 1, 2]:\n    heapq.heappush(pq, -v)   # negate for max-heap\ntop = -pq[0]  # 3 (maximum, negated back)\n```\n\nAlways check the IPO registry to confirm the heap direction.\n\n---\n\n## `std::map` vs `dict` Ordering\n\n`std::map` is a sorted BST (always sorted by key).\n`std::unordered_map` has no order guarantee.\nPython `dict` preserves insertion order (not sorted).\n\nWhen migrating `std::map`:\n```python\n# If sorted access is needed:\nfrom sortedcontainers import SortedDict\ndata: SortedDict[str, int] = SortedDict()\n\n# If sorted access is NOT needed (most cases):\ndata: dict[str, int] = {}\n# ORDERING NOTE: C++ source used std::map (sorted). Python dict is insertion-ordered.\n# If sorted iteration is required, use: sorted(data.items())\n```\n\n---\n\n## `constexpr` → Module Constants\n\n```cpp\nconstexpr int MAX_RETRIES = 3;\nconstexpr double PI = 3.14159265358979;\nconstexpr std::array<int, 4> VALID_PORTS = {80, 443, 8080, 8443};\n```\n\n```python\nfrom typing import Final\n\nMAX_RETRIES: Final[int] = 3\nPI: Final[float] = 3.14159265358979\nVALID_PORTS: Final[tuple[int, ...]] = (80, 443, 8080, 8443)\n```\n\n---\n\n## Namespace → Module\n\n```cpp\nnamespace crypto {\nnamespace internal {\n    void hash_block(const uint8_t* data, size_t len, State* state);\n}\n}\n```\n\n```python\n# crypto/internal.py\ndef hash_block(data: bytes, state: State) -> None:\n    ...\n```\n\nC++ namespaces → Python module hierarchy. Translate `namespace a::b::c` → `a/b/c.py`.\n\n---\n\n## Ecosystem Gaps\n\n| C++ | Gap | Python |\n|---|---|---|\n| `std::map` sorted order | Python dict is insertion-ordered | Use `SortedDict` from `sortedcontainers` |\n| `std::priority_queue` max-heap | Python `heapq` is min-heap | Negate values for max-heap |\n| Template specialization | No direct equivalent | Use `@overload` + isinstance dispatch |\n| RAII guarantee | Python GC is non-deterministic | Use context managers; document |\n| `const` correctness | Python has no const enforcement | Add `# CONST:` comments; use `Final` for module-level |\n| `consteval` / `constexpr` functions | No compile-time execution | Module-level computation at import time |\n| `std::thread` with hardware parallelism | Python GIL limits CPU parallelism | Use `multiprocessing` for CPU-bound; `asyncio` for I/O |\n\n---\n\n## Testing Toolchain\n\n| C++ | Python | Notes |\n|---|---|---|\n| Google Test | `pytest` | |\n| `EXPECT_EQ(a, b)` | `assert a == b` | |\n| `EXPECT_THROW(fn(), ExType)` | `pytest.raises(ExType)` | |\n| `EXPECT_NEAR(a, b, tol)` | `assert abs(a - b) < tol` or `pytest.approx` | |\n| Catch2 | `pytest` | |\n| `unittest.mock` equivalent | PROHIBITED | Real implementations only |\n| AddressSanitizer | No equivalent (GC handles) | |\n| `clang-format` | `black` | |\n| `clang-tidy` / `cppcheck` | `ruff check .` | |\n| `valgrind` | Not needed | |\n\n## Build / CI\n\n```yaml\n# C++ (source):\n- run: cmake -B build && cmake --build build\n- run: ctest --test-dir build\n\n# Python (target):\n- run: pip install -r requirements.txt\n- run: pytest\n- run: mypy .\n- run: ruff check .\n- run: black --check .\n```\n\nFile v1.3.1:references/lang-pairs/go-python.md\n\n# Language Pair: Go → Python\n\n**Difficulty tier**: Low-Moderate (both GC; error model is the main structural shift)\n\n**Key differences**:\n- Memory: Both GC — no ownership to translate\n- Errors: Go multi-return `(T, error)` → Python exceptions\n- Types: Go static → Python `typing` (maintain all annotations)\n- Goroutines: Go goroutines → Python `asyncio` or `threading`\n- Interfaces: Go implicit interfaces → Python `Protocol`\n- Zero values: Go zero-initializes everything → Python has no zero values (use `None` or defaults)\n- Nil: Go `nil` → Python `None`\n- Multiple return values: Go `(A, B)` → Python `tuple[A, B]`\n\n---\n\n## Pre-Mapped Core Types\n\n| Go | Python | Equivalence | Notes |\n|---|---|---|---|\n| `int` / `int64` | `int` | behavioral | Python int is unbounded; document original width |\n| `int32` / `int16` / `int8` | `int` | behavioral | Add range comment |\n| `uint64` etc. | `int` | behavioral | Python has no unsigned; add `assert n >= 0` |\n| `float64` | `float` | structural | |\n| `float32` | `float` | behavioral | Python float is f64; precision widening |\n| `bool` | `bool` | structural | |\n| `string` | `str` | structural | |\n| `[]byte` | `bytes` | structural | |\n| `nil` | `None` | structural | |\n| `[]T` (slice) | `list[T]` | structural | |\n| `[N]T` (array) | `list[T]` or `tuple` | behavioral | Fixed-size; document N as invariant |\n| `map[K]V` | `dict[K, V]` | behavioral | Python preserves insertion order; Go map order is random |\n| `struct{}` (empty) | None / sentinel | structural | Used as set values in Go: `map[K]struct{}` → `set[K]` |\n| `map[K]struct{}` | `set[K]` | structural | |\n| `chan T` | `queue.Queue` | structural | |\n| `interface{}` / `any` | `Any` | structural | |\n\n---\n\n## Multiple Return Values → Tuple or Exception\n\nGo's most distinctive pattern: functions return `(value, error)`.\n\n**Go:**\n```go\nfunc divide(a, b float64) (float64, error) {\n    if b == 0 {\n        return 0, fmt.Errorf(\"division by zero\")\n    }\n    return a / b, nil\n}\n```\n\n**Python:**\n```python\ndef divide(a: float, b: float) -> float:\n    if b == 0:\n        raise ValueError(\"division by zero\")\n    return a / b\n```\n\n**Rule for `(T, error)` returns**:\n- When `error != nil`, the Go function signals failure → raise an exception in Python\n- When `error == nil`, the Go function succeeds → return the value (not a tuple)\n- NEVER translate `(T, error)` to `tuple[T, Optional[Exception]]` — that is not Pythonic and loses the exception flow\n\n**Rule for genuine multi-returns** (not error tuples):\n```go\nfunc minMax(data []int) (int, int) { ... }  // returns two values, no error\n```\n```python\ndef min_max(data: list[int]) -> tuple[int, int]: ...  # Python tuple return\n```\n\n---\n\n## Error Types → Exception Classes\n\n**Go:**\n```go\nvar ErrNotFound = errors.New(\"not found\")\n\ntype ValidationError struct {\n    Field   string\n    Message string\n}\nfunc (e *ValidationError) Error() string {\n    return fmt.Sprintf(\"validation error on %s: %s\", e.Field, e.Message)\n}\n```\n\n**Python:**\n```python\nclass NotFoundError(Exception): pass\n\nclass ValidationError(Exception):\n    def __init__(self, field: str, message: str) -> None:\n        self.field = field\n        self.message = message\n        super().__init__(f\"validation error on {field}: {message}\")\n```\n\n**Rule**: Each Go `var Err* = errors.New(...)` → Python exception class.\nEach Go error struct with `Error() string` → Python exception class with matching `__init__`.\n\n---\n\n## Interface → Protocol\n\n**Go:**\n```go\ntype Reader interface {\n    Read(p []byte) (n int, err error)\n}\ntype Writer interface {\n    Write(p []byte) (n int, err error)\n}\ntype ReadWriter interface {\n    Reader\n    Writer\n}\n```\n\n**Python:**\n```python\nfrom typing import Protocol\n\nclass Reader(Protocol):\n    def read(self, n: int) -> bytes: ...\n\nclass Writer(Protocol):\n    def write(self, data: bytes) -> int: ...\n\nclass ReadWriter(Reader, Writer, Protocol): ...\n```\n\nGo's implicit interface satisfaction → Python's structural `Protocol` (any class with matching methods satisfies it automatically).\n\n---\n\n## Struct → Class / Dataclass\n\n**Go:**\n```go\ntype Person struct {\n    Name string\n    Age  int\n    Tags []string\n}\n\nfunc NewPerson(name string, age int) *Person {\n    return &Person{Name: name, Age: age, Tags: []string{}}\n}\n\nfunc (p *Person) AddTag(tag string) {\n    p.Tags = append(p.Tags, tag)\n}\n```\n\n**Python:**\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass Person:\n    name: str\n    age: int\n    tags: list[str] = field(default_factory=list)\n\n    def add_tag(self, tag: str) -> None:\n        self.tags.append(tag)\n```\n\nUse `@dataclass` when the Go struct is a plain data container.\nUse a regular class when the struct has significant behavior.\n\n---\n\n## Zero Value Convention\n\nGo zero-initializes all variables (`0`, `\"\"`, `false`, `nil`, etc.).\nPython does not — explicitly set defaults in `__init__` or dataclass `field(default=...)`:\n\n```go\n// Go: declared but not initialized — has zero value\nvar count int      // 0\nvar name string    // \"\"\nvar active bool    // false\nvar items []int    // nil (but not the same as empty slice)\n```\n\n```python\n# Python: must be explicit\ncount: int = 0\nname: str = \"\"\nactive: bool = False\nitems: list[int] = []   # Note: [] != nil; Go's nil slice is distinct from empty\n# ZERO-VALUE NOTE: Go nil slice and empty slice behave identically for append/len/range.\n# Python list is equivalent to Go empty slice. No None needed.\n```\n\n---\n\n## Goroutines → asyncio / threading\n\n| Go pattern | Python equivalent | Notes |\n|---|---|---|\n| `go func(){}()` (fire and forget) | `asyncio.create_task(coro())` | Requires async context |\n| `go func(){}()` (CPU work) | `threading.Thread(target=fn).start()` | For CPU-bound parallel work |\n| `sync.WaitGroup` | `asyncio.gather()` or `threading.Barrier` | |\n| `chan T` (unbuffered) | `asyncio.Queue(maxsize=1)` | |\n| `chan T` (buffered, n) | `queue.Queue(maxsize=n)` | |\n| `select` statement | `asyncio.wait` with `FIRST_COMPLETED` | |\n| `sync.Mutex` | `threading.Lock()` | |\n| `sync.RWMutex` | `threading.RLock()` | |\n| `sync.Once` | `threading.Event()` | |\n| `context.Context` | pass cancellation flag or use `asyncio.CancelledError` | |\n\n---\n\n## Goroutine + Channel Pattern\n\n**Go:**\n```go\nfunc producer(ch chan<- int, max int) {\n    for i := 0; i < max; i++ {\n        ch <- i\n    }\n    close(ch)\n}\n```\n\n**Python (asyncio):**\n```python\nasync def producer(queue: asyncio.Queue[int], max_val: int) -> None:\n    for i in range(max_val):\n        await queue.put(i)\n    await queue.put(None)  # sentinel instead of close()\n```\n\n---\n\n## `defer` → Context Manager / `try/finally`\n\n**Go:**\n```go\nfunc processFile(path string) error {\n    f, err := os.Open(path)\n    if err != nil { return err }\n    defer f.Close()\n    // ... use f\n    return nil\n}\n```\n\n**Python:**\n```python\ndef process_file(path: str) -> None:\n    with open(path, 'r') as f:\n        # ... use f\n        pass  # f.close() called automatically by context manager\n```\n\nMultiple `defer`s (LIFO order) → nested `with` statements or `try/finally`:\n```python\ntry:\n    resource1 = acquire1()\n    try:\n        resource2 = acquire2()\n        # work\n    finally:\n        resource2.release()\nfinally:\n    resource1.release()\n```\n\n---\n\n## Ecosystem Gaps\n\n| Go | Gap | Python |\n|---|---|---|\n| `map` random iteration order | Python dict is ordered (3.7+) | No action needed; Python is stricter |\n| `[N]T` fixed-size array | Python list is dynamic | Use `list` with size invariant comment |\n| Method sets (pointer vs value receiver) | No distinction in Python | All methods are on the class |\n| `iota` in const blocks | No equivalent | Use `enum.auto()` or explicit values |\n| Build tags (`//go:build`) | No direct equivalent | Use environment variables or conditional imports |\n| `init()` functions | Module-level code in Python | Top-level statements in the module |\n| `go generate` | Custom scripts or `makefile` | |\n\n---\n\n## Naming Convention Conversion\n\n| Go | Python |\n|---|---|\n| `CamelCase` (exported) | `snake_case` |\n| `camelCase` (unexported) | `_snake_case` (private by convention) |\n| `MixedCaps` for acronyms (`HTTPServer`) | `http_server` |\n| Receiver name (`func (s *Server)`) | `self` |\n| Error variable `err` | Exception (no variable needed usually) |\n\n---\n\n## Testing Toolchain\n\n| Go | Python | Notes |\n|---|---|---|\n| `go test ./...` | `pytest` | |\n| `t.Errorf(...)` | `assert ...` or `pytest.fail(...)` | |\n| `t.Fatal(...)` | `pytest.fail(...)` or raise | |\n| Table-driven tests | `@pytest.mark.parametrize` | Very common Go pattern; direct equivalent |\n| Benchmark `b.N` | `pytest-benchmark` | |\n| `testing/mock` | PROHIBITED — real implementations only | |\n| `go vet` | `mypy .` | |\n| `gofmt` | `black .` | |\n| `golangci-lint` | `ruff check .` | |\n\n## Build / CI\n\n```yaml\n# Go (source):\n- run: go test ./...\n- run: go vet ./...\n\n# Python (target):\n- run: pip install -r requirements.txt\n- run: pytest\n- run: mypy .\n- run: ruff check .\n- run: black --check .\n```\n\nFile v1.3.1:references/lang-pairs/python-bun.md\n\n# Language Pair: Python → Bun (JavaScript with Bun Runtime)\n\n**Difficulty tier**: Moderate\n\n**Note on target**: \"Bun\" is a JavaScript/TypeScript runtime, not a language.\nThis module covers migration to **JavaScript** running on **Bun** (not Node.js).\nIf the target is TypeScript on Bun, use `python-typescript.md` instead.\nBun-specific APIs replace Node.js equivalents (file I/O, HTTP, subprocess).\n\n**Key differences**:\n- Memory model: Python GC / JS GC (similar; both automatic)\n- Type system: Python dynamic / JavaScript dynamic (no compile-time checks)\n- Error handling: Python exceptions / JS exceptions (throw/catch — very similar)\n- Async: Python asyncio / JS Promise + async/await (similar model)\n- Numbers: Python int is unbounded / JS uses float64 for all numbers (critical gap)\n- Modules: Python imports / JS ESM + CommonJS\n\n---\n\n## Pre-Mapped Core Types\n\n| Python | Bun (JS) | Equivalence | Notes |\n|---|---|---|---|\n| `int` (< 2^53) | `number` | structural | JS float64 can represent integers exactly up to 2^53 |\n| `int` (>= 2^53) | `BigInt` | structural | Use `BigInt(n)` or `n` suffix |\n| `float` | `number` | behavioral | Both IEEE 754 double; no separate int type |\n| `bool` | `boolean` | structural | |\n| `str` | `string` | structural | JS strings are UTF-16 internally; careful with emoji/surrogate pairs |\n| `bytes` | `Uint8Array` | structural | |\n| `None` | `null` / `undefined` | behavioral | Use `null` for explicit absence; `undefined` for unset |\n| `list[T]` | `Array` | structural | Dynamic arrays; no typed generics |\n| `dict[K,V]` | `Object` or `Map` | behavioral | Use `Map` when keys are non-string or when order matters |\n| `set[T]` | `Set` | structural | |\n| `tuple[A,B]` | `[A, B]` (array) or `{first, second}` | structural | Prefer destructured array |\n| `Optional[T]` | `T \\| null` | structural | |\n\n## Critical: Number Precision Gap\n\n**Python integers are unbounded. JavaScript `number` is IEEE 754 float64.**\n\nSafe integer range: `Number.MIN_SAFE_INTEGER` to `Number.MAX_SAFE_INTEGER` (±2^53 - 1).\n\nFor every integer operation in the IPO registry:\n1. Can the value exceed 2^53? → Use `BigInt`\n2. Is it used in bitwise operations? → JS bitwise ops truncate to 32-bit signed; use `BigInt` or explicit masking\n3. Is it used as an array index? → Safe (arrays limited to 2^32 elements)\n\n```js\n// Source: Python large int computation\n// Target: use BigInt\nconst result = BigInt(a) * BigInt(b);  // NOT: a * b (may lose precision)\n```\n\n## Standard Library / Bun APIs\n\n| Python | Bun | Equivalence | Notes |\n|---|---|---|---|\n| `os.path.join` | `path.join()` (node:path) | structural | `import { join } from 'node:path'` |\n| `os.listdir` | `fs.readdirSync()` or `Bun.readdir()` | structural | Prefer Bun native API |\n| `os.environ.get` | `process.env.KEY` | structural | |\n| `open(f, 'r')` | `Bun.file(path).text()` | structural | Bun API; returns Promise |\n| `open(f, 'rb')` | `Bun.file(path).arrayBuffer()` | structural | |\n| `json.dumps` | `JSON.stringify` | structural | |\n| `json.loads` | `JSON.parse` | structural | |\n| `re.compile` | `new RegExp(pattern)` | structural | |\n| `hashlib.sha256` | `new Bun.CryptoHasher('sha256')` | structural | Bun native |\n| `time.time()` | `Date.now() / 1000` | structural | Returns float seconds |\n| `random.random()` | `Math.random()` | behavioral | Different algorithm; not seedable in standard JS |\n| `random.seed` | NO EQUIVALENT in standard JS | GAP | Use `seedrandom` npm package for reproducible RNG |\n| `subprocess.run` | `Bun.spawn()` | structural | Bun native subprocess API |\n| `logging` | `console.log/warn/error` | structural | Or `pino` for structured logging |\n| `argparse` | `Bun.argv` + manual parsing or `yargs` | structural | |\n\n## Error Handling Pattern\n\nPython exceptions map directly to JS throw/catch:\n\n**Python:**\n```python\ndef parse_int(s: str) -> int:\n    try:\n        return int(s)\n    except ValueError:\n        raise ParseError(f\"invalid int: {s}\")\n```\n\n**Bun (JS):**\n```js\nclass ParseError extends Error {\n    constructor(msg) { super(msg); this.name = 'ParseError'; }\n}\n\nfunction parseInt(s) {\n    const n = Number(s);\n    if (!Number.isInteger(n) || isNaN(n)) {\n        throw new ParseError(`invalid int: ${s}`);\n    }\n    return n;\n}\n```\n\n**Rule**: Each Python exception class → JS class extending `Error`. Each `raise ExType(msg)` → `throw new ExType(msg)`. Each `except ExType:` → `catch(e) { if (e instanceof ExType) { ... } }`.\n\n## Async Pattern\n\n**Python:**\n```python\nasync def fetch_data(url: str) -> bytes:\n    async with aiohttp.ClientSession() as session:\n        async with session.get(url) as response:\n            return await response.read()\n```\n\n**Bun:**\n```js\nasync function fetchData(url) {\n    const response = await fetch(url);  // Bun has native fetch\n    return new Uint8Array(await response.arrayBuffer());\n}\n```\n\n## Class → Class (ES6)\n\nPython classes map directly to ES6 classes:\n\n**Python:**\n```python\nclass Counter:\n    def __init__(self, start: int = 0):\n        self._count = start\n    def increment(self):\n        self._count += 1\n    def value(self) -> int:\n        return self._count\n```\n\n**JS:**\n```js\nclass Counter {\n    #count;  // private field (ES2022)\n    constructor(start = 0) {\n        this.#count = start;\n    }\n    increment() {\n        this.#count += 1;\n    }\n    value() {\n        return this.#count;\n    }\n}\n```\n\n## Anti-Patterns\n\n| Wrong | Why | Correct |\n|---|---|---|\n| `==` for equality | JS `==` coerces types | Always use `===` |\n| `parseInt(s)` (JS builtin) | Has different semantics from Python `int()` | Use `Number(s)` + `Number.isInteger` check |\n| Treating `0`, `\"\"`, `null` as false uniformly | JS falsy rules differ from Python | Explicit: `value === null`, `value === 0` |\n| `for...in` on arrays | Iterates keys (string indices) | Use `for...of` or `.forEach` |\n| Not handling Promise rejections | Silent failures | Always `await` or `.catch()` |\n\n## Ecosystem Gaps\n\n| Python | Gap | Compensation |\n|---|---|---|\n| Seedable RNG | `Math.random()` not seedable | `npm install seedrandom`; `const rng = new seedrandom(seed)` |\n| `dict` preserves order | `Object` order is implementation-defined for non-string keys | Use `Map` for reliable insertion order |\n| `int` unbounded | `number` loses precision >2^53 | Use `BigInt` where needed |\n| `bytes` mutable | `Uint8Array` is mutable; string is immutable | Use `Uint8Array` for mutable byte work |\n\n## Testing Toolchain\n\n| Python | Bun | Notes |\n|---|---|---|\n| `pytest` | `bun test` | Built-in; `test(\"name\", () => { ... })` |\n| `pytest.raises` | `expect(() => fn()).toThrow(ErrorClass)` | |\n| `unittest.mock` | PROHIBITED | Real implementations only |\n| `mypy` | N/A (dynamic JS) | Use TypeScript for type checking |\n| `black` | `bun run prettier --write .` | |\n\n## Build / CI\n\n```yaml\n# Python:\n- run: pytest\n\n# Bun:\n- run: bun install\n- run: bun test\n```\n\nFile v1.3.1:references/lang-pairs/python-c.md\n\n# Language Pair: Python → C\n\n**Difficulty tier**: High (manual memory, no stdlib collections, no exceptions)\n\n**Key differences**:\n- Memory model: Python GC / C manual malloc/free\n- Type system: Python dynamic / C static, weak, implicit coercion\n- Error handling: Python exceptions / C return codes + errno\n- OOP: Python classes / C structs + function pointers\n- Strings: Python str (unicode) / C null-terminated char arrays (encoding is caller's problem)\n- Overflow: Python int unbounded / C integer overflow is undefined behavior\n\n---\n\n## Pre-Mapped Core Types\n\n| Python | C | Equivalence | Notes |\n|---|---|---|---|\n| `int` (small) | `int64_t` | behavioral | Use stdint.h types always; never plain `int` |\n| `int` (large) | `__int128` or GMP `mpz_t` | behavioral | GMP library for truly arbitrary precision |\n| `float` | `double` | structural | Both IEEE 754 double |\n| `bool` | `bool` (stdbool.h) | structural | |\n| `str` | `char *` + length | behavioral | ALWAYS carry length separately; never assume null-term is safe |\n| `bytes` | `uint8_t *` + size | structural | |\n| `None` | `NULL` pointer | structural | Context-dependent |\n| `list[T]` | `T *` + length + capacity | structural | Implement as dynamic array struct |\n| `dict[K,V]` | hash table struct | structural | Use uthash or implement from scratch |\n| `Optional[T]` | pointer (NULL = absent) | structural | |\n\n## Critical: Memory Ownership Protocol\n\nEvery function that returns a pointer MUST document who owns it:\n```c\n// OWNED: caller must free()\nchar *create_string(const char *src);\n\n// BORROWED: do not free; lifetime tied to container\nconst char *get_name(const Person *p);\n```\n\nMap Python's implicit GC to explicit ownership. For every source object:\n1. Where is it created? → `malloc`\n2. Where is it consumed/destroyed? → `free`\n3. Is it shared? → reference counting struct or copy\n\n## Error Handling Pattern\n\n**Python:**\n```python\ndef parse_int(s: str) -> int:\n    try:\n        return int(s)\n    except ValueError:\n        raise ParseError(f\"invalid int: {s}\")\n```\n\n**C:**\n```c\ntypedef enum { PARSE_OK = 0, PARSE_ERROR_INVALID = 1 } ParseResult;\n\nParseResult parse_int(const char *s, int64_t *out) {\n    char *end;\n    errno = 0;\n    *out = strtoll(s, &end, 10);\n    if (errno != 0 || *end != '\\0') {\n        return PARSE_ERROR_INVALID;\n    }\n    return PARSE_OK;\n}\n```\n\n**Rule**: Every Python exception type becomes a C enum value. Every `try` block becomes a caller checking the return code.\n\n## Class → Struct + Function Pointers\n\n**Python:**\n```python\nclass Buffer:\n    def __init__(self, capacity: int):\n        self.data = bytearray(capacity)\n        self.size = 0\n    def push(self, byte: int):\n        self.data[self.size] = byte\n        self.size += 1\n```\n\n**C:**\n```c\ntypedef struct {\n    uint8_t *data;\n    size_t   size;\n    size_t   capacity;\n} Buffer;\n\nBuffer *buffer_create(size_t capacity) {\n    Buffer *b = malloc(sizeof(Buffer));\n    b->data = malloc(capacity);\n    b->size = 0;\n    b->capacity = capacity;\n    return b;\n}\n\nvoid buffer_push(Buffer *b, uint8_t byte) {\n    b->data[b->size++] = byte;\n}\n\nvoid buffer_destroy(Buffer *b) {\n    free(b->data);\n    free(b);\n}\n```\n\n**Rule**: Every Python class becomes a C struct + a set of `typename_verb` functions. Constructor → `_create`. Destructor → `_destroy` (always required).\n\n## Anti-Patterns\n\n| Wrong | Why | Correct |\n|---|---|---|\n| Plain `int` / `long` | Width is platform-dependent | Use `int32_t`, `int64_t` from stdint.h |\n| `gets()`, `strcpy()` without bounds | Buffer overflow | Use `fgets()`, `strncpy()` with explicit sizes |\n| Ignoring malloc return value | Null dereference on OOM | Always check: `if (!ptr) { ... }` |\n| Global mutable state for \"class\" state | Not thread-safe, not structural | Pass struct pointer explicitly |\n| Signed integer overflow | Undefined behavior in C | Use `__builtin_add_overflow` or cast to unsigned for wrap |\n\n## Ecosystem Gaps\n\n| Python | Gap | Compensation |\n|---|---|---|\n| Dynamic `list` | No stdlib equivalent | Use dynamic array pattern (data+size+capacity struct) |\n| `dict` | No stdlib equivalent | Use `uthash` library or implement open-addressing hash table |\n| `str.split/join/format` | No stdlib equivalent | Use `strtok_r`, manual formatting, or `asprintf` |\n| Exception traceback | No equivalent | Log error context manually at each return site |\n| GC | No equivalent | Explicit malloc/free; document ownership in every function |\n| `random` | `rand()` (low quality) | Use `arc4random()` or a seeded PRNG struct |\n\n## Testing Toolchain\n\n| Python | C | Notes |\n|---|---|---|\n| `pytest` | `cmocka` or `Unity` | |\n| `pytest.raises` | Check return code in test | |\n| `unittest.mock` | PROHIBITED | Real implementations only |\n| `mypy` | `-Wall -Wextra -Wpedantic` | |\n| `black` | `clang-format` | `.clang-format` config file |\n| Valgrind | memory error detector | Required: run all tests under `valgrind --leak-check=full` |\n\n## Build System\n\n```makefile\n# Adapt from Python's build system to:\nCC = gcc\nCFLAGS = -std=c11 -Wall -Wextra -Wpedantic -O2\nLDFLAGS = -lm\n\nall: $(TARGET)\ntest: $(TEST_TARGET)\n    valgrind --leak-check=full ./$(TEST_TARGET)\n```\n\n## CI Adaptation\n\n```yaml\n# Python:\n- run: pytest\n\n# C:\n- run: make test\n- run: valgrind --leak-check=full --error-exitcode=1 ./test_runner\n```\n\nFile v1.3.1:references/lang-pairs/python-cpp.md\n\n# Language Pair: Python → C++\n\n**Difficulty tier**: High (manual memory optional via RAII, template metaprogramming, multiple inheritance)\n\n**Key differences**:\n- Memory model: Python GC / C++ RAII (prefer) + manual (avoid)\n- Type system: Python dynamic / C++ static with templates + concepts (C++20)\n- Error handling: Python exceptions / C++ exceptions (use them) or `std::expected` (C++23)\n- OOP: Python single-dispatch classes / C++ full OOP with templates\n- Strings: Python str / `std::string` (value semantics, UTF-8 by convention)\n- STL: C++ has rich stdlib collections; closest to Python\n\n**Key advantage over C**: RAII eliminates most memory management complexity. C++ stdlib is close to Python's in richness.\n\n---\n\n## Pre-Mapped Core Types\n\n| Python | C++ | Equivalence | Notes |\n|---|---|---|---|\n| `int` | `int64_t` | behavioral | Use `<cstdint>` |\n| `float` | `double` | structural | |\n| `bool` | `bool` | structural | |\n| `str` | `std::string` | structural | |\n| `bytes` | `std::vector<uint8_t>` | structural | |\n| `None` | `std::nullptr_t` / `std::optional` | structural | |\n| `list[T]` | `std::vector<T>` | structural | |\n| `tuple[A,B]` | `std::tuple<A,B>` or `std::pair` | structural | |\n| `dict[K,V]` | `std::unordered_map<K,V>` | behavioral | Order not preserved |\n| `collections.OrderedDict` | No stdlib equivalent → use insertion-ordered map | behavioral | Implement or use third-party |\n| `set[T]` | `std::unordered_set<T>` | structural | |\n| `Optional[T]` | `std::optional<T>` | structural | C++17 |\n| `deque` | `std::deque<T>` | structural | |\n| `heapq` | `std::priority_queue` | structural | Note: max-heap by default; Python is min-heap |\n\n## Standard Library Mapping\n\n| Python | C++ | Equivalence | Notes |\n|---|---|---|---|\n| `os.path.join` | `std::filesystem::path` (C++17) | structural | |\n| `os.listdir` | `std::filesystem::directory_iterator` | structural | |\n| `os.environ.get` | `std::getenv` | structural | |\n| `open(f)` | `std::ifstream` / `std::ofstream` | structural | |\n| `json` | `nlohmann/json` | structural | Header-only, widely used |\n| `re` | `std::regex` | structural | |\n| `hashlib` | OpenSSL or Crypto++ | structural | |\n| `time.time()` | `std::chrono::system_clock::now()` | structural | |\n| `random.random()` | `std::mt19937` + `uniform_real_distribution` | behavioral | Different RNG |\n| `threading.Thread` | `std::thread` | structural | |\n| `asyncio` | `std::coroutine` + executor (C++20) or Boost.Asio | structural | |\n| `logging` | `spdlog` | structural | |\n| `argparse` | `CLI11` or `argparse` header | structural | |\n\n## Common Third-Party Libraries\n\n| Python | C++ | Equivalence | Notes |\n|---|---|---|---|\n| `numpy` | Eigen or xtensor | behavioral | API differs; structural at algorithm level |\n| `requests` | libcurl or cpp-httplib | structural | |\n| `pytest` | Google Test (`gtest`) or Catch2 | structural | |\n| `pydantic` | struct + nlohmann/json | structural | |\n| `click` | CLI11 | structural | |\n\n---\n\n## Error Handling\n\nC++ exceptions mirror Python exceptions most closely among systems languages:\n\n**Python:**\n```python\ndef read_file(path: str) -> str:\n    try:\n        with open(path) as f:\n            return f.read()\n    except FileNotFoundError:\n        raise IOError(f\"not found: {path}\")\n```\n\n**C++:**\n```cpp\nstd::string read_file(const std::string& path) {\n    std::ifstream f(path);\n    if (!f.is_open()) {\n        throw std::runtime_error(\"not found: \" + path);\n    }\n    return std::string(std::istreambuf_iterator<char>(f),\n                       std::istreambuf_iterator<char>());\n}\n```\n\n**Rule**: Python exception types → C++ exception types. One `except` clause = one `catch` clause. Do NOT flatten all exceptions into a generic `std::exception`.\n\n## Class → Class (with RAII)\n\n**Python:**\n```python\nclass FileReader:\n    def __init__(self, path: str):\n        self.f = open(path, 'rb')\n    def read_chunk(self, n: int) -> bytes:\n        return self.f.read(n)\n    def __del__(self):\n        self.f.close()\n```\n\n**C++:**\n```cpp\nclass FileReader {\n    std::ifstream f_;\npublic:\n    explicit FileReader(const std::string& path) {\n        f_.open(path, std::ios::binary);\n        if (!f_.is_open()) throw std::runtime_error(\"cannot open: \" + path);\n    }\n    // Destructor automatic via RAII — std::ifstream closes on destruction\n    std::vector<uint8_t> read_chunk(size_t n) {\n        std::vector<uint8_t> buf(n);\n        f_.read(reinterpret_cast<char*>(buf.data()), n);\n        buf.resize(f_.gcount());\n        return buf;\n    }\n};\n```\n\n## heapq Direction (Critical Gap)\n\nPython `heapq` is a **min-heap**. `std::priority_queue` is a **max-heap**.\n\n```cpp\n// Min-heap in C++ (mirrors Python heapq):\nstd::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;\n```\n\nAlways check the IPO registry's `process.steps` to confirm the heap direction before translating.\n\n## Anti-Patterns\n\n| Wrong | Why | Correct |\n|---|---|---|\n| Raw `new`/`delete` | RAII is available; use it | `std::unique_ptr` / `std::shared_ptr` |\n| `std::map` when Python used dict | `std::map` is sorted (O log n) | `std::unordered_map` for Python dict |\n| Catching `...` everywhere | Loses exception semantics | Catch specific types matching Python's excepts |\n| Using `#define` for constants | Not type-safe | `constexpr` |\n| Implicit `int` narrowing | Undefined behavior | Explicit cast with range check |\n\n## Testing Toolchain\n\n| Python | C++ | Notes |\n|---|---|---|\n| `pytest` | Google Test or Catch2 | |\n| `pytest.raises` | `EXPECT_THROW(expr, ExceptionType)` | |\n| `unittest.mock` | PROHIBITED | Real implementations only |\n| `mypy` | Compiler + `-Wall -Wextra` | |\n| `black` | `clang-format` | |\n| Valgrind | AddressSanitizer (`-fsanitize=address`) | Build with: `-fsanitize=address,undefined` |\n\n## Build System (CMake)\n\n```cmake\n# CMakeLists.txt target structure\ncmake_minimum_required(VERSION 3.20)\nproject(<name> CXX)\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\nadd_compile_options(-Wall -Wextra -Wpedantic)\n\n# Test target\nenable_testing()\nfind_package(GTest REQUIRED)\nadd_executable(tests <test_files>)\ntarget_link_libraries(tests GTest::gtest_main)\nadd_test(NAME unit COMMAND tests)\n```\n\n## CI Adaptation\n\n```yaml\n# Python:\n- run: pytest\n\n# C++:\n- run: cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS=\"-fsanitize=address,undefined\"\n- run: cmake --build build\n- run: ctest --test-dir build --output-on-failure\n```\n\nFile v1.3.1:references/lang-pairs/python-go.md\n\n# Language Pair: Python → Go\r\n\r\n**Difficulty tier**: Moderate\r\n\r\n**Key differences**:\r\n- Memory model: Python GC / Go GC (similar; no ownership tracking needed)\r\n- Type system: Python dynamic / Go static with interfaces (no generics before 1.18)\r\n- Error handling: Python exceptions / Go multi-return `value, error`\r\n- Concurrency: Python GIL+asyncio / Go goroutines+channels\r\n- OOP: Python classes / Go structs + interfaces (no inheritance)\r\n- Nullability: Python `None` / Go nil + zero values\r\n\r\n---\r\n\r\n## Pre-Mapped Core Types\r\n\r\n| Python | Go | Equivalence | Notes |\r\n|---|---|---|---|\r\n| `int` | `int64` | behavioral | Go int is platform-width; use int64 explicitly for portability |\r\n| `float` | `float64` | structural | Both IEEE 754 double |\r\n| `bool` | `bool` | structural | |\r\n| `str` | `string` | structural | Go strings are immutable byte sequences (UTF-8) |\r\n| `bytes` | `[]byte` | structural | |\r\n| `None` | `nil` | structural | Context-dependent (nil pointer, nil interface, nil slice) |\r\n| `list[T]` | `[]T` (slice) | structural | |\r\n| `tuple[A,B]` | struct with fields | structural | Go has no anonymous tuples (use named struct) |\r\n| `dict[K,V]` | `map[K]V` | behavioral | Go map iteration order is randomized intentionally |\r\n| `set[T]` | `map[T]struct{}` | structural | |\r\n| `Optional[T]` | `*T` or `(T, bool)` | structural | Use pointer for optional struct; bool pair for optional value |\r\n\r\n## Standard Library Mapping\r\n\r\n| Python | Go | Equivalence | Notes |\r\n|---|---|---|---|\r\n| `os.path.join` | `filepath.Join` | structural | |\r\n| `os.listdir` | `os.ReadDir` | structural | |\r\n| `os.environ.get` | `os.Getenv` | structural | |\r\n| `open(f)` | `os.Open` | structural | |\r\n| `json.dumps` | `json.Marshal` | structural | |\r\n| `json.loads` | `json.Unmarshal` | structural | |\r\n| `re.compile` | `regexp.MustCompile` | structural | |\r\n| `hashlib.sha256` | `crypto/sha256` | structural | |\r\n| `time.time()` | `time.Now().Unix()` | structural | |\r\n| `random.random()` | `rand.Float64()` | behavioral | Different algorithm |\r\n| `threading.Thread` | `go func(){}()` | structural | Goroutines are lighter |\r\n| `asyncio` | goroutines + channels | structural | Different model but same concurrency goals |\r\n| `subprocess.run` | `exec.Command` | structural | |\r\n| `logging` | `log` or `zap` | structural | |\r\n| `argparse` | `flag` or `cobra` | structural | |\r\n\r\n## Common Third-Party Libraries\r\n\r\n| Python | Go | Equivalence | Notes |\r\n|---|---|---|---|\r\n| `requests` | `net/http` (stdlib) | structural | No third-party needed |\r\n| `sqlalchemy` | `database/sql` + driver | structural | |\r\n| `pydantic` | struct + `encoding/json` tags | structural | |\r\n| `click` | `cobra` | structural | |\r\n| `pytest` | `testing` package (stdlib) | structural | |\r\n| `numpy` | `gonum.org/v1/gonum` | behavioral | API differs significantly |\r\n\r\n---\r\n\r\n## Error Handling Pattern\r\n\r\n**Python:**\r\n```python\r\ndef read_file(path: str) -> str:\r\n    try:\r\n        with open(path) as f:\r\n            return f.read()\r\n    except FileNotFoundError:\r\n        raise IOError(f\"not found: {path}\")\r\n```\r\n\r\n**Go:**\r\n```go\r\nfunc readFile(path string) (string, error) {\r\n    data, err := os.ReadFile(path)\r\n    if err != nil {\r\n        return \"\", fmt.Errorf(\"not found: %s: %w\", path, err)\r\n    }\r\n    return string(data), nil\r\n}\r\n```\r\n\r\n**Rule**: Every `try/except` block becomes a multi-return function. Each `except` clause becomes an `if err != nil` block. Maintain 1:1 mapping.\r\n\r\n---\r\n\r\n## Class → Struct + Interface\r\n\r\n**Python:**\r\n```python\r\nclass Storage:\r\n    def __init__(self, path: str):\r\n        self.path = path\r\n    def read(self, key: str) -> bytes:\r\n        ...\r\n    def write(self, key: str, data: bytes):\r\n        ...\r\n```\r\n\r\n**Go:**\r\n```go\r\ntype Storage interface {\r\n    Read(key string) ([]byte, error)\r\n    Write(key string, data []byte) error\r\n}\r\n\r\ntype FileStorage struct {\r\n    path string\r\n}\r\n\r\nfunc NewFileStorage(path string) *FileStorage {\r\n    return &FileStorage{path: path}\r\n}\r\n\r\nfunc (s *FileStorage) Read(key string) ([]byte, error) { ... }\r\nfunc (s *FileStorage) Write(key string, data []byte) error { ... }\r\n```\r\n\r\n---\r\n\r\n## Anti-Patterns\r\n\r\n| Wrong | Why | Correct |\r\n|---|---|---|\r\n| `interface{}` for everything | Loses type safety | Use concrete types or generics (Go 1.18+) |\r\n| Ignoring returned errors `_` | Hides Python exception flow | Always handle; match Python's except structure |\r\n| Using `panic` for logic errors | Not equivalent to exceptions | Use error returns |\r\n| Global `init()` for class-level state | Hides initialization order | Use explicit constructor functions |\r\n\r\n---\r\n\r\n## ⛔ Known Migration Traps (Python → Go)\r\n\r\nThese patterns have historically caused structural drift that survived compilation and basic testing.\r\n**Read this section before beginning P4 translation.** Check each trap against the IPO registry\r\nfor the function being translated before writing a single line of Go.\r\n\r\n---\r\n\r\n### Trap 1: Post-Construction Attribute Setting\r\n\r\n**Python pattern:**\r\n```python\r\nagent = start_subagent(config)\r\nagent.inc_out = True    # line 47 — NOT inside start_subagent()\r\nagent.verbose = False   # line 48 — NOT inside start_subagent()\r\n```\r\n\r\n**Failure mode**: The Go `NewSubagent()` constructor does not set `IncOut = true` or `Verbose = false`\r\nbecause those lines appear in the **caller**, not in the callee. If P3 only documented `start_subagent`,\r\nthese assignments are invisible. The Go struct uses zero-value defaults (`false` for bool),\r\nwhich is silently wrong.\r\n\r\n**Detection**: Before translating any constructor/factory function, read **all call sites**.\r\nLook for `obj.attr = X` immediately after the call. These belong in the caller's `side_effects`\r\nin the IPO registry.\r\n\r\n**Fix protocol**:\r\n1. In `start_subagent`'s IPO entry: add `translation_notes` warning callers to set these fields\r\n2. In the caller's IPO entry: list in `side_effects`: `\"sets agent.inc_out = True [line 47]\"`\r\n3. In Go: set the fields in the caller after construction, matching the Python line-for-line\r\n\r\n**Root cause category**: `side_effect_dropped`\r\n\r\n---\r\n\r\n### Trap 2: Multi-Branch Turn-Based Callbacks\r\n\r\n**Python pattern (abbreviated):**\r\n```python\r\ndef on_turn_end(turn: int, mode: str):\r\n    if turn % 65 == 0 and mode != \"plan\":  # branch A\r\n        ask_user(...)\r\n    elif mode == \"plan\" and turn % 5 == 0 and turn >= 10:  # branch B\r\n        prompt_plan_review(...)\r\n    if turn > 90 and mode == \"plan\":       # branch C — separate if, not elif\r\n        force_ask_user(...)\r\n```\r\n\r\n**Failure mode**: Go translation merges branches B and C into one `else if`, or uses a single\r\n`if/else if/else` chain when the Python uses two separate `if` blocks. The 90-turn forced\r\ncallback then never fires independently of the 5-turn cadence.\r\n\r\n**Detection rule**: Count `if/elif/else/for/while` branches in the Python body.\r\nThe number of `step` entries in the IPO registry must equal or exceed this count (READ_EVIDENCE\r\n`branch_count` field). If the Go translation has fewer `if` blocks than the Python, branches are collapsed.\r\n\r\n**Magic number check**: For functions with `type: iteration_limit` magic numbers (65, 5, 10, 90),\r\nboundary-value testing (N-1, N, N+1) is mandatory in P5 — see phase-5-verification.md.\r\n\r\n**Root cause category**: `control_flow_collapsed`\r\n\r\n---\r\n\r\n### Trap 3: Compound Processing with Conditional Secondary Transform\r\n\r\n**Python pattern:**\r\n```python\r\ndef fetch_content(url: str, text_only: bool, maxlen: int) -> str:\r\n    content = get_html(url, text_only=True)       # primary fetch\r\n    if text_only:\r\n        content = smart_format(content, maxlen // 3)  # secondary truncation\r\n    return content\r\n```\r\n\r\n**Failure mode**: Go translation implements the primary fetch but omits the secondary\r\n`smart_format` call because it appears as a one-line conditional after the main logic.\r\nResult: content is 3× longer than expected in text_only mode.\r\n\r\n**Detection**: In the IPO `process.steps`, any step whose `desc` starts with \"If [flag]:\" after\r\na primary operation is a **mandatory separate step** — not optional commentary.\r\nCount steps in the IPO entry. If the Go function body has fewer conditional blocks than steps,\r\nsecondary transforms have been dropped.\r\n\r\n**Magic number check**: `maxlen // 3` is a `magic_number` of type `threshold`. It must appear\r\nas a named constant in Go — not as `maxlen/3` inline without a name.\r\n\r\n**Root cause category**: `control_flow_collapsed` (secondary) + `magic_number_decontextualized` (constant)\r\n\r\n---\r\n\r\n### Trap 4: dict Ordering\r\n\r\n**Python pattern:**\r\n```python\r\nresult = {}\r\nfor key in sorted_keys:\r\n    result[key] = compute(key)\r\nreturn result   # dict preserves insertion order (Python 3.7+)\r\n```\r\n\r\n**Failure mode**: Go `map[string]T` iterates in randomized order. Any downstream code\r\nthat depends on the iteration order of this map will produce non-deterministic results.\r\n\r\n**Compensation**: Use `github.com/elliotchance/orderedmap` or return `[]Entry` (key-value slice)\r\nwhere Python dict insertion order is semantically important.\r\n\r\n**Detection**: Check if the function's callers iterate the dict in order, compare order-dependent\r\noutputs (e.g., joined strings, ranked lists). If yes, ordered map is required.\r\n\r\n**Root cause category**: `ecosystem_gap_unapplied`\r\n\r\n---\r\n\r\n### Trap 5: Implicit Model Capability Assumption in Agent/LLM Integrations\r\n\r\n**Python pattern:**\r\n```python\r\n# conductor.py:277-279 — design assumes consumer (Claude) will infer to call GET /chat\r\nunread = sum(1 for m in chat_messages if m.get(\"role\") == \"user\" and not m.get(\"read\"))\r\nsummary = f\"... | {unread}条用户未读消息, ...\"\r\n# No explicit instruction to fetch messages — Claude infers it from context\r\n```\r\n\r\n**Failure mode**: The Go translation faithfully replicates `conductorPrompt` (count-only). This is\r\n**correct** — the function is not the bug. The bug is that the Go deployment runs a smaller model\r\n(e.g., Qwen3.5) that does not implicitly infer \"when unread > 0, call GET /chat first.\"\r\nThe first Copilot \"fix\" (embedding message body directly) was wrong — it changed the source design.\r\n\r\n**The correct investigation path**:\r\n1. **T1**: Does Go `conductorPrompt` match Python `conductor.py:277-279`? → YES → source-faithful\r\n2. **T2**: Read `conductor.py:277-279` — source only passes count → source_matches_target: true\r\n3. **T3**: Check consumer path — does the system prompt have a `code_run` example for `GET /chat`? Does it have an explicit trigger rule? → NO → `IMPLICIT_CAPABILITY_ASSUMPTION`\r\n4. **Fix**: Add `GET /chat?last=20` code_run example + explicit \"when unread > 0, call GET /chat first\" rule to the system prompt. **Do not change `conductorPrompt` logic.**\r\n\r\n**Detection**: Look for IPO entries where `inferred_invariants` should include capability assumptions:\r\n```yaml\r\ninferred_invariants:\r\n  - \"consumer LLM can infer from unread count that it must call GET /chat to read content\r\n     [inferred from: no explicit fetch instruction in Python prompt; source used Claude]\"\r\n```\r\nWhen porting to a smaller model, every inferred invariant of this type requires an explicit\r\ninstruction or code_run example in the target system prompt.\r\n\r\n**Root cause category**: `implicit_capability_assumption`\r\n\r\n## Ecosystem Gaps\r\n\r\n| Python | Gap | Compensation |\r\n|---|---|---|\r\n| `dict` preserves order (3.7+) | `map` order randomized | Use `github.com/elliotchance/orderedmap` |\r\n| Negative indices `arr[-1]` | Panics | Use `arr[len(arr)-1]` |\r\n| `**kwargs` | No equivalent | Use variadic `options ...Option` pattern or struct |\r\n| `@property` decorator | No equivalent | Use getter/setter methods |\r\n\r\n## Testing Toolchain\r\n\r\n| Python | Go | Notes |\r\n|---|---|---|\r\n| `pytest` | `go test ./...` | Built-in |\r\n| `pytest.raises` | `if err == nil { t.Fatal(...) }` | |\r\n| `unittest.mock` | `testify/mock` (or no mock — prohibited) | No mocks; use real implementations |\r\n| `mypy` | `go vet` + compiler | |\r\n| `black` | `gofmt` | Run: `gofmt -w .` |\r\n| `pytest-benchmark` | `b.N` benchmark functions | |\r\n\r\n## Build / CI\r\n\r\n```yaml\r\n# Source (Python):\r\n- run: pip install -r requirements.txt && pytest\r\n\r\n# Target (Go):\r\n- run: go test ./...\r\n- run: go vet ./...\r\n- run: gofmt -l . | grep . && exit 1 || true\r\n```\n\nFile v1.3.1:references/lang-pairs/python-rust.md\n\n# Language Pair: Python → Rust\n\n**Difficulty tier**: High (paradigm leap — GC+dynamic vs ownership+static)\n\n**Key differences**:\n- Memory model: Python uses GC + reference counting / Rust uses ownership + borrow checker\n- Type system: Python is dynamically typed / Rust is statically typed with generics + traits\n- Error handling: Python raises exceptions / Rust uses `Result<T, E>` and `Option<T>`\n- Concurrency: Python has GIL / Rust has fearless concurrency with Send+Sync\n- Nullability: Python uses `None` / Rust uses `Option<T>`\n\n---\n\n## Pre-Mapped Core Types\n\n| Python Type | Rust Type | Equivalence | Notes |\n|---|---|---|---|\n| `int` (small) | `i64` | behavioral | Python int is unbounded; audit for values > i64::MAX |\n| `int` (big) | `num_bigint::BigInt` | structural | `num-bigint` crate |\n| `float` | `f64` | structural | Both IEEE 754 double |\n| `bool` | `bool` | structural | |\n| `str` | `String` / `&str` | structural | Rust distinguishes owned vs borrowed |\n| `bytes` | `Vec<u8>` / `&[u8]` | structural | |\n| `None` | `Option<T>::None` | structural | |\n| `list[T]` | `Vec<T>` | structural | |\n| `tuple[A, B]` | `(A, B)` | structural | |\n| `dict[K, V]` | `HashMap<K, V>` | behavioral | HashMap order is random; use `IndexMap` if order matters |\n| `set[T]` | `HashSet<T>` | structural | |\n| `collections.OrderedDict` | `IndexMap<K, V>` | structural | `indexmap` crate |\n| `collections.deque` | `VecDeque<T>` | structural | |\n| `collections.Counter` | `HashMap<T, usize>` | structural | |\n| `typing.Optional[T]` | `Option<T>` | structural | |\n| `typing.Union[A, B]` | `enum` with variants | structural | |\n\n## Numeric Precision — Critical\n\n| Python | Rust | Delta | Action |\n|---|---|---|---|\n| `int` division `//` | integer `/` | none | Both truncate toward zero |\n| `int` division `/` | `as f64` then `/` | none | Python `/` on ints returns float |\n| `float` | `f64` | none | Identical IEEE 754 |\n| `float('inf')` | `f64::INFINITY` | none | |\n| `float('nan')` | `f64::NAN` | none | |\n| Integer overflow | `i64` panics in debug, wraps in release | CRITICAL | Use `checked_add`, `saturating_add`, or `wrapping_add` explicitly |\n\n---\n\n## Standard Library Mapping\n\n| Python | Rust | Package | Equivalence | Notes |\n|---|---|---|---|---|\n| `os.path.join` | `std::path::Path::join` | std | structural | |\n| `os.listdir` | `std::fs::read_dir` | std | structural | Returns iterator |\n| `os.environ.get` | `std::env::var` | std | structural | Returns `Result` not `Option` |\n| `open(f, 'rb')` | `std::fs::File::open` | std | structural | |\n| `json.dumps` | `serde_json::to_string` | serde_json | structural | |\n| `json.loads` | `serde_json::from_str` | serde_json | structural | |\n| `re.compile` | `regex::Regex::new` | regex | structural | |\n| `hashlib.sha256` | `sha2::Sha256` | sha2 | structural | |\n| `time.time()` | `std::time::SystemTime::now()` | std | structural | |\n| `random.random()` | `rand::random::<f64>()` | rand | behavioral | Different RNG algorithm |\n| `random.seed(n)` | `StdRng::seed_from_u64(n)` | rand | behavioral | Different RNG algorithm; output sequence differs |\n| `threading.Thread` | `std::thread::spawn` | std | structural | No GIL; true parallelism |\n| `asyncio` | `tokio` | tokio | structural | Different runtime; async/await syntax identical |\n| `subprocess.run` | `std::process::Command` | std | structural | |\n| `sys.argv` | `std::env::args()` | std | structural | |\n| `logging` | `tracing` or `log` + `env_logger` | tracing | structural | |\n| `argparse` | `clap` | clap | structural | |\n\n---\n\n## Common Third-Party Library Mapping\n\n| Python Package | Rust Crate | Equivalence | Notes |\n|---|---|---|---|\n| `numpy` | `ndarray` | behavioral | Broadcasting semantics differ; see numpy section below |\n| `pandas` | `polars` | behavioral | API differs significantly; structural only at algorithm level |\n| `scipy` | (various) | partial | No single equivalent; map function by function |\n| `requests` | `reqwest` | structural | Async version: `reqwest::Client` |\n| `sqlalchemy` | `sqlx` or `diesel` | structural | |\n| `pydantic` | `serde` + struct | structural | |\n| `click` | `clap` | structural | |\n| `pytest` | `cargo test` | structural | Built-in; no crate needed |\n| `PIL/Pillow` | `image` | structural | |\n| `matplotlib` | `plotters` | behavioral | API differs |\n| `cryptography` | `ring` or `rustls` | structural | |\n| `yaml` | `serde_yaml` | structural | |\n\n### NumPy → ndarray Specifics (HIGH RISK)\n\nNumPy has many implicit behaviors that must be explicitly handled:\n\n| NumPy operation | ndarray equivalent | Gap |\n|---|---|---|\n| `arr[arr > 0]` boolean indexing | `.iter().filter()` + collect | API differs; same semantics |\n| `np.sum(arr, axis=0)` | `.sum_axis(Axis(0))` | structural |\n| Broadcasting `(3,) + (3,1)` | requires explicit `.broadcast()` | behavioral; always explicit in ndarray |\n| `arr.reshape(3, -1)` | `.into_shape((3, n))` | must compute n explicitly |\n| `np.linalg.inv` | `ndarray-linalg` crate | structural |\n| `np.random.default_rng(seed)` | `SmallRng::seed_from_u64(seed)` | behavioral; different algorithm |\n| `arr.dtype` (float32 vs float64) | Compile-time generic `Array<f32, _>` | structural; dtype is type parameter |\n\n---\n\n## Translation Patterns\n\n### Pattern 1: Exception handling → Result\n\n**Python:**\n```python\ndef parse_config(path: str) -> dict:\n    try:\n        with open(path) as f:\n            return json.load(f)\n    except FileNotFoundError:\n        raise ConfigError(f\"Config not found: {path}\")\n    except json.JSONDecodeError as e:\n        raise ConfigError(f\"Invalid JSON: {e}\")\n```\n\n**Rust:**\n```rust\nfn parse_config(path: &str) -> Result<serde_json::Value, ConfigError> {\n    let content = std::fs::read_to_string(path)\n        .map_err(|_| ConfigError::NotFound(path.to_string()))?;\n    serde_json::from_str(&content)\n        .map_err(|e| ConfigError::InvalidJson(e.to_string()))\n}\n```\n\n**Structural note**: Each `except` clause maps to one `map_err` call. Maintain 1:1 correspondence.\n\n---\n\n### Pattern 2: List comprehension → iterator chain\n\n**Python:**\n```python\nfiltered = [x * 2 for x in values if x > threshold]\n```\n\n**Rust:**\n```rust\nlet filtered: Vec<f64> = values.iter()\n    .filter(|&&x| x > threshold)   // step 1: filter (mirrors the `if`)\n    .map(|&x| x * 2.0)             // step 2: transform (mirrors the expression)\n    .collect();                      // step 3: materialize\n```\n\n**Structural note**: The filter before the map mirrors the Python `if` before the expression. Never swap order.\n\n---\n\n### Pattern 3: Class with state → struct + impl\n\n**Python:**\n```python\nclass RingBuffer:\n    def __init__(self, capacity: int):\n        self.data = [None] * capacity\n        self.head = 0\n        self.size = 0\n    \n    def push(self, item):\n        self.data[self.head] = item\n        self.head = (self.head + 1) % len(self.data)\n        self.size = min(self.size + 1, len(self.data))\n```\n\n**Rust:**\n```rust\nstruct RingBuffer<T> {\n    data: Vec<Option<T>>,\n    head: usize,\n    size: usize,\n}\n\nimpl<T> RingBuffer<T> {\n    fn new(capacity: usize) -> Self {\n        Self {\n            data: (0..capacity).map(|_| None).collect(),\n            head: 0,\n            size: 0,\n        }\n    }\n    \n    fn push(&mut self, item: T) {\n        self.data[self.head] = Some(item);\n        self.head = (self.head + 1) % self.data.len();\n        self.size = (self.size + 1).min(self.data.len());\n    }\n}\n```\n\n---\n\n### Pattern 4: Generator → Iterator trait\n\n**Python:**\n```python\ndef sliding_window(data: list, size: int):\n    for i in range(len(data) - size + 1):\n        yield data[i:i + size]\n```\n\n**Rust:**\n```rust\nstruct SlidingWindow<'a, T> {\n    data: &'a [T],\n    size: usize,\n    pos: usize,\n}\n\nimpl<'a, T> Iterator for SlidingWindow<'a, T> {\n    type Item = &'a [T];\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.pos + self.size > self.data.len() { return None; }\n        let window = &self.data[self.pos..self.pos + self.size];\n        self.pos += 1;\n        Some(window)\n    }\n}\n```\n\n**Or** use `windows()` if the pattern matches exactly: `data.windows(size)` — structural, stdlib.\n\n---\n\n## Anti-Patterns\n\n| Wrong | Why wrong | Correct |\n|---|---|---|\n| `Box<dyn Any>` for every collection | Abandons type safety; not structural | Use generics or enums |\n| `unwrap()` everywhere | Hides error handling structure | Match the Python exception pattern with `?` or `match` |\n| `unsafe` for dict-like mutation | Not required; use `HashMap` properly | Use entry API |\n| `Arc<Mutex<T>>` when Python had no locks | Adds concurrency structure not in source | Use `Mutex` only if source used locks; otherwise single-threaded |\n| `clone()` proliferation | Hides ownership model mismatch | Restructure lifetime annotations instead |\n\n---\n\n## Ecosystem Gaps\n\n| Python feature | Gap | Compensation |\n|---|---|---|\n| `int` is unbounded | `i64` overflows | Audit all arithmetic; use `num-bigint` where source values exceed i64::MAX |\n| `dict` preserves insertion order (Python 3.7+) | `HashMap` does not | Use `indexmap::IndexMap` |\n| `float` division always returns float | Rust integer `/` truncates | Track type of operands; cast when needed |\n| `**kwargs` / dynamic dispatch | Rust has no runtime dynamic dispatch for free | Use trait objects `Box<dyn Trait>` or enum dispatch |\n| Decorator pattern | No direct equivalent | Implement with wrapper structs or macros |\n| `__getattr__` / dynamic attribute | Not possible in safe Rust | Redesign as explicit method; document in translation_notes |\n| `isinstance()` at runtime | Rust uses compile-time types | Use `enum` with pattern matching instead |\n| Negative list indices `arr[-1]` | Rust panics on out-of-bounds | Use `arr.last()` / `arr[arr.len()-1]` |\n| `None` in typed collections | Rust requires `Vec<Option<T>>` | Always explicit |\n\n---\n\n## Testing Toolchain\n\n| Python | Rust | Notes |\n|---|---|---|\n| `pytest` | `cargo test` | Built-in; `#[test]` attribute |\n| `pytest.raises` | `#[should_panic]` or `Result` testing | |\n| `unittest.mock` | NO EQUIVALENT — mocks prohibited | Use real implementations |\n| `mypy` | `cargo check` | Type checking built into compiler |\n| `ruff` / `flake8` | `cargo clippy` | |\n| `black` | `rustfmt` | |\n| `pytest-benchmark` | `criterion` crate | |\n\n---\n\n## Build System\n\n| Python | Rust | Notes |\n|---|---|---|\n| `pyproject.toml` / `setup.py` | `Cargo.toml` | |\n| `requirements.txt` | `Cargo.lock` (generated) | Do not manually write; generated by cargo |\n| `pip install` | `cargo add` | |\n| `python -m module` | `cargo run --bin name` | |\n| `python setup.py build_ext` | `build.rs` | |\n\n## CI Adaptation\n\n```yaml\n# Python (source):\n- run: pip install -r requirements.txt && pytest\n\n# Rust (target):\n- run: cargo test\n- run: cargo clippy -- -D warnings\n- run: cargo fmt --check\n```\n\nArchive v1.2.1: 36 files, 135675 bytes\n\nFiles: README.md (27126b), README.zh-CN.md (25305b), references/lang-pairs/bun-python.md (8589b), references/lang-pairs/c-python.md (10351b), references/lang-pairs/cpp-python.md (9906b), references/lang-pairs/go-python.md (9013b), references/lang-pairs/python-bun.md (6887b), references/lang-pairs/python-c.md (5313b), references/lang-pairs/python-cpp.md (6420b), references/lang-pairs/python-go.md (5452b), references/lang-pairs/python-rust.md (10798b), references/lang-pairs/python-typescript.md (7993b), references/lang-pairs/python-zig.md (6917b), references/lang-pairs/rust-python.md (10509b), references/lang-pairs/TEMPLATE.md (2267b), references/lang-pairs/typescript-python.md (9786b), references/lang-pairs/zig-python.md (9690b), references/phase-0-bootstrap.md (4489b), references/phase-1-asset-scan.md (5448b), references/phase-2-ecosystem-map.md (8797b), references/phase-3-ipo-analysis.md (10770b), references/phase-4-translation.md (8936b), references/phase-5-verification.md (8844b), references/phase-6-gap-report.md (7919b), references/phase-gate-review.md (20873b), references/schemas.md (6467b), references/tdd-retrospective.md (11355b), scripts/gap_report.py (22897b), scripts/scan_assets.py (8891b), SKILL.md (18506b), templates/asset-inventory.yaml (1660b), templates/ecosystem-map.yaml (2563b), templates/ipo-registry.yaml (2679b), templates/migration-state.yaml (2653b), templates/retrospective-checklist.yaml (2221b), _meta.json (133b)\n\nFile v1.2.1:SKILL.md\n\n---\r\nname: lang-migration\r\ndescription: >\r\n  AI-driven full-project language migration skill. Use this skill whenever the user wants to\r\n  port, translate, or rewrite a codebase from one programming language to another — including\r\n  Python→Rust, Python→Go, Python→C, Python→C++, Python→Zig, Python→Bun/TS, or any other pair.\r\n  Also trigger when user mentions \"精确复刻\", \"语言迁移\", \"port project\", \"translate codebase\",\r\n  \"1:1 rewrite\", or \"language conversion\". This skill enforces structural equivalence first,\r\n  full asset coverage (no file skipped), persistent YAML state across sessions, and a strict\r\n  no-mock verification policy with human-gated blocking.\r\nlicense: MIT\r\n---\r\n\r\n## Author & Attribution\r\n\r\n**Original Author**: flynn  \r\n**Contact**: https://github.com/suifei/lang-migration-skill  \r\n**Role**: Architect, Developer, Documenter  \r\n**Expertise**: Software engineering, programming languages, AI workflow design  \r\n**Contributions**: Designed the multi-phase pipeline, defined YAML schemas, implemented blocking protocol, and wrote comprehensive documentation for the skill.\r\n\r\n---\r\n\r\n# Language Migration Skill\r\n\r\nA systematic, multi-session, AI-executable workflow for migrating any open-source project\r\nfrom one programming language to another with 1:1 structural fidelity.\r\n\r\n## Core Principles\r\n\r\n1. **No file is useless** — every file in the source project is analyzed and assigned a migration strategy\r\n2. **Structural equivalence first** — algorithm steps, loop structure, and control flow must mirror the source; behavioral equivalence is only used when the ecosystem gap makes structural impossible\r\n3. **No mock, ever** — tests must use real implementations and real test data\r\n4. **Block, don't skip** — when a decision cannot be made autonomously, stop and ask the human; never label-and-continue\r\n5. **State persists across sessions** — all state lives in YAML files in the workspace, readable by any AI agent or human\r\n6. **Evidence before completion** — every unit of work must produce verifiable evidence of execution before being marked done\r\n\r\n---\r\n\r\n## Global Anti-Cheating Policy\r\n\r\nThis skill operates under the assumption that an AI agent may attempt to mark tasks complete\r\nwithout actually doing the work. Every phase has mechanisms to detect and prevent this.\r\n\r\n**The Three Forms of AI Task Fraud (all prohibited):**\r\n\r\n| Form | Example | Detection |\r\n|---|---|---|\r\n| Batch fabrication | Scripts generate IPO content without reading source | source_lines field will be wrong/empty |\r\n| Silent bulk-confirm | NEEDS_REVIEW → CONFIRMED without evidence | confirmation_evidence field empty |\r\n| Premature phase advance | Marking P3 DONE when entries have empty fields | Self-verification checks fail |\r\n\r\n**Evidence Requirements by Phase:**\r\n\r\n| Phase | Required Evidence |\r\n|---|---|\r\n| P2 | `confirmation_evidence` block per CONFIRMED entry |\r\n| P3 | `READ_EVIDENCE` + `BEHAVIOR_PROOF` per function; `source_lines` in every step; `source_line` on every magic number |\r\n| P4 | Compilation succeeds; IPO entry updated with `target_lines`; **every fix triggers TDD Retrospective** |\r\n| P5 | **TEST OUTPUT EVIDENCE** (actual runner output, not just \"tests pass\"); **every fix triggers TDD Retrospective**; **full suite re-run after each fix**; **Checklist Summary at phase end** |\r\n| Fix | `retrospective-checklist.yaml` entry with RCA → scope_scan_query (defined BEFORE scan) → scope scan results → consistent fix (see `tdd-retrospective.md`) |\r\n| **PGR** | **Full audit report output in response** listing every item checked; each FINDING citing exact artifact (file path, field, value); each FIXED citing same artifact after change; `findings_count: 0` proven by enumerated item list; `phase_gates.PGR_N.passed_at` timestamp set only after zero-findings pass |\r\n\r\n**TDD Retrospective Integration**\r\n\r\nThe **Retrospective Protocol** is mandatory at every fix point:\r\n- **Trigger**: Compilation error, vet failure, structural deviation, test failure\r\n- **Steps**: RCA (root cause analysis) → Checklist rule → Scope scan → Consistent fix\r\n- **Output**: Entry in `retrospective-checklist.yaml` with root cause category and generalized rule\r\n- **Scope scan constraint**: `scope_scan_query` MUST be written before scanning (prevents post-hoc bias)\r\n- **Impact**: After each fix, full test suite is re-run; new failures each trigger independent retrospectives\r\n\r\nSee [Retrospective Protocol](#retrospective-protocol) below and `references/tdd-retrospective.md`.\r\n\r\n**Self-Verification is not optional.** Each phase that has a Self-Verification Protoc\n\nArchive v1.0.0: 30 files, 90821 bytes\n\nFiles: references/lang-pairs/bun-python.md (8589b), references/lang-pairs/c-python.md (10351b), references/lang-pairs/cpp-python.md (9906b), references/lang-pairs/go-python.md (9013b), references/lang-pairs/python-bun.md (6887b), references/lang-pairs/python-c.md (5313b), references/lang-pairs/python-cpp.md (6420b), references/lang-pairs/python-go.md (5452b), references/lang-pairs/python-rust.md (10798b), references/lang-pairs/python-typescript.md (7993b), references/lang-pairs/python-zig.md (6917b), references/lang-pairs/rust-python.md (10509b), references/lang-pairs/TEMPLATE.md (2267b), references/lang-pairs/typescript-python.md (9786b), references/lang-pairs/zig-python.md (9690b), references/phase-1-asset-scan.md (4520b), references/phase-2-ecosystem-map.md (7702b), references/phase-3-ipo-analysis.md (9483b), references/phase-4-translation.md (6537b), references/phase-5-verification.md (6002b), references/phase-6-gap-report.md (7919b), references/schemas.md (4201b), scripts/gap_report.py (21555b), scripts/scan_assets.py (8329b), SKILL.md (8297b), templates/asset-inventory.yaml (1660b), templates/ecosystem-map.yaml (2563b), templates/ipo-registry.yaml (2679b), templates/migration-state.yaml (1683b), _meta.json (133b)","readmeExcerpt":"Skill: 编程语言迁移 Owner: suifei Summary: AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua... Tags: latest:1.3.1 Version history: v1.3.1 | 2026-05-18T02:32:46.759Z | user v1.3 — Bug Triage Protocol + Real-World Validation Every P5 test failure now goes through a mandatory 3-step triage before any fix is attempted. ","codeSnippets":[],"executableExamples":[{"language":"javascript","snippet":"// JS: all are `number`\nconst count = 42;           // → Python int\nconst ratio = 3.14;         // → Python float\nconst index = arr.length;   // → Python int\nconst price = 9.99;         // → Python float"},{"language":"javascript","snippet":"// JS: different semantics\nfunction find(key) {\n    if (!map.has(key)) return undefined;  // not found\n    const val = map.get(key);\n    if (val === null) return null;         // explicitly absent\n    return val;\n}"},{"language":"python","snippet":"# Python: both → None; document the distinction as comment\ndef find(key: str) -> Optional[str]:\n    # JS SOURCE: returned undefined when not found, null when explicitly absent.\n    # Python: both map to None. Callers must not distinguish.\n    if key not in self._map:\n        return None   # was: undefined (not found)\n    return self._map[key]   # may be None (was: null — explicitly absent)"},{"language":"javascript","snippet":"async function fetchData(url) {\n    const response = await fetch(url);\n    if (!response.ok) throw new Error(`HTTP ${response.status}`);\n    return await response.json();\n}"},{"language":"python","snippet":"import aiohttp\n\nasync def fetch_data(url: str) -> dict:\n    async with aiohttp.ClientSession() as session:\n        async with session.get(url) as response:\n            if not response.ok:\n                raise RuntimeError(f\"HTTP {response.status}\")\n            return await response.json()"},{"language":"javascript","snippet":"class DatabaseError extends Error {\n    constructor(message, code) {\n        super(message);\n        this.name = 'DatabaseError';\n        this.code = code;\n    }\n}\n\nfunction query(sql) {\n    try {\n        return db.execute(sql);\n    } catch (e) {\n        if (e instanceof ConnectionError) {\n            throw new DatabaseError(`connection failed: ${e.message}`, 'CONN_ERROR');\n        }\n        throw e;\n    }\n}"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\r\nname: lang-migration\r\ndescription: >\r\n  AI-driven full-project language migration skill. Use this skill whenever the user wants to\r\n  port, translate, or rewrite a codebase from one programming language to another — including\r\n  Python→Rust, Python→Go, Python→C, Python→C++, Python→Zig, Python→Bun/TS, or any other pair.\r\n  Also trigger when user mentions \"精确复刻\", \"语言迁移\", \"port project\", \"translate codebase\",\r\n  \"1:1 rewrite\", or \"language conversion\". This skill enforces structural equivalence first,\r\n  full asset coverage (no file skipped), persistent YAML state across sessions, and a strict\r\n  no-mock verification policy with human-gated blocking.\r\nlicense: MIT\r\n---\r\n\r\n## Author & Attribution\r\n\r\n**Original Author**: flynn  \r\n**Contact**: https://github.com/suifei/lang-migration-skill  \r\n**Role**: Architect, Developer, Documenter  \r\n**Expertise**: Software engineering, programming languages, AI workflow design  \r\n**Contributions**: Designed the multi-phase pipeline, defined YAML schemas, implemented blocking protocol, and wrote comprehensive documentation for the skill.\r\n\r\n---\r\n\r\n# Language Migration Skill\r\n\r\nA systematic, multi-session, AI-executable workflow for migrating any open-source project\r\nfrom one programming language to another with 1:1 structural fidelity.\r\n\r\n## Core Principles\r\n\r\n1. **No file is useless** — every file in the source project is analyzed and assigned a migration strategy\r\n2. **Structural equivalence first** — algorithm steps, loop structure, and control flow must mirror the source; behavioral equivalence is only used when the ecosystem gap makes structural impossible\r\n3. **No mock, ever** — tests must use real implementations and real test data\r\n4. **Block, don't skip** — when a decision cannot be made autonomously, stop and ask the human; never label-and-continue\r\n5. **State persists across sessions** — all state lives in YAML files in the workspace, readable by any AI agent or human\r\n6. **Evidence before completion** — every unit of work must produce verifiable evidence of execution before being marked done\r\n\r\n---\r\n\r\n## Global Anti-Cheating Policy\r\n\r\nThis skill operates under the assumption that an AI agent may attempt to mark tasks complete\r\nwithout actually doing the work. Every phase has mechanisms to detect and prevent this.\r\n\r\n**The Three Forms of AI Task Fraud (all prohibited):**\r\n\r\n| Form | Example | Detection |\r\n|---|---|---|\r\n| Batch fabrication | Scripts generate IPO content without reading source | source_lines field will be wrong/empty |\r\n| Silent bulk-confirm | NEEDS_REVIEW → CONFIRMED without evidence | confirmation_evidence field empty |\r\n| Premature phase advance | Marking P3 DONE when entries have empty fields | Self-verification checks fail |\r\n\r\n**Evidence Requirements by Phase:**\r\n\r\n| Phase | Required Evidence |\r\n|---|---|\r\n| P2 | `confirmation_evidence` block per CONFIRMED entry |\r\n| P3 | `READ_EVIDENCE` + `BEHAVIOR_PROOF` per function; `source_lines` in every step; `source_line` on every magic"},{"path":"README.md","content":"<div align=\"center\">\r\n\r\n```\r\n╔═══════════════════════════════════════════════════════════════╗\r\n║                                                               ║\r\n║          ██╗      █████╗ ███╗   ██╗ ██████╗                   ║\r\n║          ██║     ██╔══██╗████╗  ██║██╔════╝                   ║\r\n║          ██║     ███████║██╔██╗ ██║██║  ███╗                  ║\r\n║          ██║     ██╔══██║██║╚██╗██║██║   ██║                  ║\r\n║          ███████╗██║  ██║██║ ╚████║╚██████╔╝                  ║\r\n║          ╚══════╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝   flynn           ║\r\n║                   M I G R A T I O N                           ║\r\n║                                                               ║\r\n╚═══════════════════════════════════════════════════════════════╝\r\n```\r\n\r\n# lang-migration\r\n\r\n**A Formal Methodology for AI-Driven, Evidence-Obligated Program Translation**\r\n\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\r\n[![Pairs: 14](https://img.shields.io/badge/Language_Pairs-14-blue)](#language-pairs)\r\n[![Phase: P0–P6](https://img.shields.io/badge/Phases-P0_through_P6-green)](#pipeline)\r\n[![Anti-Cheating](https://img.shields.io/badge/Anti--Cheating-Protocol_Enforced-red)](#the-evidence-obligation-protocol)\r\n[![Works With](https://img.shields.io/badge/Works_With-Claude_Code_|_Cursor_|_Copilot_|_OpenCode-purple)](#runtime-environments)\r\n[![ClawHub](https://clawhub.ai/favicon.ico)](https://clawhub.ai/suifei/lang-migration)\r\n[![Version: 1.3](https://img.shields.io/badge/Version-1.3-blue)](#whats-new)\r\n\r\n**English | [中文](README.zh-CN.md)**\r\n\r\n*Migrate any open-source codebase across programming languages — with structural fidelity,\r\npersistent state, and verifiable proof that the AI actually did the work.*\r\n\r\n### ✨ **What's New**\r\n\r\n**v1.3 — Bug Triage Protocol + Real-World Validation**\r\nEvery P5 test failure now goes through a mandatory 3-step triage before any fix is attempted.\r\nOnly 1 of 5 verdicts leads to modifying the translated function. Four new root cause categories.\r\nValidated against a real Python→Go migration (GenericAgent → go-GenericAgent). [Learn more →](#bug-triage-protocol-classify-before-fix)\r\n\r\n**v1.2 — Phase Gate Review (PGR)**\r\nEvery phase transition now requires passing an **autonomous self-auditing loop** before advancing.\r\nThe AI enumerates all expected outputs, audits each one, fixes any gap, and re-audits — until **zero findings**.\r\nOnly then is the phase marked DONE. No human involvement. No rubber-stamping. [Learn more →](CHANGELOG.md#v12--2026-05-15)\r\n\r\n</div>\r\n\r\n---\r\n\r\nClawHub: [https://clawhub.ai/suifei/lang-migration](https://clawhub.ai/suifei/lang-migration)\r\n\r\nSkillhub:[https://skillhub.cn/skills/lang-migration](https://skillhub.cn/skills/lang-migration)\r\n\r\n## The Problem Nobody Talks About\r\n\r\nWhen developers ask an LLM to \"migrate my Python project to Go,\" one of four things happens:\r\n\r\n1. **The LLM produces plausible-looking code that silently drops behavior.** Type semantics, precision contr"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn731g0h1z4gandq3nq2dazb8186r61a\",\n  \"slug\": \"lang-migration\",\n  \"version\": \"1.3.1\",\n  \"publishedAt\": 1779071566759\n}"},{"path":"references/lang-pairs/bun-python.md","content":"# Language Pair: Bun (JavaScript) → Python\n\n**Difficulty tier**: Low-Moderate (both dynamic; async models differ; number precision is a trap)\n\n**Key differences**:\n- Types: JS dynamic → Python `typing` annotations (ADD types; JS may have none)\n- Async: JS Promise/async-await → Python `asyncio` (structurally similar)\n- Numbers: JS `number` (float64) → Python `int` / `float` (must determine which)\n- `undefined` vs `null`: JS has both → Python has only `None`\n- Prototypal OOP: JS classes → Python classes (both ES6 class and Python class are similar)\n- Modules: JS ESM → Python modules\n\n---\n\n## Pre-Mapped Core Types\n\n| Bun (JS) | Python | Equivalence | Notes |\n|---|---|---|---|\n| `number` (integer use) | `int` | behavioral | JS uses float64 for all numbers; Python distinguishes |\n| `number` (float use) | `float` | structural | |\n| `bigint` | `int` | structural | Python int is natively arbitrary precision |\n| `boolean` | `bool` | structural | |\n| `string` | `str` | structural | JS is UTF-16 internally; Python str is abstract Unicode |\n| `null` | `None` | structural | |\n| `undefined` | `None` | behavioral | JS `undefined` (unset) → Python `None`; document |\n| `Array<T>` | `list[T]` | structural | |\n| `[A, B]` tuple | `tuple[A, B]` | structural | |\n| `Map<K,V>` | `dict[K,V]` | structural | Both preserve insertion order |\n| `Set<T>` | `set[T]` | structural | |\n| `Uint8Array` | `bytes` | structural | |\n| `ArrayBuffer` | `bytes` | structural | |\n| `Promise<T>` | `Awaitable[T]` / coroutine | structural | |\n| `null \\| T` | `Optional[T]` | structural | |\n| `A \\| B` | `Union[A, B]` | structural | |\n\n---\n\n## Number Type Disambiguation\n\nJS uses `number` for both integers and floats. When migrating, determine the correct Python type from context:\n\n```javascript\n// JS: all are `number`\nconst count = 42;           // → Python int\nconst ratio = 3.14;         // → Python float\nconst index = arr.length;   // → Python int\nconst price = 9.99;         // → Python float\n```\n\n**Decision rule** (apply per variable/parameter):\n- Used with integer arithmetic, indices, or counts → `int`\n- Used with decimal values, ratios, measurements → `float`\n- Unclear → `float` (safer; Python float is wider than JS number)\n- Was `bigint` in JS → always `int`\n\n---\n\n## `undefined` vs `null` → `None`\n\n```javascript\n// JS: different semantics\nfunction find(key) {\n    if (!map.has(key)) return undefined;  // not found\n    const val = map.get(key);\n    if (val === null) return null;         // explicitly absent\n    return val;\n}\n```\n\n```python\n# Python: both → None; document the distinction as comment\ndef find(key: str) -> Optional[str]:\n    # JS SOURCE: returned undefined when not found, null when explicitly absent.\n    # Python: both map to None. Callers must not distinguish.\n    if key not in self._map:\n        return None   # was: undefined (not found)\n    return self._map[key]   # may be None (was: null — explicitly absent)\n```\n\nIf the caller distinguished `undefined` from `null`, use a senti"},{"path":"references/lang-pairs/c-python.md","content":"# Language Pair: C → Python\n\n**Difficulty tier**: Moderate (memory management dissolves; pointer arithmetic becomes indexing)\n\n**Key differences**:\n- Memory: C manual malloc/free → Python GC (ownership structures become irrelevant mechanically but must be documented)\n- Pointers: C pointers → Python references or indices (never expose raw pointers)\n- Types: C weak static → Python `typing` (strengthen, not weaken)\n- Strings: C null-terminated `char*` → Python `str` (encoding must be made explicit)\n- Error handling: C return codes + errno → Python exceptions\n- Arrays: C fixed/dynamic arrays → Python `list` or `bytes`\n- Structs: C structs → Python `dataclass` or class\n- Function pointers: C `(*fn)(args)` → Python callable / `Callable`\n\n---\n\n## Pre-Mapped Core Types\n\n| C | Python | Equivalence | Notes |\n|---|---|---|---|\n| `int8_t` | `int` | behavioral | Document original range: [-128, 127] |\n| `int16_t` | `int` | behavioral | [-32768, 32767] |\n| `int32_t` | `int` | behavioral | |\n| `int64_t` | `int` | structural | Python int covers this range |\n| `uint8_t` | `int` | behavioral | [0, 255]; add range assertion |\n| `uint16_t` / `uint32_t` / `uint64_t` | `int` | behavioral | Document upper bound |\n| `float` | `float` | behavioral | Python float is f64; C float is f32 — document precision widening |\n| `double` | `float` | structural | |\n| `_Bool` / `bool` | `bool` | structural | |\n| `char*` (string) | `str` | behavioral | Must determine encoding; default UTF-8 |\n| `char*` (bytes) | `bytes` | structural | When used as raw bytes, not text |\n| `uint8_t*` + `size_t` | `bytes` | structural | |\n| `void*` | `Any` | behavioral | Document what types it actually points to |\n| `NULL` | `None` | structural | |\n| `T*` (array) + `size_t n` | `list[T]` | structural | The (pointer, length) pair → single list |\n| `T[N]` (fixed array) | `list[T]` | behavioral | Document that N was fixed; add `assert len(arr) == N` |\n| `struct T` | `@dataclass` class | structural | |\n| `enum` | `enum.IntEnum` or `enum.Enum` | structural | |\n| `(*fn)(args) → ret` | `Callable[[args], ret]` | structural | |\n\n---\n\n## Pointer Pairs → Single Object\n\nThe most common C pattern — a pointer and its associated length — collapses to one Python object:\n\n```c\n// C: two parameters representing one logical unit\nvoid process(const uint8_t *data, size_t len);\nint find_max(const int *arr, size_t n);\nchar *join_strings(const char **strs, size_t count);\n```\n\n```python\n# Python: one parameter\ndef process(data: bytes) -> None: ...\ndef find_max(arr: list[int]) -> int: ...\ndef join_strings(strs: list[str]) -> str: ...\n```\n\n**Rule**: Every `(T*, size_t)` pair in C source → one Python collection parameter.\nDocument the original C signature in a comment:\n\n```python\ndef process(data: bytes) -> None:\n    # C SOURCE: void process(const uint8_t *data, size_t len)\n    ...\n```\n\n---\n\n## Error Handling: Return Codes → Exceptions\n\n**C:**\n```c\ntypedef enum {\n    ERR_OK = 0,\n    ERR_NOT_FOUND = 1,\n    ERR_INVALID_ARG = 2,\n    ER"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua... Skill: 编程语言迁移 Owner: suifei Summary: AI-driven full-project language migration skill. Use this skill whenever the user wants to port, translate, or rewrite a codebase from one programming langua... Tags: latest:1.3.1 Version history: v1.3.1 | 2026-05-18T02:32:46.759Z | user v1.3 — Bug Triage Protocol + Real-World Validation Every P5 test failure now goes through a mandatory 3-step triage before any fix is attempted.","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1711,"uniquenessScore":50,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T13:08:01.714Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T13:08:01.714Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:01:20.177Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}