05 / 05 · 2025.10 — Present
◯◯ Co., Ltd. (SES)
Working in Japan as an SES engineer on legacy-system modernisation: automatic COBOL functional specs with ANTLR4 + RAG + MCP, a people-and-organisation sync tool for a major electronics maker's departmental system, and — as the engineer in charge — a rule-plus-generative-AI CMD → C# conversion platform.
- Role
- Developer (Python)
- Industry
- Contract development · legacy modernisation (SES)
- Location
- Japan
- Tenure
- 1 yr 1 mo
Key results
1,084
External-command mappings used by the CMD → C# converter (plus 33 built-in commands and 27 AST node types)
~30 sections
Organisation size covered by the people-and-organisation sync tool (4 departments)
4
Retrieval tools exposed to the model over MCP to look up the business meaning of COBOL variables on demand
Projects here
PROJECTS · 32026.04 – Present · Engineer in charge (architecture design, core implementation, review)
Legacy batch (CMD/JCL) → C# automatic conversion platform
An automatic conversion platform that migrates long-running Windows batch scripts (CMD, Shift-JIS) to C# programs on an in-house batch framework. Rewriting by hand is costly and hard to prove equivalent, so I built a two-stage system — rule-based conversion plus generative-AI completion — guided by one principle: leave a TODO rather than silently change business logic.
- Two-stage architecture: stage one converts most of each script deterministically (preprocess → Lark parse → AST → rule engine → C# generation); stage two calls an LLM only for CALL :label subroutines the rules cannot express, keeping AI scope and risk minimal
- CMD grammar modelling: designed and kept extending a ~490-line Lark (LALR) grammar that copes with cmd.exe quirks — redirects anywhere, the ambiguity of < > & |, %VAR:old=new% substitution, many IF/ELSE bracket styles, labels containing Japanese
- Input-normalisation layer (8 passes): unifies mixed line endings, glued closing brackets, multi-line ELSE, ECHO metacharacters and full-width spaces without changing semantics, so the grammar stays small
- AST and rule engine: 27 custom AST node types; 33 built-in commands plus a 1,084-entry external-command mapping table (job-process and job-flow call modes); variable expansion handled separately for string, argument-line and integer-expression contexts
- LLM subroutine conversion with semantic-preservation checks: LabelMapper aligns the .cs TODO, the .cs.ast call node and the .cmd source; structural and business-semantic validators (ERRORLEVEL, cancel branches, error jumps and status flags must survive); on failure the reason is fed back for up to 7 retries, otherwise the TODO is kept for a human
- Cost and stability: JSON cache keyed by SHA-256 of the normalised label block, exponential back-off on 429/5xx, automatic fallback from Chat Completions to the Responses API, temperature=0 for reproducibility
- Quality loop: ~465 test cases over the grammar and transpiler layers; batch runs emit .cs.ERR files that are classified into four causes (CMD source issue / grammar gap / code defect / environment), with a shared list of common errors
- Python
- Lark (LALR)
- regex
- Azure OpenAI
- C# / .NET
- pytest
- Git
System architecture
2026.01 – 2026.03(3 mos) · Development, testing, release and hand-over of a Python sync tool (dispatched)
Departmental project-management system — people & organisation auto-sync tool
A software-engineering division of a major electronics maker built its own project-management and status-reporting platform on Redmine (Angular + Go + Redmine). People and organisation data live in an internal staff directory with no usable API, so I built the sync tool: it scrapes members and the org tree with Selenium and syncs them into Redmine accounts, department/section organisations and permission groups (4 departments, ~30 sections).
- Data-source migration: when the old staff directory was retired, moved the crawler to the new site — new page structure and Microsoft SSO login — while keeping the legacy role markers so downstream sync logic needed no change
- Selenium (headless Edge) logs in automatically, walks the org tree and looks up each person's unit and role; results are pushed one-way from the intranet PC to an Azure server via paramiko SFTP
- Sync batch: diffs old and new data, generates and runs SQL for account creation, deactivation, re-hire unlock and department/section/role sync; updates the reporting permission groups through the Redmine REST API, leaving allow-listed members untouched
- Three kinds of SendGrid alert e-mails; on an unexpected organisation change the job aborts and the SQL runs only after the owner confirms it (two-phase), so bad data never lands in production directly
- Centralised department mappings scattered in code into a database config table; handled the April reorganisation per the customer's policy and designed/ran test cases covering screens, the application flow and permission groups
- Diagnosed and fixed production issues: lock mis-detection from duplicate people, missing accounts for re-hires, page time-outs under network jitter, Edge driver mismatch
- Released to two production environments (intranet PC + Azure VM): backup, deploy, dry-run with DB writes disabled to verify the SQL, then go live; wrote the operations runbook (deployment, alert guide, troubleshooting, org-change SOP) and handed over
- Ran Fortify / FOSSology security and licence scans over the whole project, fixed high-severity findings such as JSON and SQL injection, and compiled the OSS licence list
- Python
- Selenium
- paramiko
- MySQL / MariaDB
- Redmine REST API
- SendGrid
- Bash
- PowerShell
- Azure VM
System architecture
2025.10 – 2025.12(3 mos) · Design, implementation and validation (led individually)
Automatic COBOL functional-spec generation with ANTLR4 + RAG + MCP
The customer's core batch work still runs on COBOL written decades ago: no usable design documents, abbreviated variables such as TR1-HINSHU whose business meaning is scattered across DB design manuals and glossaries, and fewer and fewer people who know COBOL. The goal: feed in COBOL source and get a Japanese functional specification (Markdown) that business staff can read. Design principle — deterministic work (syntax, layout, call graph) is done by programs; the model only gives meaning and writes it up.
- Model validation and change of course: benchmarked Gemma-3 4B on COBOL comprehension; LoRA fine-tuning on Colab could not finish because of memory limits. Since the business dictionary changes per customer, moved to RAG, which needs no retraining
- Knowledge base: unified DB design manuals, glossaries and table/file/job-flow definitions into {key, value}, split semantically by file → record → field → group; embedded only the key (multilingual-e5-small) into ChromaDB, stripping OCCURS subscripts before lookup and building aliases and hierarchy paths
- COBOL parsing: generated a Python lexer/parser/visitor from Cobol85.g4; preprocessing for Shift_JIS→UTF-8, line-number removal and dialect directives such as $SET; turned the parse tree into a compact AST for the LLM; a variable extractor handling REDEFINES / OCCURS / COMP / level-88
- Call-hierarchy analysis: built a call graph from PERFORM, dropped EXT paragraphs that only serve as exits in RTN/EXT pairs, and used a topological sort to fix a bottom-up analysis order
- MCP integration: exposed vector search through FastMCP as four tools — lookup_field, lookup_record, batch_lookup_fields, get_subroutine_summary — so the model fetches only the variables it uses instead of hundreds of definitions
- Generation and prompt tuning: per subroutine, extract input/output/work variables and callees, look definitions up via MCP, pass lower-level summaries up, and have Gemma-3 write Markdown; prompt constraints drop empty items and require business language instead of literal MOVE paraphrases
- Python
- ANTLR4
- ChromaDB
- SentenceTransformers
- MCP (FastMCP)
- Gemma-3 4B
- Hugging Face Transformers
- Google Colab
- WSL
System architecture
System data flow
Abstract sketch · no internal detailsLegacy CMD scripts
Shift-JIS · municipal systems
Normalise + Lark parse
8 passes · ~490-line grammar
▲ My part
Rule engine
33 built-in + 1,084 external
▲ My part
C# generation
.cs · TODO where unsupported
LLM completion + 2-layer check
CALL :label · up to 7 retries
▲ My part
Output
.label.ai.cs · failures stay TODO
What I learned here
To work in Japan for the long term I moved here in July 2024, studied Japanese at a language school and passed JLPT N2, then joined Japanese development sites as an SES engineer after leaving the school in November 2025.
All three engagements are about making legacy systems easier to understand and migrate. The COBOL project showed me that RAG quality depends on chunk granularity and retrieval-key design; in the sync tool, with an isolated network and no API, one-way push, two-phase execution and alerts protect production data; the CMD → C# converter fixed a principle for me — leave deterministic work to programs, let generative AI handle only the smallest units rules cannot express, validate every output, and keep a TODO rather than silently change business logic.
TECH STACK
- Python
- Lark
- ANTLR4
- Azure OpenAI
- MCP
- ChromaDB
- Selenium
- C# / .NET
- Redmine REST API
- MySQL / MariaDB
- Azure VM