Application portfolio
Prepared for Saronic Technologies · Enterprise Technology Intern, AI & Automation · Fall 2026
I'm Vedant, a CS student at UGA and a Software Engineering Intern at Voya Financial, where I own an AI-assisted migration across 3,600+ test files: OpenRewrite for the bulk, Copilot agents for the long tail, MCP for the tools, and a parity gate so nothing silently breaks.
The role, mapped
Case study 01 · Voya Financial, Benefitfocus division
The suite behind a product serving 1.8M+ people needed to move from JUnit 4 to 5, with zero tolerance for a test silently going missing. Hand-conversion doesn't scale, scripts miss the subtle cases, and pure LLM runs are costly and non-deterministic, so the pipeline splits the work by character.
Hover a stage for a summary; click it to open the full description. Each slice ships as one atomic, revertible PR.
List the slice's JUnit 4 files and count them. Cheap, exact, free.
Run the slice's tests and record the passing count. You never migrate a red slice, because you couldn't tell a new failure from a pre-existing one.
red → defer, log in the tracker, next sliceThe JUnit4to5Migration recipe handles roughly 90%: imports, annotations, assertThrows, runner-to-extension swaps, and the argument-order flip. Dry-run first, review the patch, then apply. Exact and identical every time.
A custom agent converts what determinism can't: custom rules, parameterized tests, house import conventions. It follows the skill's rulebook, works in 5-file batches, and is given the smallest possible job.
Re-run the slice. It must be green with the same test count as the baseline. However a file was converted, a test that fails to compile or stops running cannot pass this gate.
fail → fix or revert, never commit a regressionA second agent that didn't do the work checks the changes against the rules and reports PASS or ISSUES with file and line. It runs with read-only tools, so it structurally cannot edit.
The agents never touch git. Every batch is atomic and revertible, which makes the human review gate real and keeps an undo button under everything.
Metrics logged per batch: files converted, OpenRewrite-vs-agent split, test count before and after. The tracker is the zero-regression evidence trail.
The fault tolerance is concentrated at stage 5. The agents can slip and the recipe can miss a case, but nothing broken can get past a deterministic, unskippable gate.
for slice in tracker.next():
base = mvn_test(slice) # must be green first
if base.red:
tracker.defer(slice); continue # log + skip, never fix here
openrewrite.dry_run(slice).review().apply()
executor.clean_residue(slice, skill) # agentic, 5-file batches
out = mvn_test(slice)
assert out.green
assert out.count == base.count # no test silently dropped
reviewer.audit(slice.diff) # read-only: PASS / ISSUES
human.review_commit_pr(java_only) # agents never touch git
tracker.log_metrics(slice)
Case study 01, continued · the MCP layer
Scaling the agent side needed semantic tools, not text search. MCP, the Model Context Protocol, is how agents get tool and function calling against real systems, so I evaluated buy vs. build and made the call.
Wired into Copilot in JetBrains via manual mcp.json: semantic search, structural matching, and recipe execution as agent tools. Org policy and licensing gates mapped.
A stdio server scoped on the TypeScript MCP SDK over the free OpenRewrite plugin: 1 to 3 days, building on a prior scaffold of mine.
Run the $0 scripted path now, price the vendor seat in parallel, build only if in-agent tool calling is confirmed. Security-reviewed first: stdio, no telemetry, no phone-home.
// The 3-tool alternative scoped in the memo: // TypeScript MCP SDK, stdio transport, over the free // Apache-2.0 rewrite-maven-plugin. const server = new McpServer({ name: "openrewrite" }); server.registerTool("list_recipes", {}, async () => parse(await mvn("rewrite:discover"))); server.registerTool("dry_run", { recipeId: z.string(), modulePath: z.string() }, async ({ recipeId, modulePath }) => { await mvn("rewrite:dryRun -Drewrite.activeRecipes=" + recipeId, modulePath); return readDiff(modulePath + "/target/rewrite/rewrite.patch"); }); // run_recipe modifies source, so it is gated: // refuses without an explicit apply: true flag. server.registerTool("run_recipe", guarded(applyHandler)); await server.connect(new StdioServerTransport());
Licensing: raw OpenRewrite (rewrite-maven-plugin) is Apache-2.0; no license or token needed for private repos. [VERIFIED] Security: mod mcp runs as a stdio subprocess, makes no network calls by default, sends no telemetry. [VERIFIED] License signature is checked against a key packaged in the CLI - no phone-home. [VERIFIED] Org gate: the "MCP servers in Copilot" policy is off by default on Business plans. [NEEDS INTERNAL CHECK] Recommendation: keep the $0 scripted path running; greenlight the ~1-3 day custom build only if in-agent tool calling is a confirmed requirement. [INFERRED]
Case study 02 · specs agents build from
The migration runs on written specs, not vibes: engineers and agents execute from the same three artifacts.
The runtime rulebook: full mapping, Java 8 and Mockito ceilings, batch rules, hard nevers. Company SOPs isolated so it ports by swapping one section.
The executor converts in 5-file batches and can't commit; the reviewer runs read-only. Separation of duty by configuration, not promise.
Definition of Done, disposition policy, PR conventions, rollback, risk register, metrics tracker. Anyone can pick it up and run it.
---
name: junit5-migration
description: Migrates this repo's remaining JUnit 4 tests to
JUnit 5, following the company SOPs and case notes below.
allowed-tools: shell
---
## Mapping (excerpt)
@Test(expected = E.class) -> assertThrows(E.class, () -> ...)
@Rule ExpectedException -> assertThrows
@RunWith(Parameterized.class) -> @ParameterizedTest + @MethodSource
Critical - the silent one: the assertion message moves from
FIRST to LAST. assertEquals("msg", expected, actual) ->
assertEquals(expected, actual, "msg"). This compiles either
way, so the build will not catch it.
### Never
- Never change a test's assertions, logic, or coverage.
- Never run git commit or git push - the human commits.
--- name: junit5-migration-reviewer description: Read-only reviewer. Audits each migration batch against the rules. Reports only; never edits. tools: ["read", "search"] --- You are an oversight reviewer for JUnit 4 -> JUnit 5 changes. Your ONLY job is to review. You never edit code, never run commands, and never fix anything - you report findings only. Output a verdict - PASS or ISSUES - with the file and line for each problem. You cannot run the build, so never claim the suite is green. If correctness depends on test results, say the human must confirm with mvn test.
Case study 03 · making it safe to run
Generative systems propose, deterministic systems verify, humans hold the commit rights. All six are live in the pipeline today.
Compile + full green + count parity vs. baseline, every batch. Validated by the gate, not by trust.
The editor never reviews, the reviewer can't edit, only the human commits.
Per-batch monitoring and logging: files converted, recipe-vs-agent split, counts before and after.
Conversion-only diffs, production code untouchable, agents blocked from git.
License and no-telemetry checks before any tool touches the IDE.
Sanitized by default: no internal identifiers, credentials, or customer data in anything shareable.
Case study 04 · Voya internal AI competition
Built in Microsoft 365 Copilot Agent Builder for Voya's intern AI competition: paste rough blocker notes, get copy-ready output. Works in reverse on vague issues you receive.
7.4K characters of system instructions: an adaptive seven-section output contract, a grounding knowledge doc, starter prompts.
Uses only what the user provided, never invents causes or metrics, labels assumptions, marks unknowns TBD.
One-step workflow designed for companywide reuse; impact framing kept conservative and honest.
# Accuracy Rules - Use only information the user provided. Never invent facts, causes, owners, approvers, timelines, dates, metrics, or resolutions. - Separate confirmed facts from assumptions, and label assumptions. - State missing information as missing; mark unknowns as unknown or TBD. - If notes contain credentials, personal information, or customer data, use neutral placeholders such as [Employee], [Team], [System] and recommend the user replace them before sharing.
Background
SimPy digital twin of a 6-station assembly line, Streamlit dashboard, MQTT.
Python control work on the Zeus 2Q humanoid; CI/CD; roughly 30% defect reduction.
Own the club's website and technical infrastructure.
Working stack