Loupely Lens ships the Cadillac build: 6 new capture fields, mismatch detection, credit refunds, and bug fixes
What this is
The Cadillac build adds 6 structured fields to every Lens capture file: dom_structure, specificity_ladder, ancestor_scan, dangerous_properties, origin_intelligence, and session_diff. These aren’t extras. They’re what makes the developer briefing precise. Before this build, the capture file described what Lens found. Now it describes what to do about it — minimum specificity to win, ancestor constraints causing the gap above an element, properties that will make content invisible on certain backgrounds, and how the element’s CSS has changed since the last time you clicked it.
Two separate Haiku calls now run on every diagnosis. One writes the founder diagnosis in normal human terms. The other writes the situation_summary for the developer in the capture file — technical language, named selectors, specificity values, origin types. One prompt can’t satisfy both audiences. Two calls means neither output hedges for the other.
Mismatch detection runs before every diagnosis. When your description contains behavioral keywords — “won’t expand,” “doesn’t work,” “nothing happens” — and the CSS classifier found a visual problem, Lens flags the gap. The triage routes to developer handoff regardless of CSS confidence. The capture file still ships. The developer gets both the CSS picture and the flag.
The triage page is rebuilt as a 3-layer structure. Option 1 (try it yourself) appears only when the route is diy_override or diy_settings. Option 2 (developer or AI handoff) is always visible on every triage page, regardless of route, without any click to reveal. The feedback form sits collapsed behind a link. Every CSS override and settings instruction carries a permanent “In testing — verify before applying” badge.
If a diagnosis is wrong, the credit comes back. Submit the feedback form within 48 hours, select a reason, and Lens refunds 1 credit automatically. One refund per diagnosis. The feedback row writes to Supabase and fires a Resend notification on every submission — inside the window or out.
Three bugs closed. The Vision Capture timing race that left the popup showing idle instead of confirming is fixed with a 6-retry polling loop covering 1200ms. The MutationObserver false-positive that cancelled active picks on pages with widget DOM mutations is fixed with a node count threshold — 10 or more non-Loupely element nodes required to treat a mutation batch as navigation. The auth callback bug that cleared capture keys during token refresh is fixed with a preserve branch in the auth handler.
What it answers
– what’s in the loupely lens capture file
– how do i know what specificity to use to override a css rule
– why does the css fix not work when i apply it
– what does loupely lens do when something looks wrong on my site
– what happens if the lens diagnosis is wrong
Why we built it
The capture file has always carried the right raw data. The Cadillac build is the layer that turns raw data into a briefing a developer can act on without asking follow-up questions. Session diff tells you whether the last change made anything better. Ancestor scan tells you which parent element is causing the gap. Specificity ladder tells you exactly what to write to win the cascade. The data was there. Now it’s organized.
- BuildDomStructure added to capture pipeline — tag, classes, children (up to 5, sensitive elements redacted), rendered text, and child count on every capture
- BuildSpecificityLadder added to capture pipeline — winner, competitors (up to 10 per property), and override_prescription with minimum specificity, whether !important is required, and confidence rating
- BuildAncestorScan added to capture pipeline — scans ancestor chain for layout constraints, overflow conditions, and spacing sources; 7 flags including LIKELY_SPACE_CAUSE, WIDTH_CONSTRAINT, OVERFLOW_HIDDEN, and FLEX_CONSTRAINT
- BuildOriginIntelligence added to capture pipeline — aggregates all origins in stylesheet_map with editability, fix strategy, and !important count per origin
- BuildSessionDiff added to capture pipeline — diffs current capture against most recent matching capture by tag + sorted classes + URL + ancestor depth; reports changed properties with FIXED/REGRESSED/CHANGED assessment and remaining ancestor issues
- User_context block added to capture file — records founder description, timestamp, behavioral keyword match, detected problem class, and mismatch flag before the diagnose call
- Mismatch detection added to popup.js — case-insensitive substring match against 20 behavioral keywords; fires class_mismatch = true and routes to developer_handoff when description implies behavior and CSS classifier found a visual problem class
- Situation_summary added as second Haiku call in lens-diagnose.ts — technical developer briefing generated from structured capture fields, not raw CSS data; non-blocking, ships as null if call fails
- Triage.rationale added to diagnosis response — 1-2 sentences explaining why the route was chosen; generated in the same call as triage route; non-blocking
- Prompt iteration deployed to Supabase — CONSTRAINT_PROPS expanded to include padding and margin properties; diagnosis quality gate-tested on 3 captures
- Triage page rebuilt as 3-layer structure — Option 1 (diy routes only), Option 2 (developer/AI handoff, always visible, never hidden), feedback form (collapsed by default behind inline link)
- Feedback table created in Supabase — 12 columns including session_id UNIQUE constraint, denormalized problem_class/triage_route/page_builder, refund_issued flag, and product column for future Core compatibility
- Lens-feedback Edge Function deployed — JWT validation, session ownership check, duplicate guard (409 before DB constraint), denormalization, 48-hour refund window check, credits.balance +1 increment, Resend notification on every submission
- Credit refund wired end-to-end — 1 credit, within 48 hours, one per session_id; annual plan users get refund_issued = false (no credits to refund), feedback row and Resend fire on the same terms
- FORCE_CREDIT_REFRESH sent to service worker after confirmed refund — popup credit balance updates without requiring a sign-out/sign-in cycle
- Bug 1 fixed: popup showed idle state instead of confirming after a capture — Vision Capture round trip (up to 1048ms) completed after initPopup read storage; fixed with 6-retry / 1200ms polling loop after getCreditStatus; confirmed 7/7 on second test day (v1.0.78)
- Bug 2 fixed: picker overlay disappeared after first click before second click was possible — MutationObserver was firing on page widget DOM mutations (8 nodes on fibermarketexchange.com) and treating them as AJAX navigation; fixed by replacing mutations.some() with a node count threshold of 10 or more non-Loupely element nodes; confirmed with full pick on previously-failing page (v1.0.80)
- Bug 3 fixed: auth callback was clearing capture keys during token refresh — LOUPELY_LENS_AUTH_CALLBACK read ll_capture_ready before clearing and preserved it when present (v1.0.70/1.0.75)
- Bug 4 fixed: picker_pending was cancelled within 1ms on some pick attempts — same root cause as Bug 2; resolved by the same MutationObserver node count threshold fix (v1.0.80)