Open to backend roles · available now · Chennai, India
The expensive bugsdon’t crash.
I’m Rohit Behera, a backend engineer. I build Java and Spring Boot services where a retry can’t run twice, and I fix the failures that pass silently in the open-source libraries underneath them, including the ones that feed text to LLMs.
- 00:00.000infoPOST /api/v1/applications Idempotency-Key: k-CC-3MXP
- 00:00.002infofilters: correlation id → bearer auth → rate limit
- 00:00.004okone transaction: applicant + application + outbox_events(PENDING) + audit
- 00:00.005ok202 Accepted CC-3MXP (no vendor called yet)
- 00:02.000okpoller → application.created outbox row PUBLISHED
- 00:02.004infodelivered to bureau-check-queue
- 00:02.007infostatus guard: RECEIVED ✓
- 00:02.127okKYC/AML verified before any bureau spend
- 00:02.217warnattempt 1/3: 503 Service Unavailable
- 00:02.217warnretry in 1s (exponential backoff)
- 00:03.307warnattempt 2/3: 503 Service Unavailable
- 00:03.307warnretry in 2s (exponential backoff)
- 00:05.487okattempt 3/3: bureau score 718
- 00:05.489infopublish bureau.completed (after commit)
- 00:05.492infoevaluate: score, debt-to-income, policy version
- 00:05.498okAPPROVED → decision_records + status in one tx
- 00:05.500infopublish decision.approved (after commit)
- 00:05.504infoclaim: DECISION_MADE → CORE_BANKING_PENDING (flushed before the call)
- 00:05.744okprovision account → ACCOUNT_CREATED
- 00:05.748okmirror row written for the legacy platform
- 00:05.751okCOMPLETED
- 19Fixes merged upstreaminto 12 projects, including Prometheus, Keycloak, LangChain4j, rclone, axios
- 10/19Never raised an errordata lost or a wrong result, with no exception to catch
- 25PRs merged into ragedcode retrieval for AI agents; I am its main contributor
- 3yrsCore-banking APIsaccount-servicing and payments, at a global bank
Selected work
Hard part first, then the evidence.
- 01Personal capstone2026
Credit-card onboarding pipeline
A duplicate message here is not wasted work. It is a second hard enquiry on a real person's credit file.
- Java 17
- Spring Boot 3.5
- PostgreSQL 15
- RabbitMQ
- Resilience4j
- Flyway
- 7 ADRs, including the ones that record what is not built yet
- 138 tests; one runs the whole pipeline against real Postgres and RabbitMQ
- 8 Prometheus alert rules, 4 Grafana dashboards
- 02Own open source · MIT2026
splitlint
The broken chunk still joins back into the original string. Nothing throws; retrieval just gets worse for one language.
- Python
- Unicode UAX
- pytest
- GitHub Actions
- 766 of 766 official Unicode grapheme conformance cases pass
- LangChain's RecursiveCharacterTextSplitter fails 10 of its 12 cases
- Grew out of an upstream fix in langchain4j
- 03Open-source contribution2026
AST-RAG: code retrieval for AI agents
Text chunks cannot answer "who calls this?". The graph can, but only if every file is parsed correctly and the parser is safe to share between threads.
- Python
- Tree-sitter
- Neo4j
- Qdrant
- SQLite
- Most of the repository's commit history is mine
- Parse cache: content-addressed, bounded, two backends
- Fixed a data race that corrupted results instead of crashing
- 04Own open source · MIT2026
Plumb
Ask an agent whether the feature works and it will say yes, sincerely, having verified nothing. "Done" was never defined, so the only available answer is a feeling.
- Python 3.10+
- Claude Code hooks & skills
- mypy --strict
- GitHub Actions
- Zero runtime dependencies, no network, no telemetry
- Uninstall removes only files whose hash it recorded
- Never changes the user's permission mode
- 05Professional · a global bank2023–2026
Legacy service modernization
Behaviour had to be provably identical before and after, including the parts nobody had documented, because the thing on the other end of the endpoint is somebody's account.
- Java
- Spring Boot
- PostgreSQL
- REST
- SOAP
- Elasticsearch
- 17+ endpoints migrated, ≈35% of the programme
- Test coverage raised to 80% by writing the test first
- Legacy maintenance overhead down ≈25%
Failure lab
Break the pipeline.
The onboarding service, simulated from its real configuration: retry counts, backoff, breaker thresholds, the outbox poll interval. Pick a failure. Every path ends in a named, audited state, except the one marked as a gap, which is written up with its fix.
Failure lab· simulated from the service’s config
In request
Client
mobile app
Intake API
filters, validation
Postgres
app + outbox, 1 tx
After 202
Outbox poller
every 2s
RabbitMQ
queue per stage
Stages
KYC
before any spend
Bureau
retry + breaker
circuit closed
Decision
pure evaluator
Core banking
claim, then call
Legacy mirror
vendor row
On nack
Dead letters
audited failure
AI engineering
The data path into an LLM.
Most of my AI work is on the unglamorous side of retrieval: getting text in without losing it, cutting it without corrupting it, indexing structure, measuring whether the right passage comes back, and making agents prove their work. Each stage below links the evidence.
01Extract
Turn HTML, PDFs and office files into text.
Breaks:Content is dropped or garbled, and the document still parses.
- trafilatura #940mergedText directly after a list, table, quote or code block was dropped from every output format.
- unstructured #4502mergedDefinition lists were discarded from HTML, so a Sphinx API reference page partitioned to its headings and nothing else.
- unstructured #4449mergedspaCy ran three times on the same text per element: 88% of partition_html() time in the profile. Now once.
- docling #3985mergedCSV conversion failed when the first quoted field spanned a newline: the dialect was sniffed from a truncated line.
- docling #4388reviewMHTML pages with a meta charset were decoded twice, turning non-ASCII text into mojibake.
02Split
Cut text into chunks small enough to embed.
Breaks:A cut lands inside a character. The chunk round-trips and embeds as garbage.
- splitlintAudits any splitter for it
- langchain4j #6091mergedThe sentence splitter returned nothing for text with no detectable sentence, so the hierarchical splitter dropped it.
- langchain4j #6308reviewSplitting by UTF-16 code unit cut surrogate pairs in half, producing chunks that cannot be encoded as UTF-8.
03Index
Represent content so it can be found: vectors, and structure where it exists.
Breaks:Structure is flattened away, or a race corrupts the index without failing.
- ragedASTs, call graph and vectors for code
04Retrieve
Find the passages that answer the question.
Breaks:A confident answer from the wrong source, and nobody measured how often.
- Ask this siteBM25 + embeddings + rank fusion, with an eval set
05Act
Agents call tools and change things.
Breaks:The agent reports done without evidence, or the tool wiring quietly points elsewhere.
- PlumbMakes coding agents prove they are done
- mastra #20591mergedNine storage adapters declared @mastra/core peer floors older than the exports they import; installs passed, then died on import.
- chainlit #3013reviewPer-user OAuth for HTTP MCP server connections.
- hermes-workspace #735reviewThe MCP server list was fetched from the wrong endpoint on both the probe and data paths.
Upstream
19 fixes merged. 10 of them never raised an error.
Fixes sent to libraries I use. Each one arrives with a regression test that fails before the patch and passes after it, because that is the only “I fixed it” a maintainer can check in a minute. The list is generated from the GitHub API; closed-unmerged PRs are left out.
| Project | Stars | PR | Class | What was wrong |
|---|---|---|---|---|
| axios | ★ 109k | #11118merged | Crash | Once an interceptor's handlers array was set to null, every later request threw a TypeError: the length was read before the null check. |
| caddy | ★ 77k | #7922merged | Wrong result | A proxy URL resolving to a port with no host (http://:80) was accepted, though the code meant to reject it. |
| docling | ★ 68k | #3985merged | Crash | CSV conversion failed when the first quoted field spanned a newline: the dialect was sniffed from a truncated line. |
| prometheus | ★ 66k | #19324merged | Crash | AWS service discovery panicked on Lightsail instances whose optional fields were absent. |
| prometheus | ★ 66k | #19396merged | Crash | The same nil-dereference class in ECS task discovery, found by reading the code around the first fix. |
| prometheus | ★ 66k | #19486merged | Performance | The 14 discovery packages that still ran their tests serially now run them in parallel, checked for shared state first. |
| rclone | ★ 60k | #9785merged | Silent loss | Box: a source that ended early was uploaded truncated and reported as a success. |
| rclone | ★ 60k | #9786merged | Silent loss | Yandex: the same truncated-upload-reported-as-success bug on a second backend. |
| rclone | ★ 60k | #9801merged | Silent loss | Huawei Drive: the same truncated-upload bug on a third backend. |
| rclone | ★ 60k | #9986merged | Crash | Valid durations such as 1d12h were rejected by the option parser. |
| rclone | ★ 60k | #9987merged | Wrong result | A --bwlimit timetable written out of week order applied the wrong limit before the first slot of the week. |
| keycloak | ★ 37k | #51356merged | Wrong result | Credential-issuer metadata carried empty-string key attestation values that the OID4VCI spec forbids. |
| mastra | ★ 29k | #20591merged | Crash | Nine storage adapters declared @mastra/core peer floors older than the exports they import; installs passed, then died on import. |
| goreleaser | ★ 16k | #6752merged | Wrong result | Every generated Homebrew Cask failed brew style: stanza order came from comparing arch strings alphabetically. |
| unstructured | ★ 16k | #4449merged | Performance | spaCy ran three times on the same text per element: 88% of partition_html() time in the profile. Now once. |
| unstructured | ★ 16k | #4502merged | Silent loss | Definition lists were discarded from HTML, so a Sphinx API reference page partitioned to its headings and nothing else. |
| langchain4j | ★ 13k | #6091merged | Silent loss | The sentence splitter returned nothing for text with no detectable sentence, so the hierarchical splitter dropped it. |
| go-git | ★ 7.8k | #2305merged | Crash | Push aborted if any tree anywhere in history held a control character in a path, even one deleted years earlier. |
| trafilatura | ★ 6.9k | #940merged | Silent loss | Text directly after a list, table, quote or code block was dropped from every output format. |
| docling | ★ 68k | #4388review | Silent loss | MHTML pages with a meta charset were decoded twice, turning non-ASCII text into mojibake. |
| docling | ★ 68k | #4391review | Silent loss | AsciiDoc: a titled paragraph and the text after it were dropped. |
| docling | ★ 68k | #4394review | Wrong result | AsciiDoc comments were emitted into the document as body text. |
| prometheus | ★ 66k | #19501review | Crash | RDS discovery dereferenced an optional cluster ARN; a response without it took the process down. |
| rclone | ★ 60k | #9787review | Silent loss | Gofile and Google Photos: the truncated-upload bug on two more backends. |
| rclone | ★ 60k | #9985review | Wrong result | A size passed to the rc API as a JSON number was read as KiB, not bytes: 44040192 asked for 42 MiB and set 42 GiB. |
| cobra | ★ 45k | #2473review | Wrong result | Help text alignment depended on the order commands were attached; cached path lengths went stale on re-parenting. |
| unstructured | ★ 16k | #4451review | Silent loss | <details>/<summary> content was discarded from HTML. |
| unstructured | ★ 16k | #4503review | Silent loss | <figure> content was discarded from HTML. |
| thanos | ★ 14k | #8976review | Crash | Remote-write v2 label references were not bounds-checked, so a malformed client payload panicked the request. |
| langchain4j | ★ 13k | #6308review | Silent loss | Splitting by UTF-16 code unit cut surrogate pairs in half, producing chunks that cannot be encoded as UTF-8. |
| chainlit | ★ 13k | #3013review | Feature | Per-user OAuth for HTTP MCP server connections. |
| go-git | ★ 7.8k | #2359review | Wrong result | A subsection name containing a newline was written raw, producing a config file neither go-git nor git can read back. |
| hermes-workspace | ★ 6.7k | #735review | Wrong result | The MCP server list was fetched from the wrong endpoint on both the probe and data paths. |