Luxembourg Energy Transition Co-PilotMapArchitectureTelemetryAboutlive
Production case study · Azure AI + geospatial data

From public data to a defensible energy prospect.

A map-first product for finding photovoltaic opportunities, applying public tenders and answering cited questions about tariffs and law. The architecture keeps model reasoning useful while moving consequential calculations, access control and evidence into deterministic services.

90-second verdict

What was built, and what it proves

This is the shortest useful path for an interviewer. Everything below adds implementation evidence; nothing is hidden behind tabs or drawers.

Business problem

Solar, tender, price and legal data is public but fragmented and difficult to turn into a prospect a developer can act on.

Product answer

One map combines roofs and sites, tender applicability, economics and a cited assistant.

Engineering answer

Scheduled Python producers feed PostGIS/pgvector; a bounded .NET agent composes five tools.

Trust answer

Numbers come from code, legal evidence from Lex MCP, SQL is read-only and unsupported answers are refused.

Scope of the claim. “Production” means publicly deployed, monitored and continuously delivered. It does not mean enterprise traffic, a formal SLA or regulated approval. Those gaps are listed explicitly below.
01 · Live system

The model plans; bounded services decide

The online path is deliberately small. The model can select tools and explain outputs, but it cannot write data, calculate a tariff or order the interface to display unsupported results.

Safety boundaryTool output—not model prose—drives map pins and cards. Typed payloads are validated; the AI explains evidence but does not become the evidence.
sql

Read-only analysis and geo candidates; the exact query is provenance.

law

Dated Luxembourg and reviewed EU text through public Lex MCP.

search_corpus

Hybrid retrieval over current energy documents in PostgreSQL.

compute_tariff

Typed inputs into deterministic code; the model never calculates.

find_offers

Current tenders and machine-checkable applicability constraints.

Request lifecycle

One question, five visible stages

Normalize and routeThe host supplies schemas and bounded tools.
Call tools, sometimes in parallelGeo and dated-law lookups can run together.
Validate outputsDatabase role, bouncer, timeouts, caps and contracts.
Ground or refuseNo usable evidence produces a refusal.
Render deterministicallyPayload shape produces pins, cards or text.
Azure delivery plane

Small because one engineer operates it

Static Web Apps serves the client. Container Apps runs the API. PostgreSQL Flexible Server owns relational, geospatial and vector data. Azure OpenAI handles chat and vision; Content Understanding extracts tender constraints. Terraform defines infrastructure; GitHub Actions deploys through OIDC.

A second search store or more agents must earn their operating cost through measured need.

02 · Data & RAG

Batch producers create reusable facts

Ingestion does expensive interpretation once. Requests read typed, provenance-carrying rows rather than repeatedly asking a model to rediscover structure.

Geospatial prospecting

National buildings became the primary source

The first design used the solar cadastre and silently missed large industrial roofs. National building polygons now lead; the cadastre is a nullable suitability signal joined spatially. Unknown remains unknown.

Vision with abstention

yes / no / maybe, never forced certainty

Ambiguous roofs stay maybe; an outage leaves the field null. Every downstream surface preserves that distinction.

Tender intelligence

Documents become filterable predicates

Content Understanding stores verbatim text plus typed constraints. “Apply tender” is deterministic filtering, not query-time invented eligibility.

Two retrieval responsibilities

Energy documents here; temporal law in Lex

The current energy corpus uses PostgreSQL FTS + pgvector with rank fusion. Legal search is not duplicated: Lex provides dated Luxembourg and reviewed EU law, history, comparison and provenance.

Key lessonData-source quality mattered more than model sophistication. Replacing the wrong roof source improved the product more than adding another model or search service would have.
03 · Controls

Controls sit where the failure happens

Prompt instructions help, but consequential controls are enforced in code, database permissions, typed contracts or deployment gates.

FailureLive controlResidual risk
Fabricated tariffDeterministic engine + C#/Python parity; model only extracts and narrates.New formulas require code; uncovered questions are refused.
Unsafe database accessanalyst_ro, forbidden-column bouncer, timeout and row cap.A permitted SELECT may still be slow, wrong or infer data.
Confident false absenceZero rows trigger witness queries and an explicit diagnosis.Main and witness queries can share a wrong assumption.
Ungrounded proseSession-wide evidence guard; judge sees actual rows, not citation labels.Rendered rows have no separate prose-grounding score.
Wrong UI actionTyped payload shape drives pins/cards; no model render tool.Bad aliases and coordinates still need validation.
Hidden uncertaintyVision abstains to maybe; estimates and unknowns remain labelled.A human must confirm ambiguous roofs.
AI governance

Transparent, bounded decision support

The interface identifies the AI. It provides research support, not automated decisions about people. Legal and monetary answers are cited or refused; inferred labels require confirmation.

Privacy

Minimal anonymous session surface

No account or profile is required. Conversation turns support bounded continuity and are inaccessible to the analytical role. Inputs are not used for fine-tuning. A formal notice and erasure path remain gaps.

Cloud identity

Passwordless CI, not a false zero-secret claim

GitHub deploys through OIDC. Runtime credentials are Container App secrets; the PostgreSQL bootstrap password remains in protected Terraform state. Managed-identity runtime auth is the next hardening step.

Network

Appropriate for public data, not enterprise isolation

HTTPS, a restricted CORS allowlist and PostgreSQL firewall are live. Private endpoints, VNet integration, per-user authorization and retrieval ACLs are not.

04 · Decisions

One decision surface, not fourteen interruptions

Only the decisions that explain the product’s shape stay here. Full alternatives, evidence and reversal history remain in the repository.

ADR-001

Models never produce consequential numbers

Instead of
Compute with a model, then verify.
Cost
Every formula needs code and tests.
Reverse if
Refusal makes normal economics questions unusable.
ADR-002

One agent over five contract-driven tools

Instead of
One routed expert per topic.
Cost
Tool schemas become critical infrastructure.
Reverse if
Ordinary questions repeatedly hit the round cap.
ADR-003

Generic SQL finder under structural controls

Instead of
A rigid filter API.
Cost
Role, bouncer and performance need ownership.
Reverse if
Leakage or cost survives those controls.
ADR-006

Content Understanding for tenders

Instead of
PDF scraping plus another extractor.
Cost
Managed-service and model compatibility risk.
Reverse if
Constraint errors make Apply unreliable.
ADR-008

Postgres hybrid retrieval before AI Search

Instead of
A second search service from day one.
Cost
Retrieval quality is owned in-house.
Reverse if
Golden-set hit@5 falls below 0.80.
ADR-009

OIDC and Terraform delivery

Instead of
Stored CI credentials and portal state.
Cost
More identity and IaC setup discipline.
Reverse if
Never; extend managed identity to runtime.
ADR-012

National buildings supersede cadastre

Instead of
Patching a source missing valuable roofs.
Cost
Migration, re-derivation and spatial join.
Reverse if
Source noise outweighs regained coverage.
ADR-014

Benchmark model tiers; reject premium

Instead of
Assuming a larger model is better.
Cost
Token spend and evaluation work.
Reverse if
A larger independent-judge run reverses it.

All decision records in GitHub ↗ · Flagship numerical-safety decision →

05 · Evidence

Claims are paired with something inspectable

Deterministic behavior is tested on every change. Hosted-model evaluations run before releases; they are not misrepresented as per-commit gates.

5,374large buildings in the measured July 2026 roof snapshot
99.98%measured cadastre-to-building join coverage
40questions per model in the three-tier run
10/10public read-only tools in the linked Lex MCP
Model · July 2026GroundednessRelevanceRefusal recallMedian tokensp50
gpt-5-nano0.790.9314 / 1610,82240.7 s
gpt-5-mini production0.760.9415 / 1610,22717.0 s
gpt-50.770.8315 / 1614,53448.3 s

Caveats: one 40-question run; gpt-5-mini was the judge; candidate capacity differed, so latency is directional. The evidence rejected the premium tier and retained mini because refusal behavior matters most here.

Live API evidenceChecking…Reading the public status contract
registered source pipelines
currently within cadence
declared model workloads
Code gates

Every push

.NET release build, tariff parity, Python tests, schema coverage and frontend tests/build.

Model gates

Before release

Groundedness, outcome, law retrieval and agent behavior against hosted models.

Delivery evidence

After deployment

Immutable image, OIDC login, health smoke, public telemetry and source freshness.

06 · Limits

A credible personal production system, not enterprise theatre

The left is live. The right is the regulated or multi-tenant target. Adding unused Azure logos would not close these gaps.

Real today

  • Public deployment and live telemetry
  • Automated pipelines with freshness status
  • Read-only and deterministic tool boundaries
  • Terraform, OIDC and tested CI/CD
  • Measured model and retrieval choices
  • Visible abstention, refusal and provenance

Enterprise adoption adds

  • Entra runtime identity, private endpoints and VNet
  • Per-principal authorization and retrieval ACLs
  • Purview-class catalog, retention and lineage governance
  • DPIA, model-risk approval and security review
  • SLOs, load tests, on-call and disaster recovery
  • Segregation of duties and release approvals
Accepted riskWhy accepted hereTrigger / next control
Runtime secrets remain.Public read-only workload; CI credential risk was removed first.Managed identity before private or enterprise data.
Model-written SELECT may infer or be wrong.Generality is useful and visible data is public.Templates or per-user views when private data appears.
Model evals are pre-release.They cost hosted tokens and wall time.Automate after higher release frequency or a regression.
No permanent UAT environment.A personal, public-data product cannot justify duplicate standing resources. Pull requests must pass deterministic gates; main deploys an immutable image, then a live health smoke confirms it.Add an isolated integration/UAT stage, approvals and segregation of duties when a team, private data, stateful migrations or an SLA makes blast radius material.
Single-region app and database.Personal traffic cannot justify redundant standing cost.Test regional recovery when an SLA requires it.
Global cost guard may stop the app.On a personal subscription, solvency outranks uptime.Service budgets and chargeback before commercialization.

The signal is judgment, not service count.

This demonstrates problem framing, data engineering, bounded agent design, RAG, Azure delivery, evaluation and honest risk ownership. The strongest choices are the capabilities deliberately left out until evidence makes them worth operating.