1import{j as e,r as m,H as B}from"./react-vendor-2456d756.js";import{S as L,E as O,a as f}from"./AdminShared-23669f86.js";import{D as R,R as I,d as P}from"./AdminCharts-e1e1fefd.js";import{D as C}from"./DiagnosticsBreakdownPanel-979be44f.js";import{L as $}from"./LatestOtaBanner-894a8b92.js";import{c as G,f as Q,M as T,r as V,a as q,o as U,m as H,Q as W,i as Y,b as D,d as v,W as K,P as z,O as J,R as X,D as Z}from"./qualityPageShared-d3dbffb6.js";import{e as ee,_ as A,$ as E}from"./index-109ef59a.js";import{g as te}from"./TelemetryBadges-3635e14f.js";import{a as ae}from"./adminTelemetryService-83f59f3d.js";import{W as le,ar as ne,T as se,cp as ie,bW as oe,G as re}from"./lucide-a6f07388.js";import"./UserAvatar-1e3e8539.js";import"./NameBadges-da81af1c.js";import"./dynamicBadgeIcons-d6336a9f.js";import"./utils-e0408a98.js";import"./adminEntityUrl-385ecbe6.js";import"./deviceLabel-966b4a53.js";import"./SpeedChart-da8f015f.js";import"./runTelemetryService-952104c5.js";import"./sentry-2cabdd57.js";import"./supabase-e274f090.js";(function(){try{var t=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{};t.SENTRY_RELEASE={id:"84e0629e1e011ac8c99cdc99289c0cc630b75609"};var n=new t.Error().stack;
1n&&(t._sentryDebugIds=t._sentryDebugIds||{},t._sentryDebugIds[n]="8452d678-2740-4812-a4ae-8065e2072386",t._sentryDebugIdIdentifier="sentry-dbid-8452d678-2740-4812-a4ae-8065e2072386")}catch{}})();const de=3,ce=["id","created_at","user_id","is_invalid","invalid_reason","start_speed","max_speed","max_g_force","start_time","end_time","sixty_to_hundred_time","sixty_to_onethirty_time","hundred_to_onefifty_time","platform","os_version","device_model","app_version","app_build","runtime_version","update_id"].join(", "),j=[{key:"sixty_to_hundred",label:"60-100 mph",time:"sixty_to_hundred_time"},{key:"sixty_to_onethirty",label:"60-130 mph",time:"sixty_to_onethirty_time"},{key:"hundred_to_onefifty",label:"100-150 mph",time:"hundred_to_onefifty_time"}],w={valid:{label:"Valid pull",color:"#36a558"},no_headline:{label:"Incomplete pull",color:"#6B7280"},empty:{label:"Empty attempt",color:"#3f3f46"},flagged_invalid:{label:"Flagged invalid",color:"#f87171"}},ue=["valid","no_headline","empty","flagged_invalid"],me=new Set(["flagged_invalid"]);function M(t){return me.has(t)}function pe(t){return t.sixty_to_hundred_time!=null||t.sixty_to_onethirty_time!=null||t.hundred_to_onefifty_time!=null}function ge(t,n,l){const i=!pe(t),o=n-l;return i&&o<de?"empty":t.is_invalid?"flagged_invalid":i?"no_headline":"valid"}function he(t){const n=t.length;return j.map(l=>{const i=t.filter(o=>o.bandTimes?.[l.key]!=null).length;return{key:l.key,label:l.label,count:i,pct:n?100*i/n:0}})}const xe=H(M,{band:(t,n)=>t.bandTimes?.[n]!=null});function fe(t,n){return{...G(t,{sinceIso:n,classes:w,order:ue,isBadClass:M,unknownDeviceLabel:"Device unknown (not stamped)"}),byBand:he(t)}}async function ye(t=12){const n=new Date(Date.now()-t*7*24*3600*1e3).toISOString();let l=[];try{l=await Q(()=>ee.from("rolling_runs").select(ce).eq("is_deleted",!1).gte("created_at",n).order("created_at",{ascending:!0}))}catch(a){return A(`${E.ui.fetch_error}.rolling_quality`)(a),null}const i=await ae(l.map(a=>a.user_id)),o=l.map(a=>{const y=(Number(a.start_speed)||0)*T,x=(Number(a.max_speed)||0)*T,u=a.user_id?i.get(a.user_id):null,p=te(u?.ota_runtime_version??null),g=V(a,p),r={};for(const _ of j)r[_.key]=a[_.time]??null;const b=a.start_time!=null&&a.end_time!=null?Number(a.end_time)-Number(a.start_time):null;return{id:a.id,createdAt:a.created_at,userId:a.user_id??null,klass:ge(a,x,y),isInvalid:!!a.is_invalid,invalidReason:a.invalid_reason??null,startMph:y,peakMph:x,maxGForce:a.max_g_force??null,durationMs:b,bandTimes:r,platform:q(a,null,g),appVersion:a.app_version??null,appBuild:a.app_build??null,os:a.platform??null,osVersion:a.os_version??null,deviceModel:a.device_model??null,updateId:a.update_id??null,fingerprintStatus:g,otaBucket:U(g),profile:u?{id:u.id,username:u.username,display_name:u.display_name,avatar_url:u.avatar_url,is_verified:u.is_verified}:null}});return{since:n,weeks:t,runs:o}}const _e=({run:t})=>{const n=j.filter(l=>t.bandTimes?.[l.key]!=null);return n.length?e.jsx("div",{className:"text-xs mt-1 flex flex-wrap items-center gap-x-2 gap-y-0.5",children:n.map((l,i)=>e.jsxs("span",{className:"flex items-center gap-x-2",children:[i>0&&e.jsx("span",{className:"text-gray-600",children:"·"}),e.jsxs("span",{className:"text-gray-300",children:[e.jsxs("span",{className:"text-gray-500",children:[l.label," "]}),D(t.bandTimes[l.key])]})]},l.key))}):null},be=t=>e.jsxs(e.Fragment,{children:[e.jsx(v,{label:"peak",value:`${Math.round(t.peakMph)} mph`}),e.jsx("span",{className:"text-gray-600",children:"·"}),e.jsx(v,{label:"max G",value:t.maxGForce!=null?t.maxGForce.toFixed(2):", ",absent:t.maxGForce==null}),e.jsx("span",{className:"text-gray-600",children:"·"}),e.jsx(v,{label:"duration",value:D(t.durationMs),absent:t.durationMs==null})]}),ve=({runs:t,drill:n,onClose:l})=>e.jsx(W,{runs:t,drill:n,onClose:l,qualityClasses:w,matchRun:xe,isNonAttempt:Y,entityKind:"rolling_run",entityNoun:"rolling run",supportsTrace:!1,noTraceText:"Rolling runs carry no telemetry trace.",renderMetrics:be,renderTimes:i=>e.jsx(_e,{run:i}),noDeviceText:()=>"device not stamped"}),je=[{key:"valid",label:"Valid",color:"#36a558"},{key:"other",label:"Flagged / incomplete / empty",color:"#6B7280"}],qe=()=>{const[t,n]=m.useState(12),[l,i]=m.useState("both"),[o,a]=m.useState(null),[y,x]=m.useState(!0),[u,p]=m.useState(null);m.useEffect(()=>{let s=!1;return x(!0),ye(t).then(d=>{s||a(d)}).catch(A(E.ui.fetch_error)).finally(()=>{s||x(!1)}),()=>{s=!0}},[t]);const g=m.useMemo(()=>{const s=o?.runs||[];return l==="both"?s:s.filter(d=>d.platform===l)},[o,l]),r=m.useMemo(()=>o?fe(g,o.since):null,[o,g]),b=m.useMemo(()=>(o?.runs||[]).filter(s=>s.platform==="unknown").length,[o]),_=m.useMemo(()=>(r?.series||[]).map(s=>{const d=s.saved||{}
1,h=d.valid||0,k=d.empty||0,N=(d.flagged_invalid||0)+(d.no_headline||0)+k,S=h+N,F=S-k;return{week:s.week,valid:h,other:N,attempts:S,validPct:F?100*h/F:0}}),[r]),c=r?.kpis;return e.jsxs(e.Fragment,{children:[e.jsxs(B,{children:[e.jsx("title",{children:"Rolling Quality, FastTrack Admin"}),e.jsx("meta",{name:"robots",content:"noindex"})]}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(le,{size:20,className:"text-[#3B82F6]"}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-white font-semibold text-lg",children:"Rolling Quality"}),e.jsx("p",{className:"text-gray-400 text-xs mt-0.5",children:"Of the rolling pulls saved, how many complete a band, and does quality track OTA build? Click any slice to inspect the runs."})]})]}),e.jsx(K,{weeks:t,onChange:n})]}),e.jsx(z,{platform:l,onChange:i,unknownCount:b}),e.jsx($,{}),y?e.jsx(L,{}):o?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-4",children:[e.jsx(f,{icon:ne,label:"Valid · real attempts",color:"#00FF7F",value:`${c.validPct.toFixed(1)}%`}),e.jsx(f,{icon:se,label:"Incomplete pulls",color:"#9CA3AF",value:c.noHeadlineCount.toLocaleString()}),e.jsx(f,{icon:ie,label:"Empty attempts",color:"#9CA3AF",value:c.emptyCount.toLocaleString()}),e.jsx(f,{icon:oe,label:"Latest build at capture",color:"#00FF7F",value:c.fingerprintReported?`${c.onLatestOtaPct.toFixed(0)}%`:", "}),e.jsx(f,{icon:re,label:"Total pulls",color:"#9CA3AF",value:c.totalRuns.toLocaleString()})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:[e.jsx(R,{title:"Rolling quality mix",subtitle:"Every saved rolling run in this window by outcome, click a slice to inspect",centerLabel:"runs",segments:r.distribution,onSegmentClick:s=>p({dim:"klass",value:s,label:`${w[s]?.label||s} runs`}),note:"Valid % is measured against REAL attempts, Empty attempts (armed at 60 mph but gained under 3 mph) are excluded, not counted as failures. 'Incomplete pull' is a real pull that gained speed but completed no band. Rolling has no phone-in-hand junk class: the tracker only arms once the car is already rolling at 60 mph."}),e.jsx(R,{title:"OTA build at capture",subtitle:"Each run's build, judged against the store latest on the day it was recorded",centerLabel:"runs",segments:r.byFingerprint,onSegmentClick:s=>p({dim:"ota",value:s,label:J[s]?.label||s}),note:"Stamped runs (2026-08 onward) carry their own runtime and are judged at capture time. Older runs fall back to the account's current fingerprint, an account-level adoption view."})]}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4",children:[e.jsx(C,{title:"Flagged rolling runs by OTA build",subtitle:c.badCount?`${c.badFromOutdated} of ${c.badCount} flagged runs (${c.badFromOutdatedPct.toFixed(0)}%) were recorded on a build that was already outdated at capture`:"No flagged rolling runs in this window",dim:"badOta",rows:r.badByOta,onSegmentClick:(s,d,h)=>p({dim:s,value:d,label:`${h} · flagged`}),emptyText:"No flagged rolling runs in this window.",note:"Rolling runs the server validation trigger marked invalid. Stamped runs are judged per run at capture time; unstamped older runs fall back to the account's current fingerprint."}),e.jsx(C,{title:"Runs by device",subtitle:"Device is stamped per run (2026-08 onward); older rolling runs have no device (no telemetry)",dim:"device",rows:r.byDevice.slice(0,10),onSegmentClick:(s,d,h)=>p({dim:s,value:d,label:h}),emptyText:"No device data in this window.",note:r.byDevice.length>10?`Showing the top 10 of ${r.byDevice.length} device models.`:void 0})]}),e.jsx(we,{rows:r.byBand,total:c.totalRuns,onDrill:p}),e.jsx(I,{series:_,segments:je,title:"Pull quality per week",subtitle:"Share of rolling pulls by outcome, bars are normalized, hover or open the table for counts",note:"Valid % is measured against real attempts (empty armed-and-never-pulled captures are excluded), matching the KPI above; the gray band in the bars still includes empties alongside flagged and incomplete pulls."}),e.jsx(X,{title:"Validation-flagged reasons",subtitle:"Rolling runs the server validation trigger marked invali
1d",rows:r.flaggedReasons,empty:"No validation-flagged rolling runs in this window."})]}):e.jsx(O,{text:"Failed to load rolling quality"})]}),u&&e.jsx(ve,{runs:g,drill:u,onClose:()=>p(null)})]})},we=({rows:t,total:n,onDrill:l})=>e.jsx(P,{title:"Band completion",subtitle:"How many rolling pulls reached each band, click a count to inspect",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"text-gray-400",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left font-normal py-1",children:"Band"}),e.jsx("th",{className:"text-right font-normal",children:"Completed"}),e.jsx("th",{className:"text-right font-normal",children:"Share of pulls"})]})}),e.jsx("tbody",{className:"text-gray-300",children:t.map(i=>e.jsxs("tr",{className:"border-t border-[#242424]",children:[e.jsx("td",{className:"py-1.5 pr-2 text-white",children:i.label}),e.jsx("td",{className:"text-right tabular-nums",children:e.jsx(Z,{value:i.count,onClick:()=>l({dim:"band",value:i.key,label:`${i.label} · completed`})})}),e.jsx("td",{className:"text-right tabular-nums text-gray-400",children:n?`${(100*i.count/n).toFixed(0)}%`:", "})]},i.key))})]})});export{qe as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.