2026-06-10 Bulk Session Tracker โ
Live working log for the 2026-06-10 multi-topic session. Single roll-up PR off claude/bulk-2026-06-10 โ dev; sub-branches merge in locally. Updated as work lands.
Session scope โ
| # | Topic | Issue | Sub-branch | Status |
|---|---|---|---|---|
| 1 | Map background โ black + VenuesMap Storybook playground (theming props + controls) | #574 | feat/574-map-dark-basemap | merged (6 commits) |
| 2 | CTA audit & consolidation against Foundations/CTAs catalog (step 9 auth/landing/merchant primaries deferred) | #564 | refactor/564-cta-consolidation | merged (7 commits) |
| 3 | User-facing public website (apps/site), decoupled from VitePress dev docs โ "What Lantern Is" deck port | #575 | feat/575-user-site | merged (3 commits) |
| 4 | GitHub billing: receipt-day costs + realtime current period; Copilot tier + status-card fixes | #576 | fix/576-github-billing-receipt-day | merged (5 commits) |
| 5 | Dynamic config: maintenance mode + editable venue config (#263; #237 re-scoped, stays open) | #263, #237 | feat/263-dynamic-config | merged (7 commits) |
| 6 | (mid-session) Hero ad missing on cold loads โ venues-anchored gate + one-way late-fill + parallel selection | #577 | fix/577-hero-cold-load-gate | merged (1 commit) |
Operating rules for this session โ
- Main checkout stays on
devuntouched; all work in worktrees under.claude/worktrees/. - Integration branch
claude/bulk-2026-06-10(offorigin/dev) is the remote backup surface โ sub-branches merge into it locally, it gets pushed periodically (standing approval granted for this session's branches, pre-PR). - One draft PR at the end (
Closes/Refslines map every issue).npm run validateruns once before the PR. - Issues filed for any topic that lacks one, before implementation.
- Operator review gate (added 2026-06-10 mid-session): after sub-branches merge into
claude/bulk-2026-06-10and validation passes, the branch is pushed and work PAUSES for Mechelle's review. The draft PR is opened only after her explicit go-ahead.
Inputs โ
- Design deck: Claude Design handoff bundle (
What Lantern Is.html+ design system + chat transcripts), extracted to/tmp/lantern-deck/what-lantern-is-slide-deck/. - #237 vs #263: overlap confirmed โ both move venue config to Firestore + admin editing. #263 (Phase C of closed #262) is the newer, detailed spec; #237's uncovered remainder (category-map/search-expansion editability) stays out of scope unless trivial.
- #325 (Docs CMS, audience-scoped builds) is related to topic 3 but distinct: topic 3 is a public marketing/about site from the deck, not the docs CMS.
Decisions โ
- Map (#574): swap to OpenFreeMap
darkstyle (same keyless host, already in CSP) + post-load paint overrides (pure-black background, brightened labels) + marker/badge contrast bumps + dark popup CSS (fixes pre-existing white-on-white popup bug). Rejected: CSS invert filters (mangles labels), vendored style JSON (50-layer maintenance). - CTA (#564):
DashboardButtonis the canonical Button (superset, only real consumers); the flat#f5333ared becomes thedangervariant's look (it's the documented deliberate design in ActiveLanternView) and all extinguish surfaces converge on it via a singleperformExtinguish(reason); filter-chip active = white; newToggleSwitchprimitive withrole="switch";UI_CATEGORY_FILTERSexported from venueConfig. Authamber-400/landing/merchant primary reconciliation deferred (biggest visual blast radius โ follow-up). - Site (#575):
apps/siteVite vanilla workspace (no React); faithful port of the final 18-section deck as a responsive scroll page; tweaks panel dropped (defaults are the design: amber accent, standard glow, numbered dividers, flicker on behindprefers-reduced-motion); the two surviving em dashes rephrased per the operator's no-em-dash rule; beacon swatch derives from@lantern/uipalette; dev-only deploy wiring (prod intentionally deferred). - Billing (#576): receipt-day subscription rows from
invoice_actuals(keyedraw_email_id, not gap-gated, subscription charge only); metered branch unchanged; reconciliation estimate includes receipt rows;GITHUB_COPILOT_PLAN=pro_plus; Copilot card picks full-month subscription charge; Billing.jsx stops discarding the CF's live GitHub number for the current-month headline. BQ cleanup of old prorated rows is a documented post-merge step, not run in this session. - Config (#263): maintenance doc gets
allow read: if true(logged-out visitors must see the gate too); other systemConfig docs read = authenticated; write = admin.VENUE_REFRESH_THRESHOLDSgets actually wired intovenueRefreshService(currently dead display-only config). #237 stays open, re-scoped to its uncovered remainder (OSM tag lists / category-map editing). - Docs exposure finding: standalone VitePress deploys (docs.ourlantern.app, docs.dev.ourlantern.app) serve the full internal corpus with no auth gate โ reported to operator privately; deliberately NOT filed as a public issue and NOT changed this session.
Round 2 โ operator QA follow-ups (all merged) โ
- Hero (#577) moved into Places Nearby: renders as the section's first card slot with a reserved sponsored-skeleton while the offer call is unsettled (1.5s cap post-venues, suppressed for areas recorded ad-less; stale hero sightings count as a prior). In-place swap = zero layout shift; late-fill fallback now inserts within the section.
- VenuesMap story realism: default
striplayout mirrors real venue density (tight clusters along a street corridor + stragglers, deterministic),layout/clusterSpreadcontrols; story regrouped toComponents/Dashboard/VenuesMapbeside LivingFlame. - Venue Config tabbed layout: users-page idiom (PageHeader breadcrumb Config โ Venue Config + routed PageTabs: Tiers | Import | Refresh | Overpass), single header Save (primary) + Reset (secondary), state survives tab switches, unsaved-changes badge. All editing semantics unchanged. Recommendation noted: later collapse the whole Config section into one tabbed page (separate PR).
- Site v2 (#575) โ deck port โ real website: sticky nav (scrollspy, mobile disclosure menu) + footer chrome as shared partials; motion layer (scroll reveals, living flame + embers, parallax ghost numbers, connector draw-in, beacon shimmer) fully behind
prefers-reduced-motion; Vite MPA architecture + README add-a-page recipe; default-deny SEO lockout (every hostname noindexed via worker header + meta tag unless in an allowlist that ships empty). Build โ two independent critics (design + quality) โ polish pass applied all MUSTs (tablet/phone nav layout, beacon palette visibility,<main>landmark, footer contrast, no-JS disclaimer) + self-hosted Inter, strict CSP without unsafe-inline. Decisions: this content = the marketing site's home page (/); domain layout (operator, 2026-06-10): app keeps the apex (ourlantern.app/dev.ourlantern.app), website =light.ourlantern.app/light.dev.ourlantern.appโ deliberate inversion of marketing-at-apex since the app URL is what users share. Recorded inapps/site/README.mdDomains section.
Landed โ
- All five topic branches merged into
claude/bulk-2026-06-10with zero conflicts; fullnpm run validate= 21/21 PASS (including the session's own new checks: CTA Classes, Site Validation). - Hero-ad investigation (mid-session addition): selection data verified healthy in Firestore (1 live hero offer), server selection timed at ~2.0s cold / ~0.9s warm vs the client's 250ms first-paint gate (
OFFERS_FIRST_PAINT_TIMEOUT_MS, HomeView.jsx). Fix pending operator decision.
Post-merge manual steps (deliberately NOT done in this PR) โ
- BigQuery cleanup (billing #576): delete old prorated GitHub rows + rebuild โ exact DELETEs, invocation, and validation queries in
docs/worklog/2026-06-10_github-billing-receipt-day_NOTES.md. Also force-dispatch the ingest-github deploy (path-gated, so theGITHUB_COPILOT_PLAN=pro_plusenv fix won't roll out on its own); May 28 invoice needs an ingest-invoices re-capture (NULL subscription breakdown). - Cloudflare Pages project (site #575): one-time
npm run site:pages:create:dev, then attachlight.dev.ourlantern.appin the CF dashboard (domain layout decided โ see README Domains section; the worker is default-deny so no host constant needs editing for dev). - Firestore rules deploy (config #263): rules ship with the PR and deploy via the normal GitHub Actions flow on merge; maintenance mode + venue config editing are inert until then. No seeding needed โ all readers tolerate missing
systemConfigdocs. - Docs-exposure decision (reported privately, not filed): standalone VitePress deploys at docs.ourlantern.app / docs.dev.ourlantern.app serve the internal corpus ungated.
Pre-PR code review (2026-06-11) โ
xhigh 9-angle review over origin/dev...HEAD: 51 raw candidates โ 33 verified non-refuted โ top 15 CONFIRMED fixed pre-PR:
services/api/venues/src/routes/import.jsโ.default(true)on the include-tier flags made the config-driven importDefaults unreachable; flags are now.optional()so omitted flags fall through to systemConfig overrides.apps/admin/src/admin/config/ConfigVenue.jsxโ reset-confirm copy claimed live clients pick defaults up in seconds; reworded to claim only what the venue API actually consumes.apps/admin/src/admin/config/ConfigVenue.jsxโ Refresh Thresholds tab now carries a "Not yet wired" caveat (values save, nothing reads them yet).apps/admin/src/admin/config/ConfigVenue.jsxโ Import Defaults lat/lng/radius/limit fields carry the same "Not yet wired" caveat (include-tier checkboxes ARE consumed).apps/admin/src/admin/config/ConfigVenue.jsxโ Overpass timeout validation now requires >= 1000 ms (sub-second values rounded to[timeout:0]server-side).services/api/venues/src/services/osm.service.jsโ converted Overpass timeout clamped to >= 1s so a bad stored override can never emit[timeout:0].services/api/venues/src/lib/dynamicConfig.jsโ tier-filter tags from Firestore are sanitized (/^[a-z0-9_:-]+$/) before being joined into the Overpass QL regex; non-conforming tags dropped with a warning, emptied arrays fall back to compiled defaults.apps/admin/src/admin/config/ConfigFeatureFlags.jsxโ maintenance toggle no longer publishes the unsaved textarea draft; it writes the persisted message, so only "Save message" publishes drafts.apps/admin/src/admin/config/ConfigFeatureFlags.jsxโ stopped writingupdatedBy/updatedByEmailinto world-readablesystemConfig/maintenance(leaked admin UID + email to logged-out visitors); display removed.apps/admin/src/admin/config/ConfigVenue.jsxโ same leak one tier down:updatedBy/updatedByEmailremoved fromsystemConfig/venueswrites and from the header display.firestore.rulesโ maintenance-doc comment updated to match the new write shape (enabled/message/updatedAt only; never write admin identity).services/dataform/definitions/norm/fact_cost_line_items.sqlxโ GitHub subscription double-count self-heal: incremental-only pre_operations DELETE of both regimes' subscription rows (receipt-day + synthetic) before the MERGE re-inserts the currently-owned set; a github_usage_raw backfill moves the ownership floor and the MERGE never deletes.tooling/scripts/lint.cta-classes.jsโ--update-baselinenow prunes ignore entries pointing at deleted files (the warning recommended a command that could never prune them).tooling/scripts/lint.story-coverage.jsโ--update-baselineno longer silently deletes thetitleExceptionskey.tooling/scripts/lint.story-coverage.jsโtitleExceptionsnow excuse only the minSegments depth rule; an excepted story still fails on a wrong group prefix or missing title.
Standing follow-up (issue to be filed): refreshThresholds and importDefaults lat/lng/radius/limit overrides save to systemConfig/venues but are not yet consumed anywhere (only tierFilters, overpass.*, and importDefaults.include* reach the venue API). The admin UI now carries an honest caveat until they're wired.