Thursday, July 30, 2026

DigitalOcean Gave Me Less Than a Month. Then React Router Made Me Upgrade Three Major Versions at Once.


I'm a solo student developer. I built Naval PM, a real project-management tool with real signed-up users, on a $200 DigitalOcean credit from the GitHub Student Developer Pack — advertised, like every year before it, as valid for one year from signup.

I created my account on July 4, 2026.

What I didn't know: DigitalOcean had already started winding the whole partnership down. On June 8, they quietly cut what the credit could be spent on. On June 12, they started emailing existing pack users that the program was ending, with every credit — no matter when it was redeemed — expiring August 1, 2026.

I signed up after that email went out, so I never saw it. What I did see was a redemption page that, as far as I could tell, still said "valid for one year." Other students who redeemed in that same window later found their actual billing page showed the real expiration — August 1 — nowhere near what the page had promised. Some only found out by asking support directly.

July 4 to August 1 is less than four weeks.

That's not a 60-90 day courtesy notice. That's not even the year I signed up expecting. That's "the marketing page and the real terms were already two different things by the time I hit redeem."

So I migrated. Fast.

I moved everything to Oracle Cloud's free tier: 1 shared vCPU, 956MB of RAM, a 45GB disk. It's small — genuinely, uncomfortably small for a Node + Postgres app with real users — but it's mine, and nobody can pull it out from under me with three weeks' notice.

I hardened it properly: three layers of firewall (Oracle's own NSG, ufw, and iptables), real Let's Encrypt TLS, and a 2GB swap file tuned so real RAM gets used first and swap is a safety net, not routine behavior. On a box this small, that last part is the difference between "a little slow" and "the OOM killer just ended your Postgres connection mid-request."

I thought that was the hard part. It wasn't.

Then GitHub flagged a "High" severity CVE

Right after finishing the migration, a Dependabot alert showed up:

React Router: RSC Mode CSRF Bypass Allows Action Execution Before 400 Response Severity: High (7.1) · Patched in react-router@8.3.0

The instinct is to panic-patch. I didn't — I checked first. The CVE only applies to React Router's unstable RSC (React Server Components) mode. My app uses plain, stable BrowserRouter / Routes / Route. Not exploitable, technically. I could've closed the alert and moved on.

I didn't. I decided to actually take the upgrade — which turned out to be a much bigger decision than it sounded, because react-router@8.3.0 requires React ≥19.2.7. One "patch a CVE" ticket became "upgrade React, react-router, and everything downstream of both, on a live app, on a box with less than 1GB of RAM."

What that actually took

  • Auditing every library that touches React to see what would actually break: react-leaflet (v4→v5, checked the one map component that uses it), resend (the email SDK — jumped 3→6 mainly to drop a dependency pinned to React 18, then double-checked the actual send API hadn't changed shape), recharts and lucide-react (deliberately held back from their newest majors — no reason to stack more risk than the upgrade already required).
  • Rewriting 29 files' worth of imports, because React Router v8 folded react-router-dom into react-router and stopped publishing it separately.
  • Catching a genuinely nasty gotcha: the upgrade had been prepared in a separate work session, from a snapshot taken before I'd hardened my production config (a capped database connection pool, Docker memory limits). Merging it in silently reverted all of that hardening — no error, no warning, just a quiet regression sitting in the diff. Had to catch it by explicitly diffing the exact files I knew I'd touched before, not by trusting a clean git status.
  • A full verification pass before deploying anything: clean install, clean production build, 348 passing tests across 37 suites, clean security/audit checks in CI — and then, because none of that actually proves a browser renders the page correctly, an honest manual click-through of the live site.
  • A ~10-minute container rebuild on a single shared vCPU, because bumping the Docker base image from Node 20 to Node 22 invalidated every cached layer.

It worked. Zero downtime, zero broken pages, and — as a nice side effect — the original CVE alert and its matching Dependabot PR both auto-closed themselves the moment the fix landed on master.

The actual lesson

None of this — the migration, the hardening, the forced three-library upgrade — was optional or was work I chose to sign up for on July 4. It was the cost of building on infrastructure I didn't control, with terms that could (and did) change under me with barely any notice.

If you're a student building something real on free credits: back up everything, assume the free tier is a loan that can be called at any time, and budget real hours for "unplanned infrastructure work" into every project — because eventually, something you didn't choose will force your hand, usually at the worst possible time.


Naval PM is a project management tool I built and run solo. If you've been through a similar forced migration or upgrade, I'd genuinely like to hear how it went for you.

Thursday, July 16, 2026

The Anatomy of a "Trivial" Dependency Update

Dear readers,

Every week, NAVAL-SEM — my free, offline SEM (structural equation modeling) desktop app — gets a batch of Dependabot PRs. Six of them showed up this week. All patch or minor version bumps. All green checkmarks. The kind of PR most maintainers merge without a second look.

I decided to actually test them first. Here's what I found instead.

Step 1: Zero tests collected

Before touching any dependency, I ran my test suite locally to establish a baseline.

collected 0 items
no tests ran in 0.24s

My test suite has 200+ tests. Running pytest from my actual repo directory found none of them. It turned out my tests lived in a separate local validation folder — kept out of the public repo deliberately, since the test cases encode methodology I don't want competitors reverse-engineering. But that folder had never been symlinked or copied into the actual working checkout. I'd been "running my tests" against an empty directory for who knows how long.

Fix: copied the tests into the repo under a gitignored tests/ folder, so they run locally without ever being pushed publicly.

Step 2: A resolver conflict hiding behind CI's green checkmark

With tests actually discoverable, I ran uv sync --upgrade to pull in the pending bumps. The resolver refused:

× No solution found when resolving dependencies
  ╰─▶ Because pydantic==2.13.4 depends on pydantic-core==2.46.4
      and your project depends on pydantic-core==2.47.0,
      we can conclude that your project's requirements are unsatisfiable.

Two lines in pyproject.toml — a direct pin on pydantic and a separate direct pin on pydantic-core — had drifted out of sync. pydantic-core isn't meant to be pinned directly at all; it's a transitive dependency pydantic manages internally. An earlier Dependabot PR had bumped pydantic-core on its own, without anyone (bot or human) checking whether pydantic itself still agreed with that version.

CI never caught this because CI only validates the diff in a given PR — not whether the cumulative state of all your pins is internally consistent.

Fix: dropped the redundant pydantic-core pin entirely and let pydantic manage it.

Step 3: A 200-test regression run, live server included

Because my tests are integration tests that hit a running instance of the app over HTTP, "run pytest" first meant "start the app in a separate terminal." Once that was in place, the full suite ran clean — twice, once for each dependency batch (narwhals + tzdata + websockets + anyio, then setuptools separately since it's a major version bump).

201 passed, 2 skipped in 805.55s

Thirteen minutes per run. Worth it — this is exactly the run that would have caught a real regression, and it's the run a solo maintainer is most tempted to skip when the CI badge already looks green.

Step 4: Chasing a log line into a dead dependency

Somewhere in the startup logs, a line caught my eye:

No graphviz package found, visualization method is unavailable

I don't call graphviz anywhere in my code. Tracing it down, it turned out to be semopy — a hard dependency for my SEM engine — silently attempting to import graphviz at module load time, for its own optional semplot() diagram function. I've never called that function. My actual model diagrams are rendered entirely client-side: a D3/SVG canvas, screenshotted via html2canvas, and shipped to the backend as a base64 PNG for report exports.

Graphviz had been sitting in my dependency tree as dead weight — a native binary with per-OS packaging quirks that I'd have had to bundle across three release platforms (Windows, macOS, Linux) for a feature I don't use.

Fix: removed the graphviz Python package and uninstalled the system binary. Nothing broke, because nothing was using it.

Step 5: The lockfile that quietly drifted

Last thing: after merging the narwhals and setuptools PRs through GitHub's UI, my local uv.lock and the committed one on master disagreed — the PRs had only touched pyproject.toml, not the lockfile. Anyone doing a fresh uv sync --locked clone would've hit a resolution mismatch that I wouldn't have seen locally, because my own environment had already been synced ahead of the commit.

Fix: regenerated and committed the lockfile in its own PR.

The takeaway

None of these six problems showed up as a red X anywhere. Every PR CI ran was green. Every one of these issues was found by actually running the software, not by trusting the badge.

If you maintain free software — even something small — this is the tax nobody sees: an hour of archaeology behind every "trivial" merge, so that the next person who clones your repo doesn't inherit a broken environment.


Thank you for reading,

N. Singh

Sunday, June 28, 2026

NAVAL-SEM: the origins

Dear Readers,

I am writing this to share something I have been quietly building for the past few months.

Today I shipped NAVAL·SEM v1.0 LTS — free, open-source software for Structural Equation Modelling. Free to download, free to use, free to cite in a methods section. No license fee. No subscription. No asking around.

Why this exists

It started with a message I saw in a research WhatsApp group. Someone was asking, at well past midnight, if anyone had a spare SmartPLS license key. Not urgently. Just quietly asking.

I have seen that kind of message before. PhD students on stipends. Researchers at institutions that cannot afford the licensing fees for professional SEM tools. The software they need to do their dissertations costs what a month's salary costs. So they ask around, and hope someone replies.

I scrolled past. But I did not forget.

The question that kept returning was simple: if a free, rigorous, citable SEM tool existed, would those people have needed to ask? The answer was no. So I set about building one.

What NAVAL·SEM does

NAVAL·SEM covers the full workflow of modern structural equation modelling research. It does PLS-SEM and CB-SEM with bootstrapped significance testing, HTMT, AVE, composite reliability, and the Fornell-Larcker criterion. In v1.0, it also adds fsQCA — fuzzy-set Qualitative Comparative Analysis with Quine-McCluskey Boolean minimisation — which rounds out the most common methodological toolkit in management and social science research.

There is a visual drag-and-drop model builder that generates lavaan syntax automatically, which means researchers who are not comfortable working from a command line can still do serious analysis. There is also a one-click APA 7th edition Word export — submission-ready measurement model tables, discriminant validity, structural model, and indirect effects, formatted to journal standards.

The release also includes moderation and mediation analysis (equivalent to Hayes PROCESS Models 7, 14 and 58/59), multi-group analysis with MICOM measurement invariance, FIMIX-PLS segmentation, Necessary Condition Analysis, Importance-Performance Map Analysis, and content validity indices.

174 tests pass in the release gate. 21 API endpoints are available for those who prefer to script their analysis.

How to get it

The software runs as a Windows desktop application and is available as an installer on SourceForge — no Python installation required. It is also listed on the Microsoft Store, which matters for researchers on managed university machines who cannot install software without administrator rights. Every release is archived on Zenodo with a citable DOI, so it can be properly referenced in a methods section.

https://naval-sem.sourceforge.io

A personal note

This was built alone, on a broken laptop. The fan runs too loud. There is a key that only registers when pressed at a particular angle. The screen flickers during heavy computation — exactly the kind that takes the longest to debug. I learned to save before every test run.

Nobody donated. The project got forked, which tells you something about perceived value, but the forks did not come with pull requests or fixes or even a kind word in the issues. The only way through that is to keep building until the work is undeniable. Not louder — just more thorough. Each release that shipped. Each test that passed. Each validated anchor value.

The laptop is still broken. The software is not.

If you know a researcher who has been quietly asking around for a license key, please share the link with them.

Yours sincerely,
N. Singh

P.S. — NAVAL·SEM is licensed under CC BY-NC-ND 4.0. The GitHub repository is at github.com/navalsingh9/naval-sem.

Wednesday, February 4, 2026

Sports Analytics Hockey: The #RourkelaPlaybook Masterclass

 As the FIH Pro League returns to the Birsa Munda International Hockey Stadium this February, the tactical landscape is shifting. Chief Coach Craig Fulton has pivoted toward a high-speed, transition-heavy style that demands absolute synchronization.

Today, I am releasing the #RourkelaPlaybook: 20 simulated tactical sequences designed to dismantle the world's best units. Every play begins with Gurjot at the center spot, highlighting India’s 2026 intent to dictate play from the first whistle.

The End of "Manual Drudgery"

The biggest bottleneck in modern coaching isn't a lack of


ideas—it's the repetitive manual work. Most analysts spend hours redrawing the same press structures or baseline exits on whiteboards or static PDFs.


Our portal changes that. With the Save & Load functionality, coaches can build a complex 11v11 simulation once, save it to the cloud, and reload it in seconds to test variations against different opponents. We are moving from sketching to simulating.

https://huggingface.co/spaces/singhn9/indian-hockey-tactics-sim 

https://navalsingh.notion.site/


Part 1: India vs. Belgium – Cracking the Red Lions

Focus: Dismantling the European "Zonal Pinch" and exploiting the 140px Keeper Restraint Zone.

B-01    The Rourkela Reset: 

High-speed center restart via Gurjot to catch the Belgian mid-block before they set.





Wednesday, December 31, 2025

DirectDelta: Farewell to the year 2025

 Dear Readers,

I am writing to you sitting at my study corner typing away my thoughts as the year 2025 passes by.

This year DirectDelta blog brought to you a data driven look at the changing jobs scenario in India.

We also kept a sharp eye out on the contemporary research and development in the domain of Artificial Intelligence by posting about NVIDIA GTC.

We also posted about the developments on database technology and highlighted the impact it would have on software applications that utilise intelligence in their functioning.

This blog crossed the milestone of 10 years of existence this year and we have kept the promise of bringing analytics to our readers in a format that common public can interpret and incorporate the resultant insights into their lives.

I am thankful to the readers and I hope that you had as much fun reading the posts as I had creating them.

See you again in 2026!



Yours sincerely,

N. Singh

PS: This blog is called DirectDelta to honour my consulting partner Mr. Dipayan Mitra, who used to call me Dirac Delta due to my ability to answer questions fast, like a Dirac Delta function spike.

Monday, July 7, 2025

Updated Monthly Job Posts Trend Chart - July 2025

Hi,

This is not the sum of all the jobs posted in India. 

Instead, this is the chart containing ana analysis of job results collected and sampled from a prominent website and therefore, the monthly trend is a quasi-indicator of market.

Thank you.

Older posts:

My post from April 2025 is linked here: https://directdelta.blogspot.com/2025/04/monthly-trend-of-new-job-posts-india.html

My post from May 2025 is linked here: https://directdelta.blogspot.com/2025/05/updated-monthly-job-posts-trend-chart.html

My post from June 2025 is linked here: https://directdelta.blogspot.com/2025/06/updated-monthly-job-posts-trend-chart.html

Tuesday, June 3, 2025

Updated Monthly Job Posts Trend Chart - June 2025

 Hi,

This is not the sum of all the jobs posted in India. Instead this is the chart containing results collected from a prominent website and the trend is an indicator of market.

My post from April 2025 is linked here: https://directdelta.blogspot.com/2025/04/monthly-trend-of-new-job-posts-india.html

My post from May 2025 is linked here: https://directdelta.blogspot.com/2025/05/updated-monthly-job-posts-trend-chart.html


Thank you.

DigitalOcean Gave Me Less Than a Month. Then React Router Made Me Upgrade Three Major Versions at Once.

I'm a solo student developer. I built Naval PM , a real project-management tool with real signed-up users, on a $200 DigitalOcean credi...