This is Part 2 of a 5-part series documenting my MSSE Capstone project at Quantic: a deployed, agentic RAG system that answers natural-language questions about European electricity markets. Part 1 covered the problem and the vision — this one covers the two pivots that shaped the actual architecture.


Pivot one: the idea I killed before writing a line of code

My first instinct for this capstone wasn’t a RAG system at all. It was a systematic trading signal: take the outage and news data, find a pattern, trade on it. That’s the world I come from, and it felt like the obvious move.

It didn’t survive contact with the actual market structure. Day-ahead prices already embed public TSO forecasts: By the time an outage notice is public, the market has priced it in. And without access to intraday settlement data, there was no honest way to backtest or validate a signal even if I found one. Chasing it would have meant either fooling myself with a signal that only looked good in-sample, or building something that couldn’t be evaluated at all.

So I killed it early, before it cost me a sprint. What survived from that dead-end was the reason it was interesting in the first place: the raw material — outages, disclosures, news — is genuinely rich, and genuinely hard to synthesize by hand. The trading angle was the wrong use for that material. An analyst that reads it all and answers questions about it, with citations, was the right one.

Pivot two: where does “zone” belong?

Once I’d landed on the RAG approach, the next design question was more mundane but mattered more in practice: where does the notion of a bidding zone — DE-LU, DK1, NO2 — actually live in the system?

The instinctive answer, and the one I built first, was to make it an ingestion-time boundary. Tag each document with its zone as it comes in, keep the corpora conceptually separate, and let a query for DK1 only ever see DK1 documents. It felt clean. It also felt like something I’d regret.

Two things broke it.

The first was a data reality: not every event respects a single zone. Cross-border transmission UMMs — a notice about the Brunsbüttel interconnector, for instance — genuinely span two zones. A schema that forces events.zone to be one value can’t represent that honestly. I could have hacked around it with duplicate rows or a delimited multi-zone field, but that’s exactly the kind of workaround that looks fine on day one and turns into a maintenance tax by day thirty.

The second was a product reality: ingestion-time zone scoping means every new zone is an ingestion-time decision. Adding a zone later — which I always intended to do — would mean re-running or re-architecting ingestion, not just widening a filter. That’s backwards for a system whose whole pitch is “start narrow, prove it works, generalize.”

The fix was to stop treating zone as a property of ingestion and start treating it as a property of the query. Ingest pan-European, tag documents with whatever zones they actually touch — one, two, or none — and let zone selection happen at retrieval time as a filter, not as a wall. This is a decision I made in Sprint 2 and held firm on for the rest of the project, including when a fourth zone got added much later. It turned “add a zone” from a re-ingestion project into a config change.

The lesson underneath both pivots

Both pivots came from the same instinct: don’t let an architecture commit to more certainty than the domain actually has. The trading signal assumed a predictability the market doesn’t offer. The ingestion-time zone boundary assumed a cleanliness the data doesn’t offer. In both cases, the fix was to push the decision later — to query time, to the analyst asking the question — rather than baking a guess in early and having to unwind it.

That’s not a glamorous lesson, but it’s the one that made the rest of the project easier than it otherwise would have been.

What’s ahead

Next up: how the corpus actually gets built — the sources, the ingestion pipeline, and the unglamorous cleanup work (stripping EIC codes and zone suffixes out of asset names, for one) that makes the difference between citations that are technically present and citations a reader can actually trust.

Leave a Reply

Trending

Discover more from Convergence Point

Subscribe now to keep reading and get access to the full archive.

Continue reading