Lantern Risk Balance: Complexity vs Stage and Build Sequencing โ
Date: 2026-06-28 Status: Living assessment Context: Companion to the business docs index and the canonical business plan it points to. Those cover the market, the model, and the money. They do not weigh build-sequencing risk: whether we are building infrastructure ahead of the stage we are actually at. This doc fills that gap. Every code-level claim below was verified against the repository during the assessment; see "Verification notes" for what held and what did not.
What this is, in one paragraph โ
Lantern's code is strong, the architecture is honest, and most of the infrastructure is already built and stable. That is exactly why the real risk is easy to miss. The danger is not that something is poorly engineered. The danger is that we have built more capability than we have validated demand for, and we are still deciding where to spend the next hour. The headline judgment: complexity is running ahead of validated demand, and the two risks that can actually sink the pilot are (1) where we point our effort, and (2) whether a venue or a user opens the app and sees it empty. Code quality and infra polish are not the threat. Allocation and liquidity are. Everything below triages what to keep investing in, what to leave alone, and what to stop building until the world gives us real data to build against.
The two risks that actually matter โ
Most risk conversations about a project like this drift toward code quality, uptime, scaling headroom, and security posture. Those are real concerns, but for Lantern at v0.1.0, pre-launch, admin-only, they are not where the project lives or dies. Two other risks are.
Risk 1: Allocation and sequencing โ
This is the risk that we build the right things in the wrong order. Lantern is essentially a solo project (roughly 113 of 145 commits are the operator's). Every hour is zero-sum. An hour spent designing an ad-attribution schema is an hour not spent finding out whether a single human being will pull out their phone and light a lantern at a bar.
The trap is subtle because the deferred work is not wrong in principle. The ad network will matter someday. An internal query tool would be nice someday. But "someday" work done today is borrowed against the only thing that is scarce right now: the learning that comes from putting the core loop in front of real people. Complexity has gotten ahead of validated demand. The fix is not to delete capability, it is to stop adding to the parts of it that real-world usage has not yet asked for.
Risk 2: Liquidity, the cold start of the network โ
Here is the plain-English version. Lantern is a "who is here right now" app. Its whole value is that you open it at a venue and see other real people present, lanterns lit, someone to wave at. Now imagine the very first person to ever open it at a venue. They see nothing, because they are first. They close it. The next person also sees nothing, because the first person already left. The app is only worth using when other people are using it, but nobody is using it until it is worth using. That circular trap is the liquidity problem, sometimes called the cold start of the network.
This is the single biggest thing that deters both venues and users, and no amount of infrastructure solves it. You cannot ship your way out of an empty room. A faster API, a prettier dashboard, a sealed identity: none of it matters if the venue's staff and patrons open the app and see zero lanterns. Solving liquidity is a go-to-market problem (concentrate users in time and place, anchor to an event, seed the room) not an engineering problem. The reason it belongs in a risk-balance doc is that it is the risk most likely to be drowned out by the satisfying, tractable work of building more software. Building is the comfortable thing to do. Filling the room is the necessary thing to do.
Load-bearing vs defer triage โ
This is the genuine side-by-side decision: for each major piece of the system, do we invest now, keep it as-is, or stop building on it until reality asks for more? "Load-bearing" means the first paying venue's experience depends on it. "Defer" means the capability is valid but the work is regret-prone if done before real data exists.
| Item | What it is | Verdict | One-line reason |
|---|---|---|---|
| Zero-knowledge encryption + sealed identity | Client-side PBKDF2 (600k) + AES-GCM, BIP39 recovery, server cannot decrypt; Stage A phone hashing shipped in dev, Stage B userId sealing committed but not yet built | Invest now | Anonymity is the differentiator, and retrofitting privacy later is near-impossible, so early is the only correct time. |
| Core-loop reliability | The "light my lantern" confirmation firing fast and reliably at the moment a user is physically standing in the venue | Invest now | This is the exact spot where "infrastructure deters users" actually bites; the moment of truth has to feel instant and certain. |
| Anonymity holding + safety controls | No deanonymization leak, plus block/report abuse controls | Invest now | A single deanonymization leak or unsafe encounter ends the trust the whole product is sold on. |
| Merchant portal UX + renew-driving metrics | The dashboard a venue owner uses to judge whether Lantern worked: lanterns lit, waves, peak times, redemptions | Invest now | In a venue-led launch the portal is the storefront the first paying customer judges. Note: the web merchant dashboard currently renders hardcoded sample data, so this is a real gap, not just polish. |
| BQ event capture + retention + billing reconciliation | Capture of raw events to BigQuery before Firestore deletes them; long-term retention; estimated-vs-invoiced cost reconciliation | Keep | Firestore data is destroyed on a short timer, so uncaptured history is gone forever. This is also the substrate of monetization: the offer, impression, and redemption events captured now are what the ad network will later be built on, and they are expensive to backfill, so the event schema deserves deliberate design today. |
| The 7-service split | auth, venues, analytics, lanterns, merchants, assistant, docs as separate Cloud Run services | Keep | The split is built, stable, and scales to zero, so idle cost is negligible; collapsing it into a monolith now would cost more than it saves. Just do not add an 8th. |
| Offer to redemption loop (monetization MVP) | A venue posts an offer, a user sees it, a user redeems it, the venue sees the redemption | Invest now | This is the revenue hypothesis itself, the whole app's monetization in miniature. It is testable at one venue with simple event capture and no serving engine, so it belongs in the pilot, not after it. |
| Ad-network serving + attribution engine | Pacing, rotation, fairness, and multi-advertiser conversion attribution on top of offers (currently explicit no-op scaffolding) | Defer (but design capture for it) | The ad network is how the entire app monetizes, which makes building its engine before real data the most expensive possible place to get an abstraction wrong. Let real impression and redemption data shape it. Criticality is the reason to sequence it carefully, not the reason to rush it. |
| In-app BigQuery console / IDE | Schema browser, saved-query rail, dry-run validation as polished internal tooling | Defer | This is polished tooling for an analyst team of one; the cloud console and CLI suffice until the data and the questions are real. |
Things we reconsidered โ
Two arguments that initially looked like clean "this is over-built" wins did not survive scrutiny. Recording them honestly matters, because a risk doc that only confirms its own thesis is not trustworthy.
Correction 1: The "7 services bleed money" argument was wrong, and we retracted it โ
The intuitive worry was that running 7 separate Cloud Run services burns money every month for a pre-launch product. That is false here. All 7 services are configured for scale-to-zero (no min-instances override exists in the deploy configs), so an idle service costs effectively nothing. At pilot traffic the idle dollar cost is rounding error. We dropped the cost framing entirely.
What survives is a much smaller, non-financial point: the 7-way split carries operational surface. Seven deploy pipelines, seven secret sets, seven OpenAPI specs to keep in sync, and seven manual IAM grants (the documented footgun where --allow-unauthenticated is silently no-op'd by an org policy, so public access to /openapi.json and /health requires a manual add-iam-policy-binding per service). That surface is real, but it is mostly already paid: the services exist and are stable. The guidance is not "collapse the split," it is "do not reflexively add an 8th or 9th service."
Correction 2: The BigQuery warehouse is NOT wholly premature โ
The tempting take was that a data warehouse is classic over-engineering for a product with no users yet. That take is half right, and the half it gets wrong is the important half. Here is the distinction that matters.
Capture is a no-regret keep. Firestore data is short-lived by design. A lantern lasts 2 hours (LANTERN_DURATION_MS = 2 * 60 * 60 * 1000), a connection roughly 4 hours, and waves expire fast as well, with both native Firestore TTL deletion and scheduled cleanup sweeps reconciling the rest. (The longer "48h / 7d / 30d" figures elsewhere in the docs are outer cleanup windows, not the active lifetime, which is much shorter.) The consequence is blunt: any event not copied into BigQuery while it exists is permanently and unrecoverably lost. You cannot backfill what is already deleted. The warehouse is the only place history can live, and billing reconciliation rides the same pipeline and is what confirms the numbers actually balance against cost. That makes capture plus retention a keep, not a luxury.
Modeling is what we defer. Building the attribution and serving model on top of that captured data is the regret-prone part, because its shape depends on real impression volume, a real advertiser's reporting and targeting requirements, and real conversion paths that do not exist yet. Capture the raw events richly now (impressions, offer views, redemptions, with venue and timing). Design the attribution schema later, once a venue running real offers gives you real data to model against. Capture without a model is fine; the events just sit there durably. A model built without data is a guess you will have to migrate out of.
So the warehouse splits cleanly: the part that catches history before it evaporates is load-bearing, and the part that interprets history into an ad product is premature.
Clarification 3: The ad network is the entire monetization model, which sharpens the sequencing rather than reversing it โ
An important note that arrived after the first pass: offers and the ad network are not a side feature, they are how the whole app makes money. The instinct is that this should pull the ad-network engine forward into "build it now." It does not, and the reason is worth stating plainly. "The ad network is the monetization" is a claim about importance. "Defer the serving engine" is a claim about timing. They do not collide. If anything, the more your revenue depends on the ad network, the more expensive it is to build its engine on guessed-at assumptions, because migrating your entire monetization schema later is the worst possible thing to have to migrate.
What the note does change is two things. First, it raises the stakes on capture: the offer, impression, and redemption events you log today are the foundation the whole revenue model will be built on, so the event schema deserves deliberate design now even though the serving logic does not. Second, it pulls the minimal monetization loop (a venue posts an offer, a user sees it and redeems it, the venue sees the redemption) into the core of what the pilot must validate. The pilot is no longer only asking "will people light lanterns," it is asking "will people respond to offers, and will a venue pay for that." The complex part (pacing, rotation, fairness, multi-advertiser attribution) still waits for volume. Criticality is the argument for sequencing it carefully, not for rushing it.
Concrete next actions โ
In order:
- Get the core loop in front of real people at one venue before adding any more infrastructure. This is the one that addresses the dominant risk. The next unit of progress is not a service, a schema, or a dashboard feature. It is one real room with real people lighting real lanterns, which is also the only thing that tests the liquidity problem. Because the ad network is the entire monetization model, that first room should also test the offer-to-redemption loop, not just presence: the business hypothesis is that people respond to offers and a venue will pay for that, and one venue can test it with simple event capture and no serving engine. Everything below is in service of making that first room succeed, not a substitute for it.
- Wire the merchant portal to live data and treat it as the storefront. The web merchant dashboard currently shows hardcoded sample offers and metrics. Connect it to the live Firestore-backed metrics (which already exist and are decoupled from BigQuery) and surface the 4 to 5 numbers that earn a renewal: lanterns lit at their venue, waves, peak times, offer redemptions, with obvious accuracy. "Up to par" means trustworthy and clear, not feature-rich.
- Keep raw event capture, defer the modeling, but design the monetization schema deliberately. Keep streaming rich raw events into BigQuery so history exists. Because the offer, impression, and redemption events are the foundation of monetization, give that schema deliberate thought now even while deferring the serving logic. Defer the ad-network attribution/serving engine and the in-app BQ console/IDE until a venue has actually run a real offer against real traffic. Capture is no-regret; the engine and bespoke tooling are regret-prone while speculative.
- Measure cold-start latency before spending to fix it. Services scale to zero, so the first request after an idle window can pay a 2 to 3 second wakeup. This is a known tradeoff, not yet a measured or reported problem at pilot traffic. Do not pre-emptively buy
min-instanceswarming. Instrument the core-loop latency first; if the moment-of-truth check-in is measurably slow, then weighmin-instancesagainst the better long-term fix for durability-critical paths, which is Firestore-backed state rather than always-warm compute. Mitigate what you measure, not what you imagine.
Verification notes โ
These claims were checked against the code during this assessment. For a future reader, here is what actually held.
- Firestore data is short-lived, so uncaptured history is permanently lost (makes BQ capture a keep): HELD (high confidence). Code-enforced expiry (lanterns 2h, connections ~4h) plus native TTL and scheduled cleanup confirmed; events are captured to BigQuery before expiry.
- Merchant dashboard reads from Firestore and is decoupled from BigQuery (portal can be venue-ready without the warehouse): HELD (high confidence).
metrics.service.jsusesadmin.firestore()only, with zero BigQuery references. Clarification: the dashboard is merchant-facing (business owner), and the user check-in path never touches analytics at all. The web merchant dashboard is currently a stub rendering sample data. - Core-path services are usually cold, so
min-instances=1is the correct cheap fix: DID NOT HOLD as stated (high confidence). Scale-to-zero on all 7 services is confirmed and cold starts can add 2 to 3 seconds, but "usually cold" and "correct fix" are not evidenced: there is no reported user-facing cold-start problem at pilot traffic,min-instancescarries a real recurring cost, and for durability-critical paths the recommended fix is Firestore-backed state, not warming. Reframed above as "measure before you mitigate." - Zero-knowledge encryption + sealed identity are genuine architectural differentiators: HELD (high confidence). Client-side PBKDF2 (600k), AES-GCM, BIP39 recovery, and server-cannot-decrypt are shipped in
encryption.js; Stage A is done in dev, the custom-token OTP bootstrap is built and dormant behind a flag, and Stage B is committed but not yet built. - Offer/ad-network infrastructure is early (capture shipped, model and merchant tooling not built): HELD (high confidence). Raw offer/ad events stream to BigQuery; the pacing/rotation/fairness engine is explicit no-op scaffolding gated behind the sealed-identity migration; the web merchant dashboard is a stub with sample data.