[{"data":1,"prerenderedAt":2289},["ShallowReactive",2],{"navigation_docs":3,"-cli-rules":500,"-cli-rules-surround":2284},[4,30,80,118,283,415,470],{"title":5,"path":6,"stem":7,"children":8,"page":29},"Start","\u002Fstart","1.start",[9,14,19,24],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fstart\u002Fintroduction","1.start\u002F1.introduction","i-lucide-info",{"title":15,"path":16,"stem":17,"icon":18},"Why start with evlog","\u002Fstart\u002Fwhy-evlog","1.start\u002F2.why-evlog","i-lucide-rocket",{"title":20,"path":21,"stem":22,"icon":23},"Installation","\u002Fstart\u002Finstallation","1.start\u002F3.installation","i-lucide-download",{"title":25,"path":26,"stem":27,"icon":28},"Quick Start","\u002Fstart\u002Fquick-start","1.start\u002F4.quick-start","i-lucide-zap",false,{"title":31,"path":32,"stem":33,"children":34,"page":29},"Learn","\u002Flearn","2.learn",[35,40,45,50,55,60,65,70,75],{"title":36,"path":37,"stem":38,"icon":39},"Overview","\u002Flearn\u002Foverview","2.learn\u002F0.overview","i-lucide-list",{"title":41,"path":42,"stem":43,"icon":44},"Simple Logging","\u002Flearn\u002Fsimple-logging","2.learn\u002F1.simple-logging","i-lucide-terminal",{"title":46,"path":47,"stem":48,"icon":49},"Wide Events","\u002Flearn\u002Fwide-events","2.learn\u002F2.wide-events","i-lucide-layers",{"title":51,"path":52,"stem":53,"icon":54},"Structured Errors","\u002Flearn\u002Fstructured-errors","2.learn\u002F3.structured-errors","i-lucide-shield-alert",{"title":56,"path":57,"stem":58,"icon":59},"Lifecycle","\u002Flearn\u002Flifecycle","2.learn\u002F4.lifecycle","i-lucide-arrow-right-left",{"title":61,"path":62,"stem":63,"icon":64},"Sampling","\u002Flearn\u002Fsampling","2.learn\u002F5.sampling","i-lucide-filter",{"title":66,"path":67,"stem":68,"icon":69},"Auto-Redaction","\u002Flearn\u002Fredaction","2.learn\u002F6.redaction","i-lucide-eye-off",{"title":71,"path":72,"stem":73,"icon":74},"Typed Fields","\u002Flearn\u002Ftyped-fields","2.learn\u002F7.typed-fields","i-simple-icons-typescript",{"title":76,"path":77,"stem":78,"icon":79},"Catalogs","\u002Flearn\u002Fcatalogs","2.learn\u002F8.catalogs","i-lucide-book-open",{"title":81,"path":82,"stem":83,"children":84,"page":29},"CLI","\u002Fcli","3.cli",[85,88,93,98,103,108,113],{"title":36,"path":86,"stem":87,"icon":44},"\u002Fcli\u002Foverview","3.cli\u002F0.overview",{"title":89,"path":90,"stem":91,"icon":92},"map","\u002Fcli\u002Fmap","3.cli\u002F1.map","i-lucide-radar",{"title":94,"path":95,"stem":96,"icon":97},"Rules","\u002Fcli\u002Frules","3.cli\u002F2.rules","i-lucide-list-checks",{"title":99,"path":100,"stem":101,"icon":102},"Scoring","\u002Fcli\u002Fscoring","3.cli\u002F3.scoring","i-lucide-gauge",{"title":104,"path":105,"stem":106,"icon":107},"CI","\u002Fcli\u002Fci","3.cli\u002F4.ci","i-lucide-git-pull-request",{"title":109,"path":110,"stem":111,"icon":112},"doctor","\u002Fcli\u002Fdoctor","3.cli\u002F5.doctor","i-lucide-stethoscope",{"title":114,"path":115,"stem":116,"icon":117},"telemetry","\u002Fcli\u002Ftelemetry","3.cli\u002F6.telemetry","i-lucide-bar-chart-3",{"title":119,"path":120,"stem":121,"children":122,"page":29},"Integrate","\u002Fintegrate","4.integrate",[123,127,195],{"title":36,"path":124,"stem":125,"icon":126},"\u002Fintegrate\u002Foverview","4.integrate\u002F0.overview","i-lucide-plug",{"title":128,"path":129,"stem":130,"children":131,"page":29},"Adapters","\u002Fintegrate\u002Fadapters","4.integrate\u002Fadapters",[132,135,175],{"title":36,"path":133,"stem":134,"icon":39},"\u002Fintegrate\u002Fadapters\u002Foverview","4.integrate\u002Fadapters\u002F01.overview",{"title":136,"path":137,"stem":138,"children":139,"page":29},"Cloud","\u002Fintegrate\u002Fadapters\u002Fcloud","4.integrate\u002Fadapters\u002Fcloud",[140,145,150,155,160,165,170],{"title":141,"path":142,"stem":143,"icon":144},"Axiom","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Faxiom","4.integrate\u002Fadapters\u002Fcloud\u002F01.axiom","i-custom-axiom",{"title":146,"path":147,"stem":148,"icon":149},"OTLP","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fotlp","4.integrate\u002Fadapters\u002Fcloud\u002F02.otlp","i-simple-icons-opentelemetry",{"title":151,"path":152,"stem":153,"icon":154},"PostHog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fposthog","4.integrate\u002Fadapters\u002Fcloud\u002F03.posthog","i-simple-icons-posthog",{"title":156,"path":157,"stem":158,"icon":159},"Sentry","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fsentry","4.integrate\u002Fadapters\u002Fcloud\u002F04.sentry","i-simple-icons-sentry",{"title":161,"path":162,"stem":163,"icon":164},"Better Stack","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fbetter-stack","4.integrate\u002Fadapters\u002Fcloud\u002F05.better-stack","i-simple-icons-betterstack",{"title":166,"path":167,"stem":168,"icon":169},"Datadog","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fdatadog","4.integrate\u002Fadapters\u002Fcloud\u002F06.datadog","i-simple-icons-datadog",{"title":171,"path":172,"stem":173,"icon":174},"HyperDX","\u002Fintegrate\u002Fadapters\u002Fcloud\u002Fhyperdx","4.integrate\u002Fadapters\u002Fcloud\u002F07.hyperdx","i-custom-hyperdx",{"title":176,"path":177,"stem":178,"children":179,"page":29},"Self-Hosted","\u002Fintegrate\u002Fadapters\u002Fself-hosted","4.integrate\u002Fadapters\u002Fself-hosted",[180,185,190],{"title":181,"path":182,"stem":183,"icon":184},"File System","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Ffs","4.integrate\u002Fadapters\u002Fself-hosted\u002F01.fs","i-lucide-hard-drive",{"title":186,"path":187,"stem":188,"icon":189},"NuxtHub","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fnuxthub","4.integrate\u002Fadapters\u002Fself-hosted\u002F02.nuxthub","i-simple-icons-nuxt",{"title":191,"path":192,"stem":193,"icon":194},"Memory","\u002Fintegrate\u002Fadapters\u002Fself-hosted\u002Fmemory","4.integrate\u002Fadapters\u002Fself-hosted\u002F03.memory","i-lucide-cpu",{"title":196,"path":197,"stem":198,"children":199,"page":29},"Frameworks","\u002Fintegrate\u002Fframeworks","4.integrate\u002Fframeworks",[200,204,209,214,219,224,229,234,239,244,249,254,259,264,268,273,278],{"title":36,"path":201,"stem":202,"icon":203},"\u002Fintegrate\u002Fframeworks\u002Foverview","4.integrate\u002Fframeworks\u002F00.overview","i-lucide-layout-grid",{"title":205,"path":206,"stem":207,"icon":208},"Nuxt","\u002Fintegrate\u002Fframeworks\u002Fnuxt","4.integrate\u002Fframeworks\u002F01.nuxt","i-simple-icons-nuxtdotjs",{"title":210,"path":211,"stem":212,"icon":213},"Next.js","\u002Fintegrate\u002Fframeworks\u002Fnextjs","4.integrate\u002Fframeworks\u002F02.nextjs","i-simple-icons-nextdotjs",{"title":215,"path":216,"stem":217,"icon":218},"SvelteKit","\u002Fintegrate\u002Fframeworks\u002Fsveltekit","4.integrate\u002Fframeworks\u002F03.sveltekit","i-simple-icons-svelte",{"title":220,"path":221,"stem":222,"icon":223},"Nitro","\u002Fintegrate\u002Fframeworks\u002Fnitro","4.integrate\u002Fframeworks\u002F04.nitro","i-custom-nitro",{"title":225,"path":226,"stem":227,"icon":228},"TanStack Start","\u002Fintegrate\u002Fframeworks\u002Ftanstack-start","4.integrate\u002Fframeworks\u002F05.tanstack-start","i-custom-tanstack",{"title":230,"path":231,"stem":232,"icon":233},"NestJS","\u002Fintegrate\u002Fframeworks\u002Fnestjs","4.integrate\u002Fframeworks\u002F06.nestjs","i-simple-icons-nestjs",{"title":235,"path":236,"stem":237,"icon":238},"Express","\u002Fintegrate\u002Fframeworks\u002Fexpress","4.integrate\u002Fframeworks\u002F07.express","i-simple-icons-express",{"title":240,"path":241,"stem":242,"icon":243},"Hono","\u002Fintegrate\u002Fframeworks\u002Fhono","4.integrate\u002Fframeworks\u002F08.hono","i-simple-icons-hono",{"title":245,"path":246,"stem":247,"icon":248},"Fastify","\u002Fintegrate\u002Fframeworks\u002Ffastify","4.integrate\u002Fframeworks\u002F09.fastify","i-simple-icons-fastify",{"title":250,"path":251,"stem":252,"icon":253},"Elysia","\u002Fintegrate\u002Fframeworks\u002Felysia","4.integrate\u002Fframeworks\u002F10.elysia","i-custom-elysia",{"title":255,"path":256,"stem":257,"icon":258},"React Router","\u002Fintegrate\u002Fframeworks\u002Freact-router","4.integrate\u002Fframeworks\u002F11.react-router","i-custom-reactrouter",{"title":260,"path":261,"stem":262,"icon":263},"Cloudflare Workers","\u002Fintegrate\u002Fframeworks\u002Fcloudflare-workers","4.integrate\u002Fframeworks\u002F12.cloudflare-workers","i-simple-icons-cloudflare",{"title":265,"path":266,"stem":267,"icon":74},"Standalone","\u002Fintegrate\u002Fframeworks\u002Fstandalone","4.integrate\u002Fframeworks\u002F13.standalone",{"title":269,"path":270,"stem":271,"icon":272},"Astro","\u002Fintegrate\u002Fframeworks\u002Fastro","4.integrate\u002Fframeworks\u002F14.astro","i-simple-icons-astro",{"title":274,"path":275,"stem":276,"icon":277},"oRPC","\u002Fintegrate\u002Fframeworks\u002Forpc","4.integrate\u002Fframeworks\u002F15.orpc","i-lucide-network",{"title":279,"path":280,"stem":281,"icon":282},"AWS Lambda","\u002Fintegrate\u002Fframeworks\u002Faws-lambda","4.integrate\u002Fframeworks\u002F16.aws-lambda","i-custom-lambda",{"title":284,"path":285,"stem":286,"children":287,"page":29},"Use Cases","\u002Fuse-cases","5.use-cases",[288,291,296,325,352,384,405,410],{"title":36,"path":289,"stem":290,"icon":97},"\u002Fuse-cases\u002Foverview","5.use-cases\u002F0.overview",{"title":292,"path":293,"stem":294,"icon":295},"Client Logging","\u002Fuse-cases\u002Fclient-logging","5.use-cases\u002F1.client-logging","i-lucide-monitor",{"title":297,"icon":298,"path":299,"stem":300,"children":301,"page":29},"AI SDK","i-simple-icons-vercel","\u002Fuse-cases\u002Fai-sdk","5.use-cases\u002F2.ai-sdk",[302,305,310,315,320],{"title":36,"path":303,"stem":304,"icon":39},"\u002Fuse-cases\u002Fai-sdk\u002Foverview","5.use-cases\u002F2.ai-sdk\u002F01.overview",{"title":306,"path":307,"stem":308,"icon":309},"Usage","\u002Fuse-cases\u002Fai-sdk\u002Fusage","5.use-cases\u002F2.ai-sdk\u002F02.usage","i-lucide-code",{"title":311,"path":312,"stem":313,"icon":314},"Options","\u002Fuse-cases\u002Fai-sdk\u002Foptions","5.use-cases\u002F2.ai-sdk\u002F03.options","i-lucide-sliders",{"title":316,"path":317,"stem":318,"icon":319},"Metadata","\u002Fuse-cases\u002Fai-sdk\u002Fmetadata","5.use-cases\u002F2.ai-sdk\u002F04.metadata","i-lucide-database",{"title":321,"path":322,"stem":323,"icon":324},"Telemetry","\u002Fuse-cases\u002Fai-sdk\u002Ftelemetry","5.use-cases\u002F2.ai-sdk\u002F05.telemetry","i-lucide-activity",{"title":326,"icon":327,"path":328,"stem":329,"children":330,"page":29},"Better Auth","i-simple-icons-betterauth","\u002Fuse-cases\u002Fbetter-auth","5.use-cases\u002F3.better-auth",[331,334,339,344,348],{"title":36,"path":332,"stem":333,"icon":39},"\u002Fuse-cases\u002Fbetter-auth\u002Foverview","5.use-cases\u002F3.better-auth\u002F01.overview",{"title":335,"path":336,"stem":337,"icon":338},"Identify User","\u002Fuse-cases\u002Fbetter-auth\u002Fidentify-user","5.use-cases\u002F3.better-auth\u002F02.identify-user","i-lucide-user-check",{"title":340,"path":341,"stem":342,"icon":343},"Middleware","\u002Fuse-cases\u002Fbetter-auth\u002Fmiddleware","5.use-cases\u002F3.better-auth\u002F03.middleware","i-lucide-shield",{"title":345,"path":346,"stem":347,"icon":295},"Client Sync","\u002Fuse-cases\u002Fbetter-auth\u002Fclient-sync","5.use-cases\u002F3.better-auth\u002F04.client-sync",{"title":349,"path":350,"stem":351,"icon":102},"Performance","\u002Fuse-cases\u002Fbetter-auth\u002Fperformance","5.use-cases\u002F3.better-auth\u002F05.performance",{"title":353,"icon":354,"path":355,"stem":356,"children":357,"page":29},"Audit Logs","i-lucide-shield-check","\u002Fuse-cases\u002Faudit","5.use-cases\u002F4.audit",[358,361,366,371,376,380],{"title":36,"path":359,"stem":360,"icon":39},"\u002Fuse-cases\u002Faudit\u002Foverview","5.use-cases\u002F4.audit\u002F01.overview",{"title":362,"path":363,"stem":364,"icon":365},"Schema","\u002Fuse-cases\u002Faudit\u002Fschema","5.use-cases\u002F4.audit\u002F02.schema","i-lucide-file-text",{"title":367,"path":368,"stem":369,"icon":370},"Recording","\u002Fuse-cases\u002Faudit\u002Frecording","5.use-cases\u002F4.audit\u002F03.recording","i-lucide-pen-line",{"title":372,"path":373,"stem":374,"icon":375},"Drains","\u002Fuse-cases\u002Faudit\u002Fpipeline","5.use-cases\u002F4.audit\u002F04.pipeline","i-lucide-link",{"title":377,"path":378,"stem":379,"icon":354},"Compliance","\u002Fuse-cases\u002Faudit\u002Fcompliance","5.use-cases\u002F4.audit\u002F05.compliance",{"title":381,"path":382,"stem":383,"icon":79},"Recipes","\u002Fuse-cases\u002Faudit\u002Frecipes","5.use-cases\u002F4.audit\u002F06.recipes",{"title":321,"icon":102,"path":385,"stem":386,"children":387,"page":29},"\u002Fuse-cases\u002Ftelemetry","5.use-cases\u002F4.telemetry",[388,391,396,401],{"title":36,"path":389,"stem":390,"icon":39},"\u002Fuse-cases\u002Ftelemetry\u002Foverview","5.use-cases\u002F4.telemetry\u002F01.overview",{"title":392,"path":393,"stem":394,"icon":395},"Setup","\u002Fuse-cases\u002Ftelemetry\u002Fsetup","5.use-cases\u002F4.telemetry\u002F02.setup","i-lucide-wrench",{"title":397,"path":398,"stem":399,"icon":400},"Ingest","\u002Fuse-cases\u002Ftelemetry\u002Fingest","5.use-cases\u002F4.telemetry\u002F03.ingest","i-lucide-server",{"title":402,"path":403,"stem":404,"icon":79},"Reference","\u002Fuse-cases\u002Ftelemetry\u002Freference","5.use-cases\u002F4.telemetry\u002F04.reference",{"title":406,"path":407,"stem":408,"icon":409},"Enrichers","\u002Fuse-cases\u002Fenrichers","5.use-cases\u002F5.enrichers","i-lucide-sparkles",{"title":411,"path":412,"stem":413,"icon":414},"eve","\u002Fuse-cases\u002Feve","5.use-cases\u002F5.eve","i-custom-eve",{"title":416,"path":417,"stem":418,"children":419,"page":29},"Extend","\u002Fextend","6.extend",[420,424,429,434,439,443,447,451,455,460,465],{"title":36,"path":421,"stem":422,"icon":423},"\u002Fextend\u002Foverview","6.extend\u002F0.overview","i-lucide-blocks",{"title":425,"path":426,"stem":427,"icon":428},"Stream","\u002Fextend\u002Fstream","6.extend\u002F1.stream","i-lucide-radio-tower",{"title":430,"path":431,"stem":432,"icon":433},"Custom framework","\u002Fextend\u002Fcustom-framework","6.extend\u002F10.custom-framework","i-lucide-puzzle",{"title":435,"path":436,"stem":437,"icon":438},"FS reader","\u002Fextend\u002Ffs-reader","6.extend\u002F2.fs-reader","i-lucide-folder-search",{"title":381,"path":440,"stem":441,"icon":442},"\u002Fextend\u002Fconsumer-recipes","6.extend\u002F3.consumer-recipes","i-lucide-chef-hat",{"title":444,"path":445,"stem":446,"icon":423},"Plugins","\u002Fextend\u002Fplugins","6.extend\u002F4.plugins",{"title":448,"path":449,"stem":450,"icon":409},"Custom enrichers","\u002Fextend\u002Fcustom-enrichers","6.extend\u002F5.custom-enrichers",{"title":452,"path":453,"stem":454,"icon":64},"Tail sampling","\u002Fextend\u002Ftail-sampling","6.extend\u002F6.tail-sampling",{"title":456,"path":457,"stem":458,"icon":459},"Identity headers","\u002Fextend\u002Fidentity-headers","6.extend\u002F7.identity-headers","i-lucide-fingerprint",{"title":461,"path":462,"stem":463,"icon":464},"Custom drains","\u002Fextend\u002Fcustom-drains","6.extend\u002F8.custom-drains","i-lucide-share-2",{"title":466,"path":467,"stem":468,"icon":469},"Drain pipeline","\u002Fextend\u002Fdrain-pipeline","6.extend\u002F9.drain-pipeline","i-lucide-workflow",{"title":402,"path":471,"stem":472,"children":473,"page":29},"\u002Freference","7.reference",[474,479,482,487,491,496],{"title":475,"path":476,"stem":477,"icon":478},"Configuration","\u002Freference\u002Fconfiguration","7.reference\u002F1.configuration","i-lucide-settings",{"title":349,"path":480,"stem":481,"icon":102},"\u002Freference\u002Fperformance","7.reference\u002F2.performance",{"title":483,"path":484,"stem":485,"icon":486},"Vite Plugin","\u002Freference\u002Fvite-plugin","7.reference\u002F3.vite-plugin","i-custom-vite",{"title":488,"path":489,"stem":490,"icon":354},"Best Practices","\u002Freference\u002Fbest-practices","7.reference\u002F4.best-practices",{"title":492,"path":493,"stem":494,"icon":495},"vs Other Loggers","\u002Freference\u002Fvs-other-loggers","7.reference\u002F5.vs-other-loggers","i-lucide-scale",{"title":497,"path":498,"stem":499,"icon":409},"Agent Skills","\u002Freference\u002Fagent-skills","7.reference\u002F6.agent-skills",{"id":501,"title":502,"body":503,"description":2273,"extension":2274,"links":2275,"meta":2280,"navigation":2281,"path":95,"seo":2282,"stem":96,"__hash__":2283},"docs\u002F3.cli\u002F2.rules.md","Map rules",{"type":504,"value":505,"toc":2248},"minimark",[506,510,519,522,612,617,620,669,685,688,695,828,833,836,860,863,874,881,1015,1020,1024,1030,1041,1098,1102,1106,1115,1126,1132,1138,1229,1234,1238,1249,1258,1274,1349,1354,1358,1361,1386,1392,1401,1435,1439,1443,1446,1463,1628,1633,1636,1643,1646,1750,1754,1760,1766,1772,1776,1808,1812,1841,1845,1854,1858,1866,1919,1926,1967,1971,1974,2019,2022,2066,2089,2096,2100,2110,2123,2126,2133,2140,2170,2174,2177,2183,2186,2190,2204,2208,2221,2228,2232,2244],[507,508,509],"p",{},"Coverage is checked by a rule engine, not a bag of heuristics. Each rule has a stable id, a documented weight, a docs link, and a set of entry point kinds it applies to — and every finding carries the file and line it came from, so a verdict is always something you can go and look at.",[511,512,514,518],"warning",{"icon":513},"i-lucide-flask-conical",[515,516,517],"strong",{},"This list is not final."," Ten rules is where the engine starts, not where it ends. Rules will be added, existing ones will get more precise about what counts, and a sharper rule can change a verdict on code you did not touch. Ids and weights are documented so the change is always explainable — but do not treat a score as comparable across CLI versions.",[507,520,521],{},"Rules come in two categories, and the difference matters:",[523,524,525,540],"table",{},[526,527,528],"thead",{},[529,530,531,534,537],"tr",{},[532,533],"th",{},[532,535,536],{},"Requirements",[532,538,539],{},"Opportunities",[541,542,543,555,566,586,601],"tbody",{},[529,544,545,549,552],{},[546,547,548],"td",{},"Effect on the score",[546,550,551],{},"Costs points when it fails",[546,553,554],{},"None, ever",[529,556,557,560,563],{},[546,558,559],{},"When it appears",[546,561,562],{},"Whenever it applies",[546,564,565],{},"Only when the project already uses the feature",[529,567,568,571,581],{},[546,569,570],{},"In the report",[546,572,573,577,578],{},[574,575,576],"code",{},"FIX FIRST"," and ",[574,579,580],{},"THEN",[546,582,583],{},[574,584,585],{},"GOING FURTHER",[529,587,588,591,596],{},[546,589,590],{},"In the JSON",[546,592,593],{},[574,594,595],{},"checks",[546,597,598],{},[574,599,600],{},"suggestions",[529,602,603,606,609],{},[546,604,605],{},"Can fail a CI gate",[546,607,608],{},"Yes",[546,610,611],{},"No",[613,614,616],"h2",{"id":615},"three-statuses","Three statuses",[507,618,619],{},"Every rule returns one of three verdicts for an entry point.",[523,621,622,632],{},[526,623,624],{},[529,625,626,629],{},[532,627,628],{},"Status",[532,630,631],{},"Meaning",[541,633,634,644,654],{},[529,635,636,641],{},[546,637,638],{},[574,639,640],{},"pass",[546,642,643],{},"The rule looked and found what it wanted",[529,645,646,651],{},[546,647,648],{},[574,649,650],{},"fail",[546,652,653],{},"The rule looked and did not — costs weight, if it is a requirement",[529,655,656,661],{},[546,657,658],{},[574,659,660],{},"n\u002Fa",[546,662,663,664],{},"The question does not make sense here, or you ",[665,666,668],"a",{"href":667},"#disabling-a-check","disabled it",[507,670,671,673,674,577,677,680,681,684],{},[574,672,660],{}," is doing real work. A handler that throws nothing is never asked whether its errors carry ",[574,675,676],{},"why",[574,678,679],{},"fix","; a handler with no ",[574,682,683],{},"catch"," is never asked whether its catches log. Those used to pass for free, which made the report claim a file handled errors it did not have. Now they are dots in the matrix, and the score is calculated over the rules that actually applied.",[613,686,536],{"id":687},"requirements",[507,689,690,691,694],{},"Six rules move the score. They apply to handler-like entry points — API handlers, middleware, scheduled jobs, and server actions — except ",[574,692,693],{},"fetch",", which is the pages-only rule.",[523,696,697,713],{},[526,698,699],{},[529,700,701,704,707,710],{},[532,702,703],{},"Column",[532,705,706],{},"Id",[532,708,709],{},"Weight",[532,711,712],{},"Expects",[541,714,715,735,754,774,790,810],{},[529,716,717,722,727,730],{},[546,718,719],{},[574,720,721],{},"log",[546,723,724],{},[574,725,726],{},"wide-event",[546,728,729],{},"40",[546,731,732],{},[574,733,734],{},"useLogger()",[529,736,737,742,746,749],{},[546,738,739],{},[574,740,741],{},"audit",[546,743,744],{},[574,745,741],{},[546,747,748],{},"25",[546,750,751],{},[574,752,753],{},"log.audit()",[529,755,756,761,766,769],{},[546,757,758],{},[574,759,760],{},"err",[546,762,763],{},[574,764,765],{},"structured-errors",[546,767,768],{},"20",[546,770,771],{},[574,772,773],{},"createError({ why, fix })",[529,775,776,780,785,787],{},[546,777,778],{},[574,779,693],{},[546,781,782],{},[574,783,784],{},"page-error-handling",[546,786,768],{},[546,788,789],{},"fetch error handling",[529,791,792,797,802,805],{},[546,793,794],{},[574,795,796],{},"ctx",[546,798,799],{},[574,800,801],{},"context",[546,803,804],{},"15",[546,806,807],{},[574,808,809],{},"log.set()",[529,811,812,816,821,823],{},[546,813,814],{},[574,815,683],{},[546,817,818],{},[574,819,820],{},"error-handling",[546,822,804],{},[546,824,825,826],{},"logging or rethrow in ",[574,827,683],{},[829,830,832],"h3",{"id":831},"log-does-this-entry-point-emit-a-wide-event","log — does this entry point emit a wide event?",[507,834,835],{},"The heaviest rule, because everything else depends on it. An entry point with no logger produces no event, and no amount of good error handling will tell you what happened inside it.",[507,837,838,839,842,843,842,846,842,849,852,853,842,856,859],{},"Satisfied by a resolved evlog logger (",[574,840,841],{},"useLogger",", ",[574,844,845],{},"createLogger",[574,847,848],{},"createRequestLogger",[574,850,851],{},"initLogger",") or an evlog wrapper (",[574,854,855],{},"withEvlog",[574,857,858],{},"withAudit",").",[507,861,862],{},"The message depends on your framework. With evlog's Nitro plugin an event is emitted for every request whether the handler asks or not, so the failure there is not silence, it is emptiness:",[864,865,872],"pre",{"className":866,"code":868,"filename":869,"language":870,"meta":871},[867],"language-text","handler adds nothing to its request event — only method, path and status are recorded\n","Nuxt \u002F Nitro","text","",[574,873,868],{"__ignoreMap":871},[864,875,879],{"className":876,"code":877,"filename":878,"language":870,"meta":871},[867],"no useLogger() — handler is a dark event\n","Next.js \u002F TanStack Start",[574,880,877],{"__ignoreMap":871},[882,883,884,963],"code-group",{},[864,885,889],{"className":886,"code":887,"filename":205,"language":888,"meta":871,"style":871},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineEventHandler(async (event) => {\n  const log = useLogger(event)\n})\n","ts",[574,890,891,932,955],{"__ignoreMap":871},[892,893,896,900,903,907,911,915,919,923,926,929],"span",{"class":894,"line":895},"line",1,[892,897,899],{"class":898},"s7zQu","export",[892,901,902],{"class":898}," default",[892,904,906],{"class":905},"s2Zo4"," defineEventHandler",[892,908,910],{"class":909},"sTEyZ","(",[892,912,914],{"class":913},"spNyl","async",[892,916,918],{"class":917},"sMK4o"," (",[892,920,922],{"class":921},"sHdIc","event",[892,924,925],{"class":917},")",[892,927,928],{"class":913}," =>",[892,930,931],{"class":917}," {\n",[892,933,935,938,941,944,947,950,952],{"class":894,"line":934},2,[892,936,937],{"class":913},"  const",[892,939,940],{"class":909}," log",[892,942,943],{"class":917}," =",[892,945,946],{"class":905}," useLogger",[892,948,910],{"class":949},"swJcz",[892,951,922],{"class":909},[892,953,954],{"class":949},")\n",[892,956,958,961],{"class":894,"line":957},3,[892,959,960],{"class":917},"}",[892,962,954],{"class":909},[864,964,966],{"className":886,"code":965,"filename":210,"language":888,"meta":871,"style":871},"export async function POST(request: Request) {\n  const log = useLogger()\n}\n",[574,967,968,997,1010],{"__ignoreMap":871},[892,969,970,972,975,978,981,983,986,989,993,995],{"class":894,"line":895},[892,971,899],{"class":898},[892,973,974],{"class":913}," async",[892,976,977],{"class":913}," function",[892,979,980],{"class":905}," POST",[892,982,910],{"class":917},[892,984,985],{"class":921},"request",[892,987,988],{"class":917},":",[892,990,992],{"class":991},"sBMFI"," Request",[892,994,925],{"class":917},[892,996,931],{"class":917},[892,998,999,1001,1003,1005,1007],{"class":894,"line":934},[892,1000,937],{"class":913},[892,1002,940],{"class":909},[892,1004,943],{"class":917},[892,1006,946],{"class":905},[892,1008,1009],{"class":949},"()\n",[892,1011,1012],{"class":894,"line":957},[892,1013,1014],{"class":917},"}\n",[507,1016,1017],{},[665,1018,1019],{"href":47},"Wide events →",[829,1021,1023],{"id":1022},"ctx-is-request-context-attached","ctx — is request context attached?",[507,1025,1026,1027,1029],{},"A logger with no ",[574,1028,809],{}," produces a technically valid event that says nothing about the request it describes. That is the most common way a wide event ends up useless in production: you get one line per request, and none of them can answer a question.",[507,1031,1032,1033,1036,1037,1040],{},"Only ",[574,1034,1035],{},"set()"," on a resolved evlog logger counts. An unrelated ",[574,1038,1039],{},"Map.set()"," does not.",[864,1042,1044],{"className":886,"code":1043,"language":888,"meta":871,"style":871},"log.set({ user: { id }, order: { id, total } })\n",[574,1045,1046],{"__ignoreMap":871},[892,1047,1048,1050,1053,1056,1058,1061,1064,1066,1069,1072,1075,1078,1080,1082,1085,1088,1091,1093,1096],{"class":894,"line":895},[892,1049,721],{"class":909},[892,1051,1052],{"class":917},".",[892,1054,1055],{"class":905},"set",[892,1057,910],{"class":909},[892,1059,1060],{"class":917},"{",[892,1062,1063],{"class":949}," user",[892,1065,988],{"class":917},[892,1067,1068],{"class":917}," {",[892,1070,1071],{"class":909}," id ",[892,1073,1074],{"class":917},"},",[892,1076,1077],{"class":949}," order",[892,1079,988],{"class":917},[892,1081,1068],{"class":917},[892,1083,1084],{"class":909}," id",[892,1086,1087],{"class":917},",",[892,1089,1090],{"class":909}," total ",[892,1092,960],{"class":917},[892,1094,1095],{"class":917}," }",[892,1097,954],{"class":909},[507,1099,1100],{},[665,1101,1019],{"href":47},[829,1103,1105],{"id":1104},"err-do-thrown-errors-carry-why-and-fix","err — do thrown errors carry why and fix?",[507,1107,1108,1111,1112,1114],{},[574,1109,1110],{},"throw new Error('failed')"," reaches the client as a string with no cause and no remedy. ",[574,1113,773],{}," is what makes an error actionable for whoever reads it at 3am.",[507,1116,1117,1118,1121,1122,1125],{},"Applies only when the handler raises something — a ",[574,1119,1120],{},"throw"," or a ",[574,1123,1124],{},"createError()"," call. The message names exactly what is missing:",[864,1127,1130],{"className":1128,"code":1129,"language":870,"meta":871},[867],"throw new Error() — use createError({ why, fix })\ncreateError() missing why and fix\ncreateError() has why but missing fix\n",[574,1131,1129],{"__ignoreMap":871},[507,1133,1134,1135,1137],{},"A ",[574,1136,1124],{}," that is returned rather than thrown is checked too, since it still shapes the response.",[864,1139,1141],{"className":886,"code":1140,"language":888,"meta":871,"style":871},"throw createError({\n  status: 400,\n  message: 'what the caller sees',\n  why: 'what actually went wrong',\n  fix: 'what to do about it',\n})\n",[574,1142,1143,1155,1169,1188,1205,1222],{"__ignoreMap":871},[892,1144,1145,1147,1150,1152],{"class":894,"line":895},[892,1146,1120],{"class":898},[892,1148,1149],{"class":905}," createError",[892,1151,910],{"class":909},[892,1153,1154],{"class":917},"{\n",[892,1156,1157,1160,1162,1166],{"class":894,"line":934},[892,1158,1159],{"class":949},"  status",[892,1161,988],{"class":917},[892,1163,1165],{"class":1164},"sbssI"," 400",[892,1167,1168],{"class":917},",\n",[892,1170,1171,1174,1176,1179,1183,1186],{"class":894,"line":957},[892,1172,1173],{"class":949},"  message",[892,1175,988],{"class":917},[892,1177,1178],{"class":917}," '",[892,1180,1182],{"class":1181},"sfazB","what the caller sees",[892,1184,1185],{"class":917},"'",[892,1187,1168],{"class":917},[892,1189,1191,1194,1196,1198,1201,1203],{"class":894,"line":1190},4,[892,1192,1193],{"class":949},"  why",[892,1195,988],{"class":917},[892,1197,1178],{"class":917},[892,1199,1200],{"class":1181},"what actually went wrong",[892,1202,1185],{"class":917},[892,1204,1168],{"class":917},[892,1206,1208,1211,1213,1215,1218,1220],{"class":894,"line":1207},5,[892,1209,1210],{"class":949},"  fix",[892,1212,988],{"class":917},[892,1214,1178],{"class":917},[892,1216,1217],{"class":1181},"what to do about it",[892,1219,1185],{"class":917},[892,1221,1168],{"class":917},[892,1223,1225,1227],{"class":894,"line":1224},6,[892,1226,960],{"class":917},[892,1228,954],{"class":909},[507,1230,1231],{},[665,1232,1233],{"href":52},"Structured errors →",[829,1235,1237],{"id":1236},"audit-does-this-sensitive-entry-point-leave-a-trail","audit — does this sensitive entry point leave a trail?",[507,1239,1240,1241,1245,1246,1248],{},"Applies only where the ",[665,1242,1244],{"href":1243},"\u002Fcli\u002Fscoring#sensitivity","sensitivity classifier"," found money or auth. Everywhere else an audit record would be noise, so the rule reports ",[574,1247,660],{}," rather than passing for free.",[507,1250,1251,1253,1254,1257],{},[574,1252,753],{}," satisfies it, including through optional chaining — ",[574,1255,1256],{},"log.audit?.deny()"," counts.",[507,1259,1260,1261,1264,1265,577,1268,1264,1271,988],{},"The suggested action is read off the route, so ",[574,1262,1263],{},"\u002Fapi\u002Fauth\u002Flogin"," suggests ",[574,1266,1267],{},"auth.login",[574,1269,1270],{},"\u002Fapi\u002Forders\u002F[id]\u002Frefund",[574,1272,1273],{},"orders.refund",[864,1275,1277],{"className":886,"code":1276,"language":888,"meta":871,"style":871},"log.audit({\n  action: 'auth.login',\n  actor: { type: 'user', id: user.id },\n})\n",[574,1278,1279,1291,1306,1343],{"__ignoreMap":871},[892,1280,1281,1283,1285,1287,1289],{"class":894,"line":895},[892,1282,721],{"class":909},[892,1284,1052],{"class":917},[892,1286,741],{"class":905},[892,1288,910],{"class":909},[892,1290,1154],{"class":917},[892,1292,1293,1296,1298,1300,1302,1304],{"class":894,"line":934},[892,1294,1295],{"class":949},"  action",[892,1297,988],{"class":917},[892,1299,1178],{"class":917},[892,1301,1267],{"class":1181},[892,1303,1185],{"class":917},[892,1305,1168],{"class":917},[892,1307,1308,1311,1313,1315,1318,1320,1322,1325,1327,1329,1331,1333,1335,1337,1340],{"class":894,"line":957},[892,1309,1310],{"class":949},"  actor",[892,1312,988],{"class":917},[892,1314,1068],{"class":917},[892,1316,1317],{"class":949}," type",[892,1319,988],{"class":917},[892,1321,1178],{"class":917},[892,1323,1324],{"class":1181},"user",[892,1326,1185],{"class":917},[892,1328,1087],{"class":917},[892,1330,1084],{"class":949},[892,1332,988],{"class":917},[892,1334,1063],{"class":909},[892,1336,1052],{"class":917},[892,1338,1339],{"class":909},"id ",[892,1341,1342],{"class":917},"},\n",[892,1344,1345,1347],{"class":894,"line":1190},[892,1346,960],{"class":917},[892,1348,954],{"class":909},[507,1350,1351],{},[665,1352,1353],{"href":359},"Audit logs →",[829,1355,1357],{"id":1356},"catch-is-every-caught-error-logged-or-rethrown","catch — is every caught error logged or rethrown?",[507,1359,1360],{},"A swallowed error is worse than an unhandled one: the request looks successful, the event says nothing, and the failure is invisible until a user reports it.",[507,1362,1134,1363,1365,1366,842,1369,842,1372,842,1375,842,1378,1381,1382,1385],{},[574,1364,683],{}," counts as handled when it logs (",[574,1367,1368],{},"log.error",[574,1370,1371],{},"log.warn",[574,1373,1374],{},"log.set",[574,1376,1377],{},"log.audit",[574,1379,1380],{},"captureException",", or any ",[574,1383,1384],{},"console.*","), rethrows, or returns. Two failures are reported separately:",[864,1387,1390],{"className":1388,"code":1389,"language":870,"meta":871},[867],"empty catch block swallows errors\ncatch block swallows error without logging or rethrow\n",[574,1391,1389],{"__ignoreMap":871},[507,1393,1394,1395,1397,1398,1400],{},"A handler with no ",[574,1396,683],{}," at all is ",[574,1399,660],{},", not a gap. evlog's framework integrations hook the runtime's error channel, so an exception that escapes your handler is still recorded on the event with its status.",[864,1402,1404],{"className":886,"code":1403,"language":888,"meta":871,"style":871},"catch (error) {\n  log.error(error)\n}\n",[574,1405,1406,1415,1431],{"__ignoreMap":871},[892,1407,1408,1410,1413],{"class":894,"line":895},[892,1409,683],{"class":898},[892,1411,1412],{"class":909}," (error) ",[892,1414,1154],{"class":917},[892,1416,1417,1420,1422,1425,1427,1429],{"class":894,"line":934},[892,1418,1419],{"class":909},"  log",[892,1421,1052],{"class":917},[892,1423,1424],{"class":905},"error",[892,1426,910],{"class":949},[892,1428,1424],{"class":909},[892,1430,954],{"class":949},[892,1432,1433],{"class":894,"line":957},[892,1434,1014],{"class":917},[507,1436,1437],{},[665,1438,1233],{"href":52},[829,1440,1442],{"id":1441},"fetch-does-this-page-survive-its-data-fetch-failing","fetch — does this page survive its data fetch failing?",[507,1444,1445],{},"The only pages rule. Applies only to pages that actually fetch something server-side — a purely presentational page has nothing to fail.",[507,1447,1448,1449,1451,1452,1455,1456,1459,1460,1462],{},"Satisfied by a ",[574,1450,683],{},", a ",[574,1453,1454],{},".catch()",", an ",[574,1457,1458],{},"onError"," handler, or an ",[574,1461,1424],{}," binding destructured from the fetch itself.",[882,1464,1465,1569],{},[864,1466,1470],{"className":1467,"code":1468,"filename":205,"language":1469,"meta":871,"style":871},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nconst { data, error } = await useFetch('\u002Fapi\u002Forders')\nif (error.value) log.error(error.value)\n\u003C\u002Fscript>\n","vue",[574,1471,1472,1499,1535,1560],{"__ignoreMap":871},[892,1473,1474,1477,1480,1483,1486,1489,1492,1494,1496],{"class":894,"line":895},[892,1475,1476],{"class":917},"\u003C",[892,1478,1479],{"class":949},"script",[892,1481,1482],{"class":913}," setup",[892,1484,1485],{"class":913}," lang",[892,1487,1488],{"class":917},"=",[892,1490,1491],{"class":917},"\"",[892,1493,888],{"class":1181},[892,1495,1491],{"class":917},[892,1497,1498],{"class":917},">\n",[892,1500,1501,1504,1506,1509,1511,1514,1516,1518,1521,1524,1526,1528,1531,1533],{"class":894,"line":934},[892,1502,1503],{"class":913},"const",[892,1505,1068],{"class":917},[892,1507,1508],{"class":909}," data",[892,1510,1087],{"class":917},[892,1512,1513],{"class":909}," error ",[892,1515,960],{"class":917},[892,1517,943],{"class":917},[892,1519,1520],{"class":898}," await",[892,1522,1523],{"class":905}," useFetch",[892,1525,910],{"class":909},[892,1527,1185],{"class":917},[892,1529,1530],{"class":1181},"\u002Fapi\u002Forders",[892,1532,1185],{"class":917},[892,1534,954],{"class":909},[892,1536,1537,1540,1543,1545,1548,1550,1552,1555,1557],{"class":894,"line":957},[892,1538,1539],{"class":898},"if",[892,1541,1542],{"class":909}," (error",[892,1544,1052],{"class":917},[892,1546,1547],{"class":909},"value) log",[892,1549,1052],{"class":917},[892,1551,1424],{"class":905},[892,1553,1554],{"class":909},"(error",[892,1556,1052],{"class":917},[892,1558,1559],{"class":909},"value)\n",[892,1561,1562,1565,1567],{"class":894,"line":1190},[892,1563,1564],{"class":917},"\u003C\u002F",[892,1566,1479],{"class":949},[892,1568,1498],{"class":917},[864,1570,1574],{"className":1571,"code":1572,"filename":210,"language":1573,"meta":871,"style":871},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","try {\n  const orders = await getOrders()\n} catch (error) {\n  log.error(error)\n}\n","tsx",[574,1575,1576,1583,1599,1610,1624],{"__ignoreMap":871},[892,1577,1578,1581],{"class":894,"line":895},[892,1579,1580],{"class":898},"try",[892,1582,931],{"class":917},[892,1584,1585,1587,1590,1592,1594,1597],{"class":894,"line":934},[892,1586,937],{"class":913},[892,1588,1589],{"class":909}," orders",[892,1591,943],{"class":917},[892,1593,1520],{"class":898},[892,1595,1596],{"class":905}," getOrders",[892,1598,1009],{"class":949},[892,1600,1601,1603,1606,1608],{"class":894,"line":957},[892,1602,960],{"class":917},[892,1604,1605],{"class":898}," catch",[892,1607,1412],{"class":909},[892,1609,1154],{"class":917},[892,1611,1612,1614,1616,1618,1620,1622],{"class":894,"line":1190},[892,1613,1419],{"class":909},[892,1615,1052],{"class":917},[892,1617,1424],{"class":905},[892,1619,910],{"class":949},[892,1621,1424],{"class":909},[892,1623,954],{"class":949},[892,1625,1626],{"class":894,"line":1207},[892,1627,1014],{"class":917},[507,1629,1630],{},[665,1631,1632],{"href":57},"Lifecycle →",[613,1634,539],{"id":1635},"opportunities",[507,1637,1638,1639,1642],{},"Four rules suggest going further. They never touch the score, and they only ever fire when the project has ",[515,1640,1641],{},"already adopted"," the feature somewhere — the point is to get more out of what you chose, not to sell you something.",[507,1644,1645],{},"Adoption is confirmed against the AST, not by searching text, so a feature mentioned in a comment does not count.",[523,1647,1648,1662],{},[526,1649,1650],{},[529,1651,1652,1654,1656,1659],{},[532,1653,703],{},[532,1655,706],{},[532,1657,1658],{},"Fires when",[532,1660,1661],{},"Scope",[541,1663,1664,1686,1703,1726],{},[529,1665,1666,1671,1676,1683],{},[546,1667,1668],{},[574,1669,1670],{},"catalog",[546,1672,1673],{},[574,1674,1675],{},"error-catalog",[546,1677,1678,1679,1682],{},"The project declares a catalog ",[515,1680,1681],{},"and"," the same inline error appears in two or more files",[546,1684,1685],{},"Per entry point",[529,1687,1688,1693,1698,1701],{},[546,1689,1690],{},[574,1691,1692],{},"audit+",[546,1694,1695],{},[574,1696,1697],{},"audit-coverage",[546,1699,1700],{},"The project records audit events, and this handler changes state without one",[546,1702,1685],{},[529,1704,1705,1710,1715,1723],{},[546,1706,1707],{},[574,1708,1709],{},"ai",[546,1711,1712],{},[574,1713,1714],{},"ai-logging",[546,1716,1717,1719,1720],{},[574,1718,1709],{}," is a dependency and the AI SDK is called without ",[574,1721,1722],{},"evlog\u002Fai",[546,1724,1725],{},"Once per project",[529,1727,1728,1733,1738,1748],{},[546,1729,1730],{},[574,1731,1732],{},"identity",[546,1734,1735],{},[574,1736,1737],{},"auth-identity",[546,1739,1740,1743,1744,1747],{},[574,1741,1742],{},"better-auth"," is a dependency and ",[574,1745,1746],{},"evlog\u002Fbetter-auth"," is not installed",[546,1749,1725],{},[829,1751,1753],{"id":1752},"catalog-should-these-duplicated-errors-become-catalog-entries","catalog — should these duplicated errors become catalog entries?",[507,1755,1756,1757,1759],{},"Deliberately narrow. An earlier version fired on any inline ",[574,1758,1124],{},", which meant handlers with perfectly good errors got lectured. Duplication is the one signal that makes the case on its own: the same status and message maintained in three places will drift.",[864,1761,1764],{"className":1762,"code":1763,"language":870,"meta":871},[867],"\"402 Card declined\" is spelled out here and in 2 other files — one catalog entry would cover them\n",[574,1765,1763],{"__ignoreMap":871},[507,1767,1768,1769],{},"The suggestion names a catalog you already have, rather than inventing one. ",[665,1770,1771],{"href":77},"Catalogs →",[829,1773,1775],{"id":1774},"audit-should-this-state-change-be-on-the-audit-trail-too","audit+ — should this state change be on the audit trail too?",[507,1777,1778,1779,1781,1782,842,1785,842,1788,842,1791,842,1794,1797,1798,1801,1802,1804,1805],{},"Complements the ",[574,1780,741],{}," requirement, which only fires on money and auth. This one is softer and wider: once you have an audit trail, every state change is a candidate, and you are the one who knows which ones matter. It looks for ",[574,1783,1784],{},"create",[574,1786,1787],{},"update",[574,1789,1790],{},"insert",[574,1792,1793],{},"upsert",[574,1795,1796],{},"delete",", or ",[574,1799,1800],{},"destroy"," calls in a handler with no audit record. Entry points already covered by the ",[574,1803,741],{}," requirement are skipped, so a gap is never reported twice. ",[665,1806,1807],{"href":368},"Recording audit events →",[829,1809,1811],{"id":1810},"ai-are-model-calls-tokens-and-latency-on-the-event","ai — are model calls, tokens and latency on the event?",[507,1813,1814,1815,842,1818,842,1821,842,1824,842,1827,1830,1831,1834,1835,1837,1838],{},"Fires on ",[574,1816,1817],{},"generateText",[574,1819,1820],{},"streamText",[574,1822,1823],{},"generateObject",[574,1825,1826],{},"streamObject",[574,1828,1829],{},"embed",", and ",[574,1832,1833],{},"embedMany"," when ",[574,1836,1722],{}," is not imported. Without it the event records that the request happened but not what the model cost, which is usually the most expensive and most variable part of it. Reported once for the whole project — one wrapped model serves every handler. ",[665,1839,1840],{"href":303},"AI SDK →",[829,1842,1844],{"id":1843},"identity-do-events-carry-the-authenticated-user","identity — do events carry the authenticated user?",[507,1846,1847,1848,1850,1851],{},"Fires on entry points where auth is actually in play: the auth routes themselves, or a handler that reads the session. ",[574,1849,1746],{}," attaches the user and session to every event, which is what turns \"a request failed\" into \"this user's request failed\". Reported once for the whole project — it is one plugin, installed once. ",[665,1852,1853],{"href":332},"Better Auth →",[613,1855,1857],{"id":1856},"how-evlog-helpers-are-recognised","How evlog helpers are recognised",[507,1859,1860,1861,1865],{},"Every rule that looks for a logger asks the same question: ",[1862,1863,1864],"em",{},"is this evlog's?"," It is answered from the AST, which is why a locally defined stub does not earn you points.",[1867,1868,1869,1880,1892,1909],"ul",{},[1870,1871,1872,1875,1876,1879],"li",{},[515,1873,1874],{},"Imported from evlog"," — ",[574,1877,1878],{},"import { useLogger } from 'evlog'",", including subpath imports.",[1870,1881,1882,1885,1886,577,1888,1891],{},[515,1883,1884],{},"Auto-imported"," — in Nuxt and Nitro, evlog's module injects ",[574,1887,841],{},[574,1889,1890],{},"createEvlogError",", so an un-imported call counts. Unless the file declares its own, in which case the local declaration wins.",[1870,1893,1894,1875,1897,1900,1901,1904,1905,1908],{},[515,1895,1896],{},"Re-exported from a local module",[574,1898,1899],{},"import { useLogger } from '@\u002Flib\u002Fevlog'"," counts when that module forwards evlog's export, which is the shape ",[665,1902,1903],{"href":211},"the Next.js guide"," recommends. Exports destructured from a factory (",[574,1906,1907],{},"export const { useLogger } = createEvlog(...)",") are resolved too.",[1870,1910,1911,1875,1914,577,1916,1918],{},[515,1912,1913],{},"Through an evlog wrapper",[574,1915,855],{},[574,1917,858],{}," instrument a handler without it ever naming a logger.",[507,1920,1921,1922,1925],{},"Two things deliberately do ",[515,1923,1924],{},"not"," count:",[1867,1927,1928,1942],{},[1870,1929,1930,1933,1934,1937,1938,1941],{},[515,1931,1932],{},"A local stub."," ",[574,1935,1936],{},"function useLogger() { ... }"," in your own file, or an import from ",[574,1939,1940],{},".\u002Fmy-logger"," that does not forward evlog's export, is not evlog's logger.",[1870,1943,1944,1933,1950,1953,1954,1957,1958,1960,1961,1963,1964,1966],{},[515,1945,1946,1947,1949],{},"evlog's ",[574,1948,721],{}," export.",[574,1951,1952],{},"log.info()"," is the ",[665,1955,1956],{"href":42},"simple logging API"," — it emits its own line rather than contributing to the request's wide event, and it has no ",[574,1959,1055],{}," or ",[574,1962,741],{},". It does not satisfy the ",[574,1965,721],{}," column.",[613,1968,1970],{"id":1969},"disabling-a-check","Disabling a check",[507,1972,1973],{},"A static analyser you cannot argue with is one you stop running. When a rule is wrong about your code — or right about it and you have decided not to care — turn it off with a comment, next to the code it is about:",[864,1975,1978],{"className":886,"code":1976,"filename":1977,"language":888,"meta":871,"style":871},"\u002F\u002F evlog-map-disable-next-line wide-event, context -- liveness probe, deliberately silent\nexport default defineEventHandler(() => ({ ok: true }))\n","server\u002Fapi\u002Fhealth.get.ts",[574,1979,1980,1986],{"__ignoreMap":871},[892,1981,1982],{"class":894,"line":895},[892,1983,1985],{"class":1984},"sHwdD","\u002F\u002F evlog-map-disable-next-line wide-event, context -- liveness probe, deliberately silent\n",[892,1987,1988,1990,1992,1994,1996,1999,2001,2003,2005,2008,2010,2014,2016],{"class":894,"line":934},[892,1989,899],{"class":898},[892,1991,902],{"class":898},[892,1993,906],{"class":905},[892,1995,910],{"class":909},[892,1997,1998],{"class":917},"()",[892,2000,928],{"class":913},[892,2002,918],{"class":909},[892,2004,1060],{"class":917},[892,2006,2007],{"class":949}," ok",[892,2009,988],{"class":917},[892,2011,2013],{"class":2012},"sfNiH"," true",[892,2015,1095],{"class":917},[892,2017,2018],{"class":909},"))\n",[507,2020,2021],{},"Three forms, matching what you would expect from a linter:",[523,2023,2024,2034],{},[526,2025,2026],{},[529,2027,2028,2031],{},[532,2029,2030],{},"Directive",[532,2032,2033],{},"Covers",[541,2035,2036,2046,2056],{},[529,2037,2038,2043],{},[546,2039,2040],{},[574,2041,2042],{},"\u002F\u002F evlog-map-disable-next-line \u003Cids>",[546,2044,2045],{},"The line below the comment",[529,2047,2048,2053],{},[546,2049,2050],{},[574,2051,2052],{},"\u002F\u002F evlog-map-disable-line \u003Cids>",[546,2054,2055],{},"The line the comment is on, as a trailing comment",[529,2057,2058,2063],{},[546,2059,2060],{},[574,2061,2062],{},"\u002F\u002F evlog-map-disable \u003Cids>",[546,2064,2065],{},"The whole file, wherever it appears",[507,2067,2068,2069,842,2071,842,2073,842,2075,842,2077,842,2079,2081,2082,2085,2086,1052],{},"The ids are the ones in the tables above — ",[574,2070,726],{},[574,2072,741],{},[574,2074,765],{},[574,2076,801],{},[574,2078,820],{},[574,2080,784],{},", and any opportunity id. Separate several with commas or spaces. ",[515,2083,2084],{},"Name no id and the directive covers every rule",", which is the right shape for a generated or vendored file and the wrong one for a handler you simply have not got to yet. Block comments work the same way, which is what you want at the top of a file: ",[574,2087,2088],{},"\u002F* evlog-map-disable -- generated by the SDK *\u002F",[507,2090,2091,2092,2095],{},"Everything after ",[574,2093,2094],{},"--"," is your reason. It is optional, and worth writing anyway: it is what the report shows, so the next person reads the decision rather than guessing at it.",[829,2097,2099],{"id":2098},"what-a-disabled-check-does-to-the-score","What a disabled check does to the score",[507,2101,2102,2103,2105,2106,2109],{},"It becomes ",[574,2104,660],{}," with your reason attached — the same status as a rule that never applied — so it costs no points, and a ",[574,2107,2108],{},"--min-score"," gate stops failing on it.",[507,2111,2112,2113,2116,2117,2119,2120,2122],{},"The rule still runs. What a directive waives is the ",[1862,2114,2115],{},"finding",", not the question: a check that would have passed is still reported as a ",[574,2118,640],{},", and a rule that never applied to that handler stays a plain ",[574,2121,660],{},". So a file-wide directive on an already-instrumented handler disables nothing, and the number of disabled checks is the number of verdicts you actually chose not to see.",[507,2124,2125],{},"Which means a disabled check has to stay visible, or the escape hatch would quietly become a way to score 100 on an app that logs nothing. It shows up in three places:",[864,2127,2131],{"className":2128,"code":2129,"filename":2130,"language":870,"meta":871},[867],"○ 2 checks disabled by comment in 1 entry point\n","evlog map",[574,2132,2129],{"__ignoreMap":871},[864,2134,2138],{"className":2135,"code":2136,"filename":2137,"language":870,"meta":871},[867],"CHECKS\n✓ log.set     context attached with log.set()\n○ useLogger   disabled at line 1 — liveness probe, deliberately silent\n","evlog map \u003Cfile>",[574,2139,2136],{"__ignoreMap":871},[507,2141,2142,2143,2146,2147,2150,2151,2154,2155,2158,2159,2161,2162,2165,2166,2169],{},"In ",[574,2144,2145],{},"--all",", a disabled cell is ",[574,2148,2149],{},"○"," rather than the ",[574,2152,2153],{},"·"," of a rule that did not apply. And in the JSON, the check carries ",[574,2156,2157],{},"\"suppressed\": true"," next to its ",[574,2160,660],{},", with ",[574,2163,2164],{},"evidence"," pointing at the comment — so a CI job can report how much of a green score is suppressed, and ",[574,2167,2168],{},"summary.suppressedChecks"," gives the project total.",[829,2171,2173],{"id":2172},"a-typo-is-loud","A typo is loud",[507,2175,2176],{},"An id no rule answers to does not silently do nothing — the scan warns above the report, and the check keeps failing:",[864,2178,2181],{"className":2179,"code":2180,"language":870,"meta":871},[867],"⚠ server\u002Fapi\u002Fprobe.get.ts:1 disables \"wide-evnt\", which is not a check evlog map runs\n",[574,2182,2180],{"__ignoreMap":871},[507,2184,2185],{},"Believing a check is off while it is still failing is worse than either state on its own, so this one is never quiet.",[613,2187,2189],{"id":2188},"exempt-entry-points","Exempt entry points",[507,2191,2192,2193,2196,2197,2199,2200,2203],{},"evlog's own client-log ingest endpoints (",[574,2194,2195],{},"\u002Fapi\u002Fevlog\u002Fingest"," and friends) are plumbing, not app code. Every rule reports ",[574,2198,660],{}," for them with the reason attached, they are never listed as something to fix, and the summary counts them as ",[574,2201,2202],{},"exempt"," rather than as your own instrumented entry points.",[613,2205,2207],{"id":2206},"reporting-a-wrong-verdict","Reporting a wrong verdict",[507,2209,2210,2211,2213,2214,2220],{},"Rules are one file each with their own test bench, so a wrong verdict is a local fix rather than an archaeology session. If ",[574,2212,2137],{}," claims something you can see is untrue, that is a bug worth ",[665,2215,2219],{"href":2216,"rel":2217},"https:\u002F\u002Fgithub.com\u002FHugoRCD\u002Fevlog\u002Fissues",[2218],"nofollow","opening an issue"," for — include the entry point's output and the handler, and the fix lands in one rule.",[507,2222,2223,2224,2227],{},"In the meantime, ",[665,2225,2226],{"href":667},"disable the check"," on that line. A false positive should cost you one comment, not your CI gate.",[613,2229,2231],{"id":2230},"next","Next",[1867,2233,2234,2239],{},[1870,2235,2236,2238],{},[665,2237,99],{"href":100}," — how weights become a number, and how sensitivity is decided",[1870,2240,2241,2243],{},[665,2242,104],{"href":105}," — gate a pull request on requirements without suggestions getting in the way",[2245,2246,2247],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":871,"searchDepth":934,"depth":934,"links":2249},[2250,2251,2259,2265,2266,2270,2271,2272],{"id":615,"depth":934,"text":616},{"id":687,"depth":934,"text":536,"children":2252},[2253,2254,2255,2256,2257,2258],{"id":831,"depth":957,"text":832},{"id":1022,"depth":957,"text":1023},{"id":1104,"depth":957,"text":1105},{"id":1236,"depth":957,"text":1237},{"id":1356,"depth":957,"text":1357},{"id":1441,"depth":957,"text":1442},{"id":1635,"depth":934,"text":539,"children":2260},[2261,2262,2263,2264],{"id":1752,"depth":957,"text":1753},{"id":1774,"depth":957,"text":1775},{"id":1810,"depth":957,"text":1811},{"id":1843,"depth":957,"text":1844},{"id":1856,"depth":934,"text":1857},{"id":1969,"depth":934,"text":1970,"children":2267},[2268,2269],{"id":2098,"depth":957,"text":2099},{"id":2172,"depth":957,"text":2173},{"id":2188,"depth":934,"text":2189},{"id":2206,"depth":934,"text":2207},{"id":2230,"depth":934,"text":2231},"Every check evlog map runs — the six requirements that move the score, the four suggestions that never do, what satisfies each one, and how evlog helpers are recognised in your code.","md",[2276,2279],{"label":99,"icon":102,"to":100,"color":2277,"variant":2278},"neutral","subtle",{"label":2130,"icon":92,"to":90,"color":2277,"variant":2278},{},{"title":94,"icon":97},{"title":502,"description":2273},"FuG2qA2yLaHN5iPS4S0ExkLe36lGZjwa87uynNpSfoU",[2285,2287],{"title":89,"path":90,"stem":91,"description":2286,"icon":92,"children":-1},"A static observability score for your app, Lighthouse-style. Scans every entry point in a Nuxt, Nitro, Next.js, or TanStack Start project, scores wide-event coverage, and names the entry points to fix first.",{"title":99,"path":100,"stem":101,"description":2288,"icon":102,"children":-1},"How evlog map turns rule results into a score — per-entry weights, the weighted project average, grade thresholds, coverage classification, and how routes are flagged as money, auth, or PII.",1785016755825]