nqzai — unit test report
2026-11-01 03:45:35 · commit 83d06b62b33f · vitest 4.1.10 · gate npm run check
Results: GitHub check run 41270354057, which tested tree fcd2e1bb83a0 — the exact code in this deploy
100%
pass rate
tests 17084
passed 17082
failed 0
files · suites 1097 · 4920
duration 267221ms
tests by area Core 8214 Chat · Feedback 3560 SEO · Keywords 3170 Billing · Cost 1274 Email 746 Middleware · Dispatch 120
test layers
Unit tests · Vitest
Deterministic pure-logic — this report.
17084 tests / 1097 files
Static guards · npm run check
tenant-scoping, graphql-seams, tool-registry, cost-refs, provider-guards, …
135 checks
LLM quality eval · Claude-as-judge
5 flows
Integration smokes · prod scripts
Live-hitting; manual, secret-gated, not in the push gate.
chat · rls
per-file detail
src/chat/answer-shapes.vitest.ts
answer-shapes: each predicate fires on its own question · 199 tests
✓
q14 matches: "my pages are indexed but get no impressions" 2.3ms
✓
q14 matches: "why do my pages get no clicks" 0.6ms
✓
q14 matches: "my pages rank but nobody clicks" 0.2ms
✓
q14 matches: "pages are indexed but impressions are tiny, what is actually wrong" 0.2ms
✓
q16 matches: "should we prune or merge the underperforming content" 1.3ms
✓
q16 matches: "which old blog posts should we delete" 0.8ms
✓
q16 matches: "is it worth rewriting our thin articles or killing them" 0.2ms
✓
q02 matches: "how do we run a technical seo audit and decide what to fix first" 1.2ms
✓
q02 matches: "what should we fix first from the crawl issues" 0.9ms
✓
q02 matches: "how do we prioritise the technical seo backlog" 0.2ms
✓
q05 matches: "how healthy is the site for crawling and indexation" 0.6ms
✓
q05 matches: "what is the state of our indexing" 0.3ms
✓
q05 matches: "are there problems with our crawling and rendering" 0.1ms
✓
q12 matches: "how should we fix duplicate content and canonicals" 0.5ms
✓
q12 matches: "what is our policy for url parameters and facets" 0.3ms
✓
q12 matches: "we have a url explosion problem from filters, how do we handle it" 0.1ms
✓
q04 matches: "what is the competitive landscape and where can we realistically win" 1.4ms
✓
q04 matches: "which competitors can we actually beat" 0.7ms
✓
q04 matches: "where is the whitespace against our competition" 0.1ms
✓
q25 matches: "a competitor consistently outranks us for the terms that matter, what is the gap we can close this quarter" 0.2ms
✓
q25 matches: "we are falling behind one competitor on our main keywords" 0.1ms
✓
q25 matches: "how do we close the gap with the competitor ahead of us" 0.1ms
✓
q25 matches: "which competitor gaps can we fix this quarter" 0.1ms
✓
q25 matches: "how do we beat the competitor that outranks us" 0.1ms
✓
q25 matches: "can we win back the terms we are falling behind on against our main rival" 0.1ms
✓
q25 matches: "we lost ground against a competitor this year, what should we do about it" 0.1ms
✓
q24 matches: "does our content demonstrate e-e-a-t for this niche" 0.3ms
✓
q24 matches: "how do we prove our expertise on these pages" 0.6ms
✓
q24 matches: "do we have enough trust signals on our content" 0.3ms
✓
q24 matches: "our authorship is missing, how do we establish credibility" 0.1ms
✓
q09 matches: "which backlinks should we earn, keep, or ignore" 0.6ms
✓
q09 matches: "should we disavow the low quality links pointing at us" 0.4ms
✓
q09 matches: "what should our link building strategy be" 0.1ms
✓
q09 matches: "is our link profile risky" 0.1ms
✓
q03 matches: "which keywords should we actually target given intent and revenue" 0.6ms
✓
q03 matches: "which search terms are worth targeting this year" 0.4ms
✓
q03 matches: "help me prioritise the keywords we are tracking" 0.1ms
✓
q03 matches: "what keywords should we stop targeting" 0.1ms
✓
q29 matches: "what should our robots.txt and sitemap actually contain" 0.5ms
✓
q29 matches: "should we block these pages in robots txt or noindex them" 0.3ms
✓
q29 matches: "our sitemap and robots file seem to disagree" 0.1ms
✓
q29 matches: "what rules should the sitemap follow" 0.1ms
✓
q10 matches: "how will we measure seo success and prove roi" 1.2ms
✓
q10 matches: "what kpis should we report on for organic search" 0.6ms
✓
q10 matches: "how do i justify the seo spend to the business" 0.3ms
✓
q10 matches: "how do we prove search is worth it" 0.1ms
✓
q27 matches: "can we use ai to draft content and stay eligible" 1.9ms
✓
q27 matches: "is it safe to use ai generated content on our blog" 1.1ms
✓
q27 matches: "what should our policy be for ai written articles" 0.1ms
✓
q27 matches: "will ai content get us penalised" 0.1ms
✓
q17 matches: "how long will seo take and what will it cost" 0.7ms
✓
q17 matches: "what happens to our rankings if we stop doing seo" 0.4ms
✓
q17 matches: "how many months before organic traffic moves" 0.1ms
✓
q17 matches: "if we pause content for a quarter what do we lose" 0.1ms
✓
q07 matches: "how do we migrate the site without losing organic traffic" 0.6ms
✓
q07 matches: "we are moving to a new domain, how do we keep our rankings" 0.5ms
✓
q07 matches: "what do we need to do for seo before a redesign" 0.1ms
✓
q07 matches: "replatforming the cms — what breaks in search" 0.4ms
✓
q19 matches: "how do we work with developers so seo recommendations actually ship" 0.4ms
✓
q19 matches: "our seo tickets never get done by engineering" 0.3ms
✓
q19 matches: "how do we get the dev team to implement these fixes" 0.1ms
✓
q20 matches: "how should our seo strategy change over the next few years" 0.4ms
✓
q20 matches: "what is our long term strategy as search becomes generative" 0.3ms
✓
q20 matches: "where should we invest in search over three years" 0.1ms
✓
q26 matches: "how do i explain this to a non-technical exec" 0.2ms
✓
q26 matches: "how do we present a delayed seo result to the board" 0.1ms
✓
q26 matches: "how should i brief the ceo on this" 0.1ms
✓
q30 matches: "how should seo and paid search work together" 0.5ms
✓
q30 matches: "our social and email and seo teams compete with each other" 0.3ms
✓
q30 matches: "how do we coordinate organic and ads" 0.1ms
✓
q18 matches: "how do we rank in cities where we have no office" 0.4ms
✓
q18 matches: "how do we show up in nearby towns we serve" 0.2ms
✓
q18 matches: "we want to target more locations, how do we rank there" 0.1ms
✓
q15 matches: "this page ranks well but nobody converts" 0.5ms
✓
q15 matches: "our landing pages get traffic but bounce is high" 0.3ms
✓
q15 matches: "the money page ranks on page one and conversions are weak" 0.1ms
✓
q22 matches: "is our crawl budget being wasted" 0.3ms
✓
q22 matches: "which url patterns should we block from crawling" 0.3ms
✓
q22 matches: "googlebot is spending time on pages that do not matter" 0.1ms
✓
q23 matches: "which core web vitals failures actually matter for us" 0.3ms
✓
q23 matches: "is page speed worth fixing on our site" 0.2ms
✓
q23 matches: "what should we fix for lcp and cls" 0.1ms
✓
q23 matches: "which core web vitals problems should we fix first" 0.1ms
✓
q23 matches: "what core web vitals issues should we prioritise" 0.1ms
✓
q08 matches: "how should we structure our topic clusters" 0.5ms
✓
q08 matches: "how do we organise internal links to build topical authority" 0.3ms
✓
q08 matches: "what should our site architecture look like for these topics" 0.1ms
✓
q13 matches: "how do we expand into other countries without cannibalising ourselves" 0.5ms
✓
q13 matches: "should we launch a german language version of the site" 0.4ms
✓
q13 matches: "we want to enter a new market, how do we rank there" 0.1ms
✓
q06 matches: "how do we recover from a core update hit" 0.2ms
✓
q06 matches: "we think we got hit by the helpful content update, what now" 0.2ms
✓
q06 matches: "how do we recover from a manual action" 0.1ms
✓
q11 matches: "are ai overviews taking our clicks" 1.3ms
✓
q11 matches: "how do ai answers affect our click through rate" 0.6ms
✓
q11 matches: "we are losing clicks to generative search" 0.1ms
✓
q11 matches: "are google ai overviews reducing traffic to our site" 0.1ms
✓
q11 matches: "did overviews cause our organic traffic drop" 0.1ms
✓
q11 matches: "our impressions are up and clicks are down since overviews appeared" 0.1ms
✓
q21 matches: "which rich results can we win" 0.4ms
✓
q21 matches: "should we add faq schema to our pages" 0.3ms
✓
q21 matches: "is our structured data valid and worth expanding" 0.1ms
✓
q28 matches: "should we be doing video for seo" 0.3ms
✓
q28 matches: "how do we optimise our youtube videos for search" 0.2ms
✓
q28 matches: "is video worth it for our search traffic" 0.1ms
✓
q28 matches: "should we invest in video for search" 0.1ms
✓
q28 matches: "is it worth investing in youtube for organic traffic" 0.1ms
✓
ai21 matches: "how do wikipedia and wikidata affect whether ai engines cite us" 0.3ms
✓
ai21 matches: "is our brand recognised as an entity by the knowledge graph" 0.2ms
✓
ai21 matches: "does our knowledge panel affect ai citations" 0.1ms
✓
ai21 matches: "does our schema sameas list affect whether ai engines cite us" 0.1ms
✓
ai21 matches: "how does entity markup change how ai engines recognise our brand" 0.1ms
✓
ai19 matches: "which passages can an ai engine actually quote from our pages" 0.4ms
✓
ai19 matches: "what makes a passage extractable by ai" 0.2ms
✓
ai19 matches: "why do ai answers paraphrase us instead of quoting us" 0.2ms
✓
ai19 matches: "is our markup why nothing of ours gets quoted by ai" 0.1ms
✓
ai19 matches: "how do we make our content liftable by ai engines" 0.1ms
✓
ai02 matches: "why do some llms confidently cite us while others ignore us entirely" 0.8ms
✓
ai02 matches: "why does chatgpt cite us but gemini does not" 0.5ms
✓
ai02 matches: "why do the engines disagree about whether to mention us" 0.2ms
✓
ai02 matches: "some ai assistants name us and others never do — why" 0.4ms
✓
ai02 matches: "which engines cite us and which ignore us" 0.3ms
✓
ai25 matches: "how do we win best x and comparison prompts without becoming a listicle farm" 0.5ms
✓
ai25 matches: "who gets cited when someone asks ai for the best tools in our category" 0.3ms
✓
ai25 matches: "should we publish a best-of roundup to win ai comparison prompts" 0.1ms
✓
ai25 matches: "are we in the top-10 listicles that llms cite" 0.1ms
✓
ai25 matches: "can we win the best-x comparison prompts our buyers ask chatgpt" 0.2ms
✓
ai26 matches: "what is the relationship between classic top rankings and the chance of being cited" 1.4ms
✓
ai26 matches: "does ranking number one mean ai will quote us" 0.6ms
✓
ai26 matches: "do rankings still matter now that ai answers the question" 0.1ms
✓
ai26 matches: "are rankings dead" 0.1ms
✓
ai26 matches: "we rank in the top 3 but chatgpt never cites us — why" 0.6ms
✓
ai26 matches: "is our google ranking connected to whether perplexity mentions us" 0.3ms
✓
ai04 matches: "is it technically possible to track whether chatgpt or perplexity mention us" 1.0ms
✓
ai04 matches: "can we even measure if ai assistants cite our site" 0.5ms
✓
ai04 matches: "is there a way to monitor whether gemini recommends us" 0.1ms
✓
ai04 matches: "how do we track mentions in ai answers" 0.1ms
✓
ai04 matches: "how would we know if chatgpt is citing our pages" 0.2ms
✓
ai04 matches: "can we measure whether ai assistants name us without buying a tool" 0.1ms
✓
ai04 matches: "is it possible to see if perplexity surfaces our brand" 0.1ms
✓
ai04 matches: "why can we not track whether chatgpt mentions us" 0.1ms
✓
ai01 matches: "how do we measure success when ai gives the complete answer and the click never happens" 0.5ms
✓
ai01 matches: "what should we report now that ai answers the question without a click" 0.3ms
✓
ai01 matches: "how do we measure zero-click success" 0.1ms
✓
ai01 matches: "what do we judge informational pages on when nobody clicks" 0.1ms
✓
ai13 matches: "does focusing on ai search cannibalize our traditional seo programme" 0.8ms
✓
ai13 matches: "will geo work hurt our existing seo" 0.4ms
✓
ai13 matches: "is ai search at the expense of classic organic rankings" 0.1ms
✓
ai13 matches: "does ai visibility work come at the cost of our seo programme" 0.1ms
✓
ai22 matches: "how do we attribute pipeline from ai exposure when sessions send no referrer" 0.2ms
✓
ai22 matches: "how do we prove revenue from ai search visibility" 0.1ms
✓
ai22 matches: "can we tie deals back to ai answers" 0.1ms
✓
ai22 matches: "how do we attribute revenue when chatgpt sends no referrer" 0.1ms
✓
ai24 matches: "how should untranslated or multi-market content be handled when citation follows language" 0.2ms
✓
ai24 matches: "do we need translated pages to get cited in other languages" 0.1ms
✓
ai24 matches: "will our english pages get cited in german ai answers" 0.1ms
✓
ai24 matches: "should we localise our content for ai visibility in other languages" 0.1ms
✓
ai14 matches: "should our b2b ai search strategy differ from b2c when we want visibility inside the tools" 0.7ms
✓
ai14 matches: "do b2b and b2c need different geo playbooks" 0.4ms
✓
ai14 matches: "is ai visibility different for enterprise buyers than for consumers" 0.1ms
✓
ai14 matches: "our b2b and b2c buyers ask llms different things — should the playbook differ" 0.4ms
✓
ai16 matches: "how do we optimise technical documentation so ai tools recommend our use cases" 0.6ms
✓
ai16 matches: "why does chatgpt cite our marketing pages instead of our docs" 0.3ms
✓
ai16 matches: "are our api docs even readable by ai crawlers" 0.1ms
✓
ai16 matches: "what stops our documentation being quoted by ai assistants" 0.1ms
✓
ai05 matches: "how does query fan out change how we structure long form content" 0.1ms
✓
ai05 matches: "should we write one long page or a page per sub-query for ai search" 0.1ms
✓
ai05 matches: "do ai engines break one question into several retrievals" 0.1ms
✓
ai07 matches: "how do we meet e-e-a-t so ai systems treat us as a primary source not a recap" 0.7ms
✓
ai07 matches: "why do the engines quote the journalist who wrote about us instead of us" 0.3ms
✓
ai07 matches: "are we being treated as a middleman by ai answers" 0.2ms
✓
ai20 matches: "how should we publish our original data so engines cite us instead of a recap" 0.5ms
✓
ai20 matches: "is our gated pdf study hurting us with ai search" 0.4ms
✓
ai20 matches: "where should our benchmark findings live so they get picked up" 0.1ms
✓
ai09 matches: "how do gbp reviews local citations and reddit mentions change whether ai recommends us" 0.4ms
✓
ai09 matches: "does our g2 profile matter for ai recommendations" 0.2ms
✓
ai09 matches: "do reviews influence which vendors llms pick" 0.1ms
✓
ai09 matches: "do reddit threads affect whether chatgpt recommends us" 0.1ms
✓
ai06 matches: "what is the practical difference between ranking for keywords and being chosen for conversational prompts" 0.5ms
✓
ai06 matches: "how does keyword ranking differ from being cited in ai answers" 0.3ms
✓
ai06 matches: "should our briefs list keywords or prompts" 0.1ms
✓
ai15 matches: "what happens to market share if rivals industrialise ai search before we do" 0.3ms
✓
ai15 matches: "what if our competitors get to ai visibility first" 0.2ms
✓
ai15 matches: "are we falling behind competitors on ai answers" 0.1ms
✓
ai08 matches: "what do we do when a model hallucinates about our brand" 0.2ms
✓
ai08 matches: "chatgpt is saying something false about us" 0.2ms
✓
ai08 matches: "ai answers keep getting our company wrong" 0.1ms
✓
ai11 matches: "should we hire a specialist ai search agency or can our team adapt" 0.4ms
✓
ai11 matches: "do we need an aeo agency or can we do geo in house" 0.2ms
✓
ai11 matches: "is an ai visibility retainer worth it versus hiring" 0.1ms
✓
ai12 matches: "what does an ai search audit check that a technical seo audit misses" 0.2ms
✓
ai12 matches: "how does a geo audit differ from a normal technical audit" 0.1ms
✓
ai12 matches: "what extra does an aeo audit add beyond our seo audit" 0.1ms
✓
ai17 matches: "what should our geo measurement contract contain" 0.4ms
✓
ai17 matches: "which aeo kpis should we report instead of a vendor blended score" 0.2ms
✓
ai17 matches: "how should we measure ai visibility without a vendor score" 0.1ms
✓
ai18 matches: "should we publish llms.txt and allow ai crawlers" 0.3ms
✓
ai18 matches: "do we block gptbot and google-extended or allow them" 0.2ms
✓
ai18 matches: "what is our policy on ai bots reading the site" 0.1ms
answer-shapes: near-misses route nowhere · 32 tests
✓
nothing matches: "make me a video about widgets" 0.9ms
✓
nothing matches: "run a speed test" 0.3ms
✓
nothing matches: "check my page speed" 0.2ms
✓
nothing matches: "build me a new website" 0.2ms
✓
nothing matches: "write me an article with ai" 0.2ms
✓
nothing matches: "generate a blog post about widgets" 0.3ms
✓
nothing matches: "draft the copy using ai" 0.3ms
✓
nothing matches: "can we generate a new article with ai" 0.3ms
✓
nothing matches: "should you write me an ai blog post" 0.2ms
✓
nothing matches: "submit my sitemap" 0.3ms
✓
nothing matches: "resubmit the sitemap to google" 0.2ms
✓
nothing matches: "show me my organic traffic" 0.2ms
✓
nothing matches: "show me my backlinks" 0.1ms
✓
nothing matches: "check my backlinks" 0.1ms
✓
nothing matches: "run a backlink scan" 0.2ms
✓
nothing matches: "what is the backlink gap against acme.com" 0.2ms
✓
nothing matches: "find keywords for my business" 0.1ms
✓
nothing matches: "find keyword ideas worth targeting" 0.1ms
✓
nothing matches: "research which keywords are worth targeting" 0.1ms
✓
nothing matches: "keyword ideas for dental implants" 0.1ms
✓
nothing matches: "what is the search volume for kyc software" 0.2ms
✓
nothing matches: "track these keywords" 0.1ms
✓
nothing matches: "what is the keyword gap between us and acme.com" 0.2ms
✓
nothing matches: "how do we close the gap with competitor rival-brand.io this quarter" 0.2ms
✓
nothing matches: "write me an article about dental implants" 0.1ms
✓
nothing matches: "run an audit" 0.2ms
✓
nothing matches: "find my competitors" 0.3ms
✓
nothing matches: "fix my indexing" 0.1ms
✓
nothing matches: "what is a canonical tag" 0.1ms
✓
nothing matches: "hi" 0.1ms
✓
nothing matches: "how is my domain authority compared to theirs" 0.1ms
✓
nothing matches: "show me my backlinks" 0.1ms
answer-shapes: NO SENTENCE MATCHES TWO PREDICATES · 231 tests
✓
exactly one match for [q14] "my pages are indexed but get no impressions" 0.3ms
✓
exactly one match for [q14] "why do my pages get no clicks" 0.2ms
✓
exactly one match for [q14] "my pages rank but nobody clicks" 0.1ms
✓
exactly one match for [q14] "pages are indexed but impressions are tiny, what is actually wrong" 0.2ms
✓
exactly one match for [q16] "should we prune or merge the underperforming content" 0.2ms
✓
exactly one match for [q16] "which old blog posts should we delete" 0.1ms
✓
exactly one match for [q16] "is it worth rewriting our thin articles or killing them" 0.1ms
✓
exactly one match for [q02] "how do we run a technical seo audit and decide what to fix first" 0.2ms
✓
exactly one match for [q02] "what should we fix first from the crawl issues" 0.2ms
✓
exactly one match for [q02] "how do we prioritise the technical seo backlog" 0.2ms
✓
exactly one match for [q05] "how healthy is the site for crawling and indexation" 0.2ms
✓
exactly one match for [q05] "what is the state of our indexing" 0.1ms
✓
exactly one match for [q05] "are there problems with our crawling and rendering" 0.1ms
✓
exactly one match for [q12] "how should we fix duplicate content and canonicals" 0.2ms
✓
exactly one match for [q12] "what is our policy for url parameters and facets" 0.3ms
✓
exactly one match for [q12] "we have a url explosion problem from filters, how do we handle it" 0.2ms
✓
exactly one match for [q04] "what is the competitive landscape and where can we realistically win" 0.2ms
✓
exactly one match for [q04] "which competitors can we actually beat" 0.2ms
✓
exactly one match for [q04] "where is the whitespace against our competition" 0.2ms
✓
exactly one match for [q25] "a competitor consistently outranks us for the terms that matter, what is the gap we can close this quarter" 0.2ms
✓
exactly one match for [q25] "we are falling behind one competitor on our main keywords" 0.1ms
✓
exactly one match for [q25] "how do we close the gap with the competitor ahead of us" 0.2ms
✓
exactly one match for [q25] "which competitor gaps can we fix this quarter" 0.2ms
✓
exactly one match for [q25] "how do we beat the competitor that outranks us" 0.1ms
✓
exactly one match for [q25] "can we win back the terms we are falling behind on against our main rival" 0.9ms
✓
exactly one match for [q25] "we lost ground against a competitor this year, what should we do about it" 0.2ms
✓
exactly one match for [q24] "does our content demonstrate e-e-a-t for this niche" 0.1ms
✓
exactly one match for [q24] "how do we prove our expertise on these pages" 0.1ms
✓
exactly one match for [q24] "do we have enough trust signals on our content" 0.1ms
✓
exactly one match for [q24] "our authorship is missing, how do we establish credibility" 0.2ms
✓
exactly one match for [q09] "which backlinks should we earn, keep, or ignore" 0.1ms
✓
exactly one match for [q09] "should we disavow the low quality links pointing at us" 0.1ms
✓
exactly one match for [q09] "what should our link building strategy be" 0.1ms
✓
exactly one match for [q09] "is our link profile risky" 0.1ms
✓
exactly one match for [q03] "which keywords should we actually target given intent and revenue" 0.1ms
✓
exactly one match for [q03] "which search terms are worth targeting this year" 0.1ms
✓
exactly one match for [q03] "help me prioritise the keywords we are tracking" 0.2ms
✓
exactly one match for [q03] "what keywords should we stop targeting" 0.2ms
✓
exactly one match for [q29] "what should our robots.txt and sitemap actually contain" 0.1ms
✓
exactly one match for [q29] "should we block these pages in robots txt or noindex them" 0.1ms
✓
exactly one match for [q29] "our sitemap and robots file seem to disagree" 0.1ms
✓
exactly one match for [q29] "what rules should the sitemap follow" 0.1ms
✓
exactly one match for [q10] "how will we measure seo success and prove roi" 0.1ms
✓
exactly one match for [q10] "what kpis should we report on for organic search" 0.2ms
✓
exactly one match for [q10] "how do i justify the seo spend to the business" 0.1ms
✓
exactly one match for [q10] "how do we prove search is worth it" 0.1ms
✓
exactly one match for [q27] "can we use ai to draft content and stay eligible" 0.1ms
✓
exactly one match for [q27] "is it safe to use ai generated content on our blog" 0.1ms
✓
exactly one match for [q27] "what should our policy be for ai written articles" 0.1ms
✓
exactly one match for [q27] "will ai content get us penalised" 0.1ms
✓
exactly one match for [q17] "how long will seo take and what will it cost" 0.1ms
✓
exactly one match for [q17] "what happens to our rankings if we stop doing seo" 0.1ms
✓
exactly one match for [q17] "how many months before organic traffic moves" 0.1ms
✓
exactly one match for [q17] "if we pause content for a quarter what do we lose" 0.1ms
✓
exactly one match for [q07] "how do we migrate the site without losing organic traffic" 0.1ms
✓
exactly one match for [q07] "we are moving to a new domain, how do we keep our rankings" 0.1ms
✓
exactly one match for [q07] "what do we need to do for seo before a redesign" 0.1ms
✓
exactly one match for [q07] "replatforming the cms — what breaks in search" 5.4ms
✓
exactly one match for [q19] "how do we work with developers so seo recommendations actually ship" 0.2ms
✓
exactly one match for [q19] "our seo tickets never get done by engineering" 0.1ms
✓
exactly one match for [q19] "how do we get the dev team to implement these fixes" 0.1ms
✓
exactly one match for [q20] "how should our seo strategy change over the next few years" 0.1ms
✓
exactly one match for [q20] "what is our long term strategy as search becomes generative" 0.1ms
✓
exactly one match for [q20] "where should we invest in search over three years" 0.1ms
✓
exactly one match for [q26] "how do i explain this to a non-technical exec" 0.2ms
✓
exactly one match for [q26] "how do we present a delayed seo result to the board" 0.1ms
✓
exactly one match for [q26] "how should i brief the ceo on this" 0.1ms
✓
exactly one match for [q30] "how should seo and paid search work together" 0.1ms
✓
exactly one match for [q30] "our social and email and seo teams compete with each other" 0.1ms
✓
exactly one match for [q30] "how do we coordinate organic and ads" 0.1ms
✓
exactly one match for [q18] "how do we rank in cities where we have no office" 0.1ms
✓
exactly one match for [q18] "how do we show up in nearby towns we serve" 0.1ms
✓
exactly one match for [q18] "we want to target more locations, how do we rank there" 0.2ms
✓
exactly one match for [q15] "this page ranks well but nobody converts" 0.1ms
✓
exactly one match for [q15] "our landing pages get traffic but bounce is high" 0.1ms
✓
exactly one match for [q15] "the money page ranks on page one and conversions are weak" 0.1ms
✓
exactly one match for [q22] "is our crawl budget being wasted" 0.1ms
✓
exactly one match for [q22] "which url patterns should we block from crawling" 0.1ms
✓
exactly one match for [q22] "googlebot is spending time on pages that do not matter" 0.1ms
✓
exactly one match for [q23] "which core web vitals failures actually matter for us" 0.1ms
✓
exactly one match for [q23] "is page speed worth fixing on our site" 0.1ms
✓
exactly one match for [q23] "what should we fix for lcp and cls" 0.1ms
✓
exactly one match for [q23] "which core web vitals problems should we fix first" 0.1ms
✓
exactly one match for [q23] "what core web vitals issues should we prioritise" 0.1ms
✓
exactly one match for [q08] "how should we structure our topic clusters" 0.2ms
✓
exactly one match for [q08] "how do we organise internal links to build topical authority" 0.1ms
✓
exactly one match for [q08] "what should our site architecture look like for these topics" 0.1ms
✓
exactly one match for [q13] "how do we expand into other countries without cannibalising ourselves" 0.2ms
✓
exactly one match for [q13] "should we launch a german language version of the site" 0.1ms
✓
exactly one match for [q13] "we want to enter a new market, how do we rank there" 0.1ms
✓
exactly one match for [q06] "how do we recover from a core update hit" 0.1ms
✓
exactly one match for [q06] "we think we got hit by the helpful content update, what now" 0.1ms
✓
exactly one match for [q06] "how do we recover from a manual action" 0.1ms
✓
exactly one match for [q11] "are ai overviews taking our clicks" 0.1ms
✓
exactly one match for [q11] "how do ai answers affect our click through rate" 0.1ms
✓
exactly one match for [q11] "we are losing clicks to generative search" 0.1ms
✓
exactly one match for [q11] "are google ai overviews reducing traffic to our site" 0.1ms
✓
exactly one match for [q11] "did overviews cause our organic traffic drop" 0.1ms
✓
exactly one match for [q11] "our impressions are up and clicks are down since overviews appeared" 0.1ms
✓
exactly one match for [q21] "which rich results can we win" 0.1ms
✓
exactly one match for [q21] "should we add faq schema to our pages" 0.1ms
✓
exactly one match for [q21] "is our structured data valid and worth expanding" 0.1ms
✓
exactly one match for [ai21] "how do wikipedia and wikidata affect whether ai engines cite us" 0.1ms
✓
exactly one match for [ai21] "is our brand recognised as an entity by the knowledge graph" 0.2ms
✓
exactly one match for [ai21] "does our knowledge panel affect ai citations" 0.1ms
✓
exactly one match for [ai21] "does our schema sameas list affect whether ai engines cite us" 0.1ms
✓
exactly one match for [ai21] "how does entity markup change how ai engines recognise our brand" 0.1ms
✓
exactly one match for [ai06] "what is the practical difference between ranking for keywords and being chosen for conversational prompts" 0.2ms
✓
exactly one match for [ai06] "how does keyword ranking differ from being cited in ai answers" 0.1ms
✓
exactly one match for [ai06] "should our briefs list keywords or prompts" 0.1ms
✓
exactly one match for [ai15] "what happens to market share if rivals industrialise ai search before we do" 0.2ms
✓
exactly one match for [ai15] "what if our competitors get to ai visibility first" 0.1ms
✓
exactly one match for [ai15] "are we falling behind competitors on ai answers" 0.1ms
✓
exactly one match for [ai09] "how do gbp reviews local citations and reddit mentions change whether ai recommends us" 0.1ms
✓
exactly one match for [ai09] "does our g2 profile matter for ai recommendations" 0.1ms
✓
exactly one match for [ai09] "do reviews influence which vendors llms pick" 0.1ms
✓
exactly one match for [ai09] "do reddit threads affect whether chatgpt recommends us" 0.2ms
✓
exactly one match for [ai26] "what is the relationship between classic top rankings and the chance of being cited" 0.1ms
✓
exactly one match for [ai26] "does ranking number one mean ai will quote us" 0.1ms
✓
exactly one match for [ai26] "do rankings still matter now that ai answers the question" 0.1ms
✓
exactly one match for [ai26] "are rankings dead" 0.1ms
✓
exactly one match for [ai26] "we rank in the top 3 but chatgpt never cites us — why" 0.7ms
✓
exactly one match for [ai26] "is our google ranking connected to whether perplexity mentions us" 0.2ms
✓
exactly one match for [ai04] "is it technically possible to track whether chatgpt or perplexity mention us" 0.3ms
✓
exactly one match for [ai04] "can we even measure if ai assistants cite our site" 0.1ms
✓
exactly one match for [ai04] "is there a way to monitor whether gemini recommends us" 0.2ms
✓
exactly one match for [ai04] "how do we track mentions in ai answers" 0.1ms
✓
exactly one match for [ai04] "how would we know if chatgpt is citing our pages" 0.1ms
✓
exactly one match for [ai04] "can we measure whether ai assistants name us without buying a tool" 0.1ms
✓
exactly one match for [ai04] "is it possible to see if perplexity surfaces our brand" 0.1ms
✓
exactly one match for [ai04] "why can we not track whether chatgpt mentions us" 0.1ms
✓
exactly one match for [ai01] "how do we measure success when ai gives the complete answer and the click never happens" 0.2ms
✓
exactly one match for [ai01] "what should we report now that ai answers the question without a click" 0.1ms
✓
exactly one match for [ai01] "how do we measure zero-click success" 0.1ms
✓
exactly one match for [ai01] "what do we judge informational pages on when nobody clicks" 0.1ms
✓
exactly one match for [ai13] "does focusing on ai search cannibalize our traditional seo programme" 0.2ms
✓
exactly one match for [ai13] "will geo work hurt our existing seo" 0.1ms
✓
exactly one match for [ai13] "is ai search at the expense of classic organic rankings" 0.1ms
✓
exactly one match for [ai13] "does ai visibility work come at the cost of our seo programme" 0.2ms
✓
exactly one match for [ai22] "how do we attribute pipeline from ai exposure when sessions send no referrer" 0.1ms
✓
exactly one match for [ai22] "how do we prove revenue from ai search visibility" 0.1ms
✓
exactly one match for [ai22] "can we tie deals back to ai answers" 0.1ms
✓
exactly one match for [ai22] "how do we attribute revenue when chatgpt sends no referrer" 0.1ms
✓
exactly one match for [ai24] "how should untranslated or multi-market content be handled when citation follows language" 0.1ms
✓
exactly one match for [ai24] "do we need translated pages to get cited in other languages" 0.1ms
✓
exactly one match for [ai24] "will our english pages get cited in german ai answers" 0.2ms
✓
exactly one match for [ai24] "should we localise our content for ai visibility in other languages" 0.1ms
✓
exactly one match for [ai14] "should our b2b ai search strategy differ from b2c when we want visibility inside the tools" 0.2ms
✓
exactly one match for [ai14] "do b2b and b2c need different geo playbooks" 0.1ms
✓
exactly one match for [ai14] "is ai visibility different for enterprise buyers than for consumers" 0.1ms
✓
exactly one match for [ai14] "our b2b and b2c buyers ask llms different things — should the playbook differ" 0.3ms
✓
exactly one match for [ai16] "how do we optimise technical documentation so ai tools recommend our use cases" 0.2ms
✓
exactly one match for [ai16] "why does chatgpt cite our marketing pages instead of our docs" 0.1ms
✓
exactly one match for [ai16] "are our api docs even readable by ai crawlers" 0.1ms
✓
exactly one match for [ai16] "what stops our documentation being quoted by ai assistants" 0.1ms
✓
exactly one match for [ai05] "how does query fan out change how we structure long form content" 0.1ms
✓
exactly one match for [ai05] "should we write one long page or a page per sub-query for ai search" 0.1ms
✓
exactly one match for [ai05] "do ai engines break one question into several retrievals" 0.3ms
✓
exactly one match for [ai07] "how do we meet e-e-a-t so ai systems treat us as a primary source not a recap" 0.2ms
✓
exactly one match for [ai07] "why do the engines quote the journalist who wrote about us instead of us" 0.2ms
✓
exactly one match for [ai07] "are we being treated as a middleman by ai answers" 0.2ms
✓
exactly one match for [ai20] "how should we publish our original data so engines cite us instead of a recap" 0.2ms
✓
exactly one match for [ai20] "is our gated pdf study hurting us with ai search" 0.2ms
✓
exactly one match for [ai20] "where should our benchmark findings live so they get picked up" 0.2ms
✓
exactly one match for [ai25] "how do we win best x and comparison prompts without becoming a listicle farm" 0.2ms
✓
exactly one match for [ai25] "who gets cited when someone asks ai for the best tools in our category" 0.2ms
✓
exactly one match for [ai25] "should we publish a best-of roundup to win ai comparison prompts" 0.2ms
✓
exactly one match for [ai25] "are we in the top-10 listicles that llms cite" 0.5ms
✓
exactly one match for [ai25] "can we win the best-x comparison prompts our buyers ask chatgpt" 0.2ms
✓
exactly one match for [ai02] "why do some llms confidently cite us while others ignore us entirely" 0.2ms
✓
exactly one match for [ai02] "why does chatgpt cite us but gemini does not" 0.2ms
✓
exactly one match for [ai02] "why do the engines disagree about whether to mention us" 0.2ms
✓
exactly one match for [ai02] "some ai assistants name us and others never do — why" 0.4ms
✓
exactly one match for [ai02] "which engines cite us and which ignore us" 0.2ms
✓
exactly one match for [ai19] "which passages can an ai engine actually quote from our pages" 0.2ms
✓
exactly one match for [ai19] "what makes a passage extractable by ai" 0.2ms
✓
exactly one match for [ai19] "why do ai answers paraphrase us instead of quoting us" 0.2ms
✓
exactly one match for [ai19] "is our markup why nothing of ours gets quoted by ai" 0.2ms
✓
exactly one match for [ai19] "how do we make our content liftable by ai engines" 0.2ms
✓
exactly one match for [ai08] "what do we do when a model hallucinates about our brand" 0.2ms
✓
exactly one match for [ai08] "chatgpt is saying something false about us" 0.2ms
✓
exactly one match for [ai08] "ai answers keep getting our company wrong" 0.2ms
✓
exactly one match for [ai11] "should we hire a specialist ai search agency or can our team adapt" 0.2ms
✓
exactly one match for [ai11] "do we need an aeo agency or can we do geo in house" 0.2ms
✓
exactly one match for [ai11] "is an ai visibility retainer worth it versus hiring" 0.2ms
✓
exactly one match for [ai12] "what does an ai search audit check that a technical seo audit misses" 0.2ms
✓
exactly one match for [ai12] "how does a geo audit differ from a normal technical audit" 0.2ms
✓
exactly one match for [ai12] "what extra does an aeo audit add beyond our seo audit" 0.2ms
✓
exactly one match for [ai17] "what should our geo measurement contract contain" 0.2ms
✓
exactly one match for [ai17] "which aeo kpis should we report instead of a vendor blended score" 0.2ms
✓
exactly one match for [ai17] "how should we measure ai visibility without a vendor score" 0.2ms
✓
exactly one match for [ai18] "should we publish llms.txt and allow ai crawlers" 0.2ms
✓
exactly one match for [ai18] "do we block gptbot and google-extended or allow them" 0.2ms
✓
exactly one match for [ai18] "what is our policy on ai bots reading the site" 0.2ms
✓
exactly one match for [q28] "should we be doing video for seo" 0.2ms
✓
exactly one match for [q28] "how do we optimise our youtube videos for search" 0.2ms
✓
exactly one match for [q28] "is video worth it for our search traffic" 0.2ms
✓
exactly one match for [q28] "should we invest in video for search" 0.1ms
✓
exactly one match for [q28] "is it worth investing in youtube for organic traffic" 0.2ms
✓
exactly one match for [none] "make me a video about widgets" 0.1ms
✓
exactly one match for [none] "run a speed test" 0.1ms
✓
exactly one match for [none] "check my page speed" 0.1ms
✓
exactly one match for [none] "build me a new website" 0.1ms
✓
exactly one match for [none] "write me an article with ai" 0.1ms
✓
exactly one match for [none] "generate a blog post about widgets" 0.1ms
✓
exactly one match for [none] "draft the copy using ai" 0.2ms
✓
exactly one match for [none] "can we generate a new article with ai" 0.1ms
✓
exactly one match for [none] "should you write me an ai blog post" 0.1ms
✓
exactly one match for [none] "submit my sitemap" 0.1ms
✓
exactly one match for [none] "resubmit the sitemap to google" 0.1ms
✓
exactly one match for [none] "show me my organic traffic" 0.1ms
✓
exactly one match for [none] "show me my backlinks" 0.1ms
✓
exactly one match for [none] "check my backlinks" 0.1ms
✓
exactly one match for [none] "run a backlink scan" 0.1ms
✓
exactly one match for [none] "what is the backlink gap against acme.com" 0.1ms
✓
exactly one match for [none] "find keywords for my business" 0.1ms
✓
exactly one match for [none] "find keyword ideas worth targeting" 0.1ms
✓
exactly one match for [none] "research which keywords are worth targeting" 0.1ms
✓
exactly one match for [none] "keyword ideas for dental implants" 0.1ms
✓
exactly one match for [none] "what is the search volume for kyc software" 0.1ms
✓
exactly one match for [none] "track these keywords" 0.2ms
✓
exactly one match for [none] "what is the keyword gap between us and acme.com" 0.1ms
✓
exactly one match for [none] "how do we close the gap with competitor rival-brand.io this quarter" 0.1ms
✓
exactly one match for [none] "write me an article about dental implants" 0.1ms
✓
exactly one match for [none] "run an audit" 0.2ms
✓
exactly one match for [none] "find my competitors" 0.3ms
✓
exactly one match for [none] "fix my indexing" 0.1ms
✓
exactly one match for [none] "what is a canonical tag" 0.1ms
✓
exactly one match for [none] "hi" 0.1ms
✓
exactly one match for [none] "how is my domain authority compared to theirs" 0.1ms
✓
exactly one match for [none] "show me my backlinks" 0.1ms
answer-shapes: the Q04/Q25 carve-out is explicit, not positional · 2 tests
✓
a sentence with both signals goes to Q25 only 0.2ms
✓
a landscape question without a shortfall still goes to Q04 0.1ms
answer-shapes: E-E-A-T does not steal backlink vocabulary · 3 tests
✓
not eeat: "how is my domain authority" 0.1ms
✓
not eeat: "what is our link authority" 0.1ms
✓
not eeat: "domain authority vs page authority" 0.1ms
an ORDER never reaches the brief shortcut · 13 tests
✓
gated: "run my AI visibility panel now for kakunin.ai — …" 9.3ms
✓
gated: "freeze my weekly AI visibility panel to the exac…" 2.9ms
✓
gated: "Freeze the weekly panel to these exact prompts: …" 0.3ms
✓
gated: "Freeze my weekly tracking panel to exactly these…" 0.3ms
✓
gated: "turn on weekly ai visibility tracking for kakuni…" 0.2ms
✓
gated: "disable the weekly cron…" 0.1ms
✓
gated: "lock my prompt set…" 0.1ms
✓
gated: "pause the campaign…" 0.2ms
✓
the audit-scope predicate no longer claims a freeze order at all 0.1ms
✓
the three REAL audit-scope questions still match — the fix narrowed, it did not delete 0.2ms
✓
"audit trails" is not an audit we run 0.1ms
✓
a bare "vs" needs a second audit before it counts as a scope comparison 0.4ms
✓
and real QUESTIONS are still claimed — the gate must not have swallowed the layer 10.4ms
src/billing/cost-quote-gate-parity.vitest.ts
quoted price never differs from gated price · 190 tests
✓
enrich_contacts (agent): approval card matches priceOfTool 2.1ms
✓
enrich_contacts (agent): gate message quotes the same figure priceOfTool decides on 0.6ms
✓
enrich_contacts (shortcut): approval card matches priceOfTool 0.3ms
✓
enrich_contacts (shortcut): gate message quotes the same figure priceOfTool decides on 0.2ms
✓
enrich_contacts: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.6ms
✓
seo_offpage_audit (agent): approval card matches priceOfTool 0.3ms
✓
seo_offpage_audit (agent): gate message quotes the same figure priceOfTool decides on 0.2ms
✓
seo_offpage_audit (shortcut): approval card matches priceOfTool 0.2ms
✓
seo_offpage_audit (shortcut): gate message quotes the same figure priceOfTool decides on 0.5ms
✓
seo_offpage_audit: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.3ms
✓
seo_backlinks (agent): approval card matches priceOfTool 0.3ms
✓
seo_backlinks (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_backlinks (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_backlinks (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_backlinks: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_request_indexing (agent): approval card matches priceOfTool 0.3ms
✓
seo_request_indexing (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_request_indexing (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_request_indexing (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_request_indexing: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_enrich_keywords (agent): approval card matches priceOfTool 0.2ms
✓
seo_enrich_keywords (agent): gate message quotes the same figure priceOfTool decides on 0.2ms
✓
seo_enrich_keywords (shortcut): approval card matches priceOfTool 0.2ms
✓
seo_enrich_keywords (shortcut): gate message quotes the same figure priceOfTool decides on 0.2ms
✓
seo_enrich_keywords: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_competitor_gap (agent): approval card matches priceOfTool 0.1ms
✓
seo_competitor_gap (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_competitor_gap (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_competitor_gap (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_competitor_gap: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_backlink_gap (agent): approval card matches priceOfTool 0.2ms
✓
seo_backlink_gap (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_backlink_gap (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_backlink_gap (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_backlink_gap: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_backlink_deep_scan (agent): approval card matches priceOfTool 0.2ms
✓
seo_backlink_deep_scan (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_backlink_deep_scan (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_backlink_deep_scan (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_backlink_deep_scan: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
full_seo_audit (agent): approval card matches priceOfTool 0.1ms
✓
full_seo_audit (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
full_seo_audit (shortcut): approval card matches priceOfTool 0.1ms
✓
full_seo_audit (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
full_seo_audit: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
keyword_volumes (agent): approval card matches priceOfTool 0.2ms
✓
keyword_volumes (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
keyword_volumes (shortcut): approval card matches priceOfTool 0.2ms
✓
keyword_volumes (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
keyword_volumes: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
scan_product (agent): approval card matches priceOfTool 0.1ms
✓
scan_product (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
scan_product (shortcut): approval card matches priceOfTool 0.1ms
✓
scan_product (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
scan_product: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
define_icp (agent): approval card matches priceOfTool 0.1ms
✓
define_icp (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
define_icp (shortcut): approval card matches priceOfTool 0.1ms
✓
define_icp (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
define_icp: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
generate_emails (agent): approval card matches priceOfTool 0.1ms
✓
generate_emails (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
generate_emails (shortcut): approval card matches priceOfTool 0.1ms
✓
generate_emails (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
generate_emails: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
search_leads (agent): approval card matches priceOfTool 0.3ms
✓
search_leads (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
search_leads (shortcut): approval card matches priceOfTool 0.1ms
✓
search_leads (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
search_leads: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
backlink_outreach_search (agent): approval card matches priceOfTool 0.4ms
✓
backlink_outreach_search (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
backlink_outreach_search (shortcut): approval card matches priceOfTool 0.1ms
✓
backlink_outreach_search (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
backlink_outreach_search: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
share_of_model (agent): approval card matches priceOfTool 0.2ms
✓
share_of_model (agent): gate message quotes the same figure priceOfTool decides on 0.2ms
✓
share_of_model (shortcut): approval card matches priceOfTool 0.2ms
✓
share_of_model (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
share_of_model: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_geo_visibility (agent): approval card matches priceOfTool 0.5ms
✓
seo_geo_visibility (agent): gate message quotes the same figure priceOfTool decides on 0.2ms
✓
seo_geo_visibility (shortcut): approval card matches priceOfTool 0.2ms
✓
seo_geo_visibility (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_geo_visibility: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
ai_overview_visibility (agent): approval card matches priceOfTool 0.2ms
✓
ai_overview_visibility (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
ai_overview_visibility (shortcut): approval card matches priceOfTool 0.2ms
✓
ai_overview_visibility (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
ai_overview_visibility: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
entity_audit (agent): approval card matches priceOfTool 0.1ms
✓
entity_audit (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
entity_audit (shortcut): approval card matches priceOfTool 0.1ms
✓
entity_audit (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
entity_audit: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
web_search (agent): approval card matches priceOfTool 0.1ms
✓
web_search (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
web_search (shortcut): approval card matches priceOfTool 0.1ms
✓
web_search (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
web_search: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
verify_contacts (agent): approval card matches priceOfTool 0.2ms
✓
verify_contacts (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
verify_contacts (shortcut): approval card matches priceOfTool 0.1ms
✓
verify_contacts (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
verify_contacts: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
seo_onpage_audit (agent): approval card matches priceOfTool 0.2ms
✓
seo_onpage_audit (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_onpage_audit (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_onpage_audit (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_onpage_audit: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_serp_spider (agent): approval card matches priceOfTool 0.3ms
✓
seo_serp_spider (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_serp_spider (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_serp_spider (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_serp_spider: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_keyword_metrics (agent): approval card matches priceOfTool 0.2ms
✓
seo_keyword_metrics (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_keyword_metrics (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_keyword_metrics (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_keyword_metrics: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
google_god_mode_report (agent): approval card matches priceOfTool 0.2ms
✓
google_god_mode_report (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
google_god_mode_report (shortcut): approval card matches priceOfTool 0.1ms
✓
google_god_mode_report (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
google_god_mode_report: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
aeo_visibility (agent): approval card matches priceOfTool 0.3ms
✓
aeo_visibility (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
aeo_visibility (shortcut): approval card matches priceOfTool 0.1ms
✓
aeo_visibility (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
aeo_visibility: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.2ms
✓
tap_volume (agent): approval card matches priceOfTool 0.2ms
✓
tap_volume (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
tap_volume (shortcut): approval card matches priceOfTool 0.1ms
✓
tap_volume (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
tap_volume: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
aeo_full_audit (agent): approval card matches priceOfTool 0.1ms
✓
aeo_full_audit (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
aeo_full_audit (shortcut): approval card matches priceOfTool 0.1ms
✓
aeo_full_audit (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
aeo_full_audit: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_geo_research (agent): approval card matches priceOfTool 0.2ms
✓
seo_geo_research (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_geo_research (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_geo_research (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_geo_research: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
aeo_page_check (agent): approval card matches priceOfTool 0.1ms
✓
aeo_page_check (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
aeo_page_check (shortcut): approval card matches priceOfTool 0.1ms
✓
aeo_page_check (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
aeo_page_check: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_content_ideas (agent): approval card matches priceOfTool 0.1ms
✓
seo_content_ideas (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_content_ideas (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_content_ideas (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_content_ideas: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_write_content (agent): approval card matches priceOfTool 0.1ms
✓
seo_write_content (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_write_content (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_write_content (shortcut): gate message quotes the same figure priceOfTool decides on 2.2ms
✓
seo_write_content: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
find_competitors (agent): approval card matches priceOfTool 0.1ms
✓
find_competitors (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
find_competitors (shortcut): approval card matches priceOfTool 0.1ms
✓
find_competitors (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
find_competitors: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_content_brief (agent): approval card matches priceOfTool 0.1ms
✓
seo_content_brief (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_content_brief (shortcut): approval card matches priceOfTool 0.2ms
✓
seo_content_brief (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_content_brief: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_content_quality (agent): approval card matches priceOfTool 0.1ms
✓
seo_content_quality (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_content_quality (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_content_quality (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_content_quality: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
set_campaign_sequence (agent): approval card matches priceOfTool 0.1ms
✓
set_campaign_sequence (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
set_campaign_sequence (shortcut): approval card matches priceOfTool 0.1ms
✓
set_campaign_sequence (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
set_campaign_sequence: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
seo_keywords (agent): approval card matches priceOfTool 0.2ms
✓
seo_keywords (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_keywords (shortcut): approval card matches priceOfTool 0.1ms
✓
seo_keywords (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
seo_keywords: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
✓
create_marketing_plan (agent): approval card matches priceOfTool 0.1ms
✓
create_marketing_plan (agent): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
create_marketing_plan (shortcut): approval card matches priceOfTool 0.1ms
✓
create_marketing_plan (shortcut): gate message quotes the same figure priceOfTool decides on 0.1ms
✓
create_marketing_plan: resolveCostApproval's gate decision agrees with priceOfTool, in both directions 0.1ms
the two tools this sprint flips · 4 tests
✓
seo_offpage_audit: agent-route quote (104K-shape) clears the 75K threshold 0.3ms
✓
seo_offpage_audit: a bare shortcut dispatch never pays a floor it does not spend — and still gates 0.1ms
✓
seo_competitor_gap: agent-route quote clears the threshold (no shortcut exists — always agent-priced) 0.2ms
✓
no tool flips gating state between routes (the set is now empty) 0.8ms
search_leads never double-counts its own floor · 1 test
✓
table entry already includes ORCHESTRATION_FLOOR — withRouteFloor must not add a second copy 0.4ms
a direct()/shortcut route never gains a floor it never pays · 1 test
✓
google_god_mode_report: shortcut price is exactly the provider-only table figure 0.1ms
priceOfTool never adds a floor to a genuinely free tool · 1 test
✓
an unpriced tool stays at zero regardless of route 0.1ms
costOfCall itself is unchanged — it stays the provider-only primitive · 1 test
✓
costOfCall never includes the floor; only priceOfTool (agent route) does 1.4ms
src/seo/playbooks.vitest.ts
every playbook satisfies the invariants, in every state · 126 tests
✓
dev_handoff — empty 3.5ms
✓
dev_handoff — populated 0.3ms
✓
dev_handoff — location saved but serves unanswered 0.3ms
✓
dev_handoff — content checked, nothing else 0.2ms
✓
dev_handoff — a tracked market 0.2ms
✓
dev_handoff — a crawl on file 0.2ms
✓
dev_handoff — a crawl that found bots blocked 0.2ms
✓
generative_strategy — empty 0.3ms
✓
generative_strategy — populated 0.6ms
✓
generative_strategy — location saved but serves unanswered 0.3ms
✓
generative_strategy — content checked, nothing else 0.2ms
✓
generative_strategy — a tracked market 0.1ms
✓
generative_strategy — a crawl on file 0.1ms
✓
generative_strategy — a crawl that found bots blocked 0.1ms
✓
exec_brief — empty 0.3ms
✓
exec_brief — populated 0.2ms
✓
exec_brief — location saved but serves unanswered 0.1ms
✓
exec_brief — content checked, nothing else 0.1ms
✓
exec_brief — a tracked market 0.1ms
✓
exec_brief — a crawl on file 0.1ms
✓
exec_brief — a crawl that found bots blocked 0.1ms
✓
channel_model — empty 0.1ms
✓
channel_model — populated 0.1ms
✓
channel_model — location saved but serves unanswered 0.1ms
✓
channel_model — content checked, nothing else 0.1ms
✓
channel_model — a tracked market 0.1ms
✓
channel_model — a crawl on file 0.1ms
✓
channel_model — a crawl that found bots blocked 0.1ms
✓
service_area — empty 0.2ms
✓
service_area — populated 0.1ms
✓
service_area — location saved but serves unanswered 0.1ms
✓
service_area — content checked, nothing else 0.1ms
✓
service_area — a tracked market 0.1ms
✓
service_area — a crawl on file 0.1ms
✓
service_area — a crawl that found bots blocked 0.1ms
✓
international — empty 0.2ms
✓
international — populated 0.1ms
✓
international — location saved but serves unanswered 0.1ms
✓
international — content checked, nothing else 0.1ms
✓
international — a tracked market 0.1ms
✓
international — a crawl on file 0.1ms
✓
international — a crawl that found bots blocked 0.1ms
✓
hallucination_recovery — empty 0.2ms
✓
hallucination_recovery — populated 0.1ms
✓
hallucination_recovery — location saved but serves unanswered 0.1ms
✓
hallucination_recovery — content checked, nothing else 0.1ms
✓
hallucination_recovery — a tracked market 0.1ms
✓
hallucination_recovery — a crawl on file 0.2ms
✓
hallucination_recovery — a crawl that found bots blocked 0.1ms
✓
ai_search_staffing — empty 0.2ms
✓
ai_search_staffing — populated 0.1ms
✓
ai_search_staffing — location saved but serves unanswered 0.1ms
✓
ai_search_staffing — content checked, nothing else 0.1ms
✓
ai_search_staffing — a tracked market 0.1ms
✓
ai_search_staffing — a crawl on file 0.1ms
✓
ai_search_staffing — a crawl that found bots blocked 0.1ms
✓
ai_audit_scope — empty 0.2ms
✓
ai_audit_scope — populated 0.1ms
✓
ai_audit_scope — location saved but serves unanswered 0.1ms
✓
ai_audit_scope — content checked, nothing else 0.1ms
✓
ai_audit_scope — a tracked market 0.1ms
✓
ai_audit_scope — a crawl on file 0.1ms
✓
ai_audit_scope — a crawl that found bots blocked 0.1ms
✓
geo_measurement_contract — empty 0.2ms
✓
geo_measurement_contract — populated 0.1ms
✓
geo_measurement_contract — location saved but serves unanswered 0.1ms
✓
geo_measurement_contract — content checked, nothing else 0.1ms
✓
geo_measurement_contract — a tracked market 0.1ms
✓
geo_measurement_contract — a crawl on file 0.1ms
✓
geo_measurement_contract — a crawl that found bots blocked 0.1ms
✓
crawler_policy — empty 0.2ms
✓
crawler_policy — populated 0.1ms
✓
crawler_policy — location saved but serves unanswered 0.1ms
✓
crawler_policy — content checked, nothing else 0.1ms
✓
crawler_policy — a tracked market 0.1ms
✓
crawler_policy — a crawl on file 0.2ms
✓
crawler_policy — a crawl that found bots blocked 0.1ms
✓
rival_industrialisation — empty 0.2ms
✓
rival_industrialisation — populated 0.1ms
✓
rival_industrialisation — location saved but serves unanswered 0.1ms
✓
rival_industrialisation — content checked, nothing else 0.1ms
✓
rival_industrialisation — a tracked market 0.1ms
✓
rival_industrialisation — a crawl on file 0.1ms
✓
rival_industrialisation — a crawl that found bots blocked 0.1ms
✓
kpi_contract — empty 0.2ms
✓
kpi_contract — populated 0.1ms
✓
kpi_contract — location saved but serves unanswered 0.1ms
✓
kpi_contract — content checked, nothing else 0.1ms
✓
kpi_contract — a tracked market 0.1ms
✓
kpi_contract — a crawl on file 0.2ms
✓
kpi_contract — a crawl that found bots blocked 0.1ms
✓
ai_cannibalisation — empty 0.2ms
✓
ai_cannibalisation — populated 0.1ms
✓
ai_cannibalisation — location saved but serves unanswered 0.1ms
✓
ai_cannibalisation — content checked, nothing else 0.1ms
✓
ai_cannibalisation — a tracked market 0.1ms
✓
ai_cannibalisation — a crawl on file 0.1ms
✓
ai_cannibalisation — a crawl that found bots blocked 0.1ms
✓
ai_pipeline_attribution — empty 0.2ms
✓
ai_pipeline_attribution — populated 0.1ms
✓
ai_pipeline_attribution — location saved but serves unanswered 0.1ms
✓
ai_pipeline_attribution — content checked, nothing else 0.1ms
✓
ai_pipeline_attribution — a tracked market 0.1ms
✓
ai_pipeline_attribution — a crawl on file 0.1ms
✓
ai_pipeline_attribution — a crawl that found bots blocked 0.1ms
✓
multi_market_language — empty 0.2ms
✓
multi_market_language — populated 0.1ms
✓
multi_market_language — location saved but serves unanswered 0.1ms
✓
multi_market_language — content checked, nothing else 0.1ms
✓
multi_market_language — a tracked market 0.1ms
✓
multi_market_language — a crawl on file 0.1ms
✓
multi_market_language — a crawl that found bots blocked 0.1ms
✓
fan_out — populated 0.1ms
✓
fan_out — location saved but serves unanswered 0.1ms
✓
fan_out — content checked, nothing else 0.1ms
✓
fan_out — a tracked market 0.1ms
✓
fan_out — a crawl on file 0.1ms
✓
fan_out — a crawl that found bots blocked 0.1ms
✓
original_data — empty 0.2ms
✓
original_data — populated 0.1ms
✓
original_data — location saved but serves unanswered 0.1ms
✓
original_data — content checked, nothing else 0.1ms
✓
original_data — a tracked market 0.1ms
✓
original_data — a crawl on file 0.1ms
✓
original_data — a crawl that found bots blocked 0.1ms
the invariants are real — playbookProblems catches each violation · 6 tests
✓
rejects a vague trigger 0.3ms
✓
rejects a signal with no window 0.2ms
✓
rejects a rule with no signal at all 0.2ms
✓
rejects an open-ended decision 0.2ms
✓
rejects an unanchored playbook with no reason given 0.2ms
✓
accepts a null anchor WITH a reason — that is the honest case 0.2ms
Q19: the definition of ready has teeth · 3 tests
✓
the gate is admission to the sprint, not deprioritisation 0.2ms
✓
anchors on the platform's own record of unshipped work 0.2ms
✓
says plainly when there is no such record 0.2ms
Q20: the defund clause survives · 4 tests
✓
stops commissioning recap content rather than merely adding bets 0.4ms
✓
makes the defund falsifiable by output going DOWN 0.3ms
✓
forces the willing-to-stop question rather than assuming it 1.2ms
✓
requires a kill condition on each bet 0.2ms
Q26: the format constraint is the answer · 4 tests
✓
is one page and one decision 0.2ms
✓
caps options at two plus doing nothing 0.3ms
✓
puts rankings in the appendix as a diagnostic 0.2ms
✓
anchors on the revenue bridge being unavailable, and does not offer to assemble one 0.2ms
Q30: ownership by query class, and one count · 4 tests
✓
assigns demand rather than coordinating calendars 0.2ms
✓
makes the taxonomy falsifiable by someone declining work 0.2ms
✓
ends the double-count and says how you would spot it 0.2ms
✓
states which channels it can and cannot see 0.2ms
Q18: the one unanswered question is the anchor · 5 tests
✓
says the serves-at-location answer is missing when it is 0.3ms
✓
adapts once the answer exists 0.3ms
✓
warns that claiming an address you do not have is a suspension risk, not a ranking one 0.2ms
✓
rejects the city-page-with-swapped-name pattern, checkably 0.2ms
✓
says when no address is saved at all 0.2ms
withContentSignals reads the shared checks rather than re-querying · 2 tests
✓
counts failing pages by check name, de-duplicated by URL 0.3ms
✓
does not query content_quality itself 1.1ms
playbooks never speak in internal vocabulary (GS-005) · 1 test
✓
keeps field and table names out of every playbook in every state 30.8ms
Q13: staffing is the SEO decision, not a detail after it · 6 tests
✓
forbids translating a market nobody will keep current 0.6ms
✓
makes the staffing rule falsifiable rather than aspirational 0.4ms
✓
requires one address structure chosen before the first page 0.3ms
✓
requires the counterpart declaration to be two-way 0.4ms
✓
anchors on the single tracked market, and says what that limits 0.4ms
✓
separates a language from a country, because they need different answers 0.2ms
src/chat/tool-format.vitest.ts
parseTextToolCall (text-JSON salvage, live leak 2026-07-22) · 3 tests
✓
salvages the exact live leak shape 2.4ms
✓
handles arguments/args keys and fenced JSON 0.6ms
✓
never salvages unregistered tools, malformed JSON, or JSON inside a real answer 0.4ms
parseJsonObjectLoose (truncation-tolerant structured output) · 3 tests
✓
parses clean and prefixed JSON 0.4ms
✓
recovers the leading object from a truncated tail 0.3ms
✓
returns null when nothing parses 0.2ms
extractTldr (server-authored lead, chat-anatomy v2) · 5 tests
✓
lifts the TL;DR line and returns the body without it 0.9ms
✓
tolerates marker variants the model produces 0.5ms
✓
passes through text without the marker unchanged 0.5ms
✓
a TL;DR with no body is just a short answer, not a lead 0.2ms
✓
never invents a lead mid-text 0.2ms
deriveReportTldr · 8 tests
✓
uses structured score data instead of report HTML or prose 0.6ms
✓
uses a structured finding count when no score is available 0.1ms
✓
keeps an honest report-ready lead when there is no stable summary field 0.1ms
✓
does not add a lead to errors or background handles 0.1ms
✓
uses the off-page findings for conclusion, why, and next action 13.2ms
✓
grounds the marketing-plan lead in plan_score and the thesis, not a generic lead 0.3ms
✓
falls back to an open-item count when no thesis is recorded 0.1ms
✓
returns null for an empty plan rather than a generic "is ready" lead 0.1ms
deriveSubstantiveAnswerTldr · 1 test
✓
uses a conservative first-answer fallback only for clearly substantive replies 0.7ms
humanizeToolName · 2 tests
✓
turns snake_case into a readable label 0.2ms
✓
handles single-word tool names 0.1ms
formatToolResult — generate_emails surfaces dropped drafts · 3 tests
✓
warns when some drafts were dropped on hallucinated contact ids 4.8ms
✓
does not claim success when every draft was dropped 0.2ms
✓
stays clean when nothing was dropped 0.2ms
resolveSilentTurnText — no bare "Done." on a failed turn · 5 tests
✓
relays the error when every tool call errored and the model was silent 0.2ms
✓
the relayed no-drafts copy satisfies the honest-copy regression regex 0.2ms
✓
keeps "Done." for a genuinely silent SUCCESS (no errors) 0.2ms
✓
keeps "Done." when only SOME tools errored (a later one may have carried the turn) 0.1ms
✓
keeps "Done." when there were no tool calls at all 0.1ms
overrideBareAcknowledgment — no bare "Done." the MODEL itself authored on a failed turn · 7 tests
✓
replaces a bare "Done." with the tool error when every call errored 0.2ms
✓
replaces bare acks case/punctuation-insensitively ("ok", "Got it!", "Sure") 0.3ms
✓
leaves a genuinely engaged reply alone, even a short one 0.2ms
✓
leaves "Done." alone on a real success 0.1ms
✓
leaves "Done." alone when only SOME tools errored 0.1ms
✓
is a no-op on empty modelText (resolveSilentTurnText owns that case) 0.1ms
✓
replaces a bare "Done." with an honest no-action message when zero tools ran 0.2ms
getNextStepSuggestions — background-job ACK · 3 tests
✓
never emits an "undefined" chip on the seo_write_content ack 1.7ms
✓
returns generic keep-working chips for every background tool ack 0.6ms
✓
still returns the real chips once the result carries fields 0.3ms
send_emails result formatting · 3 tests
✓
all-success stays terse 0.3ms
✓
failures list per-recipient reasons (live downvote: "Sent 0/3, no reason provided") 0.3ms
✓
skipped-unsafe note still appears alongside failures 0.2ms
deriveSubstantiveAnswerTldr — substantive guarantee · 6 tests
✓
still returns null for a short answer on a NON-substantive turn (unchanged) 0.1ms
✓
returns a lead for that same answer when the turn IS substantive 0.3ms
✓
never labels a question, even on a substantive turn 0.1ms
✓
never labels an approval/gate reply, even on a substantive turn 0.1ms
✓
never labels an error, even on a substantive turn 0.2ms
✓
still refuses a trivially short reply even when substantive 0.1ms
deriveReportTldr — seo_google_merge answers the question asked · 4 tests
✓
leads with direction and magnitude when a comparison window exists 0.3ms
✓
says "up" when the period improved — direction is read from the data, not assumed 0.1ms
✓
admits it is a snapshot when no comparison was run, rather than implying a trend 0.2ms
✓
never fabricates a drag page when the insight rows are empty 0.2ms
isSubstantiveSynthesis — answer vs handoff · 6 tests
✓
keeps a real explanation 0.5ms
✓
does NOT keep a bare handoff — the artifact path must be untouched 0.2ms
✓
does not keep a bare acknowledgment 0.2ms
✓
is conservative — a short reply falls back to today behaviour 0.1ms
✓
requires more than one sentence — a single long line is not an explanation 0.3ms
✓
keeps a long answer that merely OPENS with a handoff-ish phrase 0.3ms
search_leads next steps put verification before drafting · 3 tests
✓
offers verification first when the results landed in a named list 0.4ms
✓
offers verification first when there is no list 0.2ms
✓
does not push verification on a failed or empty search 0.2ms
formatToolResult seo_google_merge — tables, not bullets, and cost is never silent · 3 tests
✓
renders the share-of-voice breakdown as a markdown pipe table 0.5ms
✓
states cost explicitly — never silent about a free tool (CLAUDE.md §4) 0.2ms
✓
by-channel and top-sources sections are tables too, once ecommerce is tracked 0.4ms
formatToolResult — remaining row-shaped sites converted to tables · 10 tests
✓
seo_competitor_gap top_pages renders as a Page/URL table 1.1ms
✓
seo_content_quality categories and top fixes render as tables 0.5ms
✓
google_god_mode_report PSI runs render as a Strategy/Performance/LCP/INP table 0.6ms
✓
safe_browsing_check_v2 rows render as a URL/Status/Threats table 0.7ms
✓
gtm_audit_v2 environments render as an Environment/Type/Debug table 0.6ms
✓
sov_trend current standings render as a Brand/Share table 4.7ms
✓
seo_geo_research cited competitors render as a Lee-signals table 1.9ms
✓
ga_traffic sources view renders as a Source / medium table 0.5ms
✓
ga_traffic default view renders as a Channel table 0.3ms
✓
ga4_report_v2 rows render as a dimension/metric table 0.5ms
formatToolResult — re-audit sweep: mis-judged bullet sites converted to tables · 9 tests
✓
ga4_metadata dimensions/metrics render as Name/Type tables (custom flag is a real column) 0.8ms
✓
share_of_model top_entity_language renders as a Query/Mentions table (count was previously dropped) 0.5ms
✓
share_of_model and ai_overview_visibility leaderboards render as Domain/Citations tables (count+domain, not caught by the " • " grep) 0.6ms
✓
entity_audit entities and competitor comparison render as tables (multiple real fields were flattened into one bullet) 0.4ms
✓
the backlink report renders referring domains as a DR/Links/Value table 0.5ms
✓
seo_list_keywords renders tracked keywords as a Keyword/Volume/CPC/Rank table 0.5ms
✓
gsc_performance and gsc_performance_v2 rows render as tables 0.6ms
✓
psi_audit_v2 and crux_history_v2 render as tables 0.7ms
✓
find_competitors renders as a Domain/Title table 0.3ms
connector-degraded chips · 4 tests
✓
appends the connect chip without dropping the tool's own next steps 0.3ms
✓
never duplicates the chip when the tool already offered it 0.2ms
✓
leaves an ordinary result untouched 0.2ms
✓
renders the note itself — it is a *_note key, so the generic appender carries it 0.2ms
search reasoning: rationale OR concern, never both · 4 tests
✓
renders the rationale when the segment fits 0.3ms
✓
renders the concern INSTEAD, never under the rationale heading 0.2ms
✓
still shows the leads — the caution never deletes work the user paid for 0.3ms
✓
says nothing when the model returned neither 0.2ms
gated tools render the gate, not the success case · 5 tests
✓
does not claim a campaign resumed when it is only asking to confirm 0.2ms
✓
does not claim DNS records were applied when it is only asking to confirm 0.2ms
✓
still reports a real resume as done 0.1ms
✓
leaves send_emails to render its own gate, table and all 0.2ms
✓
falls back to asking for confirmation, never to the success branch 0.2ms
confirm chips are matched by their intent rules · 10 tests
✓
resume_campaign offers a confirm chip the router recognises 40.2ms
✓
resume_campaign offers a cancel chip the router recognises 4.5ms
✓
cloudflare_fix_email_dns offers a confirm chip the router recognises 0.8ms
✓
cloudflare_fix_email_dns offers a cancel chip the router recognises 0.9ms
✓
send_emails offers a confirm chip the router recognises 0.7ms
✓
set_standing_instruction offers a confirm chip the router recognises 0.5ms
✓
set_standing_instruction offers a cancel chip the router recognises 1.3ms
✓
resume_scheduled_scan offers a confirm chip the router recognises 0.2ms
✓
resume_scheduled_scan offers a cancel chip the router recognises 0.2ms
✓
does not treat a bare affirmative as a confirmation for either gate 2.4ms
confirm phrases survive ordinary typing · 9 tests
✓
"yes, resume it" routes to resume_confirm 0.3ms
✓
"Yes, resume it." routes to resume_confirm 0.3ms
✓
"YES, RESUME IT" routes to resume_confirm 0.3ms
✓
"yes resume it" routes to resume_confirm 0.3ms
✓
"no, leave it paused" routes to resume_cancel 0.3ms
✓
"yes, apply the dns fixes" routes to dns_confirm 0.3ms
✓
"yes, send them" routes to send_confirm 0.3ms
✓
"yes, save it" routes to standing_confirm 0.3ms
✓
still refuses a bare affirmative 1.5ms
pause/resume reach their tool without asking the model nicely · 11 tests
✓
"Resume the campaign called "Eval Pause Fixture"." → resume_start 0.4ms
✓
"resume my campaign" → resume_start 0.3ms
✓
"Restart the campaign" → resume_start 0.3ms
✓
"unpause our campaign now" → resume_start 0.3ms
✓
"Please resume the campaign Q3 founders" → resume_start 0.4ms
✓
"Stop the campaign called "Q3 founders" right now." → pause_start 0.3ms
✓
"pause my campaign" → pause_start 0.3ms
✓
"Halt the campaign" → pause_start 0.3ms
✓
"Please pause our campaign" → pause_start 0.3ms
✓
keeps the confirm phrases as confirmations, not as fresh requests 0.7ms
✓
does not claim bare resume/stop phrasings that are not about a campaign 1.6ms
campaignNameFromCommand · 2 tests
✓
reads a delimited name, straight or curly quoted 0.4ms
✓
returns null rather than guessing when no name is delimited 0.2ms
scheduled scans — text and chips · 4 tests
✓
the list reads every job with its status in words, and no currency 0.5ms
✓
every chip the three tools offer is a scan command the router sends to the scan rules 1.4ms
✓
an idle job offers no stop chip — there is nothing running to stop 0.2ms
✓
a stop confirms itself; a resume gate prints its quote, never a success 0.3ms
src/chat/presenter-producer-contract.vitest.ts
seo_offpage_audit: the presenter reads the result the real dispatch returns · 4 tests
✓
premise: the dispatch returned an audit with link health and hosting INSIDE backlink_profile, and nothing of either at the top level 2.2ms
✓
the dead pages the links land on render, worst first, with their status and how many links each wastes 1.4ms
✓
where the linking sites are hosted renders, the shared server first 0.6ms
✓
a sample too small to judge renders no hosting table, as the formatter does: the verdict says the numbers mean nothing yet 0.4ms
seo_enrich_keywords: the presenter reads the result the real dispatch returns · 1 test
✓
the domains-to-rank column carries the referring domains the provider measured 0.6ms
every presenter reads only keys its producer writes · 70 tests
✓
every presented tool has a producer sample, and every sample belongs to a presented tool 0.4ms
✓
every sample cites a real file, and a dispatch case or function that is in it 85.2ms
✓
add_contacts: nothing it reads is missing from what the producer writes 1.2ms
✓
aeo_page_check: nothing it reads is missing from what the producer writes 0.9ms
✓
ai_overview_visibility: nothing it reads is missing from what the producer writes 0.3ms
✓
backlink_outreach_search: nothing it reads is missing from what the producer writes 0.3ms
✓
campaign_stats: nothing it reads is missing from what the producer writes 0.3ms
✓
cloudflare_fix_email_dns: nothing it reads is missing from what the producer writes 0.2ms
✓
cloudflare_publish_dns_aid: nothing it reads is missing from what the producer writes 0.3ms
✓
create_campaign: nothing it reads is missing from what the producer writes 0.2ms
✓
create_marketing_plan: nothing it reads is missing from what the producer writes 0.3ms
✓
crux_history_v2: nothing it reads is missing from what the producer writes 0.4ms
✓
diagnose: nothing it reads is missing from what the producer writes 0.3ms
✓
domain_email_readiness_audit: nothing it reads is missing from what the producer writes 0.3ms
✓
enrich_contacts: nothing it reads is missing from what the producer writes 0.3ms
✓
entity_audit: nothing it reads is missing from what the producer writes 0.4ms
✓
find_competitors: nothing it reads is missing from what the producer writes 0.2ms
✓
full_seo_audit: nothing it reads is missing from what the producer writes 0.3ms
✓
ga4_metadata: nothing it reads is missing from what the producer writes 0.2ms
✓
ga4_report_v2: nothing it reads is missing from what the producer writes 0.3ms
✓
ga_traffic: nothing it reads is missing from what the producer writes 0.2ms
✓
generate_dns_fix_prompt: nothing it reads is missing from what the producer writes 0.2ms
✓
generate_emails: nothing it reads is missing from what the producer writes 0.2ms
✓
get_usage_breakdown: nothing it reads is missing from what the producer writes 0.2ms
✓
google_god_mode_report: nothing it reads is missing from what the producer writes 0.3ms
✓
gsc_performance: nothing it reads is missing from what the producer writes 0.4ms
✓
gsc_performance_v2: nothing it reads is missing from what the producer writes 0.4ms
✓
gtm_audit_v2: nothing it reads is missing from what the producer writes 0.3ms
✓
list_campaigns: nothing it reads is missing from what the producer writes 0.3ms
✓
list_connectors: nothing it reads is missing from what the producer writes 0.3ms
✓
list_contacts: nothing it reads is missing from what the producer writes 0.4ms
✓
list_scheduled_scans: nothing it reads is missing from what the producer writes 0.4ms
✓
list_sent_emails: nothing it reads is missing from what the producer writes 0.4ms
✓
list_sequences: nothing it reads is missing from what the producer writes 0.3ms
✓
list_skills: nothing it reads is missing from what the producer writes 0.2ms
✓
panel_segments: nothing it reads is missing from what the producer writes 0.2ms
✓
psi_audit_v2: nothing it reads is missing from what the producer writes 0.3ms
✓
read_url: nothing it reads is missing from what the producer writes 0.3ms
✓
safe_browsing_check_v2: nothing it reads is missing from what the producer writes 0.2ms
✓
search_leads: nothing it reads is missing from what the producer writes 0.3ms
✓
send_emails: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_aeo_check: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_backlink_gap: nothing it reads is missing from what the producer writes 0.2ms
✓
seo_backlink_value: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_backlink_verify: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_backlinks: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_competitor_gap: nothing it reads is missing from what the producer writes 13.2ms
✓
seo_content_brief_batch: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_content_ideas: nothing it reads is missing from what the producer writes 0.2ms
✓
seo_content_quality: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_enrich_keywords: nothing it reads is missing from what the producer writes 0.2ms
✓
seo_geo_research: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_geo_visibility: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_google_merge: nothing it reads is missing from what the producer writes 0.5ms
✓
seo_keyword_metrics: nothing it reads is missing from what the producer writes 0.2ms
✓
seo_keywords: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_list_keywords: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_monitor: nothing it reads is missing from what the producer writes 0.5ms
✓
seo_offpage_audit: nothing it reads is missing from what the producer writes 0.2ms
✓
seo_onpage_audit: nothing it reads is missing from what the producer writes 0.5ms
✓
seo_serp_spider: nothing it reads is missing from what the producer writes 0.3ms
✓
seo_write_content_batch: nothing it reads is missing from what the producer writes 0.2ms
✓
set_campaign_sequence: nothing it reads is missing from what the producer writes 0.2ms
✓
share_of_model: nothing it reads is missing from what the producer writes 0.3ms
✓
show_marketing_plan: nothing it reads is missing from what the producer writes 0.2ms
✓
sov_trend: nothing it reads is missing from what the producer writes 0.4ms
✓
tap_volume: nothing it reads is missing from what the producer writes 0.3ms
✓
web_search: nothing it reads is missing from what the producer writes 0.2ms
✓
every tool's samples render a table, and no cell is an object drawn as text 21.0ms
✓
a known dead read is still dead: an exemption whose key a sample now carries is stale 0.4ms
every declared tenant path is a key the producer writes · 50 tests
✓
add_contacts: every path REPLY_PART_OWNER declares is in a producer sample 0.3ms
✓
aeo_page_check: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
ai_overview_visibility: every path REPLY_PART_OWNER declares is in a producer sample 0.2ms
✓
backlink_outreach_search: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
campaign_stats: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
cloudflare_fix_email_dns: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
cloudflare_publish_dns_aid: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
create_campaign: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
crux_history_v2: every path REPLY_PART_OWNER declares is in a producer sample 0.2ms
✓
diagnose: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
domain_email_readiness_audit: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
enrich_contacts: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
entity_audit: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
find_competitors: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
full_seo_audit: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
ga4_report_v2: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
ga_traffic: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
generate_dns_fix_prompt: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
generate_emails: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
google_god_mode_report: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
gsc_performance: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
gsc_performance_v2: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
gtm_audit_v2: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
list_campaigns: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
list_contacts: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
list_sent_emails: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
list_sequences: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
psi_audit_v2: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
search_leads: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
send_emails: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_aeo_check: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_backlink_value: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_backlink_verify: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_backlinks: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_content_ideas: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_content_quality: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_geo_research: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_geo_visibility: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_google_merge: every path REPLY_PART_OWNER declares is in a producer sample 0.2ms
✓
seo_monitor: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_offpage_audit: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_onpage_audit: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
seo_serp_spider: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
set_campaign_sequence: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
share_of_model: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
sov_trend: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
tap_volume: every path REPLY_PART_OWNER declares is in a producer sample 0.1ms
✓
aeo_visibility: every path REPLY_PART_OWNER declares is in a producer sample (no presenter) 0.3ms
✓
seo_rank_track: every path REPLY_PART_OWNER declares is in a producer sample (no presenter) 0.2ms
✓
a known unwritten declaration is still unwritten 0.2ms
the on-page audit's not-indexed pages: both authors read the coverage check's own grouping · 3 tests
✓
the presenter draws one row per page, with its reason 0.2ms
✓
the formatter (the shortcut path's author) draws the same rows 6.1ms
✓
those pages are the tenant's own when the site is theirs: the declared path pins them in the formatter's text 3.4ms
a finding's directive reads as the directive vocabulary names it · 1 test
✓
every directive full_seo_audit can write has its label in the Do column, the prediction included 0.3ms
a saved contact from the owned tier says who checked its address · 1 test
✓
the search table's Email source reads the verdict our verifier stored, not "not checked" 0.6ms
a CrUX period reaches every reader as a date · 1 test
✓
fetchCruxHistory writes the API's { year, month, day } as YYYY-MM-DD, and the Period column shows it 1.6ms
src/admin/admin-worker-proxy.vitest.ts
every ADMIN_API path is proxied, no-store, secret forwarded · 97 tests
✓
GET verify (/api/admin/verify) → MAIN_APP, 200 passes through 28.5ms
✓
POST verify (/api/admin/verify) → MAIN_APP, a 403 stays a 403 1.3ms
✓
GET telemetry (/api/admin/telemetry) → MAIN_APP, 200 passes through 0.9ms
✓
POST telemetry (/api/admin/telemetry) → MAIN_APP, a 403 stays a 403 1.0ms
✓
GET users (/api/admin/users) → MAIN_APP, 200 passes through 1.1ms
✓
POST users (/api/admin/users) → MAIN_APP, a 403 stays a 403 0.9ms
✓
GET grantTokens (/api/admin/grant-tokens) → MAIN_APP, 200 passes through 0.8ms
✓
POST grantTokens (/api/admin/grant-tokens) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET broadcastCampaigns (/api/admin/broadcast/campaigns) → MAIN_APP, 200 passes through 4.1ms
✓
POST broadcastCampaigns (/api/admin/broadcast/campaigns) → MAIN_APP, a 403 stays a 403 0.9ms
✓
GET analytics (/api/admin/analytics) → MAIN_APP, 200 passes through 0.6ms
✓
POST analytics (/api/admin/analytics) → MAIN_APP, a 403 stays a 403 0.5ms
✓
GET mixpanelAdoption (/api/admin/mixpanel-adoption) → MAIN_APP, 200 passes through 0.4ms
✓
POST mixpanelAdoption (/api/admin/mixpanel-adoption) → MAIN_APP, a 403 stays a 403 0.5ms
✓
GET infra (/api/admin/infra) → MAIN_APP, 200 passes through 0.5ms
✓
POST infra (/api/admin/infra) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET nhost (/api/admin/nhost) → MAIN_APP, 200 passes through 0.7ms
✓
POST nhost (/api/admin/nhost) → MAIN_APP, a 403 stays a 403 0.8ms
✓
GET r2 (/api/admin/r2) → MAIN_APP, 200 passes through 0.7ms
✓
POST r2 (/api/admin/r2) → MAIN_APP, a 403 stays a 403 0.5ms
✓
GET neon (/api/admin/neon) → MAIN_APP, 200 passes through 0.7ms
✓
POST neon (/api/admin/neon) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET cicd (/api/admin/cicd) → MAIN_APP, 200 passes through 0.5ms
✓
POST cicd (/api/admin/cicd) → MAIN_APP, a 403 stays a 403 0.6ms
✓
GET egress (/api/admin/egress) → MAIN_APP, 200 passes through 0.6ms
✓
POST egress (/api/admin/egress) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET observations (/api/admin/observations) → MAIN_APP, 200 passes through 0.4ms
✓
POST observations (/api/admin/observations) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET tenantEconomics (/api/admin/tenant-economics) → MAIN_APP, 200 passes through 0.4ms
✓
POST tenantEconomics (/api/admin/tenant-economics) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET clientError (/api/admin/client-error) → MAIN_APP, 200 passes through 0.6ms
✓
POST clientError (/api/admin/client-error) → MAIN_APP, a 403 stays a 403 0.6ms
✓
GET gsc (/api/admin/gsc) → MAIN_APP, 200 passes through 0.6ms
✓
POST gsc (/api/admin/gsc) → MAIN_APP, a 403 stays a 403 0.6ms
✓
GET gscScan (/api/admin/gsc/scan) → MAIN_APP, 200 passes through 0.4ms
✓
POST gscScan (/api/admin/gsc/scan) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET gscIndexSubmit (/api/admin/gsc/index-submit) → MAIN_APP, 200 passes through 0.4ms
✓
POST gscIndexSubmit (/api/admin/gsc/index-submit) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET gscDisconnect (/api/admin/gsc/disconnect) → MAIN_APP, 200 passes through 0.4ms
✓
POST gscDisconnect (/api/admin/gsc/disconnect) → MAIN_APP, a 403 stays a 403 0.5ms
✓
GET ga4 (/api/admin/ga4) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4 (/api/admin/ga4) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4Properties (/api/admin/ga4/properties) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4Properties (/api/admin/ga4/properties) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4Property (/api/admin/ga4/property) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4Property (/api/admin/ga4/property) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4Landing (/api/admin/ga4/landing) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4Landing (/api/admin/ga4/landing) → MAIN_APP, a 403 stays a 403 0.5ms
✓
GET ga4Attribution (/api/admin/ga4/attribution) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4Attribution (/api/admin/ga4/attribution) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4TrackingHealth (/api/admin/ga4/tracking-health) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4TrackingHealth (/api/admin/ga4/tracking-health) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4KeyEvents (/api/admin/ga4/key-events) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4KeyEvents (/api/admin/ga4/key-events) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4AdsLink (/api/admin/ga4/ads-link) → MAIN_APP, 200 passes through 0.4ms
✓
POST ga4AdsLink (/api/admin/ga4/ads-link) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET ga4Disconnect (/api/admin/ga4/disconnect) → MAIN_APP, 200 passes through 0.3ms
✓
POST ga4Disconnect (/api/admin/ga4/disconnect) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET adoptionState (/api/admin/adoption/state) → MAIN_APP, 200 passes through 0.3ms
✓
POST adoptionState (/api/admin/adoption/state) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET adoptionCampaign (/api/admin/adoption/campaign) → MAIN_APP, 200 passes through 0.4ms
✓
POST adoptionCampaign (/api/admin/adoption/campaign) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET adoptionBackfill (/api/admin/adoption/backfill) → MAIN_APP, 200 passes through 0.4ms
✓
POST adoptionBackfill (/api/admin/adoption/backfill) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET adoptionPending (/api/admin/adoption/pending) → MAIN_APP, 200 passes through 0.4ms
✓
POST adoptionPending (/api/admin/adoption/pending) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET adoptionApprove (/api/admin/adoption/approve) → MAIN_APP, 200 passes through 0.3ms
✓
POST adoptionApprove (/api/admin/adoption/approve) → MAIN_APP, a 403 stays a 403 0.3ms
✓
GET adoptionReject (/api/admin/adoption/reject) → MAIN_APP, 200 passes through 0.4ms
✓
POST adoptionReject (/api/admin/adoption/reject) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET evalRuns (/api/admin/eval-runs) → MAIN_APP, 200 passes through 0.3ms
✓
POST evalRuns (/api/admin/eval-runs) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET releaseHealth (/api/admin/release-health) → MAIN_APP, 200 passes through 0.3ms
✓
POST releaseHealth (/api/admin/release-health) → MAIN_APP, a 403 stays a 403 0.4ms
✓
GET readiness (/api/admin/readiness) → MAIN_APP, 200 passes through 0.3ms
✓
POST readiness (/api/admin/readiness) → MAIN_APP, a 403 stays a 403 0.3ms
✓
GET readinessLabels (/api/admin/readiness/labels) → MAIN_APP, 200 passes through 0.4ms
✓
POST readinessLabels (/api/admin/readiness/labels) → MAIN_APP, a 403 stays a 403 0.9ms
✓
GET readinessLabelsCsv (/api/admin/readiness/labels.csv) → MAIN_APP, 200 passes through 0.7ms
✓
POST readinessLabelsCsv (/api/admin/readiness/labels.csv) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET feedbackRca (/api/admin/feedback-rca) → MAIN_APP, 200 passes through 0.7ms
✓
POST feedbackRca (/api/admin/feedback-rca) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET feedbackRcaGithub (/api/admin/feedback-rca/github) → MAIN_APP, 200 passes through 0.7ms
✓
POST feedbackRcaGithub (/api/admin/feedback-rca/github) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET advisory (/api/admin/advisory) → MAIN_APP, 200 passes through 0.7ms
✓
POST advisory (/api/admin/advisory) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET aiDiscovery (/api/admin/ai-discovery) → MAIN_APP, 200 passes through 0.7ms
✓
POST aiDiscovery (/api/admin/ai-discovery) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET visibilityTracker (/api/admin/visibility-tracker) → MAIN_APP, 200 passes through 0.6ms
✓
POST visibilityTracker (/api/admin/visibility-tracker) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET bugReports (/api/admin/bug-reports) → MAIN_APP, 200 passes through 0.7ms
✓
POST bugReports (/api/admin/bug-reports) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET bugReportsUpdate (/api/admin/bug-reports/update) → MAIN_APP, 200 passes through 0.7ms
✓
POST bugReportsUpdate (/api/admin/bug-reports/update) → MAIN_APP, a 403 stays a 403 0.7ms
✓
GET bugReportsScreenshot (/api/admin/bug-reports/screenshot) → MAIN_APP, 200 passes through 0.6ms
✓
POST bugReportsScreenshot (/api/admin/bug-reports/screenshot) → MAIN_APP, a 403 stays a 403 0.7ms
✓
the query string is not part of the match (view=waste reaches the analytics route) 0.6ms
PX1 — the five paths that used to get index.html · 5 tests
✓
GET /api/admin/egress is proxied, not answered by ASSETS 0.8ms
✓
GET /api/admin/observations is proxied, not answered by ASSETS 0.7ms
✓
GET /api/admin/tenant-economics is proxied, not answered by ASSETS 0.7ms
✓
GET /api/admin/cicd is proxied, not answered by ASSETS 0.7ms
✓
POST /api/admin/client-error is proxied, not answered by ASSETS 0.7ms
an unproxied /api path is a JSON 404, never the SPA shell · 10 tests
✓
/api/admin/transactional-emails (dropped by B0) → 404 JSON 2.1ms
✓
/api/admin/broadcast (dropped by B0) → 404 JSON 1.3ms
✓
/api/admin/provider-balances (dropped by B0) → 404 JSON 6.0ms
✓
/api/admin/adoption/recompute (dropped by B0) → 404 JSON 0.8ms
✓
/api/admin/adoption/run-now (dropped by B0) → 404 JSON 0.8ms
✓
/api/admin/nope → 404 JSON, neither binding called 0.4ms
✓
/api/admin/bug-reports/0b6f4c1e-8a2d-4c3b-9e7f-2d1a5b6c7d8e → 404 JSON, neither binding called 0.4ms
✓
/api/admin/egress/ → 404 JSON, neither binding called 0.3ms
✓
/api/other → 404 JSON, neither binding called 0.5ms
✓
/api → 404 JSON, neither binding called 0.4ms
everything else is the SPA · 5 tests
✓
/analytics/abc-123 → ASSETS only 0.3ms
✓
/assets/index-abc.js → ASSETS only 0.2ms
✓
/egress → ASSETS only 0.2ms
✓
/api-docs → ASSETS only 0.2ms
the registry · 3 tests
✓
holds at least the 45 paths B0 shipped, all unique, all exact admin paths 0.9ms
✓
PROXY_PATHS is exactly Object.values(ADMIN_API) — one list, not two 0.3ms
✓
PARITY: the guard's regex parse of admin-paths.ts equals the imported object 0.5ms
every key the SPA references exists and is proxied · 1 test
✓
walks admin-app/src (minus the registry and the worker) for ADMIN_API.<key> 69.9ms
nonJsonAdminResponse — the client-side second layer · 7 tests
✓
HTML with a 200 on an admin path is rejected, with a short reason 0.3ms
✓
JSON with a charset is accepted 0.3ms
✓
a blob of image/jpeg on the screenshot path is accepted (the caller asked for bytes) 0.1ms
✓
an absolute URL is parsed to its path, query ignored 0.1ms
✓
a missing content-type is named as such 0.1ms
✓
a non-admin URL, a 204 and an undefined URL are none of its business 0.1ms
✓
the reason is capped at 120 characters even for a long path 0.1ms
src/tools/lead-corpus.vitest.ts
corpus shape · 2 tests
✓
carries the 24 incident prompts and 20 paraphrases 2.5ms
✓
every entry either has arguments or a named question — no silent gaps 1.5ms
expressibility — every corpus request validates · 55 tests
✓
i01: founders working on fact checking browser extensions 0.9ms
✓
i02: founders working on political bias in search results 0.2ms
✓
i03: founders working on source credibility scoring 0.3ms
✓
i04: founders working on claim verification workflows 0.4ms
✓
i05: founders working on newsroom fact checking tools 0.2ms
✓
i06: founders working on misinformation on social platforms 0.2ms
✓
i07: founders working on automated content moderation 0.5ms
✓
i08: founders working on propaganda detection techniques 0.2ms
✓
i09: founders working on clickbait detection techniques 0.2ms
✓
i10: founders working on satire versus fake news detection 0.2ms
✓
i11: founders working on echo chambers and filter bubbles 0.1ms
✓
i12: founders working on health misinformation tracking 0.1ms
✓
i13: founders working on AI answer engine citations 0.1ms
✓
i14: founders working on brand mentions in AI assistants 0.1ms
✓
i15: founders working on featured snippet optimisation 0.1ms
✓
i16: founders working on zero click search results 0.1ms
✓
i17: founders entity based SEO 0.1ms
✓
i18: founders working on knowledge graph optimisation 0.1ms
✓
i19: founders working on schema markup for publishers 0.1ms
✓
i20: founders building topical authority SEO content strategy 0.1ms
✓
i21: founders working on content decay and content refresh 0.1ms
✓
i22: founders working on programmatic SEO for directories 0.1ms
✓
i23: founders working on misinformation research 0.1ms
✓
i24: founders working on political bias in search results 0.1ms
✓
l01: Founders, CEOs, Marketing Managers and E-commerce Managers at sm 0.3ms
✓
l02: automotive brands specialising in aftermarket accessories for mo 0.7ms
✓
l03: decision makers at plumbing companies in USA 0.1ms
✓
l04: founders of newly funded SaaS startups who need marketing agency 0.1ms
✓
l05: course creators with 500+ students 0.1ms
✓
l06: home appliances distributors in India 0.5ms
✓
l07: sustainability-focused e-commerce brands 0.1ms
✓
l08: catering services 0.1ms
✓
l10: find me leads for underwater basket-weaving 0.2ms
✓
l11: dentists in 10001 0.2ms
✓
l12: coffee shops near Indiranagar 560038 0.2ms
✓
p01: find founders building tools for programmatic SEO on directory s 0.2ms
✓
p02: I need founders whose product does programmatic SEO for director 0.1ms
✓
p03: get me startup founders in the programmatic SEO for directories 0.2ms
✓
p04: who are the founders working on programmatic SEO for directories 0.2ms
✓
p05: founders doing fact checking browser extensions 0.2ms
✓
p06: people who founded companies making browser extensions for fact 0.2ms
✓
p07: founders in the automated content moderation space 0.1ms
✓
p08: startup founders building automated content moderation 0.1ms
✓
p09: founders focused on AI answer engine citations 0.1ms
✓
p10: who is building for AI answer engine citations — get me their fo 0.1ms
✓
p11: founders whose companies handle zero click search results 0.3ms
✓
p12: founders tackling zero click search results 0.2ms
✓
p13: Pakistani e-commerce businesses — get me the founders, CEOs, mar 0.2ms
✓
p14: small and medium e-commerce companies based in Pakistan; I want 0.1ms
✓
p15: motorcycle aftermarket accessories brands in India — founders, C 0.5ms
✓
p16: Indian companies making aftermarket accessories for motorcycles, 0.5ms
✓
p17: seed and Series A SaaS founders who would need a marketing agenc 0.1ms
✓
p18: SaaS companies that just raised seed or Series A in 2026 — found 0.1ms
✓
p19: find dentists in the 10001 zip code 0.1ms
✓
p20: I want a list of dental practices in 10001, New York 0.2ms
the intent survives — it is carried, not discarded · 33 tests
✓
i01 keeps "fact checking browser extensions" 0.2ms
✓
i02 keeps "political bias in search results" 0.1ms
✓
i03 keeps "source credibility scoring" 0.1ms
✓
i04 keeps "claim verification workflows" 0.1ms
✓
i05 keeps "newsroom fact checking tools" 0.1ms
✓
i06 keeps "misinformation on social platforms" 0.1ms
✓
i07 keeps "automated content moderation" 0.1ms
✓
i08 keeps "propaganda detection techniques" 0.1ms
✓
i09 keeps "clickbait detection techniques" 0.1ms
✓
i10 keeps "satire versus fake news detection" 0.1ms
✓
i11 keeps "echo chambers and filter bubbles" 0.1ms
✓
i12 keeps "health misinformation tracking" 0.1ms
✓
i13 keeps "AI answer engine citations" 0.1ms
✓
i14 keeps "brand mentions in AI assistants" 0.1ms
✓
i15 keeps "featured snippet optimisation" 0.1ms
✓
i16 keeps "zero click search results" 0.1ms
✓
i17 keeps "entity based SEO" 0.1ms
✓
i18 keeps "knowledge graph optimisation" 0.1ms
✓
i19 keeps "schema markup for publishers" 0.1ms
✓
i20 keeps "topical authority SEO content strategy" 0.1ms
✓
i21 keeps "content decay and content refresh" 0.1ms
✓
i22 keeps "programmatic SEO for directories" 0.1ms
✓
i23 keeps "misinformation research" 0.1ms
✓
i24 keeps "political bias in search results" 0.1ms
✓
l01 keeps "e-commerce businesses" 0.1ms
✓
l02 keeps "aftermarket accessories for motorcycles" 0.1ms
✓
l03 keeps "plumbing companies" 0.1ms
✓
l04 keeps "SaaS startups that need marketing agency" 0.1ms
✓
l05 keeps "course creators with 500+ students" 0.1ms
✓
l06 keeps "home appliances distribution" 0.1ms
✓
l07 keeps "sustainability-focused e-commerce brands" 0.1ms
✓
l08 keeps "catering services" 0.1ms
✓
l10 keeps "underwater basket-weaving" 0.1ms
phrasing stops mattering — paraphrases canonicalise · 20 tests
field-level phrasing tolerance — resolved, not rejected, not guessed · 4 tests
✓
resolves the spellings a model actually writes 0.8ms
✓
resolves a city to its country instead of 400ing the run 0.3ms
✓
resolves punctuation drift in the industry taxonomy 0.4ms
✓
refuses to guess when nothing resolves, and offers no misleading candidates 2.1ms
serialisation slips are coerced, not punished · 2 tests
✓
accepts a stringified boolean 0.2ms
✓
still rejects a boolean field that carries something else 0.1ms
the incident itself cannot recur through this schema · 3 tests
✓
the exact sentence is rejected from the industry field, with candidates 1.7ms
✓
the same sentence is accepted in topic 0.2ms
✓
a title-cased duplicate of the sentence is rejected too 2.7ms
tier-specific serialisation slips (found on the live path, not by the replay) · 3 tests
✓
accepts a stringified array 0.3ms
✓
still rejects a bare sentence in an array field — coercion is not permission 1.7ms
✓
leaves a non-JSON string alone rather than inventing an array 0.2ms
src/db/user-role-dropped-reads.vitest.ts
the population: every user-role read a migration took away, derived from the files · 4 tests
✓
finds the 43 outright SELECT drops (010 x42, 183 templates) and the 19 revoked columns (010 x4, 183, 194 x14), at least 4.4ms
✓
every outright drop has a re-grant shape: the SELECT the replay held before it 1.1ms
✓
the live census holds every one too: each dropped table is declared admin_only, each revoked column is in column_exclusions 3.1ms
✓
an allowance for a column added after a narrowing names a file that adds it, and cannot cover an excluded column 0.2ms
0. the replay reads a re-grant in every envelope and table form Hasura accepts (V6-tenancy-F02) · 14 tests
✓
precondition: 183 drops templates SELECT outright, and the clean replay ends without it 0.5ms
✓
a later file re-granting it in a top-level bulk (control): the replay ends WITH it, so section 1 would fail 17.3ms
✓
a later file re-granting it in bulk_keep_going: the replay ends WITH it, so section 1 would fail 16.5ms
✓
a later file re-granting it in bulk_atomic: the replay ends WITH it, so section 1 would fail 15.9ms
✓
a later file re-granting it in concurrent_bulk: the replay ends WITH it, so section 1 would fail 15.9ms
✓
a later file re-granting it in a bulk inside a bulk: the replay ends WITH it, so section 1 would fail 16.1ms
✓
a later file re-granting it in a bulk_keep_going inside a bulk: the replay ends WITH it, so section 1 would fail 16.5ms
✓
a later file re-granting it in a top-level array: the replay ends WITH it, so section 1 would fail 16.3ms
✓
a later file re-granting it in a single operation: the replay ends WITH it, so section 1 would fail 16.9ms
✓
a later file re-granting it in a hand-applied wrapper ({ _comment, steps }): the replay ends WITH it, so section 1 would fail 17.8ms
✓
a later file re-granting it in the table as a plain string: the replay ends WITH it, so section 1 would fail 17.4ms
✓
a later file re-granting it in the table as { name } with no schema: the replay ends WITH it, so section 1 would fail 21.3ms
✓
a later file re-granting it in the v1 operation name, without pg_: the replay ends WITH it, so section 1 would fail 18.1ms
✓
every user-role object in every migration file is one the replay reads (none in an unread form) 7.1ms
1. no later migration file, and no declaration, grants one back · 3 tests
✓
the replay ends with none of the outright-dropped SELECTs 1.3ms
✓
the replay ends with none of the revoked columns back in its grant 0.5ms
✓
user_readable declares none of the dropped tables 1.7ms
2. check-graphql-schema fails on a snapshot that can read one again · 76 tests
✓
clean snapshot: passes 831.1ms
✓
adoption_email_suppressions SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 45.2ms
✓
adoption_nudges SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.9ms
✓
aeo_pillar_snapshots SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.0ms
✓
agent_observation SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.3ms
✓
appsumo_codes SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.2ms
✓
async_jobs SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.5ms
✓
backlink_rows SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.3ms
✓
bug_report SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.3ms
✓
commerce_inventory_snapshots SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.1ms
✓
commerce_orders SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.1ms
✓
commerce_refunds SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 45.1ms
✓
commerce_shops SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.4ms
✓
commerce_sync_cursors SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 41.4ms
✓
commerce_webhook_receipts SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.6ms
✓
content_pieces SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.1ms
✓
keyword_performance_history SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.1ms
✓
marketing_initiatives SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.0ms
✓
marketing_plans SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 45.2ms
✓
marketing_strategies SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 46.0ms
✓
outbound_run_approvals SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 48.0ms
✓
outbound_run_cost_ledger SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.5ms
✓
outbound_run_days SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.2ms
✓
outbound_run_drafts SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.7ms
✓
outbound_run_events SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.3ms
✓
outbound_run_leads SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.3ms
✓
outbound_run_send_intents SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 46.7ms
✓
outbound_runs SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.2ms
✓
ph_enrich_tasks SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.5ms
✓
rank_rival_snapshots SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.7ms
✓
rank_snapshots SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.4ms
✓
seo_cache SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 45.8ms
✓
seo_snapshots SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 44.7ms
✓
shared_lead_pattern_reveal SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.8ms
✓
shared_lead_reveal SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.2ms
✓
skill_runs SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 43.0ms
✓
strategic_hypotheses SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.9ms
✓
strategy_decisions SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 47.0ms
✓
strategy_outcomes SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.5ms
✓
transactional_emails SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.0ms
✓
user_adoption_state SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 42.9ms
✓
user_presence SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 41.4ms
✓
user_scores SELECT back as it was before 010 dropped it: exits 1, names the table, its roots and why (migration 010) 41.6ms
✓
templates SELECT back as it was before 183 dropped it: exits 1, names the table, its roots and why (K9) 44.6ms
✓
every dropped table readable through its base root (`<table>`) alone: exits 1 and names each with its reason 46.3ms
✓
every dropped table readable through its `_by_pk` root alone: exits 1 and names each with its reason 44.5ms
✓
every dropped table readable through its `_aggregate` root alone: exits 1 and names each with its reason 44.8ms
✓
every dropped table readable through its columns alone, no root (reached through a relationship): exits 1 and names each with its reason 47.1ms
✓
chat_response_feedback.judge_reasoning_snapshot readable again (revoked by 010): exits 1, names it and why (migration 010) 41.4ms
✓
chat_response_feedback.judge_score_snapshot readable again (revoked by 010): exits 1, names it and why (migration 010) 40.6ms
✓
connections.secret_ciphertext readable again (revoked by 010): exits 1, names it and why (migration 010) 40.0ms
✓
serp_spider_tasks.cost_usd readable again (revoked by 010): exits 1, names it and why (migration 010) 43.1ms
✓
connections.meta readable again (revoked by 183): exits 1, names it and why (K3) 43.2ms
✓
token_usage.cost_source readable again (revoked by 194): exits 1, names it and why (migration 194) 41.7ms
✓
token_usage.cost_usd readable again (revoked by 194): exits 1, names it and why (migration 194) 41.6ms
✓
token_usage.generation_id readable again (revoked by 194): exits 1, names it and why (migration 194) 42.6ms
✓
token_usage.model readable again (revoked by 194): exits 1, names it and why (migration 194) 42.8ms
✓
token_usage.provider readable again (revoked by 194): exits 1, names it and why (migration 194) 43.1ms
✓
api_usage.cost_source readable again (revoked by 194): exits 1, names it and why (migration 194) 43.0ms
✓
api_usage.cost_usd readable again (revoked by 194): exits 1, names it and why (migration 194) 41.1ms
✓
api_usage.meta readable again (revoked by 194): exits 1, names it and why (migration 194) 44.1ms
✓
api_usage.operation readable again (revoked by 194): exits 1, names it and why (migration 194) 44.3ms
✓
api_usage.provider readable again (revoked by 194): exits 1, names it and why (migration 194) 40.5ms
✓
api_usage.units readable again (revoked by 194): exits 1, names it and why (migration 194) 40.8ms
✓
aeo_snapshots.data readable again (revoked by 194): exits 1, names it and why (migration 194) 42.3ms
✓
entity_snapshots.data readable again (revoked by 194): exits 1, names it and why (migration 194) 42.3ms
✓
connections.auth_type readable again (revoked by 194): exits 1, names it and why (migration 194) 42.3ms
✓
chat_response_feedback SELECT restored to its shape before 010 (what its replace removed): exits 1 naming every column it revoked 43.3ms
✓
connections SELECT restored to its shape before 010 (what its replace removed): exits 1 naming every column it revoked 42.7ms
✓
serp_spider_tasks SELECT restored to its shape before 010 (what its replace removed): exits 1 naming every column it revoked 42.3ms
✓
connections SELECT restored to its shape before 183 (what its replace removed): exits 1 naming every column it revoked 42.7ms
✓
token_usage SELECT restored to its shape before 194 (what its replace removed): exits 1 naming every column it revoked 44.0ms
✓
api_usage SELECT restored to its shape before 194 (what its replace removed): exits 1 naming every column it revoked 43.8ms
✓
aeo_snapshots SELECT restored to its shape before 194 (what its replace removed): exits 1 naming every column it revoked 44.0ms
✓
entity_snapshots SELECT restored to its shape before 194 (what its replace removed): exits 1 naming every column it revoked 43.3ms
✓
connections SELECT restored to its shape before 194 (what its replace removed): exits 1 naming every column it revoked 43.0ms
3. a user-role read nobody declared fails, whatever it is called · 23 tests
✓
a SELECT on a table nobody declared (the waitlist, every signup's address): exits 1 as undeclared 43.3ms
✓
a SELECT on an admin-only table no migration ever granted (the suppression ledger): exits 1 as undeclared 42.1ms
✓
a SELECT with no root field on a table nobody declared (reachable only through a relationship): exits 1 43.3ms
✓
a custom root name for a readable table (myConnections): exits 1 and names the root as undeclared 40.8ms
✓
a tracked corpus function exposed on query_root: exits 1 and names the root as undeclared 42.6ms
✓
an action or remote field nobody declared: exits 1 and names the root as undeclared 41.6ms
✓
CONTROL: a new read that IS declared in user_readable passes — the rule is "declared", not "frozen" 833.9ms
✓
a declaration cannot launder a forbidden read: user_readable declaring templates fails, with or without the grant 86.5ms
✓
a declaration the user role no longer holds fails: it would let a re-grant of that read pass 42.4ms
✓
a declaration of a table that does not exist fails rather than being skipped 44.6ms
✓
a table declared both user-readable and admin-only fails, even when the role can read it 41.6ms
✓
column_exclusions and the forbidden columns must agree: a column only the live census excludes fails 41.8ms
✓
...and a forbidden column the live census no longer excludes fails too 43.2ms
✓
CONTROL: a function root declared in USER_ROLE_EXTRA_READ_ROOTS, with its reason, passes 842.3ms
✓
an extra-root allowance whose root is gone fails as stale 41.8ms
✓
an extra-root allowance cannot stand in for a table declaration 41.8ms
✓
an extra-root allowance cannot cover a forbidden table 44.0ms
✓
a snapshot without the select-column capture refuses to run blind (exit 2, run --refresh) 41.6ms
✓
an empty select-column capture is the same blind guard (exit 2) 43.0ms
✓
a declared table read by root with no columns captured is an incomplete capture (exit 2), not a pass 39.1ms
✓
without the user_readable declaration the guard refuses to run blind (exit 2) 43.0ms
✓
a snapshot that lost most of the user role's query roots is a blind guard (exit 2), not a list of stale declarations 40.2ms
✓
a snapshot that lost most of its select-column capture is a blind guard (exit 2) 39.1ms
src/email/render-hostile-corpus.vitest.ts
V12b-edge-F01 — the audit's 26 hostile bodies carry no active content on the wire · 27 tests
✓
the corpus is the audit's 26 2.3ms
✓
handler-on-allowed 1.2ms
✓
unterminated-tail-a 0.7ms
✓
plain-anchor-handler 1.5ms
✓
plain-anchor-quoted-gt 1.0ms
V12b-edge-F01 — vector classes added by this lane · 23 tests
✓
unterminated-tail-style 0.3ms
✓
unterminated-attr-value 0.3ms
✓
upper-case-handler 0.3ms
✓
slash-separated-attr 0.3ms
✓
entity-quote-breakout 0.3ms
✓
cdata-bogus-comment 0.4ms
✓
processing-instruction 0.4ms
✓
table-background-attr 2.9ms
✓
leading-space-js-href 0.6ms
✓
delegated-action-gadget 0.7ms
V12b-edge-F01 — the signature is email HTML too · 52 tests
✓
signature handler-on-allowed 1.0ms
✓
signature img-onerror 1.0ms
✓
signature style-beacon 0.7ms
✓
signature svg-onload 0.8ms
✓
signature meta-refresh 0.7ms
✓
signature entity-js-href 0.7ms
✓
signature tab-js-href 0.7ms
✓
signature data-href 0.7ms
✓
signature noscript-mxss 0.7ms
✓
signature comment-abrupt 0.8ms
✓
signature quoted-gt-dq 0.6ms
✓
signature quoted-gt-sq 0.6ms
✓
signature quoted-gt-js-href 0.6ms
✓
signature quoted-gt-style 0.6ms
✓
signature quoted-gt-img 0.6ms
✓
signature unterminated-tail 0.5ms
✓
signature unterminated-tail-a 0.5ms
✓
signature css-escape-url 0.4ms
✓
signature css-escape-url2 0.3ms
✓
signature plain-anchor-handler 0.6ms
✓
signature plain-anchor-quoted-gt 0.6ms
✓
signature plain-anchor-js 0.5ms
✓
signature css-escape-nonhex 0.5ms
✓
signature css-escape-6hex 0.4ms
✓
signature css-image-set 0.5ms
✓
signature css-entity-paren 0.5ms
✓
signature unterminated-tail-style 0.5ms
✓
signature unterminated-attr-value 0.6ms
✓
signature upper-case-handler 0.5ms
✓
signature slash-separated-attr 0.7ms
✓
signature entity-quote-breakout 0.8ms
✓
signature comment-end-bang 0.5ms
✓
signature cdata-bogus-comment 0.4ms
✓
signature processing-instruction 0.7ms
✓
signature math-mglyph-style 0.8ms
✓
signature svg-foreign-a 0.7ms
✓
signature template-content 0.9ms
✓
signature textarea-rcdata 0.7ms
✓
signature table-background-attr 0.9ms
✓
signature vbscript-href 0.7ms
✓
signature leading-space-js-href 0.7ms
✓
signature newline-in-scheme 0.7ms
✓
signature style-expression 0.7ms
✓
signature style-behavior 0.6ms
✓
signature delegated-action-gadget 0.7ms
✓
an honest signature keeps its logo, link and table layout 1.1ms
✓
a signature keeps its tel: phone link; a javascript: href beside it is still removed 1.2ms
✓
a plain-text signature is unchanged (escaped, newline → <br>) 0.2ms
V12b-edge-F01 — honest bodies are unchanged · 3 tests
✓
honest block HTML is byte-identical 1.1ms
✓
honest plain text renders as before 0.2ms
✓
a CTA button (ctaButtonHtml) in a plain-text body keeps its link and inline style 0.2ms
V12b-edge-F01 — the parse fails closed · 4 tests
✓
an unterminated final tag is dropped, never closed by the markup that follows it 0.2ms
✓
a quoted ">" is attribute text, not the end of the tag 0.2ms
✓
a CSS escape drops the whole style attribute rather than being repaired 0.2ms
✓
only http, https, mailto and tel links survive 0.2ms
V12b-edge-F01 residual — the sanitizer's cost is bounded · 8 tests
✓
the audit's 220 KB nested body finishes in under 100 ms, as escaped plain text 6.2ms
✓
a nested body just UNDER the size cap is stopped at the depth cap during the parse, not after it 6.1ms
✓
the depth cap sits exactly at EMAIL_HTML_MAX_DEPTH: 128 nested elements kept, 129 flattened 1.4ms
✓
the worst body under BOTH caps stays linear (deep to the cap, then siblings to the size cap) 129.0ms
✓
the rebuild itself never emits a tag deeper than the cap, whatever tree it is handed 1.5ms
✓
no honest body and no platform template comes near a cap (nothing is flattened) 26.2ms
✓
a flattened body is reported by composeEmail and becomes one Sentry warning without the content 30.3ms
✓
every send path that composes logs what the composer reports (campaign, transactional, resend) 2.0ms
client/draft-html.vitest.ts
V12b-edge-F02 — a stored draft body never reaches the app document as live markup · 6 tests
✓
known positive: the pre-fix preview (detached <div> innerHTML) arms an allow-listed handler text 38.4ms
✓
the editor HTML (what Quill pastes into an ATTACHED container) carries no handler and none runs 22.5ms
✓
the preview line is text from an inert parse: no element of the app document is ever given the body 11.0ms
✓
the parse it relies on is inert: a DOMParser document does not run a handler even with scripts on 10.8ms
✓
a plain-text draft is paragraph-ized as before 9.5ms
✓
an honest HTML draft (autoLinkBrand link, CTA button, Quill edit) is kept 23.8ms
V12b-edge-F02 — the dashboard and the wire apply ONE allow-list · 102 tests
✓
script: the browser-side rebuild is clean and identical to the Worker's 10.0ms
✓
handler-on-allowed: the browser-side rebuild is clean and identical to the Worker's 18.8ms
✓
img-onerror: the browser-side rebuild is clean and identical to the Worker's 10.6ms
✓
js-href: the browser-side rebuild is clean and identical to the Worker's 8.1ms
✓
iframe: the browser-side rebuild is clean and identical to the Worker's 8.9ms
✓
style-beacon: the browser-side rebuild is clean and identical to the Worker's 33.0ms
✓
svg-onload: the browser-side rebuild is clean and identical to the Worker's 8.6ms
✓
form: the browser-side rebuild is clean and identical to the Worker's 8.7ms
✓
meta-refresh: the browser-side rebuild is clean and identical to the Worker's 8.2ms
✓
entity-js-href: the browser-side rebuild is clean and identical to the Worker's 6.7ms
✓
tab-js-href: the browser-side rebuild is clean and identical to the Worker's 7.0ms
✓
data-href: the browser-side rebuild is clean and identical to the Worker's 6.7ms
✓
noscript-mxss: the browser-side rebuild is clean and identical to the Worker's 7.5ms
✓
comment-abrupt: the browser-side rebuild is clean and identical to the Worker's 18.7ms
✓
quoted-gt-dq: the browser-side rebuild is clean and identical to the Worker's 6.8ms
✓
quoted-gt-sq: the browser-side rebuild is clean and identical to the Worker's 7.2ms
✓
quoted-gt-js-href: the browser-side rebuild is clean and identical to the Worker's 8.4ms
✓
quoted-gt-style: the browser-side rebuild is clean and identical to the Worker's 7.8ms
✓
quoted-gt-img: the browser-side rebuild is clean and identical to the Worker's 7.3ms
✓
unterminated-tail: the browser-side rebuild is clean and identical to the Worker's 19.1ms
✓
unterminated-tail-a: the browser-side rebuild is clean and identical to the Worker's 7.9ms
✓
css-escape-url: the browser-side rebuild is clean and identical to the Worker's 8.4ms
✓
css-escape-url2: the browser-side rebuild is clean and identical to the Worker's 7.4ms
✓
plain-anchor-handler: the browser-side rebuild is clean and identical to the Worker's 6.8ms
✓
plain-anchor-quoted-gt: the browser-side rebuild is clean and identical to the Worker's 9.5ms
✓
plain-anchor-js: the browser-side rebuild is clean and identical to the Worker's 6.8ms
✓
css-escape-nonhex: the browser-side rebuild is clean and identical to the Worker's 18.1ms
✓
css-escape-6hex: the browser-side rebuild is clean and identical to the Worker's 7.6ms
✓
css-image-set: the browser-side rebuild is clean and identical to the Worker's 13.9ms
✓
css-entity-paren: the browser-side rebuild is clean and identical to the Worker's 6.8ms
✓
unterminated-tail-style: the browser-side rebuild is clean and identical to the Worker's 6.5ms
✓
unterminated-attr-value: the browser-side rebuild is clean and identical to the Worker's 6.4ms
✓
upper-case-handler: the browser-side rebuild is clean and identical to the Worker's 17.0ms
✓
slash-separated-attr: the browser-side rebuild is clean and identical to the Worker's 6.6ms
✓
entity-quote-breakout: the browser-side rebuild is clean and identical to the Worker's 6.9ms
✓
comment-end-bang: the browser-side rebuild is clean and identical to the Worker's 6.6ms
✓
cdata-bogus-comment: the browser-side rebuild is clean and identical to the Worker's 6.7ms
✓
processing-instruction: the browser-side rebuild is clean and identical to the Worker's 6.1ms
✓
math-mglyph-style: the browser-side rebuild is clean and identical to the Worker's 8.7ms
✓
svg-foreign-a: the browser-side rebuild is clean and identical to the Worker's 19.3ms
✓
template-content: the browser-side rebuild is clean and identical to the Worker's 12.0ms
✓
textarea-rcdata: the browser-side rebuild is clean and identical to the Worker's 9.3ms
✓
table-background-attr: the browser-side rebuild is clean and identical to the Worker's 9.5ms
✓
vbscript-href: the browser-side rebuild is clean and identical to the Worker's 6.2ms
✓
leading-space-js-href: the browser-side rebuild is clean and identical to the Worker's 6.2ms
✓
newline-in-scheme: the browser-side rebuild is clean and identical to the Worker's 6.1ms
✓
style-expression: the browser-side rebuild is clean and identical to the Worker's 17.4ms
✓
style-behavior: the browser-side rebuild is clean and identical to the Worker's 6.2ms
✓
delegated-action-gadget: the browser-side rebuild is clean and identical to the Worker's 7.8ms
✓
honest-1: the browser-side rebuild is clean and identical to the Worker's 13.8ms
✓
honest-plain: the browser-side rebuild is clean and identical to the Worker's 6.5ms
✓
script as a signature: the preview is the wire 7.1ms
✓
handler-on-allowed as a signature: the preview is the wire 16.7ms
✓
img-onerror as a signature: the preview is the wire 6.6ms
✓
js-href as a signature: the preview is the wire 7.5ms
✓
iframe as a signature: the preview is the wire 6.7ms
✓
style-beacon as a signature: the preview is the wire 7.3ms
✓
svg-onload as a signature: the preview is the wire 6.4ms
✓
form as a signature: the preview is the wire 6.7ms
✓
meta-refresh as a signature: the preview is the wire 17.2ms
✓
entity-js-href as a signature: the preview is the wire 7.0ms
✓
tab-js-href as a signature: the preview is the wire 7.7ms
✓
data-href as a signature: the preview is the wire 7.1ms
✓
noscript-mxss as a signature: the preview is the wire 6.5ms
✓
comment-abrupt as a signature: the preview is the wire 7.3ms
✓
quoted-gt-dq as a signature: the preview is the wire 6.0ms
✓
quoted-gt-sq as a signature: the preview is the wire 16.2ms
✓
quoted-gt-js-href as a signature: the preview is the wire 6.6ms
✓
quoted-gt-style as a signature: the preview is the wire 8.0ms
✓
quoted-gt-img as a signature: the preview is the wire 6.8ms
✓
unterminated-tail as a signature: the preview is the wire 6.5ms
✓
unterminated-tail-a as a signature: the preview is the wire 6.2ms
✓
css-escape-url as a signature: the preview is the wire 17.5ms
✓
css-escape-url2 as a signature: the preview is the wire 7.0ms
✓
plain-anchor-handler as a signature: the preview is the wire 6.9ms
✓
plain-anchor-quoted-gt as a signature: the preview is the wire 6.8ms
✓
plain-anchor-js as a signature: the preview is the wire 7.6ms
✓
css-escape-nonhex as a signature: the preview is the wire 7.8ms
✓
css-escape-6hex as a signature: the preview is the wire 6.4ms
✓
css-image-set as a signature: the preview is the wire 17.0ms
✓
css-entity-paren as a signature: the preview is the wire 7.1ms
✓
unterminated-tail-style as a signature: the preview is the wire 6.3ms
✓
unterminated-attr-value as a signature: the preview is the wire 7.3ms
✓
upper-case-handler as a signature: the preview is the wire 8.2ms
✓
slash-separated-attr as a signature: the preview is the wire 6.2ms
✓
entity-quote-breakout as a signature: the preview is the wire 21.2ms
✓
comment-end-bang as a signature: the preview is the wire 6.8ms
✓
cdata-bogus-comment as a signature: the preview is the wire 6.3ms
✓
processing-instruction as a signature: the preview is the wire 6.4ms
✓
math-mglyph-style as a signature: the preview is the wire 7.5ms
✓
svg-foreign-a as a signature: the preview is the wire 6.5ms
✓
template-content as a signature: the preview is the wire 6.5ms
✓
textarea-rcdata as a signature: the preview is the wire 18.3ms
✓
table-background-attr as a signature: the preview is the wire 7.5ms
✓
vbscript-href as a signature: the preview is the wire 6.9ms
✓
leading-space-js-href as a signature: the preview is the wire 6.6ms
✓
newline-in-scheme as a signature: the preview is the wire 6.3ms
✓
style-expression as a signature: the preview is the wire 6.3ms
✓
style-behavior as a signature: the preview is the wire 6.2ms
✓
delegated-action-gadget as a signature: the preview is the wire 17.6ms
✓
honest-1 as a signature: the preview is the wire 8.9ms
✓
honest-plain as a signature: the preview is the wire 7.6ms
V12b-edge-F01 residual — the dashboard applies the same cost caps, so the preview stays the wire · 3 tests
✓
220 KB nested (size cap) 10.4ms
✓
129 nested (depth cap) 29.7ms
✓
128 nested (kept) 18.5ms
never silent — a body the send will flatten says so in the Drafts panel (CLAUDE.md §3a) · 3 tests
✓
a flattened body produces the plain-words notice, exactly when the Worker flattens it 50.4ms
✓
the signature has its own notice, matching the send 23.5ms
✓
the notice node carries the words as text, never markup 14.3ms
scripts/lib/deploy-verify.vitest.mjs
touchesWorker / expectedWorkers — the dashboard watch paths · 5 tests
✓
a src/ change builds outbound only 3.1ms
✓
an admin-app/ change builds admin; outbound too only if something outside the excludes moved 0.5ms
✓
a blog-only change builds only the blog 0.3ms
✓
matches by directory prefix, not substring 0.5ms
✓
an EMPTY commit builds only the include-everything Worker (1da1e10b deployed outbound) 0.3ms
check-run reading · 4 tests
✓
pulls the build UUID out of details_url 0.6ms
✓
picks the NEWEST run of that exact name — a rerun posts a second run on the same sha 0.4ms
✓
the Actions deploy job being `skipped` is never read as a deploy verdict 0.3ms
✓
every completed non-success conclusion is a failure 0.9ms
buildFromCloudflare — tolerant, and never optimistic · 2 tests
✓
reads the documented terminal spellings 0.5ms
✓
anything it does not recognise stays PENDING, never success 0.4ms
servedRelation · 3 tests
✓
exact, contains, behind, diverged, unknown 0.4ms
✓
a SEMVER build_id is the hand-deploy alarm, never a match 0.2ms
✓
an unreachable endpoint is its own state 0.1ms
evaluate — the order of the rules IS the policy · 11 tests
✓
LIVE when /api/version serves the exact sha 0.3ms
✓
LIVE on the build-id alone, before the check run lands 0.1ms
✓
FAILED the moment the build reports failure while production is behind — 9996fc55 0.3ms
✓
two merges in quick succession: own build failed, but a LATER build containing it is live → LIVE, with the warning 0.2ms
✓
success reported but production still behind → PENDING, not live 0.1ms
✓
a production build that does not contain the sha is never live, whatever the check says 0.4ms
✓
admin has no build-id endpoint — its check run decides alone 0.2ms
✓
an admin failure fails the verification even while outbound is still pending 0.3ms
✓
admin success does not stand in for outbound 0.2ms
✓
TIMEOUT only past the deadline, and only when nothing failed 0.3ms
✓
deadlineFor: a late success buys the propagation grace 0.3ms
verifyDeploy — the loop · 11 tests
✓
9996fc55 replayed: pending, then the FAILURE check run → exit 3 at the tick it appears 1.9ms
✓
the happy path: build success, then /api/version flips → exit 0 with elapsed 0.5ms
✓
quick succession: own build fails AFTER a later build already carried it → exit 0 0.5ms
✓
no check run and no flip for the whole window → exit 4 with the builds page 0.8ms
✓
a success seen at the deadline is given the propagation grace, not an instant timeout 0.5ms
✓
success reported but production never flips → exit 4 that says the two disagree 0.4ms
✓
transient gh and /api/version failures are retried, not verdicts 0.5ms
✓
asks git about a given build_id once, not every poll 0.3ms
✓
prints only on change — a 15-minute wait is not 60 identical lines 0.9ms
✓
refuses an abbreviated sha — the GitHub API silently matches nothing on one 1.5ms
✓
checkRunObserver minIds skips the failure being retried 0.3ms
readServed · 2 tests
✓
never throws — an unreachable endpoint is an observation 0.3ms
✓
does not call git for the exact sha or a semver 0.4ms
report — failure while main has moved on: the advice follows the CARRIER, not the tip · 8 tests
✓
a later commit that touches the Worker carries the change: verify THAT, with --worker, and do not retry 0.4ms
✓
a tip that touches only OTHER Workers carries nothing: retry the sha itself (the admin-only tip was a false LIVE) 0.3ms
✓
a carrier that could not be read: says so, and offers the retry that re-checks main itself 0.2ms
✓
main could not be refreshed: never takes the stale tip as "nothing moved" 0.2ms
✓
names the admin worker in the retry command 0.2ms
✓
one Worker failed, another is LIVE: no "Production: still" line for the admin failure, and live is not "Not verified" 0.5ms
✓
the build-id Worker failed while another is still pending: Production line + Not verified, in words 0.4ms
planRetry — refuses anything that could roll production back · 8 tests
✓
plans the retry of a failed build at the tip 1.3ms
✓
REFUSES when a later main commit changed what the Worker builds from — and the hint names the CARRIER, not the tip 0.7ms
✓
allows it when the later commits never touch that Worker (admin retry after a src-only merge) 0.3ms
✓
REFUSES when production already serves it or a descendant 0.2ms
✓
REFUSES off main, with no check run, with an unfinished run, and after a success 0.5ms
✓
REFUSES when the build UUID cannot be read from the check run 0.2ms
✓
a FAILED build is retried only when production is provably BEHIND the sha — every other relation refuses 1.4ms
✓
re-runs a SUCCEEDED build only when production is provably BEHIND it, AND only with --redeploy-succeeded 0.6ms
rollbackRisk — the rule, asked at plan time AND again right before the POST · 2 tests
✓
no later files, or none on this Worker's paths → no risk 0.3ms
✓
lists at most five touching paths and counts the rest 2.6ms
retryAftermath — did the retried build roll production back? (R1) · 13 tests
✓
ROLLED BACK: production serves the retried sha exactly, and a later build for this Worker already SUCCEEDED → exit 3 0.4ms
✓
ROLLED BACK names the CARRIER, not the tip: M changed outbound, then N changed only admin-app/ 0.3ms
✓
ROLLED BACK while a NEWER carrier is still building or failed: the recovery follows the newest one 0.3ms
✓
origin/main could not be re-read after the retry → exit 4, rollback NOT ruled out 0.2ms
✓
a production answer that kept changing is not LIVE 0.2ms
✓
NOT a rollback when the later build is still running — it deploys over this one when it finishes 0.4ms
✓
a later build that FAILED on its own is not a rollback either 0.2ms
✓
an unreadable later build cannot rule it out → exit 4, never a pass 0.2ms
✓
production on a LATER commit containing the sha → LIVE, nothing replaced 0.2ms
✓
main did not move on this Worker's paths → LIVE on the exact sha 0.4ms
✓
success reported but production never showed it → exit 4, not LIVE 0.2ms
✓
a Worker with no build-id endpoint cannot show the order → a later success is "not ruled out", exit 4 0.3ms
✓
the --after-rerun line carries the replaced check run id 0.1ms
findCarrier — the newest later commit that touches the Worker · 2 tests
✓
skips a newer commit that touches only other Workers 0.3ms
✓
null when nothing later touches it; undefined when it cannot be told 0.3ms
Cloudflare trigger resolution · 5 tests
✓
reads the trigger, branch and commit off a build 0.2ms
✓
the fallback picks the ONE trigger that builds main, and refuses ambiguity 0.3ms
✓
the POST pins BOTH branch and commit 0.2ms
✓
the POST body never omits `branch`, whatever the caller passes 0.4ms
✓
the POST body refuses an abbreviated commit — it would pin nothing checkable 0.3ms
the Worker table · 1 test
✓
names every Worker Workers Builds deploys, each with its check-run name and Builds tag 0.4ms
a rename across a watch-path boundary builds BOTH Workers · 1 test
✓
src/shared.ts → admin-app/shared.ts: with --no-renames both paths are listed, and both Workers are expected 0.2ms
productionCheckRuns — a preview build posts under the SAME name · 2 tests
✓
keeps only runs in a Cloudflare suite on main, and lists the rest as preview 0.5ms
✓
a preview success is not LIVE for admin; the report says why nothing was read 0.4ms
afterRerunMinIds — --after-rerun skips the failure being rerun, never the rerun's own verdict · 4 tests
✓
one failure: the rerun has not reported — skip it 0.3ms
✓
two failures: the newest IS the rerun's verdict — skip nothing (it used to skip it and wait 15 min) 0.3ms
✓
failure then success: skip nothing, the success stands 0.1ms
✓
an explicit id skips that run and everything older, for the Worker it belongs to 0.3ms
readServed — a null ancestry answer is asked again, never cached · 1 test
✓
unknown on a failed resolution, then contains once git can place the build 0.3ms
verifyDeploy — the review fixes, on the fake clock · 8 tests
✓
an OLDER build that finishes last deploys over the sha: not LIVE while it runs, and not LIVE after it lands 0.9ms
✓
an older build that finished WITHOUT replacing it: LIVE, one poll after the older build was seen done 0.4ms
✓
an older build still running at the deadline → NOT OBSERVED, and the report says it was an older build 0.4ms
✓
check runs that could NEVER be read → exit 5, not "no build reported failure" 1.6ms
✓
reads that broke mid-run and stayed broken past READ_STALE_MS → exit 5 "since"; the last good observation stands meanwhile 0.6ms
✓
a failed read keeps the LAST GOOD observation: a success seen earlier is not rewritten as "No check run yet" 0.5ms
✓
a single failed read just before the deadline is still NOT_OBSERVED — the instrument worked 0.3ms
✓
two quick merges: production on a child git cannot place YET → LIVE once it can (one failed fetch is not the whole run) 0.4ms
the older-build gate, piece by piece · 3 tests
✓
olderInWindow: only commits inside the window that touch the Worker; an unreadable file list counts 0.3ms
✓
olderBuildsObserver caches a finished state and re-reads a pending one 0.8ms
settleServed — two reads that agree · 2 tests
✓
a flip between reads is read again; a stable live answer returns 0.4ms
✓
a behind answer keeps being read until the grace ends 0.3ms
src/billing/gate-floors.vitest.ts
P0-07b-04: the central preflight reserves what the card quotes · 38 tests
✓
seo_request_indexing at minimal realistic args, plan unknown 3.9ms
✓
seo_request_indexing at minimal realistic args, plan free 0.6ms
✓
seo_request_indexing at minimal realistic args, plan paid 0.7ms
✓
seo_geo_visibility at minimal realistic args, plan unknown 3.7ms
✓
seo_geo_visibility at minimal realistic args, plan free 0.7ms
✓
seo_geo_visibility at minimal realistic args, plan paid 0.6ms
✓
aeo_visibility at minimal realistic args, plan unknown 1.3ms
✓
aeo_visibility at minimal realistic args, plan free 0.6ms
✓
aeo_visibility at minimal realistic args, plan paid 0.9ms
✓
seo_backlink_deep_scan at minimal realistic args, plan unknown 1.2ms
✓
seo_backlink_deep_scan at minimal realistic args, plan free 0.5ms
✓
seo_backlink_deep_scan at minimal realistic args, plan paid 0.3ms
✓
backlink_outreach_search at minimal realistic args, plan unknown 1.2ms
✓
backlink_outreach_search at minimal realistic args, plan free 0.4ms
✓
backlink_outreach_search at minimal realistic args, plan paid 0.3ms
✓
tap_volume at minimal realistic args, plan unknown 0.5ms
✓
tap_volume at minimal realistic args, plan free 0.3ms
✓
tap_volume at minimal realistic args, plan paid 0.2ms
✓
share_of_model at minimal realistic args, plan unknown 0.3ms
✓
share_of_model at minimal realistic args, plan free 0.2ms
✓
share_of_model at minimal realistic args, plan paid 0.2ms
✓
seo_enrich_keywords at minimal realistic args, plan unknown 0.3ms
✓
seo_enrich_keywords at minimal realistic args, plan free 0.2ms
✓
seo_enrich_keywords at minimal realistic args, plan paid 0.3ms
✓
seo_keyword_metrics at minimal realistic args, plan unknown 1.6ms
✓
seo_keyword_metrics at minimal realistic args, plan free 0.3ms
✓
seo_keyword_metrics at minimal realistic args, plan paid 0.3ms
✓
keyword_volumes at minimal realistic args, plan unknown 0.4ms
✓
keyword_volumes at minimal realistic args, plan free 0.3ms
✓
keyword_volumes at minimal realistic args, plan paid 0.2ms
✓
seo_serp_spider at minimal realistic args, plan unknown 1.2ms
✓
seo_serp_spider at minimal realistic args, plan free 0.3ms
✓
seo_serp_spider at minimal realistic args, plan paid 0.3ms
✓
the named figures, so a regression names its tool (plan unknown) 1.3ms
✓
a free account can now reach AI visibility and the SERP spider inside its signup grant 0.8ms
✓
an unknown plan prices at the WIDEST plan, never the narrowest (google_god_mode_report) 0.3ms
✓
`index_budget` does not lower the god-mode quote: the coverage leg ignores it (gsc.ts `_budget`) 0.2ms
✓
a card that was quoting BELOW the true worst case now shows the bound 1.5ms
P0-07b-05: a run that passes the central preflight and its dispatch gate reserves once · 21 tests
✓
aeo_page_check: the minimum balance is the reservation plus the buffer, not two reservations 19.5ms
✓
backlink_outreach_search: the minimum balance is the reservation plus the buffer, not two reservations 3.1ms
✓
create_marketing_plan: the minimum balance is the reservation plus the buffer, not two reservations 2.2ms
✓
enrich_contacts: the minimum balance is the reservation plus the buffer, not two reservations 2.6ms
✓
entity_audit: the minimum balance is the reservation plus the buffer, not two reservations 2.1ms
✓
google_god_mode_report: the minimum balance is the reservation plus the buffer, not two reservations 5.3ms
✓
search_leads: the minimum balance is the reservation plus the buffer, not two reservations 3.7ms
✓
seo_backlinks: the minimum balance is the reservation plus the buffer, not two reservations 2.0ms
✓
seo_competitor_gap: the minimum balance is the reservation plus the buffer, not two reservations 2.1ms
✓
seo_content_ideas: the minimum balance is the reservation plus the buffer, not two reservations 1.9ms
✓
seo_geo_research: the minimum balance is the reservation plus the buffer, not two reservations 2.4ms
✓
seo_keyword_metrics: the minimum balance is the reservation plus the buffer, not two reservations 2.2ms
✓
seo_offpage_audit: the minimum balance is the reservation plus the buffer, not two reservations 2.1ms
✓
seo_serp_spider: the minimum balance is the reservation plus the buffer, not two reservations 2.8ms
✓
seo_write_content: the minimum balance is the reservation plus the buffer, not two reservations 1.8ms
✓
tap_volume: the minimum balance is the reservation plus the buffer, not two reservations 2.0ms
✓
seo_backlink_deep_scan: the minimum balance is the reservation plus the buffer, not two reservations 7.0ms
✓
seo_backlink_gap: the minimum balance is the reservation plus the buffer, not two reservations 2.4ms
✓
seo_request_indexing: the minimum balance is the reservation plus the buffer, not two reservations 1.8ms
✓
the window holds one reservation after both gates pass 0.2ms
✓
a dispatch that needs MORE than the central reservation reserves only the difference 0.2ms
a call that did not pass through the preflight still reserves in full · 3 tests
✓
a fresh call object at the dispatch gate reserves its whole requirement 0.3ms
✓
two call objects in one window each hold their own reservation 0.3ms
✓
a hold from a window that has since been torn down is not honoured 0.2ms
an over-asked argument still refuses · 9 tests
✓
200 URLs are gated at 200 URLs 0.6ms
✓
blank URLs are not a count: the dispatch falls back to the stored gap list (up to 200) 0.4ms
✓
a scalar where the dispatch reads only an array is not a count 0.4ms
✓
twelve prospects on a paid plan are gated at twelve domains × two contacts 0.3ms
✓
the full visibility matrix is gated at the full matrix 0.4ms
✓
an engine the dispatch does not recognise is priced as the default set, never as zero 0.2ms
✓
an engine:model pick is priced by its engine, not dropped as unknown 0.2ms
✓
a free plan that swaps the named engine for its allowlist is priced at the swap 0.2ms
✓
a named panel (segment) supplies its own prompts, so the named count bounds nothing 0.1ms
the aeo_visibility composite lends its reservation to its legs · 3 tests
✓
a free picker run: the legs add only what the composite did not price 3.2ms
✓
a paid library run needs the composite reservation and nothing more 2.7ms
✓
a leg that did not come from the composite reserves in full 0.2ms
the gate never narrows on a read it could not make · 5 tests
✓
reads the plan when every read succeeds 0.6ms
✓
a failed read is "unknown", never "free" (the dispatch may read "paid" a second later) 0.9ms
✓
a plan the ledger disagrees with is priced at the WIDEST plan, not at either one 0.6ms
✓
is read once per request for a user, and a failed read is not remembered 0.7ms
✓
only plan-shaped tools read the plan at all 0.3ms
each asserted bound matches the dispatch that enforces it · 6 tests
✓
backlink outreach: four discovery queries, the shared domain and contact caps 0.6ms
✓
request indexing: the submit cap is the one the table row prices 0.4ms
✓
keyword metrics: the ride-along count in the dispatch query is the one priced 0.2ms
✓
the engine matrix hard cap is still the one seoGeoVisibility applies 0.6ms
✓
deep scan and gap gates price through the shared functions 0.3ms
✓
every non-free plan prices the verify pass at least as deep as a topped-up run takes it 0.2ms
wiring · 5 tests
✓
the central preflight prices at the plan and records its reservation on the call 0.4ms
✓
the agent loop card prices at the same plan 0.3ms
✓
finds all 21 dispatch gates the audit listed (P0-07b lib/m3-sites.mjs), and no fewer 6.2ms
✓
every dispatch gate hands the gate its call object, so it reserves only the excess 7.5ms
✓
the aeo_visibility composite lends to every priced leg it runs through executeTool 1.6ms
V12b-money-F03: a nested leg is covered by its parent's hold · 8 tests
✓
seo_write_content with its auto-brief: parent and brief holds do not stack (max, not sum, + the buffer) 4.3ms
✓
ai_overview_visibility prices the queries it is handed: the mean as its quote, the worst case as its ceiling (capped at 8) 1.2ms
✓
the AIO reservation — standalone, and lent inside the composite — is never below the all-overview worst case 1.2ms
✓
the aeo_visibility free picker run (chatgpt × 3 prompts) needs the composite reservation and nothing more 3.3ms
✓
a lent hold survives executeTool's validation copy (the brief is schematised: its call object is replaced) 4.4ms
✓
carryReservation never ADDS to a hold: an object that already holds keeps its own 0.3ms
✓
source pin: executeTool carries a lent hold across its validation copy 6.0ms
✓
source pin: seo_write_content lends to the brief call it runs, and the AIO dispatch caps at the shared constant 1.7ms
src/tools/no-schema-speak.vitest.ts
every validation rule produces a human sentence · 88 tests
✓
has rules to check (the enumeration is real, not vacuous) 1.7ms
✓
the rule statements themselves ARE schema-speak — which is why they must never ship 0.5ms
✓
search_leads / "local_requires_category" never reaches a user as schema text 0.7ms
✓
search_leads / "local_requires_place" never reaches a user as schema text 0.4ms
✓
search_leads / "postal_code_pairs_with_country_code" never reaches a user as schema text 0.4ms
✓
search_leads / "people_fields_only_on_people_search" never reaches a user as schema text 0.4ms
✓
search_leads / "local_fields_only_on_local_search" never reaches a user as schema text 0.2ms
✓
search_leads / "audience_needs_a_handle" never reaches a user as schema text 0.2ms
✓
search_leads / "narrow_only_on_request" never reaches a user as schema text 0.5ms
✓
seo_keywords / "topic_is_a_seed_not_a_sentence" never reaches a user as schema text 0.2ms
✓
seo_list_keywords / "no_arguments_means_no_narrowing" never reaches a user as schema text 0.3ms
✓
seo_keyword_metrics / "one_keyword_not_a_question" never reaches a user as schema text 0.2ms
✓
seo_enrich_keywords / "omit_to_enrich_everything" never reaches a user as schema text 0.1ms
✓
find_competitors / "named_domain_is_the_subject" never reaches a user as schema text 0.1ms
✓
seo_competitor_gap / "competitor_must_be_named_or_saved" never reaches a user as schema text 0.1ms
✓
seo_backlink_gap / "gap_needs_our_baseline" never reaches a user as schema text 0.1ms
✓
seo_backlink_verify / "blocked_is_not_absent" never reaches a user as schema text 0.2ms
✓
seo_backlink_deep_scan / "repeat_scans_are_incremental" never reaches a user as schema text 0.1ms
✓
seo_backlink_value / "one_property_only" never reaches a user as schema text 0.1ms
✓
seo_backlink_value / "zero_is_not_worthless" never reaches a user as schema text 0.1ms
✓
seo_content_ideas / "ideas_are_not_a_brief" never reaches a user as schema text 0.1ms
✓
seo_content_brief / "brief_targets_one_primary_keyword" never reaches a user as schema text 0.1ms
✓
seo_write_content / "one_of_keyword_or_source_url" never reaches a user as schema text 0.1ms
✓
seo_write_content / "reuse_a_brief_you_already_have" never reaches a user as schema text 0.1ms
✓
seo_onpage_audit / "named_domain_is_the_subject" never reaches a user as schema text 0.1ms
✓
seo_offpage_audit / "named_domain_is_the_subject" never reaches a user as schema text 0.1ms
✓
seo_backlinks / "named_domain_is_the_subject" never reaches a user as schema text 0.1ms
✓
seo_serp_spider / "verify_index_is_opt_in" never reaches a user as schema text 0.1ms
✓
seo_serp_spider / "serp_features_keywords_is_opt_in" never reaches a user as schema text 0.1ms
✓
entity_audit / "do_not_guess_identity" never reaches a user as schema text 0.1ms
✓
entity_audit / "site_only_never_claim_listings" never reaches a user as schema text 0.1ms
✓
entity_audit / "ask_before_assuming_local" never reaches a user as schema text 0.1ms
✓
aeo_page_check / "one_page_not_a_site" never reaches a user as schema text 0.1ms
✓
aeo_full_audit / "composite_is_opt_in" never reaches a user as schema text 0.1ms
✓
sov_trend / "state_the_recurring_cost" never reaches a user as schema text 0.2ms
✓
panel_segments / "no_scheduled_measurement" never reaches a user as schema text 0.2ms
✓
panel_segments / "keyword_panels_are_derived" never reaches a user as schema text 1.8ms
✓
tap_volume / "queries_is_always_an_array" never reaches a user as schema text 0.1ms
✓
seo_generate_llms_txt / "generated_not_published" never reaches a user as schema text 0.1ms
✓
seo_request_indexing / "submission_is_irreversible_and_per_url" never reaches a user as schema text 0.1ms
✓
seo_monitor / "reads_history_never_measures" never reaches a user as schema text 0.1ms
✓
seo_rank_track / "keywords_are_search_terms" never reaches a user as schema text 0.1ms
✓
seo_content_quality / "one_page_needs_a_page" never reaches a user as schema text 0.1ms
✓
seo_google_merge / "traffic_is_not_mentions" never reaches a user as schema text 0.1ms
✓
domain_email_readiness_audit / "audit_before_first_send" never reaches a user as schema text 0.1ms
✓
cloudflare_fix_email_dns / "this_writes_live_dns" never reaches a user as schema text 0.1ms
✓
cloudflare_fix_email_dns / "only_three_fixes_exist" never reaches a user as schema text 0.1ms
✓
generate_dns_fix_prompt / "instructions_not_changes" never reaches a user as schema text 0.2ms
✓
get_usage_breakdown / "spend_is_not_a_diagnosis" never reaches a user as schema text 0.1ms
✓
list_scheduled_scans / "status_is_what_the_run_will_do" never reaches a user as schema text 0.1ms
✓
stop_scheduled_scan / "stop_is_not_delete" never reaches a user as schema text 0.1ms
✓
list_campaigns / "no_arguments_means_no_narrowing" never reaches a user as schema text 0.1ms
✓
list_sequences / "no_arguments_means_no_narrowing" never reaches a user as schema text 0.1ms
✓
list_connectors / "check_before_claiming" never reaches a user as schema text 0.1ms
✓
show_marketing_plan / "plan_status_only" never reaches a user as schema text 0.1ms
✓
create_campaign / "creating_is_not_sending" never reaches a user as schema text 0.1ms
✓
campaign_stats / "rates_need_a_denominator" never reaches a user as schema text 0.1ms
✓
create_sequence / "authoring_is_not_enrolling" never reaches a user as schema text 0.1ms
✓
connect_connector / "named_domain_is_the_subject" never reaches a user as schema text 0.1ms
✓
set_standing_instruction / "standing_means_every_future_message" never reaches a user as schema text 0.1ms
✓
scan_product / "scan_their_site_not_ours" never reaches a user as schema text 0.1ms
✓
define_icp / "proposal_not_verdict" never reaches a user as schema text 0.1ms
✓
backlink_outreach_search / "discovery_saves_real_contacts" never reaches a user as schema text 0.1ms
✓
create_marketing_plan / "plans_are_asked_for_explicitly" never reaches a user as schema text 0.1ms
✓
propose_outbound_run / "run_proposes_never_executes" never reaches a user as schema text 0.1ms
✓
aeo_visibility / "engines_are_the_cost_lever" never reaches a user as schema text 0.2ms
✓
aeo_visibility / "site_omitted_means_saved_site" never reaches a user as schema text 0.1ms
✓
generate_emails / "one_targeting_field" never reaches a user as schema text 0.1ms
✓
generate_emails / "never_invent_a_contact_id" never reaches a user as schema text 0.1ms
✓
list_contacts / "all_prevents_a_silently_partial_answer" never reaches a user as schema text 0.1ms
✓
add_contacts / "typed_contacts_are_saved_not_searched" never reaches a user as schema text 0.1ms
✓
list_sent_emails / "sent_log_is_this_tool" never reaches a user as schema text 0.1ms
✓
send_emails / "confirm_is_never_self_granted" never reaches a user as schema text 0.1ms
✓
enrich_contacts / "one_targeting_field" never reaches a user as schema text 0.1ms
✓
enrich_contacts / "vague_quality_is_not_a_filter" never reaches a user as schema text 0.1ms
✓
enrich_contacts / "redo_needs_enriched_any" never reaches a user as schema text 0.1ms
✓
verify_contacts / "never_pick_a_target_for_a_paid_run" never reaches a user as schema text 0.1ms
✓
verify_contacts / "do_not_re_verify_by_default" never reaches a user as schema text 0.1ms
✓
assign_to_campaign / "campaign_must_exist" never reaches a user as schema text 0.1ms
✓
enroll_in_sequence / "enrolment_starts_sends" never reaches a user as schema text 0.1ms
✓
start_sequence / "starting_is_sending" never reaches a user as schema text 0.1ms
✓
set_campaign_sequence / "attaching_is_not_launching" never reaches a user as schema text 0.1ms
✓
diagnose / "diagnose_before_paid_audit" never reaches a user as schema text 0.1ms
✓
diagnose / "no_revenue_data_means_no_cause" never reaches a user as schema text 0.1ms
✓
diagnose / "one_measurement_is_not_a_trend" never reaches a user as schema text 0.1ms
✓
seo_geo_research / "topic_research_not_brand_measurement" never reaches a user as schema text 0.1ms
✓
web_search / "search_before_paid_report_on_someone_elses_site" never reaches a user as schema text 0.1ms
✓
read_url / "one_page_per_call" never reaches a user as schema text 0.1ms
the exact live payload · 2 tests
✓
produces a question, not the rule statement 1.1ms
✓
names a field in plain words when it has nothing better to say 0.2ms
a cross-field rule never blames a single field · 4 tests
✓
people_fields_only_on_people_search asks which search the user meant 1.1ms
✓
local_fields_only_on_local_search asks which search the user meant 0.5ms
✓
still names a genuinely bad value when the error IS one field 0.1ms
✓
blocks BEFORE the cost-approval card rather than after the click 0.4ms
the guardrail is the floor under all of it · 4 tests
✓
redacts field=value syntax that reaches user-visible text by any other route 2.7ms
✓
redacts a parameter LIST 0.5ms
✓
leaves a single snake_case word alone — it may be the user's own term 0.2ms
✓
leaves ordinary prose untouched 0.1ms
src/planner/contracts.vitest.ts
stripFabricatedMagnitude (Track B #1 — no unsupported percentage claims) · 5 tests
✓
strips a "by N%" magnitude, keeps the directional claim 5.2ms
✓
strips multiple magnitudes in the same statement 0.3ms
✓
strips a decimal or tilde-prefixed magnitude 0.3ms
✓
leaves directional-only text untouched 0.3ms
✓
does not mangle an unrelated number (no percent sign) 0.2ms
resolveMeasurement (audit P0 — measurement contract) · 4 tests
✓
campaign target wins: replies, up 0.9ms
✓
keyword → rank, down 0.4ms
✓
aeo channel with a site → aeo_score; seo/content → onpage_score 0.4ms
✓
no site and no target → null (explicit non-learning class) 0.7ms
validateToolArgs (audit P1 — beyond tool-name whitelisting) · 2 tests
✓
accepts valid args and tolerates schema-less tools 0.4ms
✓
rejects missing/empty required, unknown args, wrong types 0.4ms
validateBetCount (Growth Bets — 3-5 range, never padded) · 5 tests
✓
accepts 3-5 non-empty bets on a plan with >=5 initiatives 0.4ms
✓
rejects fewer than 3 or more than 5 bets when >=5 initiatives exist 0.2ms
✓
allows fewer than 3 bets when the plan genuinely has fewer initiatives (no padding) 0.2ms
✓
rejects a padded/empty bet (0 linked initiatives) outright, regardless of count 0.1ms
✓
rejects zero bets on a plan that has initiatives 0.2ms
assignHorizon (execution horizons — foundation/build/scale) · 3 tests
✓
the hard-blocker item is always foundation, regardless of position 0.2ms
✓
buckets by position into roughly-even thirds 0.3ms
✓
a recurring signal (rank tracking) biases one band later than its raw position 0.2ms
deriveImpactRating / feasibilityFromEffort (no fabricated numeric confidence) · 5 tests
✓
the hard-blocker item is always high impact — it unblocks everything else 0.2ms
✓
a real, distinctly-owned measurement signal is high impact 0.1ms
✓
a real but SHARED measurement signal (Track B #3) is medium, not high 0.1ms
✓
an unmeasurable initiative defaults to medium — never fabricated higher 0.2ms
✓
feasibility is a direct remap of effort, defaulting to medium 0.2ms
valueAtStakeFor (highest-risk helper — must never fabricate or misplace a benchmark) · 3 tests
✓
returns a reference band, always carrying unverified:true, for a known unmeasurable channel 0.3ms
✓
NEVER returns a figure when a real measurement exists — even for a channel with a known band 0.2ms
✓
returns null (honest absence) for a channel with no reference band — never a placeholder 0.2ms
reflectHypothesisStatus (audit US5 — reflection) · 1 test
✓
derives status from measured outcomes only 0.3ms
planner contracts · 15 tests
✓
is stable across normalization-equivalent inputs 1.3ms
✓
differs by action, target, and keyword 0.6ms
✓
treats missing target/keyword as empty, not undefined-stringified 0.2ms
✓
position: ±1 place is neutral, beyond is directional (down = better) 0.3ms
✓
clicks: relative floor with absolute-count guard 0.3ms
✓
missing values are neutral, never a verdict 0.2ms
✓
unknown metric uses the default floor 0.2ms
✓
walks the happy path 0.4ms
✓
allows proposed to skip straight to invoked (Execute chip without explicit approve) 0.1ms
✓
pre-completed states can block or be dismissed; completed cannot 0.4ms
✓
blocked is retryable (→proposed) or dismissable, nothing else 0.2ms
✓
only proposed can expire to not_run 0.2ms
✓
completed can close as done_unmeasured (the explicit non-learning terminal) 0.2ms
✓
terminal states never move, including self-transitions everywhere 3.6ms
resolveExecutionMode (FR-003 — two states, no third) · 3 tests
✓
is executable only when a tool is actually attached 0.2ms
✓
degrades to manual for every shape that carries no runnable tool 0.2ms
✓
never returns a third state, whatever it is handed 1.4ms
manualInstructionFor (FR-001 — plain language, never a validator message) · 2 tests
✓
never emits internal vocabulary for any reason 1.0ms
✓
tells the user what to do, and stays silent when there is nothing to add 0.4ms
coerceToolArgs (T011b — repair the unambiguous, invent nothing) · 5 tests
✓
drops keys the schema never declared 0.3ms
✓
coerces unambiguous type mismatches in both directions 0.3ms
✓
leaves a non-numeric string alone rather than coercing it to NaN 0.2ms
✓
fills a missing required arg ONLY from caller-supplied context 0.3ms
✓
is a no-op for a tool with no declared parameters 0.1ms
computePlanProgress (surface 2 — progress from the ledger, no new state) · 9 tests
✓
separates work done from time spent — the pairing the panel was missing 0.8ms
✓
counts every terminal-done status as done, including the unmeasured one 0.2ms
✓
measured counts only items with a real verdict — done is not measured 0.2ms
✓
next_recheck_at is the soonest check STILL AHEAD — a past-due one is not "next" 0.3ms
✓
reports no recheck rather than a stale one when every check is past due 2.0ms
✓
flags stalled ONLY past the horizon with nothing done 0.3ms
✓
caps time at 100% — a plan can overrun, but "142% elapsed" is noise 0.3ms
✓
invents no timeline for a plan that has no horizon or no created_at 0.3ms
✓
an empty plan is 0%, never NaN 0.2ms
sanitizeStoredReason (the panel reads status_reason back out of the DB) · 3 tests
✓
replaces every legacy validator message that was persisted before the fix 0.6ms
✓
leaves a legitimate stored reason untouched 0.4ms
✓
normalises empty/absent to null 0.1ms
computePlanProgress — lineage across superseded plans · 5 tests
✓
counts work finished under an earlier plan without moving those rows 0.3ms
✓
ages the chain from the FIRST plan, not the newest — re-planning does not reset the clock 0.2ms
✓
stall is judged on the chain — re-planning cannot hide a stuck user from the warning 0.2ms
✓
is NOT stalled when the chain is long but work actually happened 0.1ms
✓
a first plan reports plan 1 and no carried work — lineage stays silent 0.2ms
classifyDirective (ordered, first-match-wins — exactly one class per item) · 5 tests
✓
returns predictive only when BOTH a baseline and a method exist 0.3ms
✓
a hard blocker is always corrective — a missing prerequisite is a fact, not an opinion 0.2ms
✓
a measured defect is corrective; measured headroom without a defect is suggestive 0.1ms
✓
an unmeasurable ACTION is suggestive; unmeasurable non-action is advisory 0.2ms
✓
never returns anything outside the vocabulary, whatever it is handed 0.7ms
directiveProvenanceLegal (FR-031 — the rule the two axes exist to express) · 2 tests
✓
rejects a corrective claim resting on anything but a measurement 0.2ms
✓
allows every other pairing — the constraint is deliberately narrow 0.3ms
classifyProvenance (recorded is never promoted to measured) · 2 tests
✓
separates what we measured from what they told us 0.2ms
✓
an industry reference outranks everything — it is the least trustworthy class 0.1ms
groupByDirective (FR-030 — an empty class states its own absence) · 3 tests
✓
always returns all four groups, in fixed order, even when every one is empty 0.4ms
✓
places each item in exactly one group and never duplicates it 0.6ms
✓
drops an unclassified (pre-013) row from every group rather than guessing one 0.1ms
enforceMeasurementKeyCap · 6 tests
✓
keeps at most 2 per key and drops the rest, preserving order 0.4ms
✓
reproduces the fixture baseline: 6-on-one-key becomes 2 0.3ms
✓
counts each key separately — distinct signals do not contend 0.2ms
✓
never drops an unmeasurable item — it is not competing for a signal 0.3ms
✓
honours the exemption — the hard-blocker gate unblocks the rest and must survive 0.3ms
✓
is a no-op on an already-compliant plan 0.4ms
enforceMeasurementKeyCap — carried-forward work spends the signal budget · 3 tests
✓
LIVE DEFECT: 2 carried + 2 new on one key produced FOUR owners of one signal 0.3ms
✓
leaves room for exactly the unspent remainder 0.3ms
✓
an empty budget behaves exactly as before — no behaviour change for a first plan 0.3ms
classifyDirective on carry-forward — no partially-classified plan · 2 tests
✓
LIVE DEFECT: pre-013 rows carried onto a classified plan rendered into NO group 0.3ms
✓
a historical row is never retroactively called corrective without evidence 0.1ms
measurement budget counts COMMITMENTS, not unactioned advice · 4 tests
✓
52 proposed rows spend NOTHING — new proposals survive 0.4ms
✓
real commitments DO still spend it — the cap is not simply disabled 3.1ms
✓
a blocked item counts — a failed execution attempt IS a commitment 0.2ms
✓
terminal statuses never spend budget — finished work is not in flight 0.3ms
src/admin/waste-meter.vitest.ts
session 6d5 (2026-09-23, 7 turns) — the send flow that cost two extra turns · 15 tests
✓
folds 7 turns, including the shortcut send turn that wrote no token row 2.6ms
✓
M1: max 3 rounds (70dfb970) — not a warn at the calibrated >= 4 1.1ms
✓
M2: one narration round, 13,573 — not a warn (needs 2 rounds or 20K) 0.7ms
✓
M3: 4 decision-only turns, 64,492 of 120,898 chat tokens (WARN) 0.6ms
✓
M4: 76,871 upper bound, share 0.5057 — ONE value per turn, never the double-counted 92,775 0.8ms
✓
M5: the product chip answered in prose — 1 turn, 19,008 (PAGE) 0.3ms
✓
M6: two turns between the drafts and the send — max 2, extra 1 (PAGE), the card was staged 0.4ms
✓
M7, M8, M9, M10: nothing 0.3ms
✓
M11: 537b7878 made 18 calls for 9 units (2.0) in two batchable groups (report) 1.6ms
✓
M12: median 141.67, max 404.83 on 7f07011a, 8 rounds — under the calibrated 350 0.4ms
✓
M15: judge $0.034800 on $0.018662 of chat, ratio 1.8648 (WARN); 4 of 7 verdicts from the anchor 0.5ms
✓
M16: two verdicts contradict the ledger — 7e72422b (1.0 on a prose non-answer) and 87ced0bb (0.1 on 9 of 9 sent) (PAGE) 0.3ms
✓
M17: 5 turns carry 10 Jev judge calls no ledger row metered 0.2ms
✓
flags: page [M5, M6, M16]; warn [M3, M15]; flagged 0.3ms
✓
the judge fixture row (no turn, no session) is counted, never guessed onto a session 0.2ms
session 3es (2026-09-21, 2 turns) — rows as they actually are · 11 tests
✓
M1 max 2; M2 one narration round, 10,776 0.2ms
✓
M3: 2 turns, 20,449 of 31,225 (WARN) — the REFUSED dispatch counts through its render 0.3ms
✓
M5 0; M6 null — there is no send turn 0.2ms
✓
M8: nothing attaches to the session; 2 refund rows (33,895) are unattributed, and never become a session 0.2ms
✓
M9: verify_contacts completed in 33,162 ms against a 30,000 budget — a hidden completion (PAGE) 0.2ms
✓
M10: 24 addresses re-verified from a different run — 24 extra calls, 36,000 basis (PAGE) 0.1ms
✓
M10 across the history: 09-18 re-bought 09-17, so the user paid 72,000 for work already done 0.3ms
✓
M12: median 190.02 0.3ms
✓
M15: no verdicts — ratio 0, anchor share null 0.2ms
✓
flags: page [M9, M10]; warn [M3]; flagged 0.2ms
session 3es as TODAY'S writers record it (gate_block row, refunds carry turn_id) · 2 tests
✓
M7: the refusal spent 11,463 on a floored catalogue ceiling — defective (PAGE) 0.2ms
✓
M8: 33,895 refunded through turn_id, and the 36,000 of verification no refund path covers 0.3ms
rules · 12 tests
✓
a refund with no turn joins through the verdict that recorded its message id (response_id) 1.5ms
✓
a refund never enters the spine: its message id must not capture the turn's judge rows 1.5ms
✓
rows from before 2026-09-17 (operation NULL) are read by round position 3.3ms
✓
a missing render row makes M3 null for that turn and counts it unmeasured — never a zero 1.5ms
✓
a round whose reasoning exceeds its completion is unmeasurable: out of M2, M3 and M12, and counted 2.3ms
✓
a duplicate inside ONE run is not repeat work (M10) — it is counted apart 1.3ms
✓
a repeat older than the lookback is not repeat work 0.2ms
✓
the send fee is BILLED spend: a refunded send turn leaves its 22,500 unrefunded 2.0ms
✓
a session that may have lost rows to the cap is marked partial 1.6ms
✓
J is measured from >= 20 shortlist calls, else falls back to 1,300 (this window has 8) 0.5ms
✓
percentiles are nearest-rank; the median averages the two middles 0.3ms
✓
the roll-up is built from sums, and the anchor alarm is per UTC day, platform-wide 3.6ms
privacy: no address, no prose, no unit key ever leaves the meter · 2 tests
✓
the mappers drop everything not whitelisted 0.4ms
✓
buildWasteView emits no @, no reasoning, no unit key, no refund text — even for rows carrying them 12.4ms
the view · 8 tests
✓
one ledger request; default turns are the flagged sessions'; the drill-down returns its session 7.8ms
✓
a named session is returned even when its account is internal — flagged as such, and kept out of the roll-up 8.6ms
✓
the widened query reads refunds and the repeat lookback in the same request 4.0ms
✓
sessions: 'none' empties the list, keeps the roll-up, and counts concentration before the list is dropped 7.3ms
✓
the concentration is counted over the roll-up population: partial sessions are out of both 6.8ms
✓
sessionConcentration counts sessions, distinct users and the largest single user — no ids 0.7ms
✓
the analytics handler passes sessions=none through, and only that value 0.4ms
✓
the analytics handler routes view=waste 0.6ms
guards: the config is the platform's own constants · 9 tests
✓
every write tool is a registry tool (a rename breaks CI, not the metric) 0.3ms
✓
every repeat source is a priced email-verification cost key 0.3ms
✓
overhead is EXACTLY billing's list — platform_send is debited, not overhead 0.3ms
✓
tool budgets are the registry's: verify_contacts has no entry, so 30,000 ms 0.2ms
✓
pool membership is the judge pool's: the grok anchor is not ours; an all-pool ensemble is 0.2ms
✓
the forbidden-judge rail is the judge pool's own predicate 0.4ms
✓
the meter's provider literals match their writers 0.2ms
✓
no file on the meter's path keeps a prefix overhead rule of its own 0.9ms
✓
waste-meter.ts imports nothing that runs 0.6ms
fold bookkeeping · 1 test
✓
every token and api row is either in a turn or counted 0.8ms
M6: each send's window opens at the later of the last draft and the last send · 7 tests
✓
two batches, one card each (the deferred-batch and "send the rest" flow): max 1, extra 0, no page 1.1ms
✓
a second send with no card of its own is UNSTAGED — the first batch's card does not cover it (PAGE) 0.5ms
✓
a send after a NEW draft set, with no card, is UNSTAGED even though an earlier batch was carded (PAGE) 0.4ms
✓
the audited shape still pages: a prose turn and then the card between the drafts and the send 0.5ms
✓
a card staged in the drafting turn itself is one card: confirms 0 is not a page when the card exists 0.4ms
✓
drafts straight to a send with no card: confirms 0 AND unstaged (PAGE) — zero confirmations never passes 0.4ms
✓
no draft in the session: the first send is unmeasured, a later batch is measured from the send before it 1.2ms
the window's own lower edge cuts sessions the way the row cap does · 4 tests
✓
a session starting inside the margin is partial even when no table hit the cap 0.3ms
✓
in a partial session, a send whose window reaches past the fetched rows is unmeasured, never UNSTAGED 0.3ms
✓
a partial session does not excuse a card-less send far from the edge: its card would have been fetched (PAGE) 1.0ms
✓
a whole session with the same shape still pages: drafts from an earlier session sent with no card 0.3ms
M15 reads failover on new rows; M15_forbidden pages on a new grok verdict · 9 tests
✓
requested mistral, served gpt-4o-mini (a POOL member) → an anchor verdict 0.6ms
✓
requested === served → NOT an anchor, even for glm (not a pool member) 0.4ms
✓
judge_retry=parse → an anchor verdict (a second, extra verdict) 0.3ms
✓
an OLD row (no judge_requested) keeps the pool rule 0.2ms
✓
the per-day alarm reads the same rule 0.3ms
✓
a NEW-shape verdict served by x-ai/grok-4.5 → forbidden 1, PAGE M15_forbidden 0.3ms
✓
a NEW-shape verdict asked of gpt-4o-mini but SERVED by x-ai → forbidden 1, PAGE M15_forbidden 0.4ms
✓
an OLD grok row (no judge_kind) → forbidden 0, no page — it ages out of the window 0.5ms
✓
M17: a reply_delivered metering row on a turn whose verdict carries jev_delivered → 0 unmetered 0.5ms
M9 and M10 read the consent and disclosure records · 6 tests
✓
M9: a run whose timeout was answered from its progress (halted_with_progress) is not hidden 1.5ms
✓
M9: shown_after_grace exempts too, and a timeout row with no run_id exempts the same tool in the same turn 1.3ms
✓
(neg) M9 still counts a late run with no disclosed-timeout record, or an undisclosed outcome 4.4ms
✓
M10: repeats inside a run the user consented to (recheck 'chip') are consented_calls, not extra_calls 3.1ms
✓
(neg) M10: recheck 'none' is still waste 1.4ms
✓
the meter's literals are the writers': the loop's outcomes and the dispatch's consent values 4.5ms
M2 reads the tool_run clock (item 5a-0) · 4 tests
✓
a turn whose last chat:v2 row is older than its tool_run is not M2 2.3ms
✓
(control) the same turn with the tool_run before its last round IS M2 — the clock is what flips it 2.0ms
✓
70dfb970 (enrich finished 1.6 s before the narration round) stays M2 = 13,573 2.6ms
✓
`tools` is in run order, oldest first, whatever order the ledger returns 3.9ms
src/db/user-role-dropped-writes.vitest.ts
the population: every user-role write a migration took away, derived from the files · 2 tests
✓
finds the eight outright drops (183 x6, 188, 193) and the ten revoked columns (188, 190), at least 2.4ms
✓
every outright drop has a re-grant shape to test with (its migration ships a _clear.json, or it is a DELETE) 1.2ms
0. the replay reads a re-grant in every envelope and table form Hasura accepts (V6-tenancy-F02) · 15 tests
✓
precondition: 183 drops token_usage INSERT outright, and the clean replay ends without it 0.9ms
✓
a later file re-granting it in a top-level bulk (control): the replay ends WITH it, so section 1 would fail 17.5ms
✓
a later file re-granting it in bulk_keep_going: the replay ends WITH it, so section 1 would fail 16.3ms
✓
a later file re-granting it in bulk_atomic: the replay ends WITH it, so section 1 would fail 19.8ms
✓
a later file re-granting it in concurrent_bulk: the replay ends WITH it, so section 1 would fail 15.2ms
✓
a later file re-granting it in a bulk inside a bulk: the replay ends WITH it, so section 1 would fail 15.5ms
✓
a later file re-granting it in a bulk_keep_going inside a bulk: the replay ends WITH it, so section 1 would fail 16.0ms
✓
a later file re-granting it in a top-level array: the replay ends WITH it, so section 1 would fail 15.6ms
✓
a later file re-granting it in a single operation: the replay ends WITH it, so section 1 would fail 15.9ms
✓
a later file re-granting it in a hand-applied wrapper ({ _comment, steps }): the replay ends WITH it, so section 1 would fail 17.2ms
✓
a later file re-granting it in the table as a plain string: the replay ends WITH it, so section 1 would fail 20.1ms
✓
a later file re-granting it in the table as { name } with no schema: the replay ends WITH it, so section 1 would fail 15.5ms
✓
a later file re-granting it in the v1 operation name, without pg_: the replay ends WITH it, so section 1 would fail 15.8ms
✓
a grant in a form the replay does not read (replace_metadata, another backend's prefix) is reported, not skipped 1.2ms
✓
every user-role object in every migration file is one the replay reads (none in an unread form) 5.7ms
1. no later migration file grants one back · 2 tests
✓
the replay ends with none of the outright-dropped permissions 0.4ms
✓
the replay ends with none of the revoked columns back in its grant 0.8ms
2. check-graphql-schema fails on a snapshot that holds one again · 50 tests
✓
clean snapshot: passes 833.3ms
✓
token_usage INSERT re-granted as 183's --clear would: exits 1, names every root and why (K10) 47.8ms
✓
insert_token_usage alone back for the user role: exits 1 and names it with its reason 41.0ms
✓
insert_token_usage_one alone back for the user role: exits 1 and names it with its reason 45.7ms
✓
token_usage_insert_input alone (no root, no document): exits 1 and names it 46.1ms
✓
api_usage INSERT re-granted as 183's --clear would: exits 1, names every root and why (K10) 44.4ms
✓
insert_api_usage alone back for the user role: exits 1 and names it with its reason 43.3ms
✓
insert_api_usage_one alone back for the user role: exits 1 and names it with its reason 45.4ms
✓
api_usage_insert_input alone (no root, no document): exits 1 and names it 42.9ms
✓
shared_lead_selection INSERT re-granted as 183's --clear would: exits 1, names every root and why (K10) 45.0ms
✓
insert_shared_lead_selection alone back for the user role: exits 1 and names it with its reason 44.4ms
✓
insert_shared_lead_selection_one alone back for the user role: exits 1 and names it with its reason 44.7ms
✓
shared_lead_selection_insert_input alone (no root, no document): exits 1 and names it 43.4ms
✓
templates INSERT re-granted as 183's --clear would: exits 1, names every root and why (K9) 45.0ms
✓
insert_templates alone back for the user role: exits 1 and names it with its reason 43.1ms
✓
insert_templates_one alone back for the user role: exits 1 and names it with its reason 43.6ms
✓
templates_insert_input alone (no root, no document): exits 1 and names it 40.9ms
✓
templates UPDATE re-granted as 183's --clear would: exits 1, names every root and why (K9) 41.7ms
✓
update_templates alone back for the user role: exits 1 and names it with its reason 42.0ms
✓
update_templates_by_pk alone back for the user role: exits 1 and names it with its reason 41.1ms
✓
update_templates_many alone back for the user role: exits 1 and names it with its reason 44.3ms
✓
templates_set_input alone (no root, no document): exits 1 and names it 41.5ms
✓
templates DELETE re-granted as 183's --clear would: exits 1, names every root and why (K9) 42.4ms
✓
delete_templates alone back for the user role: exits 1 and names it with its reason 42.6ms
✓
delete_templates_by_pk alone back for the user role: exits 1 and names it with its reason 44.7ms
✓
emails_sent DELETE re-granted as 188's --clear would: exits 1, names every root and why (P1-08t-F05) 43.0ms
✓
delete_emails_sent alone back for the user role: exits 1 and names it with its reason 43.4ms
✓
delete_emails_sent_by_pk alone back for the user role: exits 1 and names it with its reason 43.9ms
✓
shared_lead_list_item INSERT re-granted as 193's --clear would: exits 1, names every root and why (K11) 45.3ms
✓
insert_shared_lead_list_item alone back for the user role: exits 1 and names it with its reason 43.5ms
✓
insert_shared_lead_list_item_one alone back for the user role: exits 1 and names it with its reason 43.5ms
✓
shared_lead_list_item_insert_input alone (no root, no document): exits 1 and names it 42.7ms
✓
contacts_insert_input.campaign_id back (revoked by 188): exits 1, names it and why (P1-08p-F01) 46.4ms
✓
contacts_insert_input.unsubscribed_at back (revoked by 188): exits 1, names it and why (P1-08t-F05) 43.6ms
✓
contacts_set_input.unsubscribed_at back (revoked by 188): exits 1, names it and why (P1-08t-F05) 41.4ms
✓
contacts_set_input.verified_status back (revoked by 188): exits 1, names it and why (P1-08t-F05) 43.5ms
✓
contacts_set_input.verified_at back (revoked by 188): exits 1, names it and why (P1-08t-F05) 41.4ms
✓
contacts_set_input.verified_source back (revoked by 188): exits 1, names it and why (P1-08t-F05) 42.2ms
✓
emails_sent_set_input.bounced_at back (revoked by 188): exits 1, names it and why (P1-08t-F05) 42.6ms
✓
contacts_insert_input.verified_status back (revoked by 190): exits 1, names it and why (P1-08t-F05) 42.8ms
✓
contacts_insert_input.verified_at back (revoked by 190): exits 1, names it and why (P1-08t-F05) 41.7ms
✓
contacts_insert_input.verified_source back (revoked by 190): exits 1, names it and why (P1-08t-F05) 42.1ms
✓
emails_sent_insert_input.status back (revoked by 196): exits 1, names it and why (DECISIONS #52) 45.1ms
✓
emails_sent_set_input.status back (revoked by 196): exits 1, names it and why (DECISIONS #52) 39.3ms
✓
emails_sent_set_input.sent_at back (revoked by 196): exits 1, names it and why (DECISIONS #54) 42.4ms
✓
emails_sent_set_input.opened_at back (revoked by 196): exits 1, names it and why (DECISIONS #54) 43.5ms
✓
emails_sent_set_input.clicked_at back (revoked by 196): exits 1, names it and why (DECISIONS #54) 47.8ms
✓
emails_sent_set_input.replied_at back (revoked by 196): exits 1, names it and why (DECISIONS #54) 41.5ms
✓
emails_sent_set_input.channel back (revoked by 196): exits 1, names it and why (DECISIONS #54) 43.6ms
✓
emails_sent_set_input.error_message back (revoked by 196): exits 1, names it and why (DECISIONS #54) 43.2ms
3. a user-role write nobody declared fails, whatever it is called · 18 tests
✓
a table custom_name (insert_sharedLeadListItem): exits 1 and names each root as undeclared 43.2ms
✓
a custom root field (addSharedLeadListItem): exits 1 and names each root as undeclared 43.9ms
✓
a tracked corpus function on mutation_root: exits 1 and names each root as undeclared 41.2ms
✓
the selection-owner function exposed to the user role: exits 1 and names each root as undeclared 43.4ms
✓
a new grant on a table nobody declared: exits 1 and names each root as undeclared 43.1ms
✓
an insert input for a table nobody declared, with no root and no document (a reveal ledger): exits 1 41.9ms
✓
a set input alone, for a table whose UPDATE nobody holds (the corpus list item): exits 1 42.6ms
✓
an insert input for a table that is neither declared nor forbidden, with no root: exits 1 as undeclared 42.7ms
✓
a set input for a declared table whose UPDATE is not declared (contact_list_memberships is insert/delete only): exits 1 as undeclared 42.9ms
✓
a nested-insert input type for an undeclared table (contact_lists gains shared_lead_list_items): exits 1 on the type Hasura generates with it 42.5ms
✓
CONTROL: a new write that IS declared in user_writable passes — the rule is "declared", not "frozen" 853.8ms
✓
a declaration cannot launder a forbidden write: user_writable declaring templates INSERT fails, with or without the grant 90.8ms
✓
a declaration the user role no longer holds fails: it would let a re-grant of that write pass 43.0ms
✓
without the user_writable declaration the guard refuses to run blind (exit 2), never passes 40.0ms
✓
CONTROL: a function root declared in USER_ROLE_EXTRA_WRITE_ROOTS, with its reason, passes 827.0ms
✓
an extra-root allowance whose root is gone fails as stale 44.0ms
✓
an extra-root allowance cannot cover a forbidden root 45.5ms
✓
a snapshot that lost the user role's mutation roots is a blind guard (exit 2), not a list of stale declarations 40.7ms
src/runtime/tool-outcomes.vitest.ts
isExpectedToolOutcome — recurring Sentry noise is suppressed · 37 tests
✓
suppresses: Campaign name required 2.1ms
✓
suppresses: Insufficient token balance for on-page audit 0.8ms
✓
suppresses: No contacts found in list(s): new. No contact 1.0ms
✓
suppresses: No contacts found in list(s): test. Available 0.5ms
✓
suppresses: flexifunnels.com is your own site, not a comp 0.7ms
✓
suppresses: No product brief set. Run scan_product with y 0.5ms
✓
suppresses: Which site? Tell me the domain (or set your s 0.2ms
✓
suppresses: found 0 results 0.3ms
✓
suppresses: generated 0 drafts 0.5ms
✓
suppresses: sent 0 of total 0.2ms
✓
suppresses: No contacts found 0.2ms
✓
suppresses: Unknown connector "instagram". Available: sla 0.1ms
✓
suppresses: tool scan_product: Failed to fetch URL: HTTP 0.2ms
✓
suppresses: Failed to fetch URL: Invalid URL: www.pointto 0.2ms
✓
suppresses: tool scan_product: Failed to fetch URL: Fetch 0.1ms
✓
suppresses: tool send_emails: Too many at once (7). Send 0.1ms
✓
suppresses: tool send_emails: You have no drafts waiting 0.1ms
✓
suppresses: tool seo_onpage_audit: The SEO data provider 0.4ms
✓
suppresses: tool send_emails: sent 0 of total 0.1ms
✓
suppresses: tool send_emails: Those email ids aren't vali 0.1ms
✓
suppresses: tool send_emails: No draft emails to send. Ge 0.1ms
✓
suppresses: tool seo_keywords: Which topic or keyword sho 0.5ms
✓
suppresses: tool seo_geo_visibility: No site set. Add you 0.3ms
✓
suppresses: tool aeo_page_check: Give me the URL to audit 0.3ms
✓
suppresses: tool seo_keywords: No keywords to enrich. Add 0.6ms
✓
suppresses: tool seo_keywords: None of those look like ke 0.4ms
✓
suppresses: tool seo_google_merge: No GA4 property found 0.3ms
✓
suppresses: tool seo_gtm: No Google Tag Manager accounts 0.2ms
✓
suppresses: tool seo_redirect_fix: No Cloudflare zone fou 0.1ms
✓
suppresses: tool seo_pagespeed: No CrUX field data for ht 0.1ms
✓
suppresses: tool seo_onpage_status: No on-page crawl is i 0.2ms
✓
suppresses: tool fix_dns: No safe auto-fixable DNS issues 0.2ms
✓
suppresses: tool set_standing_instruction: A standing ins 0.8ms
✓
suppresses: tool create_report: A report title is require 0.3ms
✓
suppresses: tool assign_contacts: No campaign specified. 0.2ms
✓
suppresses: tool gsc_inspect: No URLs to inspect — the si 0.1ms
✓
null/empty is not reportable 0.1ms
isExpectedToolOutcome — genuine faults still reach Sentry · 9 tests
✓
reports: apify trigger HTTP 400 0.5ms
✓
reports: Mixpanel export HTTP 500 0.4ms
✓
reports: unexpected response shape from provider 0.1ms
✓
reports: DFS_TASK_TIMEOUT 0.1ms
✓
reports: Cannot read properties of undefined (rea 0.1ms
✓
reports: Failed to render the Product panel: Type 0.1ms
✓
reports: GA4 property lookup failed: HTTP 503 fro 0.1ms
✓
reports: Cloudflare zone lookup returned malforme 0.1ms
✓
reports: on-page crawl is in progress but the sta 0.1ms
recurring expected outcomes (2026-08-01 sweep) · 8 tests
✓
treats I couldn't find a list called "this-list-does-not-exist-xyz". Your lists are: AI brand mentions founders, … as expected, not a fault 0.1ms
✓
treats I can only draft and send to your saved contacts, and [email] isn't one yet — so I've not queued anything. Add them as a contact, then ask me to draft. as expected, not a fault 0.2ms
✓
treats None of those contacts are confirmed deliverable. Drop that condition, or pick a different list. as expected, not a fault 0.1ms
✓
treats No email provider is connected yet, so nothing was sent. Add your sending credentials once in the Connectors panel — your 31 drafts are saved and untouched. as expected, not a fault 0.1ms
✓
still reports the genuine fault: Database query error: field 'enriched_source' not found in type: 'contacts_set_input' 0.1ms
✓
still reports the genuine fault: APIFY_BACKLINKS_ERROR_400 0.1ms
✓
still reports the genuine fault: tool 'seo_serp_spider' timed out after 120000ms 0.1ms
✓
still reports the genuine fault: report contract violation (campaign_stats): funnel.opened=1 exceeds sent=0 0.1ms
a tool asking the user a question is blocked, never failed · 3 tests
✓
recognises the search_leads missing-argument refusal by its marker 0.2ms
✓
would NOT have caught that wording by prose alone — which is why the marker exists 0.1ms
✓
does not let the marker whitewash a genuine fault 0.2ms
the clarify refusals across the tool surface carry markers · 5 tests
✓
blocks, not fails: { needs_clarification: true, error: 'Which site? Tell me the domain (or set your site URL in the Product panel).' } 0.1ms
✓
blocks, not fails: { needs_clarification: true, error: 'What should the standing instruction be?' } 0.1ms
✓
blocks, not fails: { needs_clarification: true, error: 'What message should I post to Slack?' } 0.1ms
✓
blocks, not fails: { needs_clarification: true, error: 'Which topic or keyword should I find ideas for? Give me a short search term — for example "ai seo tools".' } 0.1ms
✓
blocks, not fails: { needs_clarification: true, error: 'What should I write about? Give me a topic/keyword, or a URL to rewrite.' } 0.1ms
an error KEY is not an error VALUE · 6 tests
✓
does NOT call a successful search failed just because the key exists 0.2ms
✓
does NOT call an honest zero-result search failed either 0.1ms
✓
still recognises a real failure 0.1ms
✓
treats an EMPTY-STRING error as a real failure, not a success 0.1ms
✓
ignores non-objects rather than guessing 0.1ms
✓
regression: the OLD predicate called every search a failure 0.2ms
expected outcomes found in the 2026-08-25 telemetry sweep · 11 tests
✓
treats as expected: read_url own-site internal directive (15 events, largest family) 0.4ms
✓
treats as expected: rag_readiness honest empty on a thin/client-rendered page (11 events) 0.1ms
✓
treats as expected: pause_campaign named a campaign that does not exist 0.1ms
✓
treats as expected: resume_campaign, same class 0.1ms
✓
treats as expected: enroll_in_sequence named a list that does not exist or is empty 0.1ms
✓
treats as expected: a third-party site refused us with HTTP 403 0.2ms
✓
treats as expected: a third-party page could not be read 0.1ms
✓
treats as expected: a run that dropped an unrecognized engine and PROCEEDED anyway 0.1ms
✓
treats as expected: a crawl that reached the host and returned zero pages 0.2ms
✓
treats as expected: the same, after JS rendering had already been tried 0.1ms
✓
treats as expected: the pre-v2.565.0 phrasing still resolving from held jobs 0.1ms
genuine faults from the same window still report · 8 tests
✓
still reports: a hallucinated tool name reaching the dispatch default 0.1ms
✓
still reports: an unresolved hallucinated name with no canonical target 0.1ms
✓
still reports: a plan that failed while persisting 0.1ms
✓
still reports: a drafting step that genuinely failed — the copy says so 0.1ms
✓
still reports: a raw TypeError surfacing through a tool result 0.3ms
✓
still reports: the zero-yield breaker tripping 0.1ms
✓
still reports: a provider 502 0.1ms
✓
still reports: a provider 400 0.1ms
src/tools/contract-gaps.vitest.ts
list_contacts — the silently-partial answer · 5 tests
✓
declares `all`, the opt-out that had no way to be expressed 2.4ms
✓
declares `campaign`, so a named campaign can be asked for directly 0.3ms
✓
still accepts the two it always had 0.3ms
✓
says in its own rules why `all` matters 0.8ms
✓
rejects an off-schema field rather than ignoring it 0.3ms
send_emails — channel stays OUT while the feature is off · 8 tests
✓
does not declare channel — a dormant capability is not part of the contract 0.2ms
✓
rejects channel if the model tries it anyway 0.4ms
✓
says nothing about Gmail in the model-facing copy 0.5ms
✓
keeps the two-step confirm contract declarable 0.6ms
✓
rejects a fabricated draft id shape 0.3ms
✓
still states that confirm is never self-granted 0.3ms
✓
the model-facing text never tells the model to call confirm:true itself 0.4ms
✓
the system prompt no longer calls another two-step gate "exactly like send_emails" 59.6ms
enrich_contacts — the single-list ceiling · 2 tests
✓
declares `list_names`, which the dispatch already preferred 0.2ms
✓
still accepts the singular and specific contacts 0.4ms
every schematised tool holds the same line · 70 tests
✓
every one is registered 0.9ms
✓
seo_backlink_gap rejects unknown fields and names no vendor or USD price 0.4ms
✓
seo_backlink_verify rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_backlink_deep_scan rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_backlink_value rejects unknown fields and names no vendor or USD price 0.2ms
✓
search_leads rejects unknown fields and names no vendor or USD price 0.3ms
✓
seo_keywords rejects unknown fields and names no vendor or USD price 0.2ms
✓
aeo_visibility rejects unknown fields and names no vendor or USD price 0.2ms
✓
generate_emails rejects unknown fields and names no vendor or USD price 0.2ms
✓
list_contacts rejects unknown fields and names no vendor or USD price 0.2ms
✓
send_emails rejects unknown fields and names no vendor or USD price 0.3ms
✓
enrich_contacts rejects unknown fields and names no vendor or USD price 0.2ms
✓
verify_contacts rejects unknown fields and names no vendor or USD price 0.2ms
✓
assign_to_campaign rejects unknown fields and names no vendor or USD price 0.2ms
✓
enroll_in_sequence rejects unknown fields and names no vendor or USD price 0.2ms
✓
set_campaign_sequence rejects unknown fields and names no vendor or USD price 0.2ms
✓
pause_campaign rejects unknown fields and names no vendor or USD price 0.2ms
✓
resume_campaign rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_geo_research rejects unknown fields and names no vendor or USD price 0.2ms
✓
diagnose rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_list_keywords rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_keyword_metrics rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_enrich_keywords rejects unknown fields and names no vendor or USD price 0.3ms
✓
find_competitors rejects unknown fields and names no vendor or USD price 1.4ms
✓
seo_competitor_gap rejects unknown fields and names no vendor or USD price 0.3ms
✓
seo_content_ideas rejects unknown fields and names no vendor or USD price 0.3ms
✓
seo_content_brief rejects unknown fields and names no vendor or USD price 0.3ms
✓
seo_write_content rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_onpage_audit rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_offpage_audit rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_backlinks rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_serp_spider rejects unknown fields and names no vendor or USD price 0.2ms
✓
entity_audit rejects unknown fields and names no vendor or USD price 0.3ms
✓
aeo_page_check rejects unknown fields and names no vendor or USD price 0.2ms
✓
aeo_full_audit rejects unknown fields and names no vendor or USD price 0.2ms
✓
sov_trend rejects unknown fields and names no vendor or USD price 0.2ms
✓
panel_segments rejects unknown fields and names no vendor or USD price 0.1ms
✓
tap_volume rejects unknown fields and names no vendor or USD price 0.1ms
✓
add_contacts rejects unknown fields and names no vendor or USD price 0.2ms
✓
list_sent_emails rejects unknown fields and names no vendor or USD price 2.5ms
✓
start_sequence rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_generate_llms_txt rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_request_indexing rejects unknown fields and names no vendor or USD price 0.2ms
✓
seo_monitor rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_rank_track rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_content_quality rejects unknown fields and names no vendor or USD price 0.1ms
✓
seo_google_merge rejects unknown fields and names no vendor or USD price 0.1ms
✓
domain_email_readiness_audit rejects unknown fields and names no vendor or USD price 0.1ms
✓
cloudflare_fix_email_dns rejects unknown fields and names no vendor or USD price 0.2ms
✓
generate_dns_fix_prompt rejects unknown fields and names no vendor or USD price 0.1ms
✓
list_campaigns rejects unknown fields and names no vendor or USD price 0.1ms
✓
list_sequences rejects unknown fields and names no vendor or USD price 0.1ms
✓
list_connectors rejects unknown fields and names no vendor or USD price 0.1ms
✓
show_marketing_plan rejects unknown fields and names no vendor or USD price 0.1ms
✓
create_campaign rejects unknown fields and names no vendor or USD price 0.1ms
✓
campaign_stats rejects unknown fields and names no vendor or USD price 0.2ms
✓
create_sequence rejects unknown fields and names no vendor or USD price 0.1ms
✓
connect_connector rejects unknown fields and names no vendor or USD price 0.1ms
✓
set_standing_instruction rejects unknown fields and names no vendor or USD price 0.1ms
✓
scan_product rejects unknown fields and names no vendor or USD price 0.1ms
✓
backlink_outreach_search rejects unknown fields and names no vendor or USD price 0.1ms
✓
create_marketing_plan rejects unknown fields and names no vendor or USD price 0.1ms
✓
propose_outbound_run rejects unknown fields and names no vendor or USD price 0.2ms
✓
web_search rejects unknown fields and names no vendor or USD price 0.2ms
✓
read_url rejects unknown fields and names no vendor or USD price 0.1ms
✓
define_icp rejects unknown fields and names no vendor or USD price 0.1ms
✓
get_usage_breakdown rejects unknown fields and names no vendor or USD price 0.1ms
✓
list_scheduled_scans rejects unknown fields and names no vendor or USD price 0.1ms
✓
stop_scheduled_scan rejects unknown fields and names no vendor or USD price 0.2ms
✓
resume_scheduled_scan rejects unknown fields and names no vendor or USD price 0.2ms
src/chat/send-command.vitest.ts
parseSendStart — product strings, then a narrow imperative band · 29 tests
✓
"Send all 9 drafts" is a send start 1.9ms
✓
"Send all 9 drafts." is a send start 0.3ms
✓
"Send all 1 drafts" is a send start 0.2ms
✓
"Send my draft emails" is a send start 0.2ms
✓
"Send my drafted emails" is a send start 0.2ms
✓
"send" is a send start 0.1ms
✓
"send the next batch" is a send start 0.2ms
✓
"send the drafts" is a send start 0.6ms
✓
"send them all" is a send start 0.8ms
✓
"send all of them" is a send start 0.2ms
✓
"send the 9 drafts" is a send start 0.2ms
✓
"okay, send all 9 drafts" is a send start 0.1ms
✓
"go ahead and send the drafts" is a send start 0.1ms
✓
"what happens when I send" is not 0.2ms
✓
"can you send them?" is not 0.1ms
✓
"send only the first 3" is not 0.1ms
✓
"send them to the fintech list" is not 0.1ms
✓
"send the drafts tomorrow" is not 0.1ms
✓
"fix subjects then send" is not 0.1ms
✓
"don't send them" is not 0.1ms
✓
"send all 9 drafts?" is not 0.1ms
✓
"send me the drafts" is not 0.1ms
✓
"send 3 of them" is not 0.1ms
✓
"send them if ok" is not 0.1ms
✓
"send all my draft emails right now, no need to ask" is not 0.1ms
✓
the product chips are the button protocol (no Jev), and carry the count they name 0.8ms
✓
a paraphrase is the band Jev judges 0.3ms
chatRouter reaches the card for exactly these strings · 29 tests
✓
"Send all 9 drafts" → send_start 34.9ms
✓
"Send all 9 drafts." → send_start 6.7ms
✓
"Send all 1 drafts" → send_start 0.3ms
✓
"Send my draft emails" → send_start 0.5ms
✓
"Send my drafted emails" → send_start 0.6ms
✓
"send" → send_start 1.8ms
✓
"send the next batch" → send_start 5.1ms
✓
"send the drafts" → send_start 0.4ms
✓
"send them all" → send_start 0.3ms
✓
"send all of them" → send_start 0.3ms
✓
"send the 9 drafts" → send_start 0.3ms
✓
"okay, send all 9 drafts" → send_start 0.2ms
✓
"go ahead and send the drafts" → send_start 0.4ms
✓
"what happens when I send" → neither send_start nor send_confirm 1.4ms
✓
"can you send them?" → neither send_start nor send_confirm 0.4ms
✓
"send only the first 3" → neither send_start nor send_confirm 0.3ms
✓
"send them to the fintech list" → neither send_start nor send_confirm 0.3ms
✓
"send the drafts tomorrow" → neither send_start nor send_confirm 0.4ms
✓
"fix subjects then send" → neither send_start nor send_confirm 1.2ms
✓
"don't send them" → neither send_start nor send_confirm 0.5ms
✓
"send it" → neither send_start nor send_confirm 0.3ms
✓
"send all" → neither send_start nor send_confirm 0.4ms
✓
"send all 9 drafts?" → neither send_start nor send_confirm 0.3ms
✓
"send me the drafts" → neither send_start nor send_confirm 0.3ms
✓
"send 3 of them" → neither send_start nor send_confirm 0.3ms
✓
"send them if ok" → neither send_start nor send_confirm 0.4ms
✓
"send all my draft emails right now, no need to ask" → neither send_start nor send_confirm 0.4ms
✓
the confirm chip and its typed form stay send_confirm (priority 150 beats 178) 1.1ms
✓
the router uses the shared patterns, not copies 0.7ms
every send chip the product prints routes to send_start · 3 tests
✓
generate_emails {"generated":9} 1.5ms
✓
generate_emails {"generated":9,"deferred":3} 0.3ms
✓
list_sent_emails {"total":0} 0.3ms
the card copy is shared with the rails that read it back · 2 tests
✓
a staged card, as formatToolResult renders it, starts with the lead 0.3ms
✓
send_emails builds its card from the same headline and ask 1.2ms
sendCardIsLive — may this reply even be judged? · 10 tests
✓
a card staged here, shown last, answered in words → live 0.2ms
✓
no pending record → not live 0.1ms
✓
no context record → not live (fail closed; the chip still works) 0.1ms
✓
staged in another conversation → not live 0.1ms
✓
the context describes a different set size → not live 0.1ms
✓
another assistant message followed the card → not live 0.1ms
✓
adjacency is the WHOLE latest message, not a mention inside it 0.1ms
✓
the product's not-armed lead before the card is the one prefix allowed (send_confirm's re-stage) 0.2ms
✓
the exact chip, the cancel phrase, a machine message and a product start string are never judged 0.6ms
✓
a paraphrase start IS judged against the live card (it answers it) 0.2ms
sendCardIsLive — imitation of the card is not the card · 6 tests
✓
the card send_emails rendered for this record → live 0.3ms
✓
prose opening "Ready to send 3 emails" over a 9-email record → not live, whatever the reply 0.3ms
✓
the right count and the card's own ask, without the card → not live 0.1ms
✓
the card with one row changed → not live 0.1ms
✓
the card with anything appended → not live 0.1ms
✓
a fingerprint differs on any change of text, and not otherwise 0.5ms
sendConfirmArmed — the exact chip · 5 tests
✓
sends what was staged in this conversation 0.3ms
✓
re-stages a card from another conversation instead of sending it 0.2ms
✓
tolerates a missing context record (records staged before it existed) 0.2ms
✓
nothing pending → nothing armed 0.2ms
✓
the cancel pattern is the exact phrase only 0.2ms
src/seo/brand-boilerplate.vitest.ts
the live incident · 2 tests
✓
rejects the exact page that produced it 2.4ms
✓
rejects the string itself wherever it is declared 0.9ms
boilerplate the crawler will meet · 42 tests
✓
rejects "Loading..." 0.3ms
✓
rejects "Just a moment..." 0.2ms
✓
rejects "One moment" 0.2ms
✓
rejects "Redirecting…" 0.3ms
✓
rejects "Please wait" 0.3ms
✓
rejects "Checking your browser before accessing" 0.6ms
✓
rejects "Attention Required! | Cloudflare" 0.2ms
✓
rejects "Verifying you are human" 0.2ms
✓
rejects "Access Denied" 0.2ms
✓
rejects "Forbidden" 0.1ms
✓
rejects "403 Forbidden" 0.2ms
✓
rejects "404 Page Not Found" 0.1ms
✓
rejects "Not Found" 0.1ms
✓
rejects "Site Maintenance" 0.2ms
✓
rejects "Under Construction" 0.1ms
✓
rejects "Coming Soon" 0.2ms
✓
rejects "Please enable JavaScript" 0.1ms
✓
rejects "JavaScript is required" 0.1ms
✓
rejects "You need to enable JavaScript to run this app" 0.1ms
✓
rejects "React App" 0.3ms
✓
rejects "Vite + React" 0.2ms
✓
rejects "Web site created using create-react-app" 0.2ms
✓
rejects "Untitled" 0.1ms
✓
rejects "Untitled Document" 0.1ms
✓
rejects "Document" 0.1ms
✓
rejects "New Page" 0.2ms
✓
rejects "Default Web Site Page" 0.1ms
✓
rejects "Homepage" 0.1ms
✓
rejects "index.html" 0.1ms
✓
rejects "My Website" 0.2ms
✓
rejects "Domain for sale" 0.1ms
✓
rejects "This domain is parked" 0.1ms
real brands that merely CONTAIN those words · 29 tests
✓
keeps "Home Depot" 0.3ms
✓
keeps "Welcome Pickups" 0.2ms
✓
keeps "Error Solutions Ltd" 0.1ms
✓
keeps "Loading Dock Equipment Co" 0.1ms
✓
keeps "Documental" 0.1ms
✓
keeps "Document Crunch" 0.1ms
✓
keeps "Website Toolbox" 0.1ms
✓
keeps "Indexed Finance" 0.1ms
✓
keeps "Index Ventures" 0.1ms
✓
keeps "Moment Energy" 0.1ms
✓
keeps "Wait Less Health" 0.1ms
✓
keeps "Access Softek" 0.1ms
✓
keeps "Denied Claims Recovery" 0.1ms
✓
keeps "Maintenance Connection" 0.1ms
✓
keeps "Construction Junction" 0.1ms
✓
keeps "Soon Technologies" 0.1ms
✓
keeps "JavaScript Mastery" 0.1ms
✓
keeps "Untitled Art" 0.1ms
✓
keeps "Coming of Age Media" 0.1ms
✓
keeps "Forbidden Root Brewery" 0.1ms
✓
keeps "The 404 Agency" 0.1ms
✓
keeps "Reactive Apps Inc" 0.1ms
the ladder falls through instead of giving up · 5 tests
✓
takes og:site_name when the JSON-LD org name is boilerplate 0.2ms
✓
takes the WebSite name when both stronger tiers are boilerplate 0.2ms
✓
takes the good half of a mixed title 0.2ms
✓
scans past a boilerplate Organization to a real one 0.2ms
✓
returns null only when EVERY tier is boilerplate 0.2ms
unchanged behaviour for ordinary sites · 3 tests
✓
still prefers Organization JSON-LD 0.3ms
✓
still prefers the shorter title segment as the brand 0.2ms
✓
still returns null on a page that declares nothing 0.2ms
src/admin/readiness-gates.vitest.ts
1. wilson95 · 2 tests
✓
24/30 → lo 0.6269; 25/30 → lo 0.6644 (4 places) 2.4ms
✓
n ≤ 0 knows nothing: {lo 0, hi 1} 1.1ms
2. the Wilson threshold rule · 3 tests
✓
24/30 is FAIL-measured: the point 0.80 meets the threshold, the lower bound is what fails 1.7ms
✓
n = 29 is FAIL-unmeasurable with a traffic unlock first 0.7ms
3. null never passes · 2 tests
✓
a null measure, a null value, a null num or a null den → FAIL-unmeasurable, even when the rest would pass 0.7ms
✓
the catalogue unlock is kept on a missing figure 0.4ms
4. stale never passes · 3 tests
✓
a prod snapshot 27 h old with passing numbers → snapshot_stale; 25 h old → PASS 0.7ms
✓
a production recon seed with passing numbers → seed_never_fresh, instrument unlock prepended 0.8ms
✓
freshnessOf: prod ≤ 26 h, static by sha or ≤ 1 day, register ≤ 7 days, live always, recon_seed never 0.9ms
5. an unratified map never passes · 5 tests
✓
passing numbers on an unratified map → map_unratified with an owner_decision unlock 0.5ms
✓
failing on P_real with no widest figure → FAIL-unmeasurable 0.3ms
✓
failing with widest 0/135 on P_candidate → FAIL-measured (fail_on_widest) 0.4ms
✓
a stale widest figure cannot make a fail measured 0.2ms
✓
a figure with no population needs the map too 0.2ms
6. ungraduated input never passes · 3 tests
✓
jev [{status: shadow}] with passing numbers → jev_ungraduated with an owner_labels unlock 0.4ms
✓
basis jev_shadow with failing numbers → basis_not_fact, not FAIL-measured 0.3ms
✓
basis jev_shadow with passing numbers and no jev list still cannot pass 0.3ms
7. G1 bounds · 12 tests
✓
point 25/30 passes but the worst case 18/30 has lb < 0.65 → g1_worst_case 0.4ms
✓
a missing worst case never meets the bound 0.2ms
✓
point and worst case both clear → PASS 0.2ms
✓
best case 20/30 (0.667 < 0.80, n 30) → FAIL-measured 0.3ms
✓
point fails but the best case passes → g1_best_case_passes 0.2ms
✓
a best case below n 30 cannot make the fail measured 0.2ms
✓
a stale or recon-seed worst case never backs a PASS → g1_worst_case 0.4ms
✓
a worst case below n 30 never backs a PASS, whatever its lower bound 0.3ms
✓
a failing best case alone → map_unratified, not FAIL-measured 0.3ms
✓
a failing best case plus a fresh widest figure below 0.80 at n ≥ 30 → FAIL-measured (fail_on_widest) 0.2ms
✓
a widest figure that meets 0.80, is stale, or is below n 30 cannot make it measured 0.4ms
✓
a best case that passes still reads g1_best_case_passes, map or no map 0.3ms
8. S2 — a stale static figure, both branches · 5 tests
✓
fails, scope_changed false → FAIL-measured (the census still describes the code) 0.3ms
✓
fails, scope_changed true → static_stale_scope_changed with a re-census unlock 0.3ms
✓
fails, scope_changed null → static_stale_scope_unknown with a re-census unlock 0.3ms
✓
stale and passing → static_stale_passing 0.2ms
✓
a static source whose sha is the live build and that fails → FAIL-measured 0.4ms
9. combineGate · 2 tests
✓
FAIL-measured beats FAIL-unmeasurable beats PASS, in any order 0.4ms
✓
zero subs never pass 0.2ms
10. verdicts · 10 tests
✓
all PASS, 0 blocking, register source, register 6 days old → READY on both 0.5ms
✓
one unrated finding → NOT READY 0.3ms
✓
a fixed-unverified finding rated critical counts in open_critical_high → NOT READY 0.3ms
✓
fixed-verified and decided-freeze do not count 0.3ms
✓
register 8 days old → NOT READY 0.2ms
✓
source seed → NOT READY regardless of age 0.2ms
✓
scoreFixture: a seed register's freshness is 'never' whatever its age; a real register ages normally 2.1ms
✓
a covered gate that is not PASS → NOT READY, and the reason names it 0.3ms
✓
a missing gate is never PASS 0.2ms
✓
READY is reachable end to end through scoreFixture 0.5ms
11. G8(a) — this response carries every required field · 8 tests
✓
a complete fixture → PASS 3.0ms
✓
removing the population from one figure → FAIL-measured, with that id in failing_ids 0.6ms
✓
0 figures → FAIL-unmeasurable 0.5ms
✓
a P_code figure with a sha and no band or window is complete 0.3ms
✓
a production figure with no band is incomplete 0.1ms
✓
a ratio figure with a value and no den is incomplete; a count needs num === value 0.3ms
✓
G8(a)'s own figure is not counted, even when the input carries an incomplete one 0.8ms
✓
g8aCompleteness over no figures is 0 of 0 0.2ms
12. checkInvariants · 3 tests
✓
a FAIL-unmeasurable sub with empty unlocks is a violation 0.2ms
✓
a malformed unlock is a violation 0.6ms
✓
the committed catalogue and seed hold every invariant 1.8ms
13. seed pin — the catalogue scored against the recon seed is exactly spec §4.1 · 5 tests
✓
26 subs in catalogue order: 25 FAIL-unmeasurable with the listed reasons, G8(a) PASS on complete provenance 1.0ms
✓
G1–G8 FAIL-unmeasurable, both verdicts NOT READY, 33 unrated from the seed 0.6ms
✓
G8(a) over the seed alone reads 0 missing: the three G3(e) figures declare where they came from 0.5ms
✓
the G1 unlocks, in order: instrument, owner_labels, owner_decision, traffic 0.2ms
✓
the same seed scores identically whatever the live build (a recon seed is never fresh) 0.7ms
14. source text — the engine loads under Node type stripping with no build step · 8 tests
✓
no-import rule: readiness-gates.ts must not import anything (the script loads it natively) 0.3ms
✓
no-import rule: readiness-gates.ts must not re-export from another module 0.2ms
✓
no-import rule: readiness-gates.ts must not require() 0.2ms
✓
erasable-syntax rule: no enum in readiness-gates.ts 0.2ms
✓
erasable-syntax rule: no namespace in readiness-gates.ts 0.1ms
✓
no-clock rule: readiness-gates.ts must not read Date.now() — pass `now` in 0.1ms
✓
no-clock rule: readiness-gates.ts must not call new Date() with no argument — pass `now` in 0.1ms
✓
type-only-import rule: readiness-seed.ts imports nothing but types 0.6ms
5b. a map counts as ratified only by a dated owner ratification · 3 tests
✓
mapRatifiedBy: a past ISO timestamp ratifies; null, junk or a future time does not 0.2ms
✓
subInputsFromSeed carries the ratification to every sub, and defaults to unratified 0.2ms
✓
a failing P_real figure on a RATIFIED map is FAIL-measured on its facts, not map_unratified 0.2ms
src/reports/marketing-plan-report.vitest.ts
create_marketing_plan report · 25 tests
✓
renders the checklist with statuses, effort, token-only costs, and Execute chips 3.1ms
✓
explains a non-executable PROPOSED item in plain language, never a validator message 0.6ms
✓
renders the measurement contract honestly: measuring line vs non-learning notice 0.4ms
✓
renders strategy thesis + hypotheses with live status 0.7ms
✓
renders the SCR-labeled diagnosis: Situation, Complication, Resolution 0.4ms
✓
Complication states plainly when no blocker was found, never a blank section 0.3ms
✓
show_marketing_plan reuses the renderer and adds the Recommendations section 0.5ms
✓
returns null for errors and empty plans 0.2ms
✓
forensic contract: cap and status vocabulary hold on the fixture, and violations are caught 1.9ms
✓
forensic contract: plan_score stays in range, delta recomputes, no stray baseline on unmeasurable work 0.6ms
✓
groups initiatives under their named Growth Bet (US2) 0.6ms
✓
renders three named execution horizon sections when initiatives carry a horizon (US4) 0.4ms
✓
falls back to the flat/measurable-split layout when no initiative carries a horizon (FR-015) 0.3ms
✓
renders Impact/Feasibility badges when present, falls back to Effort otherwise (US3, FR-015) 4.1ms
✓
the cost chip and Effort fallback share the rating badge's slim geometry, not the bulkier chip-tag 0.3ms
✓
Execute is the primary CTA (brand green modifier); Dismiss stays secondary/ghost 0.2ms
✓
renders Value-at-Stake as an explicitly unverified, visually distinct benchmark (US5) 0.2ms
✓
renders a pre-feature plan (no new fields at all) completely and without error 0.4ms
✓
forensic contract: prior-session fixtures (plan_score, bare fixture) still pass cleanly 0.4ms
✓
forensic contract: bet count outside [3,5] on a >=5-initiative plan is caught 0.3ms
✓
forensic contract: an invalid horizon value is caught 0.2ms
✓
forensic contract: the hard-blocker item must be horizon=foundation 0.3ms
✓
forensic contract: value_at_stake without unverified:true is caught 0.2ms
✓
forensic contract: value_at_stake coexisting with a real measurement is caught 2.9ms
✓
forensic contract: a numeric (non-enum) impact/feasibility rating is caught 0.2ms
create_marketing_plan — execution integrity (specs/013 US1) · 4 tests
✓
renders a manual step as a deliberate item, not a degraded one 0.3ms
✓
never renders internal vocabulary — the exact strings that shipped in the fixtures 0.4ms
✓
an executable item still gets its Execute affordance 0.2ms
✓
renders a pre-013 plan (no execution_mode at all) exactly as before — FR-025 0.3ms
create_marketing_plan — forensic contract (specs/013 US1) · 4 tests
✓
fails a plan whose copy carries a validator message 0.3ms
✓
fails an item that claims to be executable with nothing to execute 0.2ms
✓
fails a third execution state — FR-003 admits exactly two 0.2ms
✓
passes a well-formed plan carrying both modes 0.2ms
show_marketing_plan — progress markers (specs/013 surface 2) · 5 tests
✓
shows work done and time spent together — the pairing the panel lacked 13.8ms
✓
names the next measurement date instead of leaving the user to guess 0.4ms
✓
states plainly when nothing has been re-measured yet 0.3ms
✓
names a stalled plan outright rather than rendering a quiet 0% 0.4ms
✓
renders no progress strip for a plan with no progress data — FR-025 0.3ms
show_marketing_plan — the ledger still holds pre-013 leaks (specs/013 surface 2) · 1 test
✓
never renders a legacy validator message read back out of the DB 0.3ms
show_marketing_plan — lineage across re-plans (specs/013 Option A) · 3 tests
✓
tells the user their earlier progress survived the re-plan 0.3ms
✓
stays silent on a first plan — lineage on plan 1 would be noise 0.4ms
✓
singularises correctly — one day, one item 0.4ms
marketing plan — organised by directive (specs/013 US10) · 5 tests
✓
renders all four classes in fixed order — Fix, Try, Understand, Expect 0.7ms
✓
an empty class states its own absence rather than vanishing (FR-030) 0.3ms
✓
never invents a Predictive item — the class is gated until audit Q3 0.5ms
✓
keeps 005 horizons and Growth Bets nested INSIDE a directive, not replaced (FR-026) 0.9ms
✓
a pre-013 plan with no directive on any row renders exactly as before (FR-025) 0.4ms
marketing plan — directive forensic contract (specs/013 US10) · 5 tests
✓
fails a corrective item resting on nothing measurable — FR-031 0.4ms
✓
fails a generated Predictive item — gated until audit Q3 (RULING-2) 0.2ms
✓
fails a PARTIALLY classified plan — rows without a directive fall out of every group 0.2ms
✓
fails an unknown directive value 0.2ms
✓
passes an all-unclassified pre-013 plan and a fully-classified one alike 0.2ms
marketing plan — leads with a judgement (specs/013 US4) · 2 tests
✓
leads with the finding, and demotes the objective below it 0.3ms
✓
falls back to the old inventory line rather than fabricating a finding (GS-009) 0.2ms
marketing plan — the complication is theirs, not ours (specs/013 US5) · 3 tests
✓
keeps capability-unlock copy OUT of the Complication 0.4ms
✓
each gap carries the action that resolves it 0.2ms
✓
renders no gaps block at all on a pre-013 plan (FR-025) 0.2ms
marketing plan — never instructs a rebuild (specs/013 US7) · 1 test
✓
states the grounding gap as a finding, with no instruction to pay again 0.4ms
marketing plan — the invisible moat, said out loud (specs/013 US8) · 5 tests
✓
states how many dismissed actions were excluded — a chatbot cannot do this 0.3ms
✓
singularises, and stays silent when nothing was excluded 0.3ms
✓
explains what the plan score measures 0.2ms
✓
a day-0 plan says FIRST BASELINE, never "unchanged 0 points" 0.4ms
✓
still reports a REAL zero-change once something has been re-measured 0.2ms
show_marketing_plan — the shell is hydrated on EVERY surface (GS-005) · 4 tests
✓
the builder still emits placeholders — they are filled downstream, by design 0.2ms
✓
artifact mode fills title, timestamp and id 0.7ms
✓
live mode does NOT claim to be a saved artifact 5.1ms
✓
render integrity flags an unhydrated shell, so no future surface can ship one silently 1.7ms
show_marketing_plan — one population per number (the 9 / 6 / 13 screen) · 5 tests
✓
the header counts the PLAN, and says so 0.2ms
✓
the header count reconciles with the progress denominator 0.2ms
✓
orphan recommendations are counted separately, not folded in or dropped 0.1ms
✓
no "Suggested" tile when there are none — a zero tile is a slot filled to look complete 0.2ms
✓
singular reads as English 0.2ms
src/chat/misroute-guard.vitest.ts
isDiagnosticQuestion · 22 tests
✓
recognises "why is my AI visibility down?" 2.5ms
✓
recognises "why am I not getting any replies?" 0.8ms
✓
recognises "why is my traffic dropping" 0.2ms
✓
recognises "what is holding my site back" 0.2ms
✓
recognises "did anything change with my rankings" 0.2ms
✓
recognises "what happened to my open rate" 0.1ms
✓
recognises "how come nobody replies to my emails" 0.2ms
✓
recognises "what's wrong with my deliverability" 0.2ms
✓
recognises "why are my citations falling" 0.5ms
✓
recognises "what is causing the drop in leads" 0.2ms
✓
does not fire on the conversational "why do you need my website URL?" 0.2ms
✓
does not fire on the conversational "why can I not skip this step" 0.4ms
✓
does not fire on the conversational "what happened to the button that was here" 0.3ms
✓
does not fire on the conversational "why is this taking so long" 0.1ms
✓
does not fire on the conversational "why does the chat keep asking for my domain" 0.1ms
✓
leaves the measurement/action ask "how is my AI visibility" alone 0.8ms
✓
leaves the measurement/action ask "check my AI visibility" alone 0.4ms
✓
leaves the measurement/action ask "run a full AEO audit" alone 0.1ms
✓
leaves the measurement/action ask "find me 50 CTOs at fintech startups" alone 0.1ms
✓
keeps the first-person complaint "why can't I get any replies" diagnostic 0.1ms
✓
keeps the first-person complaint "why am I not getting replies" diagnostic 0.1ms
✓
needs a subject or a decline, not a bare why 0.2ms
isEvidenceFirstGated · 19 tests
✓
never gates diagnose itself — that would be a loop 0.2ms
✓
never gates the core tool web_search 0.1ms
✓
never gates the core tool read_url 0.1ms
✓
never gates the core tool generate_emails 0.1ms
✓
never gates the core tool send_emails 0.1ms
✓
never gates the core tool list_contacts 0.1ms
✓
never gates the core tool add_contacts 0.1ms
✓
never gates the core tool list_campaigns 0.1ms
✓
never gates the core tool create_campaign 0.1ms
✓
never gates the core tool search_leads 0.1ms
✓
never gates the core tool scan_product 0.1ms
✓
never gates the core tool campaign_stats 0.1ms
✓
never gates the core tool create_marketing_plan 0.1ms
✓
never gates the core tool show_marketing_plan 0.1ms
✓
never gates the core tool propose_outbound_run 0.1ms
✓
never gates the core tool diagnose 0.1ms
✓
gates the paid report tools a why-question actually misroutes into 0.3ms
✓
gates every non-core tool the billing table prices 1.1ms
✓
does not gate an unpriced tool 0.2ms
hasExplicitActionIntent · 2 tests
✓
sees the action in a mixed ask 14.1ms
✓
does not count diagnose itself as an action 2.8ms
a factual lookup does not collect an evidence step · 5 tests
✓
stands down on "How much have I spent so far, and on what?" 0.5ms
✓
stands down on "How many contacts do I have?" 0.1ms
✓
stands down on "Which campaigns are running?" 0.1ms
✓
still augments a real why-question whose tools are all free 2.2ms
✓
still REPLACES a paid report on a question that is not diagnostic by shape 0.5ms
resolveMisroute · 9 tests
✓
redirects a paid report on a why-question 0.7ms
✓
carries the user's own words through so diagnose answers what was asked 0.2ms
✓
stands down when the model already called diagnose 0.1ms
✓
allows the paid tool once diagnose has already run 0.1ms
✓
fires at most once per run 0.1ms
✓
stands down when the message also carries an explicit action ask 0.1ms
✓
AUGMENTS a turn with no priced tool in it — the evidence step is not about cost 0.2ms
✓
leaves a measurement ask completely alone 0.1ms
✓
replaces only the priced calls and dedupes 0.2ms
diagnose intent registration · 2 tests
✓
is registered on the LLM router 0.1ms
✓
does not outrank search_leads for a lead ask 0.4ms
the ladder — which rung a why-question goes to (Phase 2) · 8 tests
✓
sends a question about SOMEONE ELSE'S page to the primitives, not to diagnose 0.4ms
✓
sends a question about the tenant's OWN numbers to diagnose 0.2ms
✓
treats a named URL as outside when we do not know the tenant's site 0.2ms
✓
ignores www and scheme when deciding whose site it is 0.3ms
✓
flags the tenant's OWN site when it is named alongside a competitor's 0.2ms
✓
does not claim the own site was named when only outsiders were 0.2ms
✓
caps how many pages one redirect will read 0.3ms
✓
still stands down when the user explicitly asked for the paid thing 1.9ms
a revenue question is REPLACED by diagnose even when the model chose only free tools (2026-09-15) · 2 tests
✓
seo_google_merge is displaced for "why did my sales drop" 0.5ms
✓
a non-revenue why-question on a free tool still augments, as before 0.2ms
src/billing/plans.vitest.ts
plan resolution · 4 tests
✓
follows the payment signal by default 1.8ms
✓
lets an explicit override win, so testing never needs a fake payment row 0.3ms
✓
ignores a malformed override rather than failing open to paid 0.4ms
✓
accepts case and whitespace, since the value comes from a settings row 0.2ms
depth resolution · 5 tests
✓
narrows to the plan cap but never widens past what was asked 0.2ms
✓
leaves a dimension the plan does not cap to the tool default 0.2ms
✓
reports when it trimmed, which is what warrants an offer 0.3ms
✓
mirrors the caps that are live today 0.3ms
✓
models search_leads as delivery-capped over a fixed fetch, and marks it withholding 0.6ms
defaults are fail-safe · 7 tests
✓
falls back to the plan default for an unlisted tool 0.6ms
✓
never denies on an unknown plan id — it falls back to free, not open 0.2ms
✓
denies only what was already paid-only 0.3ms
✓
bounds the run count of EVERY paid tool on the free plan 0.2ms
✓
bounds an unlisted paid tool by default, and leaves free tools alone 0.2ms
✓
never counts a paid user — the balance is their bound 0.8ms
✓
classifies every tool exactly once 0.8ms
uplift offers · 9 tests
✓
leads with what was delivered, not with what is missing 0.4ms
✓
makes NO offer when nothing was actually withheld 0.2ms
✓
never upsells a plan that already has the thing 0.1ms
✓
covers every exit reason — a capped exit with no offer is a dead end 0.5ms
✓
only claims results are "ready" when they were actually paid for 0.2ms
✓
offers once for the biggest shortfall, not once per capped dimension 0.2ms
✓
says nothing when the run was not trimmed 0.1ms
✓
reads withholds from the PLAN, not from the caller 0.1ms
plan simulation · 3 tests
✓
allows everything when the plan sets no run caps 0.4ms
✓
reports what a candidate plan would have prevented 1.2ms
coverage · 1 test
✓
resolves a limit for every priced tool, on every plan 4.0ms
identity-constrained dimensions · 5 tests
✓
intersects with the allowlist before applying the count 0.2ms
✓
never lets a count cap pick an engine the plan does not permit 0.3ms
✓
still yields a usable run when the ask and the allowlist do not overlap 0.1ms
✓
leaves paid selections alone 0.2ms
✓
applies the count cap on dimensions with no allowlist 0.8ms
cron entitlements · 4 tests
✓
caps the weekly rank scan for free, which runs for every tenant and is not opt-in 0.3ms
✓
withholds the weekly SoV composite from free — one run is a full AEO fan-out 0.1ms
✓
disables an undeclared cron rather than defaulting it on 0.1ms
✓
leaves a dimension the plan does not cap alone 0.1ms
search_leads run cap (the -1.87M incident) · 3 tests
✓
allows three free runs — a COUNT still, because the provider path still bills late 0.2ms
✓
does not cap the paid plan 0.1ms
✓
cannot be solved by depth — cost is identical at either delivery cap 0.1ms
depth caps added in the second pass · 10 tests
✓
seo_enrich_keywords caps keywords at 10 free / 300 paid 0.2ms
✓
seo_keyword_metrics caps keywords at 10 free / 200 paid 0.1ms
✓
seo_serp_spider caps pages at 15 free / 30 paid 0.1ms
✓
seo_onpage_audit caps pages at 50 free / 300 paid 0.1ms
✓
seo_competitor_gap caps rows at 10 free / 25 paid 0.1ms
✓
seo_offpage_audit caps rows at 10 free / 25 paid 0.1ms
✓
seo_backlinks caps rows at 5 free / 10 paid 0.2ms
✓
brings seo_enrich_keywords under the bonus 0.2ms
✓
caps both once a real row parameter exists 0.1ms
✓
leaves aeo_full_audit undeclared, since its sub-tool governs the fan-out 0.1ms
web_search is priced per QUESTION, not per run (ledger #13) · 2 tests
✓
does not inherit the paid default meant for 10-50x pricier tools 0.2ms
✓
is still bounded on free — cheap is not unlimited 0.1ms
appsumo (lifetime deal) — 3 stack levels · 13 tests
✓
is reachable only through the override or a real redemption — never from hasPaidTopUp alone 0.2ms
✓
a real top-up does NOT lift a redeemed buyer to paid — the caps are permanent by design 0.2ms
✓
the test override still wins over a real redemption, for QA 0.1ms
✓
falls back to free, not open, on the malformed-override path 0.1ms
✓
keeps paid-level depth at every stack level — a lifetime deal is not a crippled starter tier 0.2ms
✓
scales run counts 1x/2x/4x across stack levels — a stacking INCENTIVE, not linear 1x/2x/3x 0.2ms
✓
caps aeo_visibility tighter than its neighbours at every level — it alone was 39.6% of measured real spend 0.2ms
✓
caps the #2 real driver too, even though it is not an LLM/CoT tool 0.2ms
✓
still bounds search_leads by count, same reasoning as the -1.87M incident on free 0.2ms
✓
gives web_search its own generous line instead of the generic fail-safe default 0.1ms
✓
bounds an unlisted paid tool by default at every level — no unlimited surface on a flat one-time price 0.2ms
✓
leaves seo_request_indexing denied, same as free, since the underlying provider question is still open 0.1ms
✓
withholds the weekly SoV composite by default, same reasoning as free 0.1ms
src/tools/filter-corpus.vitest.ts
every corpus request has a schema-valid destination · 35 tests
✓
f01 "enrich all the contacts in the list developer-leads that a" validates on enrich_contacts 3.3ms
✓
f02 "re-enrich everyone in developer-leads, including the ones " validates on enrich_contacts 0.4ms
✓
f03 "re-enrich my developer-leads, the data is stale" validates on enrich_contacts 0.3ms
✓
f04 "refresh the research on everyone in developer-leads" validates on enrich_contacts 0.4ms
✓
f05 "enrich the developer-leads contacts we have not researched" validates on enrich_contacts 0.4ms
✓
f06 "which of my contacts have never actually been verified?" validates on list_contacts 0.5ms
✓
f07 "show me the contacts with a confirmed working email" validates on list_contacts 0.6ms
✓
f06-inv "list everyone whose email we have checked and confirmed" validates on list_contacts 0.5ms
✓
f08 "show everyone in developer-leads except the ones in do-not" validates on list_contacts 0.6ms
✓
f09 "who in developer-leads still doesn't have an email address" validates on list_contacts 0.3ms
✓
f10 "show me everyone I haven't emailed yet" validates on list_contacts 0.3ms
✓
f11 "list the people we have already reached out to" validates on list_contacts 0.2ms
✓
f12 "enrich the developer-leads contacts that have an email and" validates on enrich_contacts 0.2ms
✓
f13 "show my unverified contacts that I have not contacted yet" validates on list_contacts 0.1ms
✓
f16 "draft emails to everyone in developer-leads I haven't emai" validates on generate_emails 0.2ms
✓
f17 "verify the ones with no verification yet in developer-lead" validates on verify_contacts 0.1ms
✓
f18 "re-verify everything in developer-leads, I do not trust th" validates on verify_contacts 0.2ms
✓
f19 "add everyone in developer-leads I haven't contacted to the" validates on assign_to_campaign 0.2ms
✓
f20 "enroll the developer-leads contacts with a verified email " validates on enroll_in_sequence 0.2ms
✓
f01 reaches the same filter whether the list arrives as list_name or in_lists 0.4ms
✓
f02 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f03 reaches the same filter whether the list arrives as list_name or in_lists 0.3ms
✓
f04 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f05 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f08 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f09 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f12 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f16 reaches the same filter whether the list arrives as list_name or in_lists 0.3ms
✓
f17 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f18 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
f19 reaches the same filter whether the list arrives as list_name or in_lists 0.3ms
✓
f20 reaches the same filter whether the list arrives as list_name or in_lists 0.2ms
✓
folds list_names (plural) too, and de-duplicates against the filter 0.2ms
✓
does not invent a list from the literal strings a model sends for "none" 0.2ms
✓
covers both tools and every kind, so the corpus cannot quietly narrow 0.4ms
a complement is a DIFFERENT query — the §11.6 acceptance · 4 tests
✓
f01 and f02 do not compile to the same where 0.5ms
✓
f06 and f06-inv do not compile to the same where 0.2ms
✓
f10 and f11 do not compile to the same where 0.3ms
✓
the owner's inverse drops the enriched predicate entirely, rather than negating it 0.3ms
paraphrases converge on one canonical form · 4 tests
✓
f03 resolves identically to f02 0.3ms
✓
f04 resolves identically to f02 0.1ms
✓
f05 resolves identically to f01 2.4ms
✓
f07 resolves identically to f06-inv 0.1ms
the ceiling holds: an ask outside the vocabulary has no destination · 2 tests
✓
f14 "enrich the ones that replied but never opened th" cannot be expressed, and that is correct 0.3ms
✓
f15 "enrich the good ones" cannot be expressed, and that is correct 0.1ms
every corpus filter can explain itself to the user · 19 tests
✓
f01 produces a disclosure sentence 0.3ms
✓
f02 produces a disclosure sentence 0.1ms
✓
f03 produces a disclosure sentence 0.2ms
✓
f04 produces a disclosure sentence 0.1ms
✓
f05 produces a disclosure sentence 0.1ms
✓
f06 produces a disclosure sentence 0.1ms
✓
f07 produces a disclosure sentence 0.1ms
✓
f06-inv produces a disclosure sentence 0.1ms
✓
f08 produces a disclosure sentence 0.1ms
✓
f09 produces a disclosure sentence 0.1ms
✓
f10 produces a disclosure sentence 0.1ms
✓
f11 produces a disclosure sentence 0.2ms
✓
f12 produces a disclosure sentence 0.1ms
✓
f13 produces a disclosure sentence 0.1ms
✓
f16 produces a disclosure sentence 0.1ms
✓
f17 produces a disclosure sentence 0.1ms
✓
f18 produces a disclosure sentence 0.1ms
✓
f19 produces a disclosure sentence 0.1ms
✓
f20 produces a disclosure sentence 0.1ms
src/chat/present.vitest.ts
records() — the invariant that makes the defect unrepresentable · 4 tests
✓
returns null for zero rows, so no presenter can emit a header with no body 1.6ms
✓
returns null when every row is empty 0.3ms
✓
returns null with no columns 0.2ms
✓
caps rows and never lets total fall below what is shown 1.2ms
wave 1 presenters · 12 tests
✓
list_contacts keeps the column contract records-as-tables.vitest.ts already pins 1.3ms
✓
list_contacts says it is a page when it is one, and does not when it is not 0.3ms
✓
list_contacts carries the filter scope, so a narrowed list never reads as complete 0.3ms
✓
falls back to the email when a contact has no name 0.2ms
✓
campaigns, sequences and connectors each present as records 1.0ms
✓
campaign_stats is one funnel row with measured zeros — [6.4.1] 0.6ms
✓
create_campaign confirms itself with the name on screen — [6.1.1] 0.5ms
✓
seo_keywords drops an all-empty CPC column and says the ranking is not profitability — [4.8.1] 0.6ms
✓
an empty listing presents nothing, so the caller keeps its honest no-records copy 0.2ms
✓
errors and confirmation gates are not record listings 0.1ms
✓
an unpresented tool returns null rather than throwing — most tools are still migrating 0.4ms
✓
covers exactly the migrated tools — a floor, so a deleted presenter fails loudly 0.3ms
marketing plan — the tools the judge caught at 0.30 · 6 tests
✓
create_marketing_plan renders initiatives as records, not prose 0.5ms
✓
show_marketing_plan renders initiatives as records, not prose 0.3ms
✓
carries the plan score and thesis as scope rather than letting the model invent a header 0.2ms
✓
a null token_estimate stays empty — it means no extra cost, not a missing value 0.1ms
✓
never denominates the estimate in currency 0.2ms
✓
returns null on an empty plan, so no header ships without rows 0.1ms
wave 4 — the report tools · 6 tests
✓
every one is modelPathOnly and consumes nothing 2.3ms
✓
the manifest still goes to the model even though nothing is stripped 0.2ms
✓
the ASCII share bar becomes a real number 0.2ms
✓
seo_google_merge share-of-voice columns are named for what they hold 0.2ms
✓
backlink value is withheld where DR is unknown, as the markdown did 0.3ms
✓
a blocked backlink is never folded into present or absent 8.0ms
wave 3 — a number keeps its value and the column wears the unit · 7 tests
✓
numeric cells are raw; the prefix/suffix/decimals live on the column 0.6ms
✓
the em-dash for "no data" becomes null, never a string in a number column 0.3ms
✓
seo_list_keywords keeps the Rank column when any row has a position, or when the read failed with a note 1.3ms
✓
crux history takes the TAIL — the recent periods, not the oldest fifty 0.4ms
✓
a multi-table tool emits one block per table, and drops the empty ones 0.7ms
✓
every wave-3 presenter declares NO lead — the formatter keeps its synthesis sentence 1.0ms
✓
a failed PSI run keeps its row and reports the error in the fix column 0.2ms
wave 2 — the leads/email family · 7 tests
✓
search_leads renders from `all`, not the five-row `preview` 0.5ms
✓
search_leads consumes BOTH preview and all 0.3ms
✓
wave 2 declares NO lead — the formatter keeps its framing 0.4ms
✓
a search still running, or out of credits, presents nothing 0.2ms
✓
generate_emails and backlink_outreach_search carry every row 0.6ms
✓
NO sibling array survives that duplicates the presented rows 0.5ms
✓
Email is a DECLARED column on both, which is what switches selection on 0.2ms
modelResultView — the model cannot transcribe what it cannot see · 2 tests
✓
removes the consumed key and says so, keeping everything else intact 0.8ms
✓
is a no-op without a presentation, so unpresented tools are untouched 0.1ms
blocksToMarkdown — the fallback serialisation · 2 tests
✓
caps at the prose limit and names the remainder 0.4ms
✓
escapes a pipe that would otherwise split the row 0.3ms
stripRenderedTables — the belt · 6 tests
✓
removes a rowless table even when the turn attached no block at all 0.5ms
✓
leaves a real table alone when nothing was rendered for the user 0.4ms
✓
removes a populated duplicate only when a block was attached, and counts it 0.2ms
✓
handles alignment separators and several tables in one answer 0.2ms
✓
is a cheap no-op on text with no pipe at all 0.1ms
✓
never throws on a non-string 0.1ms
entity_audit blocks — the three blocks say three different kinds of thing · 3 tests
✓
declares Priority as severity, not status — so the pills rank instead of going flat grey 0.9ms
✓
marks the coverage disclosure as a note, and ONLY that block 0.3ms
✓
still emits the disclosure when the site is clean — that is the case it exists for 0.2ms
a lead replaces a count line, never the model's answer · 4 tests
✓
keeps the model's answer when the caller declares it model-authored 0.3ms
✓
still replaces the formatter count line the lead exists for 0.2ms
✓
falls back to the formatter when there is no lead and no message 0.2ms
✓
list_contacts still declares the lead — the wave-1 case is unchanged 0.1ms
EXCEPTION_ONLY_PRESENTERS · 3 tests
✓
is exactly send_emails today, and every member is a real presenter 0.2ms
✓
each member renders NOTHING for a clean success, and a block for a result with failures 0.4ms
✓
a presenter that tables its SUCCESSES is not exception-only (list_contacts renders a clean result) 0.2ms
src/chat/judge-prompt.vitest.ts
resolveJudgeUserPrompt — control-token resolution · 6 tests
✓
resolves Cost confirm to the original request with an approval note 2.0ms
✓
resolves Next action chips the same way 0.3ms
✓
skips earlier control messages when walking history 0.2ms
✓
falls back to a semantic marker when history is unavailable 0.2ms
✓
passes real user messages through untouched 0.2ms
✓
classifies all known control prefixes 0.5ms
buildOutcomeNote — ground-truth outcome signal · 2 tests
✓
empty when the run had no soft failure 0.2ms
✓
carries the failure, the score cap, and the healthy-zero exception 0.4ms
buildStoredContextLine · 2 tests
✓
marks a stored key as a failure-to-ask and a missing key as correct-to-ask 0.8ms
✓
covers all four ground-truth keys 0.3ms
clampJudgeVerdict · 2 tests
✓
enforces the disproportionate <= 0.6 taxonomy cap (observed 0.7 verdict 2026-07-16) 0.3ms
✓
leaves other modes untouched and clamps to [0,1] 0.2ms
JUDGE_POLICY_GROUND_TRUTH · 4 tests
✓
names every mandated behavior class the judge was falsely penalizing 0.5ms
✓
does not excuse bad answers — accuracy framing stays 0.1ms
✓
recognizes a genuinely-required clarifying question as a correct turn 0.2ms
✓
keeps the anti-deferral guard so it does not excuse menus or re-asking 0.2ms
clean empty vs non-delivery · 7 tests
✓
does not tell the judge to score a clean zero as an incomplete outcome 0.3ms
✓
still gives the judge the ground truth — it must not infer zero rows from prose 0.1ms
✓
names the real states that produce a legitimate zero 0.2ms
✓
redirects the judgement to how the empty was HANDLED 0.2ms
✓
an ERRORED zero still gets the full non-delivery note 0.1ms
✓
a delivered turn still gets no note at all, either way 0.2ms
✓
a declared honest empty still short-circuits before either branch 0.1ms
buildStoredContextLine carries the VALUE, not only the fact of storage (2026-09-15) · 4 tests
✓
names the stored site so the judge cannot call it an invented domain 0.2ms
✓
quotes the brief so claims drawn from it are grounded, and bounds the excerpt 0.3ms
✓
an absent value stays the plain NOT-stored line with no quote 0.2ms
✓
the policy declares token quotes as system ground truth 0.1ms
the conversational judge reads an HTML reply as text (source pin) · 1 test
✓
index.ts strips tags off a no-tool HTML reply before slicing it for the judge 4.6ms
judgeKindOf — content outranks report outranks conversation · 2 tests
✓
an artifact is content even when the reply is also a report 0.2ms
✓
a report without an artifact is a report; neither is a conversation 0.1ms
isCleanEmptyResult — the result had nothing to return, read from the result · 4 tests
✓
records returned (yield > 0) are NOT clean-empty, whatever else is true 0.6ms
✓
an unreadable yield is NOT clean-empty — we do not know it had nothing 0.2ms
✓
a readable zero with no soft failure and no error IS clean-empty 0.1ms
✓
an error or a declared soft failure is never clean-empty 0.2ms
deliveryClampApplies — only a VERIFIED clean empty on a conversation escapes the clamp · 5 tests
✓
seo_backlink_gap, 991 prospects, 0 rows: clamps, and the note says it did NOT deliver 0.5ms
✓
an unreadable yield keeps the clamp until the owner rules on it 0.2ms
✓
a verified clean empty on a conversation: the clean-empty note, and no clamp beside it 0.2ms
✓
a REPORT whose note fired always clamps — the report template carries no note (diagnose, 2026-09-03) 0.3ms
✓
content never clamps on delivery; no note never clamps 0.3ms
ensembleMedian — a median, not the higher of two · 2 tests
✓
two judges average (10 of 11 ensembles since 09-19 stored the higher score) 0.9ms
✓
odd counts are unchanged; one judge is its own score; the input is not mutated 0.4ms
sendOutcomeFact — the send outcome is a LEDGER fact · 4 tests
✓
9 of 9 with 9 ledger rows is delivered (87ced0bb was judged 0.1 empty_outcome) 0.3ms
✓
a count the ledger does not confirm is unverified — never handed to the judge 0.2ms
✓
failures, skips and deferrals make a partial even when sent === total 0.2ms
✓
a staged card, an error and an empty batch are what they are 0.6ms
buildSendOutcomeNote — only a confirmed outcome reaches the judge · 4 tests
✓
delivered: the counts, and that a successful send renders no table 0.4ms
✓
partial: names the remainder, and calls an all-sent claim a hallucination 0.5ms
✓
none states 0 of N 0.3ms
✓
staged, unverified and error say nothing — and nothing at all without a fact 0.3ms
buildContentFacts — facts for the content judge, never an instruction to score · 2 tests
✓
generate_emails: the draft mode and up to three tool hints, each capped 0.7ms
✓
nothing for any other tool, or an empty result 0.3ms
scoreAgainstJudge switches every part on judgeKind (source) · 7 tests
✓
kind is computed once, from judgeKindOf 0.2ms
✓
the report parser, the stored-context line and the system prompt each read kind 0.2ms
✓
content has its own template: GENERATED COPY, content facts, no conversation rubric, no notes 0.2ms
✓
content is clamped only on a concealed failure, never on delivery 0.2ms
✓
the fixture capture is gated on judgeKind === report, at both write sites 0.5ms
✓
both verdict rows are tagged from judgeKind, never is_report from the HTML flag alone 1.0ms
✓
the ensemble stores a real median 0.5ms
persisted work changes the failure notes, and only when there is some · 3 tests
✓
persisted 3 → the saved results are ground truth, not invention 0.3ms
✓
(neg) persisted 0 → the notes are exactly as before 0.2ms
✓
the judge caller passes the tool's own progress counter 5.7ms
src/admin/ai-discovery.vitest.ts
E1 — the OpenAI index probe cannot see the URL · 2 tests
✓
searches by title only, cache-only, nqz.ai only 5.0ms
✓
the page-cache probe never fetches live either 0.6ms
E2 — Gemini grounding redirects are resolved · 3 tests
✓
returns the Location of a grounding redirect without following it 24.1ms
✓
passes ordinary URLs through untouched and never calls the network for them 0.5ms
✓
keeps the redirect link when resolution fails — it then simply does not match 0.5ms
E2b — the grounding HEAD goes through the egress choke point · 2 tests
✓
gemini_cite sends nothing to a private host a grounding chunk names, and still resolves the public ones 6.1ms
✓
the choke-point fetcher: a private grounding link is kept unresolved and never requested; a public one is one HEAD, not followed 0.7ms
E3 — own pages are fetched from the worker that serves them · 2 tests
✓
routes /blog and /blog/* to the blog worker 0.2ms
✓
routes everything else to SELF — including paths that merely start with "blog" 0.5ms
URL rules · 3 tests
✓
canonicalizes the way citations arrive (utm, trailing slash, www) 0.3ms
✓
accepts only public https nqz.ai pages 0.4ms
✓
searches by the title a person would type, without the brand suffix 0.4ms
robots.txt · 4 tests
✓
falls back to the * group 0.8ms
✓
a bot with its own group ignores the * rules 0.2ms
✓
consecutive user-agent lines share one group 0.1ms
✓
longest rule wins, Allow wins a tie, and no file means allowed 0.3ms
page facts · 1 test
✓
reads title, H1, canonical, robots, description and visible words only 1.2ms
OpenAI response parsing · 2 tests
✓
lists sources in order, canonicalized and de-duplicated 0.5ms
✓
bills every web_search_call plus model tokens 0.5ms
citation evaluation · 1 test
✓
separates "this page", "another nqz.ai page" and "not cited" 0.5ms
crawler windows · 1 test
✓
counts only the exact path — pageSearch is a substring match 0.8ms
the crawled / indexed / cited matrix · 12 tests
✓
everything is pending before any probe runs; only Copilot cited is honestly not measured 0.8ms
✓
Copilot: Bing impressions prove indexed; crawled-without-impressions stays unknown; unknown URL is a no 0.6ms
✓
Claude indexed: found, not found, and an empty search that decides nothing 0.3ms
✓
Google cited is cited on ANY Google surface, and says which 0.2ms
✓
Google: Search Console decides crawled and indexed; "Discovered – not indexed" is a no 0.4ms
✓
a live fetch is not a crawl: ChatGPT-User alone leaves ChatGPT "not crawled" 0.3ms
✓
an uninstrumented blog is "unknown", never "no visits" 0.1ms
✓
no DataFast key: the crawler probe reports "not tracked" with the reason, and never calls out 0.6ms
✓
a failed probe is unknown and carries its error 0.3ms
✓
an EMPTY search is inconclusive, never "not indexed" (measured: 2 of 4 identical calls returned 0 results) 0.2ms
✓
a search that returned OTHER pages is a real "no" 0.1ms
✓
cited distinguishes this page from a sibling page 0.2ms
Google AI Mode (cloro) parsing · 3 tests
✓
orders sources by position, then appends inline citation pills 0.3ms
✓
tolerates a payload with no result 0.2ms
✓
keeps the labels cloro gives sources and pills — a round-up is often only recognisable by its title 0.2ms
Claude web search · 7 tests
✓
separates what the search returned from what the answer cited 0.4ms
✓
captures the searches Claude ran and the titles of what it read 0.3ms
✓
a search error arrives as an object, not an array — it is reported, not read as zero results 0.2ms
✓
costs tokens at the model price plus $0.01 per search 0.3ms
✓
the index check searches by title on nqz.ai only and never sees the URL (same rule as OpenAI, E1) 0.3ms
✓
index on Haiku 5.5, answer on Sonnet 5.5 (owner choice 2026-10-15, on measured cost) 0.2ms
✓
both checks pin web_search_20250305 — the _20260209 variant answers with no citation objects (measured) 0.2ms
Bing Webmaster route · 1 test
✓
goes through the broker, never direct — Bing answers ThrottleIP to Cloudflare egress (measured 2026-10-15) 0.3ms
Bing Webmaster parsing (shapes captured live 2026-10-15) · 3 tests
✓
reads .NET JSON dates and treats the year-0001 sentinel as "never" 0.5ms
✓
a crawled page is known; an unknown URL (sentinel dates, size 0) is not 0.3ms
✓
sums one page across periods, canonicalising the URL, and reports the window 0.3ms
combineCiteSignals · 1 test
✓
pending only when nothing has run; failed + not-run is unknown 0.4ms
cost visibility · 3 tests
✓
a probe total is the sum of its lines, in USD and tokens 0.2ms
✓
a run total includes re-run attempts, not just the latest 0.2ms
✓
the estimate covers every probe plus the start 0.4ms
run history · 2 tests
✓
run ids sort newest first and carry their start time 0.7ms
✓
groups objects into runs and sums cost from metadata alone 1.3ms
fan-out capture · 2 tests
✓
reads every search OpenAI ran, singular and plural forms, de-duplicated 0.4ms
✓
titles survive canonicalisation and only for sources that were kept 0.3ms
citation gap · 5 tests
✓
counts only engines that answered, and which of them cited us 0.3ms
✓
merges a source several engines chose and ranks it first, with its best position 0.3ms
✓
marks our own page and classifies the others by shape and fix owner 0.3ms
✓
turns the evidence into actions: searches to rank for, pages to get onto, threads to join, format to match 0.9ms
✓
says nothing when no engine answered 0.2ms
src/chat/contact-target.vitest.ts
extractContactTarget — what a finished run records · 11 tests
✓
list_contacts: the page ids only when the page is the whole set 3.2ms
✓
list_contacts with shown < total: an EXACT read — lists + filter, no ids 0.5ms
✓
(neg) an unscoped, campaign-scoped or status-tag page with no ids is not a set to reuse 0.6ms
✓
a campaign page returned whole is pinned by its ids, and is NOT exact 1.3ms
✓
generate_emails: the contacts drafted for, count = those ids 0.4ms
✓
enrich_contacts / verify_contacts: the ids in the RESULT, count = those ids 0.5ms
✓
search_leads / add_contacts: the saved contact ids 0.5ms
✓
(neg) an acting tool whose result names no ids records NOTHING — its selector is not its set 0.4ms
✓
(neg) a set no tool could take — more ids than CT_IDS_MAX and not exact — is not saved 1.3ms
✓
(neg) an errored or blocked result, count <= 0, or any other tool → null 0.3ms
✓
(neg) a list name that could carry an address or an id is never stored; free-form filter keys are dropped 0.3ms
validTarget — the fingerprint, not the history length (C1) · 5 tests
✓
valid for the message it was saved with, inside a day 0.3ms
✓
fp mismatch → false 0.1ms
✓
more than 24h old → false 0.1ms
✓
C1 regression: a history of 20 on both sides with a different last message → false 1.0ms
✓
(neg) null or a malformed record → false 0.3ms
resolveTargetArgs · 3 tests
✓
ids path: contact_ids = the saved ids; limit, instruction and mode kept; target gone 0.3ms
✓
filter path, EXACT sets only: saved lists + filter + the model's clauses 0.4ms
✓
other_targeting: target plus a list, list_names, contact_ids, a campaign or filter.in_lists is refused 0.6ms
review 2026-09-24 — the set a run ACTED ON, resolved per tool, never unscoped · 6 tests
✓
F1 regression: enrich by list with a remainder, then generate_emails → contact_ids = exactly the enriched ids 0.9ms
✓
F1 regression: verify by list with verified "unchecked" → generate_emails = the addresses that got a verdict 0.4ms
✓
F2 regression: more ids than the tool takes and no exact list → too_large, never in_lists: [] 0.7ms
✓
F2 regression: a campaign page returned whole (150) cannot be enriched by target — refused, campaign never dropped 0.3ms
✓
the per-tool caps are the schemas' contact_ids maxItems 0.2ms
✓
too_large is refused before Jev, with its own sentence 1.1ms
the arm · 2 tests
✓
is deterministic, off everywhere at "0", on everywhere at "100" 0.5ms
✓
the eval override beats the percentage 0.2ms
the wire: `target` on note turns only, and only on the three contact tools · 2 tests
✓
withTargetParam clones exactly CT_TOOLS with the target property; every other tool is the same object 2.3ms
✓
runChatV2 adds it only when the note is on (a valid saved set AND the ON arm) 0.6ms
the Jev rail — resolved or refused before anything prices it · 8 tests
✓
honoured (p >= 0.9): the call is rewritten to the saved ids and runs 1.2ms
✓
declined (p < 0.9): a refusal, and executeTool is never reached 0.4ms
✓
unavailable (Jev off, throw or timeout → null): a refusal, and executeTool is never reached 0.4ms
✓
no valid set, or the OFF arm: refused without asking Jev 0.9ms
✓
rejected: target plus a list is refused without asking Jev 0.4ms
✓
asks Jev once per round, and leaves calls without `target` alone 0.3ms
✓
the threshold is 0.9 and the question is the calibrated wording, its own call 0.3ms
✓
the Jev state masks addresses and carries no id 0.7ms
ordering in runChatV2 — resolved before billing, before the re-check decision · 2 tests
✓
the resolve block precedes const unrunnableIds and decideVerifyRecheck( 0.7ms
✓
the executor short-circuits a refused call right after the search_tools branch, before executeTool 0.5ms
the backstop: `target` is not in the static schema (C2) · 1 test
✓
each contact tool rejects target beside a list, and target alone 1.4ms
no PII in the note · 1 test
✓
contactTargetLine prints list names and clauses only — no @, no uuid 0.4ms
target_shape on the tool_run row · 3 tests
✓
previous / ids / lists / none 0.3ms
✓
the loop marks a resolved call on its signal, never as an argument, and executeTool reads it 0.4ms
✓
executeTool records it for the three contact tools, through the run-meta allowlist 0.7ms
the save: once per turn that captured a set, beside the history it belongs to · 2 tests
✓
persistChatHistory saves the captured set with the fingerprint of the message it persists 0.7ms
✓
putContactTarget → readContactTarget round-trips through KV and the isolate cache, one-day TTL 0.5ms
review 2026-09-24 — a refused call is loop plumbing, not a failed run (F8) · 3 tests
✓
why: counted like a run, the refusal is a failure, and a bare reply becomes the internal sentence 3.1ms
✓
the settle loop takes it out with search_tools — before lastTool, toolCallCount, toolErrorCount and the trace 0.5ms
✓
it never starts a stage, and is never staged on a cost card 1.1ms
review 2026-09-24 — the arm override is read before the first await (F4) · 1 test
✓
captured beside planSessionId, and the arm reads the local 0.5ms
review 2026-09-24 — a honoured call behind a cost card keeps its mark (F5) · 2 tests
✓
the staged record carries target_previous through writeCostPending → consumeCostPending 2.3ms
✓
runChatV2 stages the mark for honoured calls; the confirm puts it on the run's signal 1.3ms
review 2026-09-24 — a stale isolate cache cannot serve a superseded set (F10) · 5 tests
✓
a newer set written by another isolate wins over this isolate's cached one 0.4ms
✓
the turn after a set retires it; a stale isolate then reads the tombstone, not its cached set 0.4ms
✓
read-your-own-write: while this isolate's put has not landed, the cached set still answers 0.2ms
✓
retire writes nothing when no live set is held (one write per saved set, not per turn) 0.3ms
✓
persistChatHistory retires when the turn captured no set 0.4ms
the calibrated Jev state is pinned (CONTACT_TARGET_MIN_P re-run 2026-09-24) · 1 test
✓
an enrich-by-list set renders exactly the state the re-run scored — a shape change means re-calibrating 0.4ms
src/chat/scan-commands.vitest.ts
parseScanCommand · 34 tests
✓
stop: stop my weekly rank scan 3.8ms
✓
stop: Stop the rank tracking 1.0ms
✓
stop: pause my keyword rank scan 0.3ms
✓
stop: please stop scanning my keywords every week 6.3ms
✓
stop: stop tracking my keywords 3.0ms
✓
stop: Can you turn off the weekly keyword tracking? 0.2ms
✓
stop: turn my rank scan off 0.3ms
✓
stop: turn off all my scans 0.2ms
✓
stop: stop all scheduled scans. 0.6ms
✓
stop: pause my scans 0.3ms
✓
stop: disable every scan 0.3ms
✓
stop: stop the weekly store digest 0.1ms
✓
stop: cancel the digest emails 0.2ms
✓
stop: turn off AI visibility tracking 0.1ms
✓
stop: stop weekly share of voice tracking 0.2ms
✓
stop: disable the published content check 0.2ms
✓
resume: resume my rank scan 0.9ms
✓
resume: turn my rank scan back on 3.3ms
✓
resume: restart the weekly keyword tracking 0.2ms
✓
resume: switch the store digest back on 2.6ms
✓
resume: re-enable the publish check 0.2ms
✓
resume: turn on AI visibility tracking 0.2ms
✓
not a whole scan command: should I stop my rank scan? 1.6ms
✓
not a whole scan command: why did my rank scan stop? 0.8ms
✓
not a whole scan command: what scans are running in my account? 0.2ms
✓
not a whole scan command: how much does the weekly rank scan cost? 0.3ms
✓
not a whole scan command: stop my campaign 0.2ms
✓
not a whole scan command: pause the campaign called Q4 0.2ms
✓
not a whole scan command: stop tracking the keyword crm software 0.2ms
✓
not a whole scan command: stop weekly tracking 0.2ms
✓
not a whole scan command: resume all my scans 0.1ms
✓
not a whole scan command: run a rank scan now 0.2ms
✓
not a whole scan command: start my rank scan 0.2ms
✓
not a whole scan command: stop my weekly rank scan and delete my keywords and also tell me which competitors outrank me on every tracked term 0.2ms
the chat router sends scan commands to the scan rules first · 24 tests
✓
stop: stop my weekly rank scan 1.4ms
✓
stop: Stop the rank tracking 0.7ms
✓
stop: pause my keyword rank scan 0.1ms
✓
stop: please stop scanning my keywords every week 0.2ms
✓
stop: stop tracking my keywords 0.2ms
✓
stop: Can you turn off the weekly keyword tracking? 0.1ms
✓
stop: turn my rank scan off 0.2ms
✓
stop: turn off all my scans 1.6ms
✓
stop: stop all scheduled scans. 0.3ms
✓
stop: pause my scans 0.2ms
✓
stop: disable every scan 0.3ms
✓
stop: stop the weekly store digest 0.2ms
✓
stop: cancel the digest emails 0.2ms
✓
stop: turn off AI visibility tracking 1.0ms
✓
stop: stop weekly share of voice tracking 0.2ms
✓
stop: disable the published content check 0.1ms
✓
resume: resume my rank scan 0.2ms
✓
resume: turn my rank scan back on 0.2ms
✓
resume: restart the weekly keyword tracking 0.2ms
✓
resume: switch the store digest back on 0.2ms
✓
resume: re-enable the publish check 0.2ms
✓
resume: turn on AI visibility tracking 0.2ms
✓
the confirm and cancel chips reach their own rules 0.2ms
✓
campaign commands still reach the campaign rules 30.5ms
src/seo/counterplan-eeat-wiring.vitest.ts
Q25 and Q24 are reachable from the sentence · 4 tests
✓
both flags are computed and both are in the shortcut condition 4.6ms
✓
each is traceable to its own route, not merged into a neighbour 0.8ms
✓
the DISPATCHER publishes the brief's own headline, not a hardcoded one 0.9ms
✓
ONE renderer serves them, like every other brief 1.1ms
both are built BEFORE the empty-evidence gate · 3 tests
✓
the counter-plan is built above the gate 0.4ms
✓
the E-E-A-T brief is built above the gate 0.3ms
✓
and both are in the chain the gate returns 0.7ms
the rival reading is shared, not duplicated · 2 tests
✓
Q04 and Q25 gather ONCE between them 0.9ms
✓
each brief is computed once 1.0ms
neither steals the tool it sits beside · 3 tests
✓
a NAMED competitor domain still belongs to the paid keyword-gap tool 0.9ms
✓
"find my competitors" still goes to the tool that finds them 0.9ms
✓
backlink authority questions do not become E-E-A-T briefs 0.9ms
both briefs answer rather than refuse when nothing is on file · 2 tests
✓
the counter-plan says what was never measured 1.0ms
✓
the E-E-A-T brief says what was never checked 0.6ms
Q09 and Q03 are reachable and traceable · 5 tests
✓
both flags are computed and both are in the shortcut condition 2.9ms
✓
each has its own routeDebug label 0.5ms
✓
the same renderer serves them 0.6ms
✓
both are built above the empty-evidence gate and are in its chain 0.5ms
✓
each is computed once 0.6ms
Q09 and Q03 do not steal the tools they sit beside · 3 tests
✓
backlink fetch/scan/verify phrasings keep their tools 0.8ms
✓
a named competitor domain still belongs to the paid backlink gap tool 0.1ms
✓
keyword research and lookup phrasings keep their tools 0.8ms
Q29 and Q10 are reachable and traceable · 4 tests
✓
both flags are computed and in the shortcut condition 2.9ms
✓
each has its own routeDebug label and the shared renderer serves it 0.9ms
✓
Q29 is the FOURTH consumer of the shared technical evidence, not a new reader 0.5ms
✓
both are above the empty-evidence gate and in its chain 0.5ms
Q29 and Q10 do not steal their neighbours · 3 tests
✓
sitemap submission requests keep their tool 0.7ms
✓
a request to SHOW a number is a report, not a measurement question 0.8ms
✓
reporting questions with no search subject stay away 0.3ms
Q27 and Q17 are reachable and traceable · 5 tests
✓
both flags are computed and in the shortcut condition 2.9ms
✓
each has its own routeDebug label and the shared renderer serves it 1.0ms
✓
Q27 reads content_quality THROUGH Q24 rather than re-querying it 0.5ms
✓
Q17 does not shadow the keyword growth horizon 0.3ms
✓
both are above the empty-evidence gate and in its chain 0.5ms
Q27 and Q17 do not steal their neighbours · 3 tests
✓
a request to WRITE something keeps going to the writing tool 1.4ms
✓
measurement questions stay with Q10 0.8ms
✓
"how long" about something other than search does not match 0.2ms
Q07 is reachable, traceable, and shares the index reader · 5 tests
✓
the flag is computed and in the shortcut condition 2.5ms
✓
reads the index through the shared gatherer, keeping ONE reader of serp_spider_urls 0.5ms
✓
uses the SHARED url normaliser rather than a fourth local one 0.3ms
✓
is above the empty-evidence gate and in its chain 0.4ms
✓
does not fire on a request to BUILD a site 1.3ms
the playbook questions are reachable and rendered by their OWN block · 5 tests
✓
all five route through the shortcut 1.6ms
✓
each is traceable to its own label 1.2ms
✓
renders through a SEPARATE block, not the hypothesis renderer 0.9ms
✓
survives the empty-evidence gate — a playbook never has evidence 0.5ms
✓
is computed once, from one shared gather 0.3ms
the playbook predicates do not steal the briefs · 5 tests
✓
Q02 keeps "prioritise the technical seo backlog" 0.6ms
✓
Q17 yields to Q20 on a multi-year investment question 0.6ms
✓
Q10 yields to Q26 when an audience is named 0.5ms
✓
one channel alone is not a channel-model question 0.5ms
✓
a place word alone is not a service-area question 0.5ms
Q08 and Q13 are reachable · 3 tests
✓
Q08 routes as a brief and Q13 as a playbook 1.1ms
✓
Q08 is above the empty-evidence gate and in its chain 0.3ms
✓
Q08 reuses the shared query classifier rather than re-deriving it 0.2ms
the brief owns its title on BOTH return paths · 3 tests
✓
computes the answer chain ONCE, above the gate 0.6ms
✓
the main return prefers the brief's headline over the generic one 0.4ms
✓
the empty-evidence return still uses it too 0.2ms
src/routes/public-tool-egress.vitest.ts
'website health check' refuses internal targets before connecting · 12 tests
✓
http://169.254.169.254/latest/meta-data/ 29.8ms
✓
http://127.0.0.1:8080/admin 1.2ms
✓
http://2130706433/ 1.5ms
✓
http://0251.0376.0251.0376/ 0.8ms
✓
http://0xA9FEA9FE/ 0.7ms
✓
http://[::ffff:169.254.169.254]/ 1.0ms
✓
http://localhost./ 1.3ms
✓
refuses a public URL that redirects inward — every hop is re-checked 6.8ms
✓
a refused address does not spend the caller's allowance 0.6ms
✓
refuses a scheme that is not http(s) with the same readable message 0.5ms
'GEO scorecard' refuses internal targets before connecting · 12 tests
✓
http://169.254.169.254/latest/meta-data/ 0.8ms
✓
http://127.0.0.1:8080/admin 0.5ms
✓
http://2130706433/ 0.5ms
✓
http://0251.0376.0251.0376/ 0.5ms
✓
http://0xA9FEA9FE/ 0.4ms
✓
http://[::ffff:169.254.169.254]/ 0.5ms
✓
http://localhost./ 0.4ms
✓
refuses a public URL that redirects inward — every hop is re-checked 4.2ms
✓
a refused address does not spend the caller's allowance 0.5ms
✓
refuses a scheme that is not http(s) with the same readable message 0.4ms
'AI search prompt generator' refuses internal targets before connecting · 12 tests
✓
http://169.254.169.254/latest/meta-data/ 0.7ms
✓
http://127.0.0.1:8080/admin 0.4ms
✓
http://2130706433/ 0.5ms
✓
http://0251.0376.0251.0376/ 0.5ms
✓
http://0xA9FEA9FE/ 0.5ms
✓
http://[::ffff:169.254.169.254]/ 0.5ms
✓
http://localhost./ 0.6ms
✓
refuses a public URL that redirects inward — every hop is re-checked 7.4ms
✓
a refused address does not spend the caller's allowance 0.4ms
✓
refuses a scheme that is not http(s) with the same readable message 0.3ms
'website health check' still works for a legitimate public URL · 3 tests
✓
a plain public page 11.6ms
✓
a public page reached through ordinary redirects 5.1ms
✓
a public host that merely starts with "fc" or "fd" is not mistaken for an IPv6 private range 2.3ms
'GEO scorecard' still works for a legitimate public URL · 3 tests
✓
a plain public page 17.1ms
✓
a public page reached through ordinary redirects 16.2ms
✓
a public host that merely starts with "fc" or "fd" is not mistaken for an IPv6 private range 17.2ms
'AI search prompt generator' still works for a legitimate public URL · 3 tests
✓
a plain public page 2.7ms
✓
a public page reached through ordinary redirects 1.6ms
✓
a public host that merely starts with "fc" or "fd" is not mistaken for an IPv6 private range 1.4ms
the egress record · 5 tests
✓
every crawl fetch is counted, in one write per phase rather than one per URL 3.3ms
✓
a refusal by the 'website health check' is recorded as a denial 0.6ms
✓
a refusal by the 'GEO scorecard' is recorded as a denial 0.5ms
✓
a refusal by the 'AI search prompt generator' is recorded as a denial 0.5ms
✓
the GEO scorecard counts every page it fetched 10.0ms
website health: robots.txt Sitemap lines are held to the crawl's own domain · 2 tests
✓
fetches a same-site Sitemap line and never an off-site or internal one 4.1ms
✓
a same-site sitemap <loc> or page that redirects inward is refused, not followed 2.9ms
GEO scorecard OG card: the favicon parameter never reaches the renderer as a URL · 5 tests
✓
an internal favicon http://169.254.169.254/latest/meta-data/ is not fetched, by us or by the renderer 1.2ms
✓
an internal favicon http://[::1]/x.png is not fetched, by us or by the renderer 0.5ms
✓
an internal favicon http://2130706433/x.png is not fetched, by us or by the renderer 0.4ms
✓
a favicon that redirects inward is not followed 0.5ms
✓
a legitimate public favicon still appears on the card 1.2ms
src/connectors/gate.vitest.ts
connectorGate — one shape for every connector · 10 tests
✓
carries the connector, the chip target, and composed copy 2.8ms
✓
uses the registry label, so a rename propagates everywhere at once 0.4ms
✓
appends a genuine alternative when the caller has one 0.2ms
✓
slack offers a connect route 0.2ms
✓
google offers a connect route 0.2ms
✓
notion offers a connect route 0.2ms
✓
apollo offers a connect route 0.2ms
✓
wordpress offers a connect route 0.2ms
✓
vercel offers a connect route 0.4ms
✓
cloudflare offers a connect route 0.2ms
connectorGate — DISABLED is not DISCONNECTED · 3 tests
✓
a disabled connector offers NO connect route 0.4ms
✓
says the capability is unavailable, and points at what still works 0.2ms
✓
ignores `unlocks` for a disabled connector — there is nothing to unlock 0.1ms
connectorGate — a gate is not a defect · 10 tests
✓
slack gate is an EXPECTED outcome 2.5ms
✓
shopify gate is an EXPECTED outcome 1.8ms
✓
google gate is an EXPECTED outcome 1.7ms
✓
gmail gate is an EXPECTED outcome 0.2ms
✓
notion gate is an EXPECTED outcome 0.1ms
✓
apollo gate is an EXPECTED outcome 0.1ms
✓
wordpress gate is an EXPECTED outcome 0.1ms
✓
vercel gate is an EXPECTED outcome 0.1ms
✓
cloudflare gate is an EXPECTED outcome 0.1ms
✓
a genuine fault is still reported 0.4ms
connectorDegraded — proceeded, but say what is missing · 1 test
✓
keeps the payload and explains the gap without erroring 0.4ms
isConnectorGate · 2 tests
✓
recognises both enabled and disabled gates 0.2ms
✓
does not claim ordinary errors 0.1ms
preflightConnector — answer before the turn is spent (§3.5) · 8 tests
✓
a Google-gated tool with no Google connection is stopped up front 0.3ms
✓
names Search Console for a gsc_ tool and Analytics for a ga tool 0.2ms
✓
proceeds when the connector is live 0.1ms
✓
proceeds for a tool no connector blocks 0.2ms
✓
never pre-empts search_leads — it switches to the In-house source 0.1ms
✓
never pre-empts send_emails — it falls back to the configured provider 0.1ms
✓
never pre-empts domain_email_readiness_audit — it still returns its findings 0.1ms
✓
fails OPEN — a flaky connection read must not block a runnable tool 0.2ms
reverse index · 3 tests
✓
connectorBlocking maps a tool to the connector that makes it impossible 0.2ms
✓
toolsRequiring lists what a connector unlocks 0.7ms
✓
every blocked tool is also declared in actions — blocks is a SUBSET 0.6ms
funnel-selling copy (§5.2) — sell breadth only where it exists · 7 tests
✓
a broad connector names what else the one connection buys 0.2ms
✓
slack does not invent breadth 0.2ms
✓
notion does not invent breadth 0.1ms
✓
wordpress does not invent breadth 0.1ms
✓
vercel does not invent breadth 0.1ms
✓
apollo does not invent breadth 0.1ms
✓
names no internal tool slugs — CLAUDE.md §4 0.4ms
per-connector chip (§5.4) · 3 tests
✓
names the connector, so the chip is a decision not a navigation instruction 0.2ms
✓
no chip for a disabled connector — it would be a dead end 0.1ms
✓
keeps the panel-chip wire format the client already parses 0.1ms
the email-provider gate leads with the button, not the prose · 5 tests
✓
renders a human chip label, not the internal identifier 0.3ms
✓
offers the connect route 0.2ms
✓
states the block in ONE sentence and leaves the instruction to the button 0.3ms
✓
still protects the user's work when the caller passes it 0.1ms
✓
is recognised as a connector gate, so the chip layer picks it up 0.1ms
connectorDegraded — say what was lost, and offer the fix · 4 tests
✓
marks the result so the chip layer can see it 0.2ms
✓
is NOT a blocking gate — a degraded run produced a real answer 0.1ms
✓
offers no chip for a DISABLED connector — a panel with nothing to connect is a dead end 0.1ms
✓
says nothing for an ordinary result 0.1ms
src/db/user-role-write-permissions.vitest.ts
a cross-tenant reference write is refused by the user role · 20 tests
✓
emails_sent.insert with contact_id = another tenant's row is refused 2.2ms
✓
emails_sent.insert with contact_id = the caller's own row is still allowed 0.4ms
✓
emails_sent.insert with campaign_id = another tenant's row is refused 0.2ms
✓
emails_sent.insert with campaign_id = the caller's own row is still allowed 0.3ms
✓
drip_enrollments.insert with contact_id = another tenant's row is refused 0.2ms
✓
drip_enrollments.insert with contact_id = the caller's own row is still allowed 0.2ms
✓
drip_enrollments.insert with sequence_id = another tenant's row is refused 0.3ms
✓
drip_enrollments.insert with sequence_id = the caller's own row is still allowed 0.2ms
✓
drip_enrollments.insert with campaign_id = another tenant's row is refused 0.6ms
✓
drip_enrollments.insert with campaign_id = the caller's own row is still allowed 0.3ms
✓
drip_enrollments.update with campaign_id = another tenant's row is refused 0.2ms
✓
drip_enrollments.update with campaign_id = the caller's own row is still allowed 0.1ms
✓
campaigns.update with sequence_id = another tenant's row is refused 0.1ms
✓
campaigns.update with sequence_id = the caller's own row is still allowed 0.1ms
✓
contacts.update with campaign_id = another tenant's row is refused 0.2ms
✓
contacts.update with campaign_id = the caller's own row is still allowed 0.2ms
✓
contacts.insert with campaign_id = another tenant's row is refused 0.1ms
✓
contact_list_memberships.insert with contact_id = another tenant's row is refused 0.1ms
✓
contact_list_memberships.insert with contact_id = the caller's own row is still allowed 0.1ms
✓
an unassigned reference (null) is still allowed where the product writes one 0.2ms
the user role can no longer clear a suppression record · 5 tests
✓
no suppression column is in its UPDATE or INSERT lists, per the permission JSON 1.8ms
✓
it cannot DELETE a send row (a deleted bounce row is a cleared bounce) 0.2ms
✓
it holds NO permission of any kind on the suppression ledger (migration 189), and the snapshot has no root for it 0.7ms
✓
the schema snapshot agrees: no suppression field in its set/insert inputs, no delete root 0.8ms
✓
and nothing a real user flow writes was taken away 5.6ms
the user role cannot write the send claim (DECISIONS #52, migration 196) · 2 tests
✓
replayed from the migration files, neither its UPDATE nor its INSERT on emails_sent names status 0.3ms
✓
and the snapshot agrees: status is in neither input type the user role is given 0.2ms
the replay reads a re-grant of the send claim in every envelope and table form (V6-tenancy-F02) · 12 tests
✓
a later drop + create with status, the create in a top-level bulk (control): the replay's UPDATE names status 19.3ms
✓
a later drop + create with status, the create in bulk_keep_going: the replay's UPDATE names status 15.7ms
✓
a later drop + create with status, the create in bulk_atomic: the replay's UPDATE names status 15.5ms
✓
a later drop + create with status, the create in concurrent_bulk: the replay's UPDATE names status 16.3ms
✓
a later drop + create with status, the create in a bulk inside a bulk: the replay's UPDATE names status 15.7ms
✓
a later drop + create with status, the create in a bulk_keep_going inside a bulk: the replay's UPDATE names status 18.4ms
✓
a later drop + create with status, the create in a top-level array: the replay's UPDATE names status 16.4ms
✓
a later drop + create with status, the create in a single operation: the replay's UPDATE names status 15.6ms
✓
a later drop + create with status, the create in a hand-applied wrapper ({ _comment, steps }): the replay's UPDATE names status 20.4ms
✓
a later drop + create with status, the create in the table as a plain string: the replay's UPDATE names status 20.8ms
✓
a later drop + create with status, the create in the table as { name } with no schema: the replay's UPDATE names status 15.5ms
✓
a later drop + create with status, the create in the v1 operation name, without pg_: the replay's UPDATE names status 15.6ms
the user role cannot write a send's server record (DECISIONS #54, migration 196) · 2 tests
✓
replayed from the migration files, neither its UPDATE nor its INSERT on emails_sent names any of the six 0.8ms
✓
and the snapshot agrees 0.6ms
a tenant cannot place a shared-corpus entity in its own list (K11, migration 193) · 3 tests
✓
replayed from the migration files, the user role holds no INSERT or UPDATE on shared_lead_list_item, and keeps its SELECT 0.3ms
✓
the schema snapshot agrees: no write root and no insert input for the table, and both read roots remain 0.9ms
✓
the reveal ledgers: the user role holds no permission of any kind on either, and the snapshot has no root for them 0.6ms
check-graphql-schema fails when a suppression write comes back (header item 5) · 12 tests
✓
clean snapshot: passes 836.4ms
✓
contacts.unsubscribed_at writable again: exits 1 and names it 46.5ms
✓
a user-token document writing a suppression column fails the user-role check (the handleUpdateLeadStatus shape) 838.4ms
✓
emails_sent DELETE back: exits 1 and names it 45.8ms
✓
insert_shared_lead_list_item back for the user role: exits 1, names it and says why (K11) 46.0ms
✓
insert_shared_lead_list_item_one back for the user role: exits 1, names it and says why (K11) 43.3ms
✓
update_shared_lead_list_item back for the user role: exits 1, names it and says why (K11) 42.8ms
✓
update_shared_lead_list_item_by_pk back for the user role: exits 1, names it and says why (K11) 43.5ms
✓
update_shared_lead_list_item_many back for the user role: exits 1, names it and says why (K11) 42.1ms
✓
shared_lead_reveal write roots back for the user role: exits 1 and names all seven (swept with K11) 53.7ms
✓
shared_lead_pattern_reveal write roots back for the user role: exits 1 and names all seven (swept with K11) 46.4ms
✓
the insert input back with the 049 columns (a refresh after a re-grant): exits 1 43.6ms
scripts/lib/model-pricing-lib.vitest.mjs
listPrice — a discounted headline is never the list price · 6 tests
✓
deepseek, pinned to StreamLake: its UNDISCOUNTED price, never the 0.0886 headline 3.7ms
✓
deepseek without the pin: the cheapest provider charging no discount (DeepInfra) 0.6ms
✓
gpt-5.6-luna: the 0.20/1.20 headline — never the 0.10/0.60 flex endpoint 0.6ms
✓
glm-5.2: 0.70/2.20 — neither the 0.6496 headline (Novita −53.6%) nor 0.5625 (DeepInfra −25%) 0.5ms
✓
an id with no endpoint list is priced from the headline with its discount UNKNOWN 0.2ms
✓
every endpoint discounted: the headline is returned but flagged, never as a list basis 0.6ms
classify · 8 tests
✓
llama candidate is the cheapest provider, 0.10/0.32 0.4ms
✓
llama paying 1.19x over 897 rows is NEEDS_DECISION (paid_above_candidate), never DOWN_AUTO 0.5ms
✓
with the owner hold, the same cut is HELD — and still never DOWN_AUTO 0.6ms
✓
a minimax-shaped increase (0.25/1.00 → 0.30/1.20) is UP 0.4ms
✓
a cut deeper than 50% needs a decision (1.00 → 0.20); a 2.3% list cut is written (0.7168 → 0.70) 0.7ms
✓
an unreadable ledger never lets a cut through on its own 0.3ms
✓
a held model with an INCREASE is NEEDS_DECISION, and no Jev answer writes it 0.3ms
✓
within 0.5% is MATCH; absent from the catalog is GONE; an expiry inside 45 days rides along 0.3ms
Jev rails — its answer writes only when every rail holds · 8 tests
✓
durable at 0.8 with rails OK → write 0.2ms
✓
durable at 0.8 on a discounted basis → no write 0.2ms
✓
durable at 0.6 → no write 0.1ms
✓
promotion → no write 0.1ms
✓
a failed paid rail blocks even a confident durable 0.2ms
✓
no key → SKIPPED, stated, never a pass 0.2ms
✓
state addresses items by jevKey, never by position, and carries no verdict of ours 0.7ms
✓
jevKey and the endpoint agree with src/llm/jev.ts 0.3ms
rewriteTable · 4 tests
✓
changing luna rewrites exactly one line; every other byte is untouched 2.1ms
✓
an unknown id throws — the sync never adds an entry 0.9ms
✓
key order is preserved and the output parses back with the same keys 4.8ms
✓
setVerifiedAt moves only the date 0.5ms
formatRate · 1 test
✓
two to four decimals 0.2ms
the real table · 5 tests
✓
parses at least 20 entries — the floor that catches a guard gone blind 0.4ms
✓
blanking the tables removes every entry from the scan and keeps line numbers 0.8ms
✓
LLM_PRICE_HOLDS (the drift monitor's mirror in src/) agrees with PRICE_HOLDS, id and date 0.2ms
✓
PROVIDER_PINS agrees with the router pin (AGENT_LOOP_PROVIDER) 0.5ms
✓
legacy margin: luna at list never loses; gpt-5.4-mini loses past 33%; grok on every turn 0.3ms
checkCatalog — fetch injected · 5 tests
✓
the table this PR ships: every row MATCH, llama HELD, jev exempt → exit 0 1.6ms
✓
luna back at 1.00/6.00 exits 1 — an 80% cut is a decision, not a write 0.8ms
✓
a table BELOW list exits 1 (UP) 0.8ms
✓
a catalog it cannot read is BLIND (exit 2), never a pass or an ordinary failure 0.4ms
✓
an expiry inside 14 days fails --check; inside 45 only warns 1.3ms
review — a mixed move (one side up, the other cut) is a CUT, never UP · 5 tests
✓
a 70% output cut on a DISCOUNTED headline is not written as an increase 0.2ms
✓
a headline_only candidate cut on output is discount_unknown, not UP 0.2ms
✓
deepseek 0.14/0.28 → pinned 0.05/0.30 (64% input cut) is large_cut, never UP 0.2ms
✓
a small list-basis mixed move is mixed_move — a decision, not a write 0.2ms
✓
an increase on BOTH sides is still UP 0.1ms
review — a non-standard service tier is never the list price; the 50% cap is strict · 3 tests
✓
tags: /flex, /fast, /batch are tiers; regions, quantisations and DeepInfra's /turbo are not 0.4ms
✓
the standard tier discounted: the candidate is NEVER the 0.10/0.60 flex endpoint 0.4ms
✓
a cut of EXACTLY 50% is large_cut, not DOWN_AUTO 0.2ms
review — a pin that matches no endpoint is never silently dropped · 4 tests
✓
StreamLake absent: basis pin_missing, NEEDS_DECISION, never DOWN_AUTO, never a list basis 0.4ms
✓
pin_missing is a decision even when the fallback price happens to match the table 0.2ms
✓
renamed 'Streamlake' (case) or a new display name with the same tag still resolves the pin 0.5ms
✓
checkCatalog with StreamLake gone: deepseek is NEEDS_DECISION pin_missing and --check exits 1 0.4ms
review — a failed read of OUR OWN is an instrument failure, not a price finding · 2 tests
✓
deepseek endpoints 429 twice: UNRESOLVED (not NEEDS_DECISION discount_unknown), exit 2 0.6ms
✓
one 429 then success: the retry resolves the pin and the row is MATCH 1.0ms
review — a $0 candidate is never writable · 2 tests
✓
classify: 0/0 against a priced table is NEEDS_DECISION zero_candidate 0.3ms
✓
rails: a confident durable answer cannot write a zero, and a null ratio over ≥ 20 rows is a FAILED rail 0.4ms
review — who counts as a caller, and which quotes a price feeds · 2 tests
✓
tests and fixtures are not callers; the price tables are not callers of themselves 5.1ms
✓
quotesFed counts calcLlmCost(name, …) where `const name = '<id>'` in the same file 2.0ms
src/leads/args.vitest.ts
personaFromArgs — mapping, not guessing · 4 tests
✓
reads the audience the model declared instead of classifying the sentence 1.9ms
✓
marks executive seniority from the titles asked for, not from words in prose 0.5ms
✓
department is always undefined now that business_function no longer exists 0.2ms
✓
takes geography from the declared country, never from a parsed city 0.2ms
planFromArgs — strategy from declared fields · 3 tests
✓
routes local business by the declared search_type, not a postcode regex 0.9ms
✓
routes to named domains when the model supplied them 0.2ms
✓
sends niche audiences to their curated source and everything else to the provider 0.3ms
localPlanFromArgs — the pairing rule the geocode requires · 2 tests
✓
pairs postcode with country and never with a locality 0.3ms
✓
falls back to free-text location when no postcode was given 0.5ms
describeArgs — one request, one string · 2 tests
✓
produces the same description regardless of how the request was phrased 0.4ms
✓
describes a local search by category and place 0.2ms
argsFromLegacyQuery — carries the words, guesses nothing · 1 test
✓
puts the whole sentence in topic and infers no provider filter 0.2ms
list naming and Apollo titles · 2 tests
✓
names a list from the request when the user did not 0.3ms
✓
prefers the titles the user asked for over the audience default 0.7ms
rankByTopic — the other half of the topic contract · 4 tests
✓
surfaces the lead whose organisation matches the intent 0.4ms
✓
keeps provider order when the topic says nothing 0.3ms
✓
drops nothing — ranking reorders, it never filters 0.4ms
✓
ignores words that carry no signal, so a whole sentence still ranks 0.2ms
suggestIndustries — propose, never auto-filter · 5 tests
✓
matches the taxonomy on the user's own words 8.1ms
✓
returns nothing when the overlap is not distinctive 1.1ms
✓
ignores taxonomy filler that would otherwise match everything 0.2ms
✓
prefers the more specific name among equal matches 0.6ms
✓
never proposes a value the provider would reject 1.3ms
corpusRequestFromArgs · 5 tests
✓
sends the role as a filter and never inside the query 1.1ms
✓
takes titles ONLY from person_titles, never the audience default 0.4ms
✓
sends the topic as match text and the industry as a filter — never both 0.6ms
✓
asks a local search for the business category and no role at all 0.6ms
✓
returns an empty query rather than a stray separator when nothing was given 0.3ms
describeArgs survives model-shaped arguments · 3 tests
✓
does not throw when an array field arrives as a bare string 0.9ms
✓
describes a scalar exactly as it describes the one-element array 0.2ms
✓
still handles null, undefined and empty arrays without inventing text 0.4ms
corpusRequestFromArgs — who gets ranked first · 3 tests
✓
a LOCAL search stops preferring business mailboxes 0.1ms
✓
a PEOPLE search keeps preferring them — the B2B default is unchanged 0.4ms
✓
the flag travels as an explicit boolean, never undefined 0.7ms
corpusRequestFromArgs — firmographics reach the corpus · 6 tests
✓
passes industry, geography and a headcount RANGE 1.4ms
✓
takes the WIDEST bounds across several requested bands 0.5ms
✓
omits bounds entirely when no size was asked for 0.4ms
✓
KEEPS A TRANSLATED INDUSTRY OUT OF THE QUERY — it is a filter, not match text 0.6ms
✓
KEEPS AN UNTRANSLATED industry in the query — there the text is all we have 0.9ms
✓
local business still sends no role and no firmographics 0.2ms
country reaches the corpus in the alphabet the corpus stores · 4 tests
✓
translates the provider’s country NAME into ISO-2 0.5ms
✓
leaves an ISO code alone 0.3ms
✓
sends NOTHING rather than a string too long for the column 0.3ms
✓
never emits anything but two letters 1.3ms
corpusRequestFromArgs — local business keeps its own geography (RCA 2026-08-29) · 5 tests
✓
carries the locality into regions instead of dropping it 0.3ms
✓
carries the country, so the search does not silently fall back to the US default 0.2ms
✓
still ranks consumer mailboxes fairly and asks for no job title 0.3ms
✓
leaves a postal code unapplied rather than sending it as a region 0.4ms
✓
omits country when none was given rather than inventing one 0.2ms
person_locality reaches the corpus as a region (migration 151) · 1 test
✓
sends a city, not just a US state 0.4ms
describeArgs treats a named company domain as a complete ask (2026-09-15) · 2 tests
✓
"contacts at stripe.com" is described, not refused 0.2ms
✓
an empty ask is still empty 0.2ms
a country we cannot filter on is DECLARED, never defaulted (2026-09-15) · 3 tests
✓
"Antarctica" is carried out as countryUnmatched with no country filter 0.5ms
✓
a resolvable name and a bare ISO code carry no unmatched marker 1.1ms
✓
no country named means no marker either 0.3ms
src/runtime/egress.vitest.ts
normalizeUserUrl · 8 tests
✓
adds https to a bare host — existing product behaviour, kept 3.6ms
✓
refuses schemes that are not http(s) 0.8ms
✓
refuses hosts nobody should be able to name 1.8ms
✓
does NOT refuse public hosts that merely look similar 0.7ms
✓
refuses the IPv6 forms of an internal address, not only [::1] 2.0ms
✓
refuses decimal, octal, hex and short IPv4 spellings — what fetch connects to, not what was typed 1.0ms
✓
refuses trailing-dot, .localhost, single-label and shared-address-space hosts 0.6ms
✓
does NOT refuse public hosts that start with "fc" or "fd" — only IPv6 literals are in fc00::/7 0.7ms
batch tally — one write per phase, not one per URL · 2 tests
✓
counts into the tally and writes the bucket once, on flush 10.4ms
✓
never passes its own options through to fetch() 1.6ms
screenUserUrl · 1 test
✓
answers before any connection and records a refusal 0.7ms
fetchUserUrl · 9 tests
✓
records every fetch, which is what makes an abuse report answerable 0.9ms
✓
records a DENIAL separately — that is the number worth watching 0.5ms
✓
re-validates EVERY redirect hop — a public host must not redirect us inward 0.6ms
✓
follows a legitimate redirect and returns the final response 5.2ms
✓
stops at the redirect cap instead of looping 0.8ms
✓
refuses an oversized response before reading it 0.8ms
✓
never leaks the target or an internal detail into user-facing copy 0.7ms
✓
a metrics outage never fails the fetch 1.3ms
✓
with no metrics binding it still fetches — the record is best-effort, the control is not 0.9ms
readEgressBuckets · 1 test
✓
returns the hours that exist, newest first, and tolerates gaps 0.8ms
isPrivateHost — every IPv6 form that embeds an IPv4 address is judged by that address · 2 tests
✓
refuses SIIT, local-use NAT64, 6to4 and Teredo forms of an internal address 1.4ms
✓
still passes those prefixes when the address inside them is public 0.6ms
fetchUserUrl — the body cap holds whether or not a length is declared · 3 tests
✓
refuses a body with no Content-Length once it passes the cap, and stops reading it 2.4ms
✓
applies the 8 MB default to an undeclared body too 1.6ms
✓
hands a body under the cap through byte for byte, with its status, headers and final URL 0.9ms
fetchUserUrl — followRedirects: false · 1 test
✓
returns the 3xx itself, unfollowed, so a caller recording a chain can check each next hop 2.7ms
userUrlFetcher — the choke point in the shape of fetch() · 3 tests
✓
throws an EgressRefusal for a private target and never connects 0.5ms
✓
re-checks a redirect a caller asked to follow, and returns the final response otherwise 1.1ms
✓
throws a plain error with the readable reason when the site cannot be reached 0.6ms
fetchUserUrl — a redirect on a request that carries credentials is refused, never followed · 23 tests
✓
301 with Authorization (object): refused at the first hop, nothing sent on 0.5ms
✓
301 with authorization (Headers): refused at the first hop, nothing sent on 0.3ms
✓
301 with Cookie (tuples): refused at the first hop, nothing sent on 0.4ms
✓
301 with Proxy-Authorization: refused at the first hop, nothing sent on 0.3ms
✓
302 with Authorization (object): refused at the first hop, nothing sent on 0.3ms
✓
302 with authorization (Headers): refused at the first hop, nothing sent on 0.3ms
✓
302 with Cookie (tuples): refused at the first hop, nothing sent on 0.4ms
✓
302 with Proxy-Authorization: refused at the first hop, nothing sent on 0.3ms
✓
303 with Authorization (object): refused at the first hop, nothing sent on 0.2ms
✓
303 with authorization (Headers): refused at the first hop, nothing sent on 0.3ms
✓
303 with Cookie (tuples): refused at the first hop, nothing sent on 0.3ms
✓
303 with Proxy-Authorization: refused at the first hop, nothing sent on 0.2ms
✓
307 with Authorization (object): refused at the first hop, nothing sent on 0.2ms
✓
307 with authorization (Headers): refused at the first hop, nothing sent on 0.3ms
✓
307 with Cookie (tuples): refused at the first hop, nothing sent on 0.2ms
✓
307 with Proxy-Authorization: refused at the first hop, nothing sent on 0.2ms
✓
308 with Authorization (object): refused at the first hop, nothing sent on 0.2ms
✓
308 with authorization (Headers): refused at the first hop, nothing sent on 0.3ms
✓
308 with Cookie (tuples): refused at the first hop, nothing sent on 0.2ms
✓
308 with Proxy-Authorization: refused at the first hop, nothing sent on 0.2ms
✓
a same-site redirect is refused too — the rule is about the credential, not the destination 0.3ms
✓
followRedirects:false does not hand a credentialed caller the 3xx to follow itself 0.3ms
✓
a request with no credential still follows its redirect 0.5ms
src/chat/speech-act-orders.vitest.ts
orders are recognised as orders · 16 tests
✓
directive: "run my AI visibility panel now for kakunin.ai — 12 promp…" 11.2ms
✓
directive: "freeze my weekly AI visibility panel to the exact 8 prom…" 2.8ms
✓
directive: "Freeze the weekly panel to these exact prompts: best KYC…" 0.2ms
✓
directive: "Freeze my weekly tracking panel to exactly these 8 promp…" 0.2ms
✓
directive: "turn on weekly ai visibility tracking for kakunin.ai…" 0.2ms
✓
directive: "run an seo audit…" 0.1ms
✓
directive: "disable the weekly cron…" 0.2ms
✓
directive: "lock my prompt set…" 0.1ms
✓
directive: "pause my active campaign…" 0.5ms
✓
directive: "stop weekly tracking…" 0.2ms
✓
directive: "schedule the panel for Sundays…" 0.2ms
✓
directive: "re-run the AI visibility check…" 0.1ms
✓
directive: "why is my visibility down, and find me 50 CTOs at fintec…" 0.1ms
✓
directive: "do it…" 0.1ms
✓
directive: "ok do it…" 0.1ms
✓
directive: "go ahead…" 0.1ms
the failures this module exists for stay questions · 14 tests
✓
question: "We have 200 tokens of budget and one week. Is it smarter…" 0.1ms
✓
question: "budget is 200 tokens and one week, technical SEO or thre…" 2.1ms
✓
question: "technical SEO or three articles, given 200 tokens?…" 0.7ms
✓
question: "budget for one week. technical fixes or new articles?…" 0.1ms
✓
question: "limited budget this week. fix technical SEO, or write th…" 0.1ms
✓
question: "with one week and 200 tokens, should we fix technical SE…" 0.1ms
✓
question: "is it worth fixing technical SEO or writing three articl…" 0.1ms
✓
question: "one week of budget: fix the technical issues, or publish…" 0.1ms
✓
question: "Explain how AI search engines decide which sites to cite…" 0.1ms
✓
question: "my numbers dropped…" 0.1ms
✓
question: "why is my AI visibility down…" 0.1ms
✓
question: "Am I visible in AI search?…" 0.1ms
✓
question: "how do I improve the SEO of vercel.com?…" 0.1ms
✓
the whole 161K-token paraphrase class, counted 0.6ms
the product can read its own copy · 13 tests
✓
tool-format.ts weeklyTrackingLine: "stop weekly tracking" 0.1ms
✓
tool-format.ts weeklyTrackingLine: "track weekly with ChatGPT only" 0.1ms
✓
dashboard.ts prompt library: "Show my saved contacts" 0.1ms
✓
tool-format.ts chip: "Show my Share of Voice trend" 0.1ms
✓
tool-format.ts chip: "Show my tracked keywords" 0.1ms
✓
skills.ts chip: "View usage" 0.1ms
✓
dashboard.ts prompt library: "Fix my safe email DNS issues in Cloudflare" 0.1ms
✓
tool-format.ts chip: "Re-run AI visibility check" 0.1ms
✓
tool-format.ts chip: "Rewrite this page for AEO+GEO" 0.1ms
✓
tool-format.ts chip: "Try the audit again" 0.1ms
✓
dashboard.ts prompt library: "Assign my contacts to my active campaign" 0.1ms
✓
dashboard.ts prompt library: "Enroll my contacts in my welcome sequence" 0.1ms
✓
dashboard.ts prompt library: "Show campaign performance for my active campaign" 0.1ms
the previous predicate's false positives stay fixed · 4 tests
✓
not an order: "do we have enough trust signals on our content…" 0.1ms
✓
not an order: "do we need an aeo agency or can we do geo in house…" 0.1ms
✓
not an order: "do we block gptbot and google-extended or allow them…" 0.1ms
✓
not an order: "our social and email and seo teams compete with each oth…" 0.1ms
the closed-class guard is what makes the wide vocabulary safe · 4 tests
✓
a declared verb after an overt subject is not an imperative 0.3ms
✓
politeness is stripped before the guard, or "can you check X" reads as the auxiliary 0.2ms
✓
an explanation verb is imperative in form and still not an order 0.2ms
✓
a verb whose complement is `why` orders understanding, not work 0.2ms
src/admin/readiness-labels.vitest.ts
auth — the same refusal as GET /api/admin/readiness, before any KV call · 6 tests
✓
no header → 403 {error:'Forbidden'} on all three routes, identical to the readiness route, 0 KV calls 28.1ms
✓
a wrong header → 403 {error:'Forbidden'} on all three routes, identical to the readiness route, 0 KV calls 2.5ms
✓
a CORRECT ?secret= and no header → 403 {error:'Forbidden'} on all three routes, identical to the readiness route, 0 KV calls 2.1ms
✓
a ?secret= beside a valid header → 403 {error:'Forbidden'} on all three routes, identical to the readiness route, 0 KV calls 1.0ms
✓
the Nhost admin secret opens it too, by header (checkAdminSecret accepts both) 1.8ms
✓
a method the route does not serve is a 405 after auth, not a silent GET 0.6ms
validation — every bad value is refused and nothing is written · 20 tests
✓
refuses a not in the set 1.6ms
✓
refuses a with the wrong case 0.7ms
✓
refuses a as a number 0.9ms
✓
refuses b = partly (only (a) has partly) 0.7ms
✓
refuses b = nothing_asked 0.7ms
✓
refuses c negative 0.6ms
✓
refuses c with a letter 2.7ms
✓
refuses c with semicolons 0.7ms
✓
refuses c with a decimal 0.6ms
✓
refuses c with an empty item 0.5ms
✓
refuses c as an array 0.5ms
✓
refuses a note over the limit 0.5ms
✓
refuses a note with a line break 0.5ms
✓
refuses a note with a tab 0.6ms
✓
refuses a note with an email address 0.8ms
✓
refuses a note that is not text 0.7ms
✓
refuses an unknown field 1.0ms
✓
refuses a body that is not a JSON object 1.6ms
✓
accepts every defined value, blanks as "not answered", and normalises (c) 2.1ms
the frame — only its 24 sessions can be saved · 2 tests
✓
a session_id outside the frame is refused and nothing is written 1.9ms
✓
GET serves all 24 in seq order with no answers yet, and labelled counts (a) AND (b) 2.4ms
the transcript badge comes from transcript_readable_est and the date beside it · 2 tests
✓
on 2026-10-31: seq 4, 5, 11, 13, 16 readable to ~2026-11-11; seq 18 and the rest expired 1.1ms
✓
readable through the expiry date, expired the day after 0.2ms
CSV round trip — the export is the source sheet · 4 tests
✓
nothing saved: the export IS the sheet the frame was built from (sha256 22226c4e…) 1.5ms
–
on a machine with the sheet: header line and every byte equal the real labels.csv 0.0ms
✓
saved answers come back through the parser unchanged; fact columns and other rows untouched 15.8ms
✓
quoting is the source rule: only a quote, comma or line break is quoted 0.9ms
CSV injection — a note that starts like a formula is inert in the export (V-labels F-01) · 2 tests
✓
all ten are stored verbatim, and no exported cell starts with = + - @ tab or CR 22.4ms
✓
every leading character the rule names is neutralised, and nothing else is touched 2.0ms
failure — never a blank answer, never "saved" · 5 tests
✓
a KV read that fails → GET 503 in plain words, reported to Sentry, no rows served 1.5ms
✓
a KV read that fails → the CSV is refused (503 JSON), never a sheet with blanks 0.7ms
✓
a KV write that fails → POST 503 "Not saved", no ok, reported to Sentry 0.7ms
✓
an unreadable saved value is flagged on its row, reported, and blocks the export 1.4ms
✓
no KV binding → 503 that says so, for reads and saves 0.4ms
telemetry — seq and which answers are set, never their text · 1 test
✓
readiness_label_saved carries no note, no session id and no answer value 0.5ms
generator — the committed frame is what the sheet generates, and it refuses what must not ship · 8 tests
–
on a machine with the sheet: --check passes (the committed module is the generator's output) 0.0ms
✓
the committed module is byte-identical to the generator run over the sheet it records (reconstructed from the frame) 118.6ms
✓
refuses an @ in a fact cell, writes nothing, and never prints the cell 111.6ms
✓
refuses a foreign domain, writes nothing, and never prints the cell 116.2ms
✓
refuses a name in a count column, writes nothing, and never prints the cell 109.2ms
✓
refuses CRLF line endings, writes nothing, and never prints the cell 120.0ms
✓
refuses a formula-leading cell (the export would neutralise it, so it could never match), writes nothing, and never prints the cell 110.9ms
✓
refuses a missing answer column, writes nothing, and never prints the cell 121.3ms
scripts/lib/deploy-retry.vitest.mjs
deploy:retry — R1, a merge that lands DURING the retried build · 8 tests
✓
ROLLED BACK: the later merge built and deployed first, then the retried older sha replaced it → exit 3 6.8ms
✓
the same merge still BUILDING when the retry finishes is not a rollback → exit 0 with a note 1.1ms
✓
a later merge that touches only the blog cannot be rolled back by an outbound retry 0.6ms
✓
REFUSES at the last moment when main moves between the plan and the POST — nothing is triggered 0.7ms
✓
the recovery the ROLLED BACK line prints is not a dead end: redeploying the carrier is allowed WITH --redeploy-succeeded 0.7ms
✓
R1 with a later ADMIN-ONLY merge on top: the line names M (the outbound carrier), never the tip N 1.1ms
✓
a later build that finishes WHILE the later builds are being read is not a false ROLLED BACK (reads builds first, production after) 0.8ms
✓
a retried deploy not yet visible is not a false LIVE: production still shows M on the first read, then S 0.7ms
deploy:retry — the rest of the flow · 9 tests
✓
a retried build that fails too → exit 3, and says so 2.9ms
✓
the plain case: retried build succeeds and production flips to the sha → exit 0 0.6ms
✓
success that production never shows within the grace → exit 4, not LIVE 0.4ms
✓
a retried build the Cloudflare API can never read → exit 5 (state UNKNOWN), not "did not finish" 1.2ms
✓
a build that never finishes → exit 4 after the timeout, state UNKNOWN 0.5ms
✓
reads ONLY CLOUDFLARE_BUILDS_TOKEN — the deploy token's name is not a fallback 0.4ms
✓
--dry-run with a token resolves the trigger and prints the POST, and posts nothing 0.3ms
✓
--no-wait says the rollback check does not run 0.2ms
✓
refuses when the build it would reuse ran for a different commit 0.3ms
deploy:retry — a stale origin/main or an unplaceable production is a refusal, never a rollback · 6 tests
✓
the reviewer's reproduction: git fetch FAILS and production serves a later commit this clone never saw → exit 5, nothing sent 0.4ms
✓
fetch works but production serves a commit this clone cannot place ("unknown") → REFUSED, nothing sent 0.3ms
✓
the fetch right before the POST fails → exit 5, nothing sent 0.3ms
✓
the fetch AFTER the retried build fails → exit 4, rollback NOT ruled out (never LIVE) 0.4ms
✓
diverged, unstamped and unreachable production each refuse; unreachable proceeds only with --allow-unreachable 0.8ms
✓
a Worker with no build-id endpoint is not asked for a relation (admin retry after a src-only merge) 0.3ms
verifyCommit — end to end against a fake world (the --after-rerun branch included) · 7 tests
✓
--after-rerun after the rerun FAILED too (two failures): exit 3 at once — it used to skip the rerun's verdict and wait 15 min 1.6ms
✓
--after-rerun with one failure: skips it, then the rerun's success and the flip → LIVE 0.7ms
✓
--after-rerun <id> skips exactly that run and older, so a second rerun is waited for 0.6ms
✓
FAILED while main moved on to an ADMIN-ONLY tip: offers deploy:retry of the sha, never deploy:verify of the tip 0.4ms
✓
FAILED while main moved on with an outbound change: verify the carrier with --worker, do not retry 0.4ms
✓
FAILED and main cannot be refreshed: says so instead of treating the stale tip as "nothing moved" 0.3ms
✓
check runs unreadable for the whole window → exit 5 through verifyCommit too 0.7ms
deploy-io — the git reads · 3 tests
✓
both diffs pass --no-renames (a move out of src/ must still name its src/ path) 0.9ms
✓
fetchMain REPORTS whether git fetch worked — every rollback check depends on it 0.3ms
✓
makeIsAncestor re-fetches after a backoff instead of once per pair — one failed fetch is not permanent 0.5ms
merge-pr — arguments · 5 tests
✓
`--deploy-timeout-min 20 130` merges #130, not #20 0.6ms
✓
defaults: patch, 15 minutes, watching 0.9ms
✓
the skip is --skip-deploy-watch, or NQZ_SKIP_DEPLOY_VERIFY=1 for a scripted batch 0.2ms
✓
anything but exactly 1 in the env var still watches — and says so 0.4ms
✓
usage errors: no number, a bad level, a non-positive timeout 0.2ms
merge-pr — after the merge · 5 tests
✓
base ≠ main → exit 0 at once: Workers Builds deploys main only 0.3ms
✓
the escape hatch → exit 0 with the line that says merged is not live 0.5ms
✓
a waived watch with NO merge sha still exits 0 — a batch under set -e must not die on a lookup nobody needed 0.3ms
✓
otherwise → verify 0.2ms
✓
a non-LIVE verify says the PR IS merged 0.1ms
readMergeSha — GitHub never reports the merge commit → exit 5, "MERGED" wording · 5 tests
✓
exhausts its 6 attempts, 5 s apart, then merge-pr exits 5 saying the PR IS merged 0.7ms
✓
gh throwing every time is the same exhausted path, not a crash 0.2ms
✓
a merge commit that will not resolve locally is retried, not trusted 0.3ms
✓
a waived watch reads the merge commit ONCE and fetches nothing (readMergeShaFor) 0.5ms
✓
an OPEN PR or an abbreviated oid never returns a sha 0.4ms
the retry script still runs as a script · 1 test
✓
prints usage and exits 1 when invoked directly — importing it for these tests must not have made it a silent no-op 39.5ms
src/billing/population.vitest.ts
classifyPopulation reproduces the ratified P0-01 map (R3, 351 ids, 0 changes) · 3 tests
✓
has the ratified universe 2.3ms
✓
agrees on class, subkind and rule for every id 1.1ms
✓
counts P_real 313 / P_harness 35 / P_probe 1 / unmapped 2 — the ratified figures 0.6ms
session shapes — the instrument SESSION RULE, verbatim · 25 tests
✓
session-k3j4h5g6f7 → client 0.5ms
✓
SESSION-ABC123 → client 0.2ms
✓
session-1758790000000 → epoch 0.2ms
✓
session-1758790004321 → epoch 0.2ms
✓
teval-abc123 → eval 0.5ms
✓
deepeval-0a1b2c → eval 0.2ms
✓
replay-01 → replay 0.2ms
✓
probe-read2-abc → other_scripted 0.1ms
✓
smoke-a1 → other_scripted 0.1ms
✓
win-abc123 → other_scripted 0.1ms
✓
faudit-xyz → other_scripted 0.1ms
✓
job:11111111-2222-4333-8444-555555555555 → product 0.1ms
✓
report:11111111-2222-4333-8444-666666666666 → product 0.1ms
✓
chatmsg-11111111-2222-4333-8444-777777777777 → product 0.1ms
✓
sov-cron-0a1b2c3d → product 0.1ms
✓
rank-cron-deadbeef → product 0.1ms
✓
harness-shaped = epoch, eval, replay, other scripted; never client, product or empty 0.4ms
✓
agrees with isSyntheticSession on every non-product, non-epoch id (the allowlist is pinned to sessions.ts) 0.3ms
✓
EVAL_SESSION_PREFIXES is the same literal observability.ts declares 0.6ms
✓
the client still mints the shape the client rule allows 2.5ms
featuresFor applies the list semantics the map and the code use · 7 tests
✓
R01: the test-cap id is the probe tenant whatever else it is 1.0ms
✓
R02: a harness login is harness/momentic 0.3ms
✓
R05: a +tag or gmail-dot sibling of a listed address is a probe signup 0.4ms
✓
R06: a listed email (normalised) or a listed id is internal 0.5ms
✓
R07/R08/R09: empty, label and unlisted-email ids 0.6ms
✓
R10–R14: session shapes decide the rest 0.6ms
✓
an unknown auth status never demotes a uuid: it is assumed in auth 0.2ms
the Hasura spelling · 3 tests
✓
P_real excludes the id list, non-uuid ids and harness-shaped sessions 0.5ms
✓
a table without a session column gets the id arms only 0.2ms
✓
pooled is an always-true field so the query shape is shared 0.1ms
excludedIds — ids only, never an address · 1 test
✓
collects listed ids, env ids and users whose email classifies them out 0.4ms
the row-level index · 4 tests
✓
P_real keeps real ids on non-harness sessions only 0.7ms
✓
THE SESSION RULE stands on its own: a real id (known from auth, no rows observed) on a harness-shaped session is not P_real 0.3ms
✓
P_probe keeps the test tenant; pooled keeps everything 1.1ms
✓
an id outside a complete users list is not in auth 0.2ms
only CHAT rows carry a chat session · 1 test
✓
a Stripe top-up row with its checkout session id neither demotes the id nor is dropped 0.3ms
ledgerPopulation — the declaration · 2 tests
✓
pooled must say why; P_harness has no query-side spelling 1.0ms
✓
filter() applies the index to fetched rows 0.3ms
population-env wiring · 3 tests
✓
builds the lists from env, gate.ts and the env-driven harness ids 0.5ms
✓
emailVariantPattern matches +tags and gmail dots of a listed address and nothing else 1.0ms
✓
HARNESS_LOGIN_EMAILS in wrangler.toml is exactly what the harness configs type 0.6ms
src/chat/weekly-optin-routing.vitest.ts
weekly opt-in orders reach the weekly opt-in, not a one-off measurement · 4 tests
✓
(a) "Track my AI visibility weekly on Tuesdays" is not claimed by the measurement route 34.7ms
✓
(b) "Track my share of voice weekly on Tuesdays" reaches the opt-in deterministically 1.4ms
✓
(c) the phrasing that already worked now takes the same deterministic road 0.4ms
✓
a one-off measurement ask still goes to the measurement route 9.6ms
ordersRecurringWork: an order or request carrying a calendar cue · 18 tests
✓
order: Track my AI visibility weekly on Tuesdays 0.3ms
✓
order: Monitor my share of voice every week 0.2ms
✓
order: please check my AI visibility once a week 0.2ms
✓
order: Can you track my AI visibility every Monday? 0.2ms
✓
order: I want my share of voice tracked every Friday 0.7ms
✓
order: Can I get weekly AI visibility tracking? 0.4ms
✓
order: Track my AI visibility weekly with ChatGPT only 0.2ms
✓
order: Send me a weekly AI visibility report 0.1ms
✓
order: Email me my rankings every Monday 0.1ms
✓
order: Run the AI visibility check on a weekly basis 0.1ms
✓
not an order: Check my AI visibility 0.2ms
✓
not an order: check my weekly traffic 0.1ms
✓
not an order: Is weekly tracking on? 0.1ms
✓
not an order: What does weekly tracking cost? 0.1ms
✓
not an order: How did my AI visibility change last week? 0.1ms
✓
not an order: We track our AI visibility weekly 0.1ms
✓
not an order: why is my weekly share of voice down 0.1ms
✓
no measurement route answers a schedule order it cannot run as one 0.5ms
parseSovWeeklyCommand · 21 tests
✓
Track my AI visibility weekly on Tuesdays -> day 2 0.7ms
✓
Track my share of voice weekly on Tuesdays -> day 2 0.3ms
✓
Track my share of voice weekly -> day null 0.2ms
✓
Switch on weekly share of voice tracking, running every Tuesday -> day 2 0.2ms
✓
Turn on weekly AI visibility tracking on Sundays -> day 0 0.1ms
✓
Please monitor our AI visibility every Monday -> day 1 0.2ms
✓
Can you track my share of voice every week? -> day null 0.2ms
✓
I want my AI visibility tracked every Friday -> day 5 0.2ms
✓
Set up weekly SOV tracking on Saturdays -> day 6 0.1ms
✓
Measure my visibility in AI search once a week -> day null 0.1ms
✓
not a whole weekly command: Check my AI visibility 0.1ms
✓
not a whole weekly command: Is weekly AI visibility tracking on? 0.1ms
✓
not a whole weekly command: Track my AI visibility weekly with ChatGPT only 0.1ms
✓
not a whole weekly command: Track my AI visibility weekly on Mondays and Thursdays 0.1ms
✓
not a whole weekly command: Track my AI visibility daily 0.2ms
✓
not a whole weekly command: Track my AI visibility every other week 0.1ms
✓
not a whole weekly command: Track my keywords weekly 0.1ms
✓
not a whole weekly command: Track my AI visibility weekly and email me the results 0.1ms
✓
not a whole weekly command: Stop my weekly AI visibility tracking 0.1ms
✓
anything it declines still leaves the measurement route and reaches the model 3.0ms
✓
is stable across calls (no global-regex state carried between messages) 0.3ms
the rules around it keep their own phrases · 2 tests
✓
stop / resume commands stay with the scan rules 0.4ms
✓
the confirm and cancel chips stay with the sov_trend gate rules 3.1ms
the "Track my share of voice weekly" chip and the rule that catches it · 1 test
✓
sov_trend offers it when weekly tracking is off, and the router sends it to the opt-in 2.1ms
sovWeeklyOptInArgs: the first half of the gate, in the schema's own words · 1 test
✓
weekly on, the day as `day`, never `confirm` — and valid against the sov_trend schema 2.0ms
weeklyTrackingLine names the tenant's own day · 2 tests
✓
on and off lines say "every Tuesday", not the Monday they printed before 0.6ms
✓
with no resolver output it says "every week" rather than guess a day 0.1ms
src/runtime/route-error-text.vitest.ts
a database failure at a user-facing route reaches the person as the route's own sentence · 26 tests
✓
GET /api/emails/drafts 90.8ms
✓
PATCH /api/emails/d0000000-0000-4000-8000-000000000001 7.4ms
✓
DELETE /api/emails/d0000000-0000-4000-8000-000000000001 3.0ms
✓
POST /api/emails/drafts/delete 4.1ms
✓
GET /api/emails/sent 3.3ms
✓
POST /api/contacts/delete 2.5ms
✓
GET /api/contacts/d0000000-0000-4000-8000-000000000001/activity 2.6ms
✓
PATCH /api/contacts/d0000000-0000-4000-8000-000000000001/status 4.5ms
✓
POST /api/lists/Founders/members 3.7ms
✓
POST /api/contacts/import 6.6ms
✓
PATCH /api/contacts/campaign 5.2ms
✓
POST /api/campaigns 3.5ms
✓
DELETE /api/campaigns/d0000000-0000-4000-8000-000000000001 12.4ms
✓
GET /api/campaigns/d0000000-0000-4000-8000-000000000001/dashboard 3.4ms
✓
POST /api/keywords/delete 2.6ms
✓
POST /api/ai-prompts/delete 3.0ms
✓
PATCH /api/ai-prompts/d0000000-0000-4000-8000-000000000001 2.1ms
✓
GET /api/sequences 4.2ms
✓
POST /api/sequences 2.5ms
✓
GET /api/connectors 4.3ms
✓
DELETE /api/connectors/slack 1.6ms
✓
GET /api/seo/serp-spider/tasks 2.5ms
✓
GET /api/seo/serp-spider/results?taskId=d0000000-0000-4000-8000-000000000001 1.6ms
POST /api/website-health-check: a crawl failure is a count by type, not a Sentry event · 1 test
✓
a site that redirects the crawler inward is counted as refused_private_host, anonymously 6.3ms
routeErrorText: the choke point a route's catch calls · 3 tests
✓
a database failure becomes the route's sentence, and the raw text goes to Sentry 0.7ms
✓
a transport failure of the database is the route's sentence too 0.6ms
✓
CONTROL: a plain sentence of ours is kept as it is 0.7ms
check-route-error-text: a new raw-error response at a user-facing route fails the build · 19 tests
✓
the tree as it is passes 2097.2ms
✓
the failing batch reports exactly one finding per fixture, and nothing else 2013.7ms
✓
fails on e.message 0.3ms
✓
fails on e?.message ?? String(e) 0.2ms
✓
fails on String(e) 0.1ms
✓
fails on a template 0.2ms
✓
fails on a local alias 0.2ms
✓
fails on a 200 with an error field 0.1ms
✓
fails on Response.json 0.1ms
✓
fails on new Response 0.1ms
✓
fails on instanceof ternary 0.2ms
✓
fails on a .catch( callback that answers with the error 0.1ms
✓
passes publicErrorText 2119.4ms
✓
passes routeErrorText 0.3ms
✓
passes a predicate on the error in the status 0.3ms
✓
passes a comparison on the message 0.1ms
✓
passes a status code read 0.1ms
✓
passes an admin gate before it 0.1ms
✓
an emptied tree is not a pass: exit 2 56.4ms
src/admin/gsc-query-quality.vitest.ts
classifyQuery — real noise from the live table · 12 tests
✓
flags scraper query "ai seo tools" -site:reddit.com -site:twitter.com -site:x.com 1.8ms
✓
flags scraper query "moz" "serp" -site:reddit.com -site:twitter.com -site:x.com 0.3ms
✓
flags scraper query "backlinko" -site:reddit.com -site:twitter.com -site:x.com 0.1ms
✓
flags scraper query "otterly.ai" -site:reddit.com -site:twitter.com -site:x.com 0.2ms
✓
flags stacked quoted phrases — the compound-query signature of a research tool 1.1ms
✓
leaves a SINGLE quoted phrase alone — people really do search exact phrases 0.7ms
✓
keeps the genuine query nqzai 0.6ms
✓
keeps the genuine query nqz.ai 0.2ms
✓
keeps the genuine query ai marketing planner 0.5ms
✓
keeps the genuine query domain reputation checker 0.2ms
✓
separates zero-impression rows as no_signal rather than calling them junk 0.3ms
✓
does not mistake a hyphenated word for a negative operator 0.1ms
classifyQueries · 2 tests
✓
splits the list, counts every bucket, and never silently drops a row 0.5ms
✓
ranks useful queries by IMPRESSIONS, surfacing demand we are failing to convert 0.2ms
queryOpportunity · 4 tests
✓
calls out striking distance in the 4-20 band 0.2ms
✓
does not call position 2 striking distance — that win is already banked 0.1ms
✓
flags ranks-well-but-unclicked as a title/meta problem, not a ranking one 0.2ms
✓
stays silent when there is too little data to claim anything 0.1ms
classifyQuery — text no person types (spec §4.1, certain) · 22 tests
✓
+dbzy5.com domain reputation → machine (encoding artifact (leading + or %)) 0.1ms
✓
%dbzy5.com domain reputation → machine (URL-encoded text) 0.3ms
✓
%hr software 7 day free trial ultimate de → machine (encoding artifact (leading + or %)) 0.1ms
✓
+generate 4 buyer search prompts. → machine (encoding artifact (leading + or %)) 0.1ms
✓
best%20free%20project%20management%20software → machine (URL-encoded text) 0.1ms
✓
best+free+seo+tools → machine (URL-encoded text (+ for spaces)) 0.1ms
✓
keyword-zenpcqdf → machine (generated test token) 0.1ms
✓
### 3. geographic prioritization → machine (markup fragment) 0.1ms
✓
seo "audit" tool → machine (markup fragment) 0.1ms
✓
"acme corporation" ceo john smith leadership page → machine (placeholder entity) 0.1ms
✓
a pasted spreadsheet row is machine: "keyword explorer",https://moz.com/explorer,,140,1,1,1,1 0.2ms
✓
a pasted spreadsheet row is machine: keywords,search vol.,traffic forecast,cpc 0.2ms
✓
a sentence lifted from the middle of a document is machine 0.2ms
✓
keeps the human query ai sales plan generator 0.1ms
✓
keeps the human query free ai tools for image generation 0.1ms
✓
keeps the human query alternativa a moz 0.1ms
✓
keeps the human query 410 redirect htaccess moz 0.1ms
✓
keeps the human query moz becuase email outreach 0.1ms
✓
keeps the human query 50% off seo tools 0.2ms
✓
keeps the human query c++ seo tool 0.1ms
✓
keeps the human query seo, sem, and ppc tools 0.2ms
✓
keeps the human query but why is my site not indexed 0.2ms
classifyQuery — the judgment layer (held out as suspect, never machine) · 5 tests
✓
a confident "software" judgment makes the row suspect and says why 0.2ms
✓
an unsure judgment leaves the row useful — the one measured miss sat at 0.43 0.1ms
✓
a person judgment leaves it useful 0.1ms
✓
never judges our own brand, whatever the model says 0.2ms
✓
a rule verdict wins over a judgment — certainty first 0.1ms
judgeCandidates and classifyQueries with judgments · 3 tests
✓
sends only rule-useful, non-brand queries to the model, largest first, capped 0.3ms
✓
counts suspects separately, tags the brand, and still drops nothing 0.4ms
✓
without judgments it is exactly the rules — the flag-off path 0.9ms
src/billing/refund-claim.vitest.ts
the exploit: an amount the server never granted earns nothing · 5 tests
✓
a messageId with no entitlement is refused and writes no ledger row and sends no email 9.1ms
✓
a hundred fresh ids earn a hundred refusals, not a hundred credits 25.1ms
✓
the credit is the amount the SERVER recorded, whatever the caller asks for 1.9ms
✓
the refund row names the TURN it refunds, so the waste meter can attach it (2026-09-24) 0.8ms
✓
another user's entitlement cannot be claimed 0.5ms
the payout is bounded by what the ledger charged this user for this turn · 5 tests
✓
an entitlement larger than the turn charged pays only the charge 0.6ms
✓
a turn id that leaked in from another tenant's request pays nothing 0.5ms
✓
a turn with no charged rows pays nothing 0.4ms
✓
under cost billing the bound is the cost converted, so a refund cannot exceed the debit 0.9ms
✓
reads Hasura string aggregates and treats a null sum as zero 0.4ms
once per message, enforced by the primary key · 7 tests
✓
a second claim is "already refunded" and credits nothing more 1.2ms
✓
three concurrent claims (double click, two tabs) credit exactly once 0.7ms
✓
once the entitlement has expired, a claimed message still says "already refunded" 0.5ms
✓
an insert that committed but whose response was lost still clears the balance and emails once 0.7ms
✓
an unexpected ledger error with no row behind it is thrown to the route 2.3ms
✓
a follow-up that fails after the credit landed does not turn success into failure 0.5ms
✓
a successful credit drops the cached balance and emails once, deduped on the ledger id 0.5ms
input shape · 10 tests
✓
rejects messageId %p with 400 before any read 0.5ms
✓
rejects messageId %p with 400 before any read 0.2ms
✓
rejects messageId %p with 400 before any read 0.2ms
✓
rejects messageId %p with 400 before any read 0.1ms
✓
rejects messageId %p with 400 before any read 0.1ms
✓
rejects messageId %p with 400 before any read 0.2ms
✓
rejects messageId %p with 400 before any read 0.3ms
✓
rejects messageId %p with 400 before any read 0.2ms
✓
rejects messageId %p with 400 before any read 0.2ms
✓
rejects messageId %p with 400 before any read 0.2ms
recordRefundEntitlement — what the server grants · 12 tests
✓
writes amount, reason and turn under this user and message, with a 30-day expiry 0.8ms
✓
writes nothing for a payload that is not refundable 0.2ms
✓
without a turn id there is nothing to bound the payout, so no offer is made 0.3ms
✓
a turn that ended by asking (an approval card) gets no entitlement and loses the offer 0.3ms
✓
a turn that ended by asking (a picker) gets no entitlement and loses the offer 0.2ms
✓
a turn that ended by asking (a confirmation preview) gets no entitlement and loses the offer 0.2ms
✓
no messageId: no entitlement, and the button is not offered 0.2ms
✓
zero tokens: no entitlement, and the button is not offered 0.1ms
✓
negative tokens: no entitlement, and the button is not offered 0.1ms
✓
non-numeric tokens: no entitlement, and the button is not offered 0.2ms
✓
when the entitlement cannot be written, the offer is withdrawn and the error is reported 0.5ms
✓
an entitlement written before turn ids were recorded is not honoured 0.2ms
refundLedgerId · 3 tests
✓
is a deterministic RFC 9562 version-8 uuid per (user, message) 0.9ms
✓
is byte-identical to the #511 algorithm, so every refund row already written still collides 0.3ms
✓
recognises the Hasura collision wording and nothing else 0.2ms
wiring in src/index.ts · 5 tests
✓
the claim route passes only the messageId and never writes the ledger itself 0.7ms
✓
the messageId is minted in exactly one place, and that place records the entitlement with the turn id 0.7ms
✓
agent loop: the turn-level flag is stamped, and the capability merge told not to decide, BEFORE attach 0.6ms
✓
shortcut path: the payload is finalized (refund stripped on a gate) BEFORE attach records it 0.3ms
✓
the capability builder does not refund a blocked outcome, and stands down when told to 0.3ms
src/seo/directive-measurement.vitest.ts
Q29: robots governs crawl, not indexation · 6 tests
✓
leads the decision with the distinction the question turns on 2.3ms
✓
explains why blocking cannot remove a page 0.4ms
✓
confirms the hypothesis from the pair, not from a single count 0.4ms
✓
kills it when nothing blocked is indexed 0.3ms
✓
names example URLs so the finding is checkable 0.8ms
✓
always states the correct division of labour, even with no fault found 0.5ms
Q29: a clean sitemap can never be confirmed, only a dirty one disproved · 4 tests
✓
states the coverage limit when status is mostly unknown 0.5ms
✓
adds a rule to generate the sitemap from the source rather than check it after 0.5ms
✓
does NOT report a coverage percentage when nothing was checked 0.8ms
✓
drops the caveat when coverage is complete 0.3ms
Q29: contradictions are pairs and are reported as such · 3 tests
✓
flags blocked-and-in-the-sitemap as two files disagreeing 0.5ms
✓
keeps the staging hypothesis permanently untested 0.3ms
✓
separates "never checked" from "checked and clean" 0.4ms
Q10: rankings and domain rating are demoted UNCONDITIONALLY · 6 tests
✓
stays a diagnostic for {} 14.3ms
✓
stays a diagnostic for {"rows":[{"keyword":"a","impressions":5000,"c 0.6ms
✓
stays a diagnostic for {"searchRead":false,"analyticsRead":false} 0.3ms
✓
stays a diagnostic for {"rows":[{"keyword":"acmewidgets","impression 0.2ms
✓
says so in the decision, in the rule's own terms 0.2ms
✓
produces the contract even with nothing connected 0.3ms
Q10: branded demand is separated from earned demand · 3 tests
✓
flags branded credit when most clicks are people searching the name 0.4ms
✓
kills it when the clicks are mostly earned 0.3ms
✓
reports visibility without visits as the case for the rule 0.4ms
Q10: the answer box is a signature, never a sighting · 5 tests
✓
detects the pattern 0.4ms
✓
refuses to claim it observed one 0.3ms
✓
ignores queries below the sample floor 0.2ms
✓
ignores queries too low to have earned a click 0.2ms
✓
ignores a healthy CTR 0.2ms
Q10: no ROI number is offered without a revenue join · 5 tests
✓
keeps the revenue hypothesis untested and names WHICH of the three states it is in 0.4ms
✓
distinguishes analytics being SILENT from nothing being counted 0.4ms
✓
warns against quoting a return figure 0.2ms
✓
marks the assisted-enquiry KPI as an intention rather than a number 0.3ms
✓
asks for the one figure that would change that, and states the lag 0.2ms
Q29 and Q10: no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps field and table names out of the prose 0.7ms
policy briefs deliver their policy even when nothing survives · 3 tests
✓
Q29 states the division of labour rather than refusing 0.3ms
✓
Q10 states the contract rather than refusing 0.3ms
✓
and BOTH still carry the honest coverage sentence — the policy is added, not substituted 0.4ms
countUrlSignals: the derivation nothing was testing · 11 tests
✓
a null status is UNKNOWN, never 200 0.5ms
✓
counts a known status 0.2ms
✓
a null status in the sitemap is not counted as a broken sitemap entry 0.2ms
✓
counts blocked-and-indexed as the pair it is, and keeps examples 0.4ms
✓
caps the example list at five 0.9ms
✓
counts blocked-and-submitted, and a 4xx in the sitemap 0.2ms
✓
counts only ALLOWED parameter URLs — a blocked one is already handled 0.2ms
✓
treats `unverified` as not-checked, never as refused 0.2ms
✓
collects the indexed URL LIST, not just the count (Q07 needs the list) 0.2ms
✓
caps the indexed URL list 2.2ms
✓
does not mutate the base it was given 0.2ms
src/chat/chip-guard.vitest.ts
a chip is read without its protocol prefix, and with everything after it · 3 tests
✓
strips exactly the prefixes the app strips before it renders a chip 2.8ms
✓
the prefix is protocol the app never renders or sends: a panel name that spells a vendor does not drop the chip 3.9ms
✓
what follows the prefix IS read: a populate payload becomes the next message, a label is what the person reads 0.9ms
a chip the guardrail would alter is named, with the exit's own options · 2 tests
✓
a vendor, a price, a "free" claim, a key, an internal tool name 0.7ms
✓
the exit's options carry through: a figure the person typed, and a tenant-money turn, are not ours 0.7ms
the tenant's own records: only the vendor check is lifted, and only where the product draws the record · 9 tests
✓
a quoted name, a whole domain, an unquoted tail 1.0ms
✓
an unquoted tail counts only where it ends the chip, and merging keeps every kind 0.5ms
✓
a domain is matched in any case, at its own offsets in the text that is scanned 2.4ms
✓
never part of a longer host, and never a bare word 0.8ms
✓
a chip quoting the record ships; a model naming the same vendor any other way is still dropped 0.8ms
✓
a price or a "free" claim inside the tenant's own record is still caught 0.4ms
✓
records come from the declared result fields only, and competitors only on the pick 0.7ms
✓
a search's list is a record only when the run saved contacts into it 1.9ms
✓
the finished skill's campaign and list are records only when the step that saved them says so 1.1ms
every chip the product builds from a vendor-named tenant record ships · 26 tests
✓
verify_contacts {"needs_selection":true,"lists":[{"name":"Apify leads"}]} 0.5ms
✓
verify_contacts {"verified":3,"list_name":"Apify leads"} 0.4ms
✓
search_leads {"found":3,"saved":3,"list_name":"Apify leads"} 0.6ms
✓
backlink_outreach_search {"found":3,"saved":3,"list_name":"Apify leads"} 0.4ms
✓
generate_emails {"needs_selection":true,"lists":[{"name":"Apify leads"}]} 0.4ms
✓
list_contacts {"available_lists":["Apify leads"]} 0.3ms
✓
enrich_contacts {"enriched":2,"remaining":5,"target_lists":["Apify leads"]} 0.3ms
✓
list_campaigns {"campaigns":[{"name":"Apify outreach"}]} 0.3ms
✓
create_campaign {"campaign":{"name":"Apify outreach"}} 0.5ms
✓
assign_to_campaign {"assigned":3,"campaign":"Apify outreach"} 0.4ms
✓
campaign_stats {"status":"active","campaign":"Apify outreach"} 0.3ms
✓
campaign_stats {"status":"paused","campaign":"Apify outreach"} 0.2ms
✓
campaign_dashboard {"audience":4,"campaign":"Apify outreach"} 0.3ms
✓
campaign_dashboard {"campaign":"Apify outreach"} 0.2ms
✓
set_campaign_sequence {"steps":3,"campaign":"Apify outreach"} 0.5ms
✓
set_campaign_cadence {"campaign":"Apify outreach"} 0.6ms
✓
resume_campaign {"campaign":"Apify outreach"} 0.4ms
✓
resume_campaign {"needs_human_start":true,"sequence":"Apify drip"} 0.4ms
✓
launch_campaign {"campaign":"Apify outreach"} 1.2ms
✓
launch_campaign {"needs_human_start":true,"sequence":"Apify drip","campaign":"Apify ou 0.5ms
✓
create_sequence {"sequence":{"name":"Apify drip"}} 0.3ms
✓
start_sequence {"needs_human_start":true,"sequence":"Apify drip"} 0.3ms
✓
start_sequence {"still_waiting":2,"sequence":"Apify drip"} 0.2ms
✓
seo_backlink_gap {"needs_competitor_pick":true,"competitors":["apify.com","rival.exampl 0.5ms
✓
seo_competitor_gap {"needs_competitor_pick":true,"competitors":["apify.com","rival.exampl 0.3ms
✓
the chips built from the saved site and the saved competitors (settings), outside any tool result 9.4ms
every chip the product writes ships as written · 6 tests
✓
the confirm chips of every card gate (a dropped one would leave a card without its button) 0.9ms
✓
pickers, onboarding, the generic fallback, promise, budget, horizon, connector, escalation, plan and drip chips 7.1ms
✓
every withheld card's fix chip 0.6ms
✓
getNextStepSuggestions, every case, every shape 21.0ms
✓
every chip literal in a suggestions or chips array 15.5ms
✓
the plan-cap uplift chips (executeTool attaches one to any run the plan trimmed) 0.6ms
src/seo/serp-fallback.vitest.ts
(a) an outage-class failure gets one fallback, in the shape every caller reads · 4 tests
✓
a 503 is answered by the fallback: organic rows come back, normalised 32.8ms
✓
a 429 and a timeout get the same one fallback 8.5ms
✓
web search hands the model the fallback rows like any other search 2.4ms
✓
the fallback runs inside the first search slot, so the in-flight cap counts searches 2.8ms
(b) the fallback request is the ruling, exactly · 1 test
✓
excludes the provider that failed, carries the per-call ceiling, sends {q, limit:10} 2.7ms
(c) two ledger rows: the first search failed, the fallback was charged · 4 tests
✓
billed at the charge the fallback reports, with the serving provider in the meta only 4.9ms
✓
with no charge reported, the row is priced at the ceiling and says so (no override, so estimated) 1.7ms
✓
the charge in the body is read when the header is absent 2.0ms
✓
the fallback writes a Sentry log naming what it bought 2.3ms
(d) the fallback fits the caller deadline, or does not run · 2 tests
✓
a timeout with too little time left fails as before: one call, one failure row, no fallback 1.8ms
✓
a fast 503 leaves room, and the fallback wait is cut to what is left 1.7ms
(e) no fallback outside the outage classes · 5 tests
✓
a 400 is the request at fault: one call, no fallback 1.9ms
✓
no auth, refused or not found: no fallback either 1.6ms
✓
a missing first-provider key makes no call anywhere, even with the fallback token set 0.9ms
✓
an empty query makes no call anywhere 0.7ms
✓
no fallback token: the first error, as before 1.1ms
(f) both failing is one clean failure · 4 tests
✓
a 503 then a fallback 500: no status, no vendor, two failure rows, nothing billed 2.1ms
✓
a fallback that answers no rows is a failure, not "nothing ranks for this" 1.6ms
✓
what the user reads names no status and no vendor, on every surface that turns it into words 4.6ms
✓
a fallback that times out reads as a timeout 9.5ms
(g) nothing a provider adds reaches a caller · 2 tests
✓
no vendor name, no feedback channel, no raw body and no routing metadata in the result 1.5ms
✓
rows are rebuilt from title, link, snippet and position only 0.9ms
the price of a search covers the fallback · 1 test
✓
one search costs at most the first provider plus the fallback ceiling: 10,750 tokens 0.5ms
(h) out of credits: the fallback answers, and the account is flagged once · 6 tests
✓
a 402 is answered by the fallback 1.5ms
✓
raises one error-level alert that the credits are exhausted, grouped on one issue 1.1ms
✓
a burst of 402s files ONE alert in the hour, and a new hour files again 3.7ms
✓
another isolate already alerted this hour (the KV marker): nothing is filed 1.9ms
✓
the alert fires even when no fallback can run 0.9ms
✓
the user still reads no status and no vendor 1.1ms
(i) a shared fallback allowance caps how many fallbacks a caller buys · 3 tests
✓
the 21st failure on an allowance of 20 does not fall back, and says why 11.0ms
✓
a fallback that fails still spends its share — the reservation priced the attempt 1.0ms
✓
a skip that is not the cap does not spend it 0.7ms
(j) the privacy page names the fallback beside the first provider · 1 test
✓
lists it in the SEO/SERP line, right after the first provider 2.2ms
(k) a reported charge is never billed above the ceiling we sent · 8 tests
✓
X-Treg-Cost-Micro: 9000 is an anomaly (over_ceiling): billed at the ceiling, as an estimate, and reported 1.6ms
✓
X-Treg-Cost: 1500 is an anomaly (over_ceiling): billed at the ceiling, as an estimate, and reported 1.1ms
✓
X-Treg-Cost-Micro: 0.0015 is an anomaly (fractional_micro): billed at the ceiling, as an estimate, and reported 1.0ms
✓
X-Treg-Cost-Micro: -5 is an anomaly (negative): billed at the ceiling, as an estimate, and reported 1.1ms
✓
X-Treg-Cost-Micro: abc is an anomaly (not_a_number): billed at the ceiling, as an estimate, and reported 1.0ms
✓
each field is read in its own unit only 4.7ms
✓
a free answer (our own key at the provider) is billed at zero, not at the ceiling 3.1ms
✓
a failed fallback reporting an over-ceiling charge absorbs the ceiling, not the reported figure 1.7ms
(l) a first-provider timeout on a 30 s tool leaves the fallback its time · 3 tests
✓
the first wait ends SERP_FALLBACK_MIN_CALL_MS early, and the fallback answers inside the deadline 4.2ms
✓
a first answer inside the shortened wait is still the first provider 1.2ms
✓
with no fallback possible, the first search keeps its whole wait, as before 1.4ms
(m) every SERP-bearing ceiling covers the fallback · 1 test
✓
seo_competitor_gap and seo_content_brief price their search at its worst case 0.7ms
src/chat/judge-pool.vitest.ts
the judge pool · 8 tests
✓
no longer carries grok-4.5 2.3ms
✓
uses the luna id THAT ACTUALLY SERVES, not the batch one 0.5ms
✓
the pool comment records that a fallback chain hid the failure 0.5ms
✓
every pool model is priced EXACTLY — a suffixed id must not fall to the default 0.8ms
✓
prices the batch variant an order of magnitude below the synchronous one 0.8ms
✓
weights still sum to 1, so the cheap model keeps the bulk of the volume 0.6ms
✓
stays disjoint from the WRITER pool, which is the rule that actually matters 0.7ms
✓
index.ts no longer keeps a private copy of the pool or its anchors 11.0ms
isPoolJudgeModel · 3 tests
✓
every pool member is a pool model; the anchor chain now leads with one (grok removed 2026-09-24) 0.9ms
✓
an ensemble verdict is a pool verdict only if EVERY member is 0.3ms
✓
an empty or unknown id is not a pool model 0.2ms
judge sampling is subject-aware · 6 tests
✓
a REAL user is always judged, whatever the secret says 11.5ms
✓
the rate is read ONLY on the internal branch 11.3ms
✓
uses the canonical internal predicate rather than a second list 6.4ms
✓
the CODE default is still 1.0, so an environment without the var judges every eligible turn 8.0ms
✓
wrangler.toml sets it to 0.25 (owner, 2026-09-25) — for internal accounts, by the literal-1 rule above 0.3ms
✓
a turn whose reply HIDES a tool failure never meets the dice 7.2ms
the forbidden-judge rail · 24 tests
✓
no configured judge id is forbidden 0.8ms
✓
a parse failure by the anchor head can still be retried (the retry model is not the anchor head) 0.3ms
✓
the offline report gate and the admin endpoint have their own named defaults 0.1ms
✓
x-ai/grok-4.5 is forbidden 0.2ms
✓
x-ai/grok-4.7 is forbidden 0.1ms
✓
~x-ai/grok-latest is forbidden 0.1ms
✓
openrouter/auto is forbidden 0.1ms
✓
X-AI/Grok-4.6 is forbidden 0.1ms
✓
ensemble:openai/gpt-4o-mini+x-ai/grok-4.5 is forbidden 0.1ms
✓
grok-4.5 is forbidden 0.1ms
✓
somehost/Grok-3-mini is forbidden 0.1ms
✓
x-ai/some-future-model is forbidden 0.1ms
✓
openrouter/auto:floor is forbidden 0.1ms
✓
@preset/judge-slug is forbidden 0.1ms
✓
@PRESET/anything is forbidden 0.1ms
✓
ensemble:openai/gpt-4o-mini+@preset/x is forbidden 0.1ms
✓
groq/llama-3.3-70b is allowed 0.1ms
✓
z-ai/glm-5.2 is allowed 0.1ms
✓
openai/gpt-4o-mini is allowed 0.1ms
✓
ensemble:openai/gpt-4o-mini+mistralai/mistral-small-2603 is allowed 0.1ms
✓
grokking/model is allowed 0.1ms
✓
openrouter/autonomous-x is allowed 0.1ms
✓
someone/@preset-like is allowed 0.1ms
the mistral slot is gpt-6-luna; mistral is history only · 3 tests
✓
gpt-6-luna carries the 0.55 slot and mistral is not pickable 0.2ms
✓
a retired member still reads as a pool verdict, so pre-swap history is not re-labelled a failover 0.3ms
✓
the nightly user-scores chain moved with it 0.3ms
src/chat/reply-provenance.vitest.ts
alignProbe: each declared value pinned to its slot, exactly, or nothing · 8 tests
✓
finds every slot, including a value drawn twice 3.3ms
✓
a value at the very start or end of the rendering 0.6ms
✓
ambiguous — a literal of the layout also occurs inside a value — pins nothing 0.4ms
✓
a placeholder character in the real text — a forgery — pins nothing 0.3ms
✓
a probe the renderer mangled (a broken placeholder) pins nothing 0.3ms
✓
a renderer whose literal text differs between the two runs pins nothing 0.3ms
✓
a placeholder a renderer percent-encoded (a value inside a URL) is the same slot 0.3ms
✓
adjacent placeholders share one gap 0.2ms
renderedTenantSpans: the tenant's records in the renderer's own layout · 10 tests
✓
a paused campaign: both places its name is drawn, and nothing else 1.6ms
✓
a send result: the addresses it could not reach are the tenant's; the reason is not 0.7ms
✓
a renderer that reads a declared value's content (not just draws it) pins nothing 0.3ms
✓
a renderer that throws on the probe pins nothing, and never throws itself 0.3ms
✓
a tool with nothing declared, or a value never drawn, has no spans 0.5ms
✓
a MODEL part is the person's only when they typed its whole text, verbatim 1.7ms
✓
a saved sequence or contact-list name is the tenant's record, typed or not (DECISIONS #47) 0.7ms
✓
a name the tool saved NOTHING under stays the model's: the person's only when typed (savedAs) 1.0ms
✓
a card result is never this module's: tenantRenderings returns nothing for needs_confirmation 0.7ms
✓
every declared part says whose it is and where it lives 7.8ms
typedByPerson: the whole text, verbatim, in the person's own turns · 2 tests
✓
a server-signed follow-up action is not the person typing 0.3ms
ownedRangesIn: honoured only where the reply carries the rendering's own line or sentence · 6 tests
✓
the rendering inside a longer reply: both names exempt, the vendor a model added is not 5.7ms
✓
a model sentence that repeats the tenant value is still checked 2.5ms
✓
the bare value is never an anchor, even as a sentence of the rendering 0.5ms
✓
a lead split off the first sentence: each half keeps its spans 1.7ms
✓
whitespace the exit collapsed or added does not lose the spans 0.6ms
✓
a sentence of the rendering glued into a longer word is not the rendering; the next one, standing alone, is 0.4ms
only the vendor check is lifted inside a tenant span · 5 tests
✓
the name alone ships whole 2.1ms
✓
a price inside the tenant's campaign name is still nqzai's to redact 0.5ms
✓
a "free" claim inside it is still rewritten 0.4ms
✓
a key inside it still blocks the whole reply 0.5ms
✓
an instruction-shaped line inside it is still removed 0.6ms
the tenant's own site: the same host, exactly · 5 tests
✓
siteHost reads a host out of any site, domain or URL form 0.4ms
✓
isOwnSite: the saved site and its www twin, never a subdomain, a lookalike or nothing 0.4ms
✓
an audit of the tenant's own domain names it; the same audit of another domain does not 4.1ms
✓
needsOwnSite: only a tool with a site part asks for the saved site 0.3ms
✓
Search Console's own property is the tenant's record, no site check needed 14.9ms
a slot exempts only the value itself · 3 tests
✓
isRenderingOf: the value as written, escaped, encoded, re-cased or cut short — nothing else 0.5ms
✓
a renderer that draws its own copy in a slot when the value fails a test exempts nothing there 0.4ms
✓
identical values share a placeholder, so a renderer that groups them behaves the same on the probe 0.3ms
markup is lined up one tag at a time: a stretch drawn differently loses only its own spans · 2 tests
✓
an avatar initial taken from the value does not cost the rest of the report its spans 0.3ms
✓
without markup a single divergence still pins nothing 0.2ms
report artifacts: the renderer's own slots in the hydrated HTML · 2 tests
✓
a Search Console + Analytics report: property, pages, queries and traffic sources are spans; the bucket taxonomy is not 21.5ms
✓
the campaign report: its name is a span wherever the report draws it 1.1ms
src/leads/industry-vocabulary.vitest.ts
the case this exists for · 2 tests
✓
finds farms when the user says agriculture 2.5ms
✓
says what it searched instead of what was typed 0.6ms
tenant be12ebf7's ICP — the six words that returned nothing · 8 tests
✓
places permanent crop in the vocabulary rather than dropping it to free text 0.5ms
✓
places tree fruit in the vocabulary rather than dropping it to free text 0.2ms
✓
places nuts in the vocabulary rather than dropping it to free text 0.4ms
✓
places citrus in the vocabulary rather than dropping it to free text 0.2ms
✓
places berries in the vocabulary rather than dropping it to free text 0.3ms
✓
places vines in the vocabulary rather than dropping it to free text 0.3ms
✓
reaches wine and spirits, which no key could reach at all 1.4ms
✓
resolves the whole ICP to farms and vineyards, not to nothing 0.5ms
exact stored values pass through untouched · 3 tests
✓
does not expand a term that IS a stored value 0.3ms
✓
emits no note when nothing was expanded 0.2ms
✓
is case- and whitespace-insensitive 0.2ms
word containment, NOT similarity · 4 tests
✓
resolves software to the stored values containing it as a word 0.2ms
✓
does NOT match a town because it shares letters with an industry 0.3ms
✓
A ONE-LETTER FRAGMENT IS NOT A WORD: e-commerce must not resolve to e-learning 0.4ms
✓
still honours genuinely short industry words the user typed themselves 0.2ms
phrases fall back to their words, and the exceptions are listed · 4 tests
✓
reaches the head word of a phrase 0.3ms
✓
does NOT send defense contractors to construction firms 0.3ms
✓
does NOT send veterinary clinics to hospitals 0.2ms
✓
does NOT drag oil and gas into a renewable energy search 0.2ms
the table normalises its OWN keys, or half of them are unreachable · 4 tests
✓
oil and gas reaches oil & energy 0.2ms
✓
m&a reaches investment banking 0.2ms
✓
k-12 reaches primary/secondary education 0.2ms
✓
import/export reaches import and export 0.2ms
the corpus decides what is offerable · 3 tests
✓
never returns a value the corpus does not hold 0.2ms
✓
reports an unplaceable term rather than dropping it 0.5ms
✓
keeps the matched part and declares the rest on a mixed request 0.3ms
translation and relaxation are two different promises · 4 tests
✓
does not fold food manufacturing into agriculture in the CORE tier 0.3ms
✓
widens ONLY when the core tier found nothing, and reports it as relaxed 0.3ms
✓
never widens when the core tier could serve the request 0.2ms
✓
gives the widening its own sentence and its own verb 0.2ms
widenIndustries — the retry a zero-result search asks for · 5 tests
✓
offers adjacent values even when the core tier resolved fine 0.6ms
✓
EXCLUDES everything the first pass already tried 0.5ms
✓
offers nothing for a concept with no adjacent entry, so no retry is made 1.8ms
✓
names the widening as a widening, not as a translation 0.5ms
✓
says nothing when nothing was widened 0.2ms
the tables cannot rot silently · 6 tests
✓
every target in BOTH tiers is spelled as the corpus spells it 0.7ms
✓
resolves every stored corpus value to itself 7.3ms
✓
resolves EVERY value the model is allowed to emit 24.2ms
✓
does not let a generic tail eat the sector in <Subject> Manufacturing 0.7ms
✓
keeps the tail when the tail IS the sector 0.2ms
✓
covers the concepts a B2B user actually types 1.9ms
src/leads/shared/reveal.vitest.ts
verification age · 3 tests
✓
treats a missing verification date as NOT verified 1.8ms
✓
holds a verification current up to the window and not past it 0.4ms
✓
refuses to treat an unparseable date as a verification 0.2ms
source ownership · 2 tests
✓
answers NULL when the corpus did not tell us — never false, never true 0.2ms
✓
counts our own corpus as owned and a bought rung as not 0.3ms
revealSelection · 11 tests
✓
claims purpose "reveal" — the caller never supplies it 1.8ms
✓
bills an UNVERIFIED identifier at the reduced rate, and still reports it as unverified 0.8ms
✓
bills a currently-verified identifier whose verdict is VALID 0.6ms
✓
reveals but bills NOTHING when the verdict says the address is dead 0.7ms
✓
bills nothing when the corpus refuses (empty result is not an error) 2.3ms
✓
bills nothing when the rights gate rejects the call outright 1.3ms
✓
bills nothing on a repeat reveal of the same identifier 0.3ms
✓
does not disclose anything when the selection is not this tenant's 0.6ms
✓
falls back through all three projections when the corpus predates migration 060, and stamps null lineage 0.7ms
✓
bridges to a contact whose provenance says the corpus supplied it and nobody checked it 0.6ms
✓
still records the disclosure when the contact bridge fails 0.4ms
what the user is told · 3 tests
✓
never calls an unchecked address verified 0.3ms
✓
states the age when the check has lapsed 0.1ms
✓
says nothing was charged on a repeat 0.1ms
contact provenance columns · 1 test
✓
never travels with verified_at 0.2ms
verificationSells — recency AND a valid verdict · 9 tests
✓
sells a fresh VALID verdict 0.2ms
✓
never sells a proven-dead address, however fresh the check 0.1ms
✓
does not sell risky (catch-all) — the domain answered, the mailbox did not 0.1ms
✓
does not sell unknown — the probe never completed 0.1ms
✓
does not sell unverified 0.1ms
✓
fails closed when the corpus does not tell us the verdict 0.1ms
✓
a stale VALID verdict does not sell either — both halves are required 0.2ms
✓
never sells without a timestamp at all 0.1ms
✓
leaves verificationIsCurrent as a RECENCY test — it drives the staleness copy 0.1ms
verificationPriceFactor — the half-price ruling · 8 tests
✓
pays FULL for a confirmed mailbox 0.2ms
✓
pays HALF for a DERIVED catch-all, which has no mailbox date at all 0.1ms
✓
pays HALF for a PROBED catch-all too 0.1ms
✓
pays NOTHING for an address we proved bounces, however fresh 0.1ms
✓
drops a STALE domain classification to the unverified rate, not to half 0.1ms
✓
FAILS CLOSED when the corpus cannot say WHAT it checked 0.2ms
✓
prices genuinely UNVERIFIED data down, not to zero (owner ruling 2026-08-18) 0.2ms
✓
never pays full price for a domain-scoped "valid" 0.2ms
revealNote — what the customer is told they bought · 2 tests
✓
says the DOMAIN was checked, not the address, when charging half price 0.2ms
✓
still warns plainly when nothing was checked at any level 0.1ms
an outage is reported as unavailable, never filed as a refusal · 4 tests
✓
the ownership check not answering is `unavailable`, not `not_found` 0.5ms
✓
a RAISE from the ownership RPC is still `not_found` 0.3ms
✓
the corpus not answering is `unavailable` after ONE round trip — no fall-through to two more projections 0.5ms
✓
a rights rejection is still `refused`, after all three projections 1.0ms
src/billing/outcome-rollup.vitest.ts
grouping: the RUN is the unit, not the call · 4 tests
✓
sums every row sharing a runId into one run 3.6ms
✓
separates distinct runs of the same outcome 0.5ms
✓
ignores rows with no run attribution 0.2ms
✓
never lets a negative amount enter a cost stat 0.4ms
measured vs modelled · 3 tests
✓
one non-reported row disqualifies the WHOLE run 0.2ms
✓
a floor-sourced row also disqualifies it 0.2ms
✓
unmeasured runs count toward n but never toward the distribution 0.5ms
quantiles are nearest-rank, never interpolated · 2 tests
✓
returns an observed value 0.5ms
✓
is total on the edges 0.5ms
cost floor by sampling tier · 6 tests
✓
tier A uses p90 and requires n>=30 0.6ms
✓
tier B bounds with max x 1.25 at n>=3, because a p90 is not computable 0.4ms
✓
tier B still refuses below n=3 0.2ms
✓
tier C is deferred — never priceable this sprint 0.5ms
✓
an all-zero distribution is an instrumentation gap, not a free outcome 0.2ms
✓
reports WHY an outcome is unpriceable, so it is never silently estimated 0.2ms
orchestration attribution · 5 tests
✓
folds a turn's orchestration into its single outcome 0.4ms
✓
splits equally across a turn's outcomes, not proportionally to their cost 0.2ms
✓
does not double-count when one turn runs the same tool twice 0.4ms
✓
leaves a no-tool turn's orchestration unattributed 0.7ms
✓
reproduces the canary: run-level rollup saw 32% of the real cost 0.5ms
token conversion stays identical to the biller · 2 tests
✓
uses the same anchor as usage.ts 0.1ms
✓
produces the same tokens as apiCostToTokens 0.2ms
what counts as a measurement · 6 tests
✓
a provider-reported figure always counts 0.2ms
✓
a verified flat rate counts 0.2ms
✓
an estimate from a provider that DOES report is a capture miss, never a measurement 0.2ms
✓
an unverified constant is never a measurement 0.2ms
✓
floor and NULL are never measurements 0.1ms
✓
unblocks the canary run that the strict rule rejected 0.1ms
gemini reconciliation (July 2026 Google invoice) · 4 tests
✓
derives the all-in per-request rate the API_COST constant now carries 0.2ms
✓
quantifies how far the old constant was out 0.2ms
✓
shows the bill is tokens, not a grounding-request fee 0.2ms
✓
gemini now reports its own cost rather than leaning on a constant 0.2ms
outcomes that escaped the pilot · 4 tests
✓
a turn with no run_tool ANYWHERE strands its whole cost 0.3ms
✓
declaring the outcome recovers the whole run 0.2ms
✓
a zero-spend run is still counted, and still collects its orchestration 0.4ms
✓
the marker's $0 is its exact cost, not a missing measurement 0.1ms
failed runs never enter a price · 5 tests
✓
counts only delivered runs toward the priceable set 0.2ms
✓
a $0 failed run cannot drag the floor below the real cost 0.3ms
✓
an all-failed outcome is unpriceable, and says why 0.2ms
✓
reads the status off the tool_run marker row 0.2ms
✓
treats an unknown exit as not priceable 0.2ms
src/campaigns/draft-batching.vitest.ts
planDraftBatches · 6 tests
✓
splits a 53-contact list so no batch can overflow the output budget — the incident case 2.7ms
✓
every recipient it attempts appears exactly once, in order 0.9ms
✓
a list inside the cap defers nothing 0.4ms
✓
handles an empty list without producing an empty batch 0.3ms
✓
opener mode batches larger — it emits one short opener each, not a full body 0.4ms
✓
a full-body batch fits the output budget with headroom 0.5ms
fullBodyBatchShape · 4 tests
✓
6 or fewer are unchanged: one batch at the 4,000 budget 0.4ms
✓
7–9 are one call at the single-call budget 0.2ms
✓
10 and more keep batches of 6 at 4,000 0.6ms
✓
plan(9) is one batch; plan(12) is two 0.4ms
runDraftBatches · 5 tests
✓
accumulates every batch result in order 0.6ms
✓
one failing batch does not discard the others, and its reason is reported 0.4ms
✓
respects the concurrency cap — never more than N calls in flight 4.8ms
✓
passes a batch index so recipient numbering stays continuous across batches 0.3ms
✓
surfaces a non-Error throw as a string rather than "undefined" 0.3ms
remaining count is derived from what landed, not what was planned · 3 tests
✓
53 requested, 40 attempted, 32 delivered → 21 remaining, never 13 0.5ms
✓
delivered + remaining always equals the original list size 0.2ms
✓
a fully delivered list leaves nothing remaining, so no note is shown 0.1ms
wall-clock deadline · 4 tests
✓
stops starting waves past the deadline and keeps what it already drafted 0.3ms
✓
always runs the first wave, even with a zero budget — never returns nothing 0.2ms
✓
a run inside its budget completes every batch 0.2ms
✓
a full-size run fits in ONE wave, so the deadline never bites in the normal case 0.2ms
a single slow wave cannot eat the whole budget · 3 tests
✓
abandons a wave that outlives the deadline and reports why 60.9ms
✓
keeps what earlier waves returned when a later one is abandoned 59.9ms
✓
does not abandon a wave that finishes inside the budget 0.4ms
one slow batch does not discard its siblings · 2 tests
✓
keeps the batches that finished when one hangs — the zero-drafts incident 61.0ms
✓
reports WHICH batch was abandoned, not just that something was 61.1ms
personalized mode is bounded by research, not by the output budget · 2 tests
✓
drafts no more contacts than it researches — otherwise openers are generic 0.5ms
✓
is stricter than the full-body cap, since research costs a call per contact 0.1ms
deferredDraftNote · 4 tests
✓
is empty when nothing was deferred, so callers can append unconditionally 0.1ms
✓
names both counts so the user knows what is still waiting 0.1ms
✓
reads correctly for a single deferred contact 0.1ms
✓
never puts a dollar figure in front of the user 0.1ms
salvage — a run that produced nothing retries small · 4 tests
✓
returns something when every batch times out 31.0ms
✓
does not fire when the run already produced drafts 0.5ms
✓
is itself bounded, and says so 40.7ms
✓
can be switched off entirely 0.3ms
draftTimeBudget · 4 tests
✓
gives the full budget (minus the post-processing reserve) when setup was instant 0.3ms
✓
shrinks the wall clock (not just ignores) when setup already spent real time 0.2ms
✓
never returns a budget that would push total elapsed past the tool ceiling, below the floor threshold 0.3ms
✓
floors the wall clock so a slow setup does not starve the main wave to near-zero — even trading away the no-overrun guarantee 0.3ms
src/chat/capability-denial.vitest.ts
detects a capability claim · 9 tests
✓
flags "I am not able to execute this task as it requires additional tools and functionality beyond what is available in the given functions." 2.3ms
✓
flags "That is beyond what is available in the given functions." 0.6ms
✓
flags "I don't have a tool for that." 0.2ms
✓
flags "I do not have access to a tool that can send email." 0.2ms
✓
flags "There is no function available to do that." 0.2ms
✓
flags "That is outside the scope of the available functions." 0.1ms
✓
flags "This is not available in my current toolset." 0.2ms
✓
flags "I lack the tools to complete this request." 0.1ms
✓
flags "I cannot do that without the appropriate function." 0.5ms
stays off everything else — the corpus that matters · 19 tests
✓
ignores "I need your website URL first — tell me your domain and I will take it from there." 0.5ms
✓
ignores "I need a product brief before I can tailor that." 0.2ms
✓
ignores "Which list should I save these to?" 0.1ms
✓
ignores "You're out of tokens for this billing period. Top up to keep going." 0.1ms
✓
ignores "That confirmation timed out — approvals expire after 10 minutes." 0.1ms
✓
ignores "Insufficient token balance for lead search (~663K tokens)." 0.1ms
✓
ignores "I hit a safety check on that response and can't share it as written. Could you rephrase what you need, and I'll try again?" 0.1ms
✓
ignores "I couldn't find any leads matching that." 0.1ms
✓
ignores "No contacts saved yet." 0.1ms
✓
ignores "I can only send to 200 recipients in one go." 0.1ms
✓
ignores "State-level targeting is not available yet, so I matched on country instead." 0.1ms
✓
ignores "I'll use the lead search function to find them." 0.1ms
✓
ignores "Running the lead search tool now." 0.1ms
✓
ignores "That feature is ready whenever you are." 0.1ms
✓
ignores "I've queued this feature for you." 0.1ms
✓
ignores "This is a straightforward template rendering — no tool needed. Here is your drafted email:" 0.1ms
✓
ignores "No tool is required for this." 0.1ms
✓
ignores "No function is necessary — the variables are already resolved." 0.1ms
✓
ignores empty and nullish input 1.8ms
the correction states the fact and does not command · 3 tests
✓
names the tool the model said it lacked 0.2ms
✓
leaves a genuinely-wrong tool free to be declined honestly 0.2ms
✓
removes only the explanation we disproved 0.1ms
the fallback is honest about what did NOT happen · 4 tests
✓
never implies the action ran 0.3ms
✓
withdraws the false reason rather than repeating it 0.1ms
✓
does not invent a cause we have not established 0.2ms
✓
reads as prose, not as an identifier 0.1ms
the gate in runChatV2 — refutability is the whole safety property · 6 tests
✓
requires the named tool to have actually been offered 0.1ms
✓
only applies to the high-stakes intents, at confident classification 0.2ms
✓
corrects at most once per run 0.1ms
✓
never spends the last turn on a correction 0.1ms
✓
does not touch tool_choice — nothing is forced 0.1ms
✓
reports every occurrence, because the rate is the point 0.1ms
src/reports/heavy-tier-phase2.vitest.ts
campaign_stats — an active campaign that never sent is stalled, not healthy · 3 tests
✓
says stalled, and says what to check 1.8ms
✓
is no longer headed "signals healthy" 0.4ms
✓
a live campaign that IS sending is untouched 0.4ms
campaign_stats — advice needs a measurement behind it · 2 tests
✓
does not talk about subject lines on a campaign that never sent one 0.4ms
✓
still gives the tuning advice once there is something to tune 0.4ms
campaign_stats — the funnel and the send count measure different populations · 4 tests
✓
labels the contradiction instead of hiding it 0.2ms
✓
does NOT silently correct the numbers 0.2ms
✓
stays quiet when the campaign has actually sent 0.3ms
✓
stays quiet on an all-zero funnel — there is no contradiction to explain 0.6ms
entity_audit — a score from one query is provisional · 4 tests
✓
greys the score and labels it rather than painting full confidence 0.3ms
✓
says how little it read, in words 0.2ms
✓
does NOT change the arithmetic 0.1ms
✓
a broader audit scores in colour with no caveat 0.4ms
search_leads — the batch path carried a count and nothing else · 4 tests
✓
the async result now carries what the renderer reads 0.2ms
✓
derives tiers per lead, not as a hard-coded label 0.1ms
✓
bounds `all` but keeps `found` true, and says when the cap bit 0.2ms
✓
the renderer shows rows and an honest overflow once the shape is right 0.5ms
campaign_stats — the funnel is rebuilt on emails_sent · 6 tests
✓
queries this campaign's own replies, clicks and bounces 0.2ms
✓
the reply RATE no longer counts replies to other campaigns 0.2ms
✓
the contact lifecycle survives under its own name, never mixed into the funnel 0.2ms
✓
a current run cannot render the impossible state at all 0.3ms
✓
shows the delivery stages once there is delivery 0.3ms
✓
an artifact stored BEFORE the rebuild keeps its old shape and its label (trap 14) 4.0ms
seo_google_merge — an absence claim needs enough data to be an absence · 4 tests
✓
says "not enough to tell", not "nothing found", on thin data 0.6ms
✓
names the threshold and the best page against it, not the site total 0.3ms
✓
engagement and striking-distance say WHY they cannot answer 0.3ms
✓
a site with real volume still gets the clean-bill verdict 0.2ms
the backlink report analyses the anchors instead of asking the user to · 5 tests
✓
never tells the reader to go and check the sample 1.2ms
✓
classifies the anchors and names the pattern 0.6ms
✓
calls out a keyword-heavy profile as the thing to dilute 0.8ms
✓
recognises branded anchors as healthy 0.5ms
✓
states the provider profile total as coverage, not as the sample 0.6ms
generate_emails — markup never reaches a draft body · 3 tests
✓
strips incoming markup before the link guards inspect the body 0.1ms
✓
only strips when markup is actually present 0.2ms
✓
does not strip the html WE add afterwards 0.8ms
seo_content_quality — "which category leads" named the weakest one · 4 tests
✓
names the weakest category, and the heading matches the answer 0.2ms
✓
contrasts it with the strongest, so the gap is the finding 0.1ms
✓
picks the weakest by SCORE, not by array position 0.3ms
✓
stops reporting our own check coverage as a finding about the page 0.2ms
domain_email_readiness_audit — the parts must add up to the header · 2 tests
✓
accounts for every issue, whatever its severity 0.5ms
✓
says nothing extra when the two named severities already cover them 0.3ms
src/tools/numeric-band.vitest.ts
the dead end this replaces · 2 tests
✓
the lexical ladder offers nothing for a band mismatch 2.3ms
✓
and when it does offer something, it is worse than nothing 1.0ms
parseBand · 3 tests
✓
reads the shapes models actually emit 1.3ms
✓
refuses anything that is not a band 0.3ms
✓
refuses a backwards range rather than silently swapping it 0.2ms
expandNumericBand · 6 tests
✓
maps the LinkedIn bands onto ours by OVERLAP 0.4ms
✓
handles the open-ended top band 0.3ms
✓
reports whether the match widened the request 0.4ms
✓
returns nothing for a non-band value 0.9ms
✓
never fires on a vocabulary that is not numeric bands 0.4ms
✓
returns nothing when the range misses every band 0.2ms
the live call, end to end through the validator · 6 tests
✓
no longer rejects the LinkedIn bands 1.0ms
✓
produces legal, de-duplicated bands 1.1ms
✓
discloses the widening instead of applying it silently 0.5ms
✓
says nothing when our own bands are used 0.3ms
✓
still rejects a value that is not a size at all 0.5ms
✓
keeps the RAW values on the rejected path so the error names what the model sent 0.3ms
the words a brief is actually written in · 15 tests
✓
resolves mid-market 0.3ms
✓
resolves midmarket 0.2ms
✓
resolves enterprise 0.3ms
✓
resolves small business 0.2ms
✓
resolves Fortune 500 0.3ms
✓
reads a number carrying ordinary words: 200-2000 employees 0.2ms
✓
reads a number carrying ordinary words: over 1000 0.2ms
✓
reads a number carrying ordinary words: at least 200 0.2ms
✓
reads a number carrying ordinary words: 200+ employees 0.1ms
✓
reads a number carrying ordinary words: 1,000 employees 0.2ms
✓
reads a number carrying ordinary words: no more than 50 0.2ms
a segment name is an interpretation, and is said out loud · 4 tests
✓
discloses what it took the word to mean, even though the edges line up exactly 0.2ms
✓
tells the user how to override it 0.2ms
✓
uses the OTHER sentence for a boundary that genuinely moved 0.2ms
✓
says nothing when the value was already one of ours 0.1ms
it cannot leak into a vocabulary that is not sizes · 4 tests
✓
does not turn enterprise into a band on a non-band enum 0.1ms
✓
does not turn large into a band on a non-band enum 0.1ms
✓
does not turn medium into a band on a non-band enum 0.1ms
✓
does not turn small into a band on a non-band enum 0.1ms
src/billing/redelivery-repeat-not-billed.vitest.ts
a redelivered job that calls its provider again pays once (DECISIONS #86) · 9 tests
✓
[fail-first] an unnamed provider call: 2 rows, the second marked, the balance debited once 51.5ms
✓
[fail-first] a provider-NAMED call (a new task id each delivery): 2 rows, the second marked, debited once 17.0ms
✓
[fail-first] an LLM call (a new generation each delivery): 2 rows, the second marked, debited once; the refund bound agrees 9.6ms
✓
[fail-first] the usage page and the usage-breakdown tool agree with the balance 20.4ms
✓
a third delivery is a third row, also unbilled 8.7ms
✓
a call the first delivery never made is a NEW charge on the redelivery, and is billed 6.8ms
✓
the same write arriving twice in one delivery is still one row (no false repeat) 3.2ms
✓
a zero-cost marker re-written by the redelivery stays one row (nothing to bill twice) 4.0ms
✓
isRedeliveryRepeat names only the suffix 5.2ms
the views that mirror the debit leave the repeat out of "billed" too · 1 test
✓
[fail-first] sessions and the waste meter file a repeat under overhead, not billed provider spend 4.2ms
V10-money2: a redelivery is recognised by the job and the call's position, whatever its cost or meta · 11 tests
✓
[fail-first] a redelivered leads scrape with a new run id and different rows debits once and records two rows 7.2ms
✓
[fail-first] a redelivered AI-visibility call with a different measured cost (and a new call id) debits once 2.8ms
✓
[fail-first] a writer-keyed call whose measured cost and units differ on the redelivery debits once 5.2ms
✓
[fail-first] a redelivered LLM call answered by a different model from a different prompt debits once 8.5ms
✓
[fail-first] a caller-keyed paid row redelivered with a second provider charge records it as :redelivery (index probe: scan + URL) 2.9ms
✓
[fail-first] a caller-keyed paid cron row re-run with a second provider charge records it as :redelivery (user + day) 7.0ms
✓
a caller key names its EVENT: a different email sent on the redelivery is a second fee, billed, never matched by position 4.6ms
✓
a chat turn or a first delivery that writes a caller-keyed event twice is one row (a second path, not a repeat) 1.4ms
✓
re-polling the same provider task inside a redelivery is still one row (the same charge) 2.8ms
✓
[fail-first] a call made for the FIRST time on a redelivery and metered twice is one billed row, never a phantom repeat 2.9ms
✓
[fail-first] the admin sessions debited total equals the balance movement (a failed-over turn and a redelivered job) 18.8ms
DECISIONS #90: a manual / admin re-run of a caller-keyed job records the second charge, never debits it · 8 tests
✓
[fail-first] the cron scores a user, then an admin recompute the same day: both charges on the ledger, the second marked manual 1.5ms
✓
[fail-first] every manual run is its own re-execution; the same write twice inside one run is still one repeat 1.9ms
✓
[fail-first] a billable caller-keyed charge re-run by an operator is recorded AND left out of the balance 2.2ms
✓
a send fee is collapsed across paths by design: an operator request that names the same email writes nothing more 1.4ms
✓
a user request is no re-execution: the same caller-keyed event reaching the ledger again is one row 0.8ms
✓
a zero-cost marker re-written by an operator stays the one event it was 0.9ms
✓
manualTriggerForRoute names the operator routes, by path only, and nothing else 0.5ms
✓
[fail-first] the fetch entry point seeds every request scope with its manual trigger (src/index.ts, pinned in source) 3.9ms
V11-money-F01: inside a named job a provider-named call's position counts CALLS, not writes · 3 tests
✓
[fail-first] X3: a task re-logged in delivery 1 does not shift the next call's position, so delivery 2's repeats are both recognised 9.7ms
✓
[fail-first] X1: one provider id written twice CONCURRENTLY in a redelivery is one unbilled repeat, however the reads land 32.0ms
✓
two DIFFERENT provider ids in one delivery still take two positions (nothing collapses that should not) 2.0ms
V11-money-F02: two writes of ONE event that overlap inside a re-execution record the repeat exactly once · 3 tests
✓
[fail-first] L1: a caller-keyed paid row written twice concurrently in delivery 1 and again in delivery 2: one row, then one repeat 84.7ms
✓
[fail-first] L2: one Jev usage written twice concurrently (the implicit write and an onUsage write) in each delivery: one row, then one repeat 84.4ms
✓
a double-write that collides with THIS invocation's own insert is still no repeat, concurrent or not (the #671 rule kept) 11.9ms
DECISIONS #93: the admin index scan's duplicate and stall-restart chunks record their second paid probe · 4 tests
✓
[fail-first] two chunks that both read cursor 0 (a duplicate chain) probe the same URLs: every second probe is an unbilled chunk repeat, none is dropped 14.9ms
✓
[fail-first] a stall-restart chunk re-probing a URL the chain already probed records the second probe as a chunk repeat 2.7ms
✓
a chunk's first probe of a URL is a plain row — the chain marker alone never makes a repeat 1.3ms
✓
the chain marker is a scope marker: a caller-keyed collision under it outside the scan is a chunk repeat too, and a user turn is not 1.5ms
src/seo/keyword-guard.vitest.ts
isRegistrableKeyword — the write-path junk guard · 5 tests
✓
accepts normal search terms 4.7ms
✓
rejects the exact junk classes seen in prod 0.8ms
✓
enforces the length ceiling and non-empty rule 0.6ms
✓
rejects control chars and non-ascii (en/US registry only) 0.3ms
✓
rejects sentence-like blobs over the word-count backstop 0.3ms
normalizeKeywordForVolume — DFS forbidden-symbol stripping · 4 tests
✓
strips the "?" that 40501-rejected whole enrichment batches in prod (2026-07-09) 0.4ms
✓
strips other DFS-forbidden symbols and collapses whitespace 0.4ms
✓
keeps clean keywords untouched (hyphens and apostrophes survive) 0.3ms
✓
returns empty string for symbol-only input 0.4ms
classifyIntent — precedence · 2 tests
✓
transactional beats commercial beats informational 0.4ms
✓
defaults unmodified topics to informational 0.2ms
computeKES — (volume × cpc) / difficulty · 3 tests
✓
computes the efficiency score with difficulty 0.2ms
✓
treats null difficulty as 1 (volume×cpc first-pass) and null vol/cpc as 0 0.2ms
✓
floors difficulty at 1 so a 0 difficulty never divides by zero 0.1ms
opportunity scoring — first-party GSC keywords must not sink to zero · 2 tests
✓
weights striking-distance positions highest 0.3ms
✓
blends KES with behavioral demand so a KES=0 GSC keyword still scores 0.2ms
a URL is an observation, not a target · 14 tests
✓
rejects "https://golfstreams.me/" 0.2ms
✓
rejects "https://portal.web.nhk/kakunin" 0.1ms
✓
rejects "https://www.kakunin.cloud/" 0.1ms
✓
rejects "www.kakunin.ai" 0.1ms
✓
rejects "rhetoric.com" 0.2ms
✓
rejects "freeconvert.com" 0.1ms
✓
rejects "iancloud.ai" 0.1ms
✓
rejects "rhetoric-index.org" 0.1ms
✓
rejects "advoira.com" 0.1ms
✓
rejects "rhetoricaudit.com" 0.1ms
✓
keeps "openai.com pricing" — a domain inside a phrase is a real query 0.1ms
✓
keeps "is notion.so down" — a domain inside a phrase is a real query 0.1ms
✓
keeps "g2.com vs capterra reviews" — a domain inside a phrase is a real query 0.1ms
a string with no word in it cannot be targeted · 9 tests
✓
keeps "pci dss 4.0" 0.1ms
✓
keeps "eu ai act 2026" 0.1ms
✓
keeps "web 3.0 identity" 0.1ms
src/billing/lead-estimate.vitest.ts
the quote follows the rung that will actually answer · 10 tests
✓
quotes the CORPUS when the corpus runs first — as a range, not a point 1.9ms
✓
is cheaper than the provider quote it replaces — the DIRECTION is the invariant 0.3ms
✓
lets a BRAND-NEW user run a lead search on the signup bonus alone 0.3ms
✓
SCALES with limit, so one number cannot be wrong in both directions at once 0.3ms
✓
a free-tier search fits comfortably inside the signup bonus 0.2ms
✓
scales with the ask, because the corpus bills per delivered lead 0.3ms
✓
reverts to the PROVIDER quote the moment paid sources are allowed 0.2ms
✓
quotes the provider when the corpus is not in play at all 0.2ms
✓
local_business quotes the corpus range like every shape — the Maps rung is gone, so its ceiling must not gate the run (2026-09-18) 0.6ms
✓
never assumes the corpus is free — it reads the price 0.2ms
the ladder stops where the quote stops · 3 tests
✓
refuses to buy from a provider without allow_paid_sources 0.3ms
✓
the stop still sits below the corpus tier, so the quote covers everything above it 0.2ms
✓
returns what it DID find rather than failing the search 0.2ms
every quoting path prices the same search the same way · 4 tests
✓
estimateForCall routes search_leads through searchLeadsEstimate WITH the context 0.3ms
✓
the agent loop actually passes the tenant context, not undefined 0.4ms
✓
the lead shortcut passes it too 0.2ms
✓
the two paths produce the SAME number for the same search 0.7ms
search_candidates orders totally, not just by score · 2 tests
✓
both ORDER BYs end in the unique entity id 0.2ms
✓
the tiebreak is the LAST key — it must not outrank score 0.2ms
lead search quote reads the mode from the arguments that drive the run · 3 tests
✓
quotes the local-business ceiling when the shape is local, even if search_type says people 0.3ms
✓
a postal code alone is enough — it is a local-only field 0.2ms
✓
leaves a genuine people search on the cheap corpus quote 0.2ms
the lead quote is a range, and the gate reads its ceiling · 5 tests
✓
quotes corpus-rate at the bottom and provider-rate at the top 0.2ms
✓
the spread is real — a range whose ends are equal is not a range 0.2ms
✓
SAFETY DOES NOT MOVE: the ceiling is still the provider rate 0.2ms
✓
a call whose LOW end is under the gate threshold still gates on its ceiling 0.6ms
✓
the gate message names BOTH ends, not just the ceiling 0.4ms
searchLeadsEstimate sizes to the requested count · 7 tests
✓
reads `count`, the field the schema actually declares 0.2ms
✓
a LARGER ask quotes MORE — the under-quote direction is the unrecoverable one 0.3ms
✓
still honours `limit` for internal callers that build args by hand 0.1ms
✓
`count` wins when both are present 0.1ms
✓
falls back to 25 only when neither is given, and never to zero or NaN 0.4ms
✓
clamps an absurd ask rather than quoting it 0.1ms
✓
the corpus rung sizes to the ask too 0.2ms
the lead-search floor is the one this tool pays · 4 tests
✓
is well above every measured run, and well below the generic agent floor 0.2ms
✓
does not move ORCHESTRATION_FLOOR, which governs every other tool 0.1ms
✓
is the fixed part of the quote at every size 0.3ms
✓
the size-that-fits offer subtracts the same floor it quoted 0.1ms
src/chat/intent-router.vitest.ts
chatRouter explicit off-page audit · 1 test
✓
routes a named off-page audit directly instead of opening the broad SEO picker 46.0ms
chatRouter aeo_intent · 5 tests
✓
does NOT hijack the AEO writer chip "Write <topic> in AEO mode" (live 2026-07-12) 8.9ms
✓
does not hijack generic content-writing asks that mention AEO 1.9ms
✓
still routes visibility asks to aeo_intent 0.5ms
✓
still routes "am I cited by chatgpt" to aeo_intent 0.9ms
✓
page readiness asks stay off the engine selector (registry #9) 0.4ms
keyword asks no longer hijacked by a deleted shortcut · 6 tests
✓
"give me keyword ideas for media bias detection" is not claimed by a keyword shortcut 0.5ms
✓
"create a content brief for the keyword media literacy tools" is not claimed by a keyword shortcut 0.5ms
✓
"track my keyword rankings for rhetoric audit" is not claimed by a keyword shortcut 0.7ms
✓
"what are the most profitable keywords for my niche" is not claimed by a keyword shortcut 1.0ms
✓
"show me my saved keywords" is not claimed by a keyword shortcut 0.7ms
✓
the economics ask reaches the model rather than a veto regex 0.3ms
standing-instruction confirm/cancel shortcuts (injection-persistence guard) · 2 tests
✓
matches the exact confirm/discard chip phrases 1.0ms
✓
does not fire on unrelated affirmatives (only the exact chip text confirms a persist) 0.8ms
chatRouter lead-gen asks that mention SEO · 3 tests
✓
does not hijack a lead search into the SEO route picker 15.0ms
✓
leaves other find-a-prospect phrasings alone too 0.9ms
✓
still routes genuine own-site SEO asks to the picker 1.0ms
lead_disambig matches the PURPOSE, not the noun (r-owned-inventory-first) · 4 tests
✓
catches a role-noun ask with an outreach purpose 0.8ms
✓
still catches the generic nouns it always did 0.4ms
✓
still stands down when the user explicitly wants NEW people 0.3ms
✓
does not swallow an ask that merely contains a purpose-shaped phrase 0.5ms
recoverLeadQuery · 6 tests
✓
reports the chip decision instead of silently discarding it 0.3ms
✓
handles the pre-2026-07-31 chip wording still sitting in live histories 0.2ms
✓
does not claim the decision when the user never made it 0.1ms
✓
never returns the prefix as part of the audience 0.1ms
✓
survives an empty or whitespace input without inventing a decision 0.3ms
✓
does not carry state between calls — the regex is global-flag free 0.2ms
backlink_worth shortcut · 2 tests
✓
owns the worth / value phrasings for backlinks 0.7ms
✓
does not take a backlink question that is not about worth 0.8ms
a machine-authored message is never a question (2026-09-17) · 4 tests
✓
a next-action chip matches next_action_exec and nothing else 0.2ms
✓
a cost confirm matches cost_confirm — the approved spend must run, not be re-quoted (bklink 2026-09-18) 0.3ms
✓
an initiative execute matches no phrasing intent (index.ts handles it before the router) 0.1ms
✓
the diagnose shortcut is guarded at its entry 5.1ms
protocol messages reach their own handler, never a question classifier · 5 tests
✓
a skill reply whose chosen option reads as a question resumes the skill (the live defect) 0.3ms
✓
every other protocol with a question-shaped payload reaches its declared owner 0.3ms
✓
the router reads the registry: every declared owner is reachable, and nothing else reads a protocol 0.8ms
✓
every picker confirm template in the product mints a registered protocol 8.6ms
✓
findLatestLeadSearchQuery skips protocol messages through the registry, not its own copy 3.4ms
src/leads/shared-tier.vitest.ts
the flag · 3 tests
✓
is off unless explicitly set to 1 1.9ms
✓
is SEPARATE from the route flag — a reachable API is not an earned tier position 0.3ms
✓
costs nothing at all when off — the fetch is never even called 1.4ms
a hostile client cannot reach the caller · 5 tests
✓
a client that hangs forever returns on time, not never 2.7ms
✓
a REJECTED promise degrades, never throws 0.6ms
✓
a SYNCHRONOUS throw inside the fetch degrades too 0.4ms
✓
a wrong-shaped return is treated as nothing, not spread into the ladder 0.6ms
✓
passes real results straight through 0.3ms
the budget · 2 tests
✓
clears a Neon cold start at the current corpus scale, and still leaves search_leads enough of its 120s 0.7ms
✓
a timeout does NOT leave a timer holding the isolate open 1.4ms
silence is not an answer · 1 test
✓
a degraded tier says so, because "nobody like that" and "we could not ask" differ 1.5ms
the lead-source question is only asked when it has two real answers · 4 tests
✓
checks the Apollo connection BEFORE rendering the picker 0.2ms
✓
falls through to the SAME selection path rather than a second lead flow 0.6ms
✓
SAYS the choice was made for them, with the way to change it 0.5ms
✓
still asks when Apollo IS connected — then both answers are real 0.1ms
our corpus is searched before the provider, and priced to the market · 11 tests
✓
runs above the paid boundary, not below it 0.2ms
✓
no longer triggers the dead people-search actor 0.2ms
✓
costs the user $0.01 per lead — the market rate we chose to match 0.2ms
✓
is CHEAPER than the provider rung, never dearer 0.2ms
✓
records the repricing as a DECISION, with the market data behind it 0.2ms
✓
the estimate must read the price, never assume the corpus is free 0.1ms
✓
bills on DELIVERY, and bills it in exactly ONE place 0.3ms
✓
only counts rows that can actually receive an email 0.1ms
✓
hands the SHORTFALL down the ladder rather than replacing the run 0.2ms
✓
reports the split instead of one blended list 1.1ms
✓
never names a vendor in a user-facing label (CLAUDE.md §4) 1.9ms
the tenant reaches the gate · 4 tests
✓
a tenant-list flag arms the WRAPPER, not just the factory 0.3ms
✓
refuses a tenant not on the list 0.2ms
✓
refuses when no tenant is supplied at all 0.1ms
✓
the ladder passes its tenant to the gate 0.6ms
sharedLeadsTier — a skipped rung explains itself · 4 tests
✓
returns a note when the tier is off, not a bare empty result 0.2ms
✓
says NOT SEARCHED rather than empty — they are different facts 0.2ms
✓
names no internal flag or vendor 0.2ms
✓
stays silent when the tier is ON and simply found nothing 0.2ms
a rung may answer with { leads, note } (2026-09-15) · 1 test
✓
the note reaches the caller and the leads are the leads 0.5ms
the wrapper passes the budget down and the degraded sentence up · 3 tests
✓
the fetch receives the budget it must fit inside 0.2ms
✓
its own deadline and failure outcomes are degraded, and say so as OUR fault 5.8ms
✓
a rung outcome carrying `degraded` reaches the caller; one without stays shaped as before 0.4ms
src/tools/registry.vitest.ts
tool-name aliases (LLM hallucination guard) · 5 tests
✓
maps confirmed hallucinated names to their canonical tool 2.4ms
✓
maps the two misfires found in the 2026-08-30 sweep 0.5ms
✓
every alias TARGET is a real registered tool 0.9ms
✓
passes real/unknown tool names through untouched 0.3ms
✓
has no chained or circular aliases (every target is a terminal dispatch name) 0.6ms
V2_SYSTEM execution discipline · 5 tests
✓
orders action on explicit asks instead of option menus 0.5ms
✓
forbids re-asking facts already established in the conversation 0.4ms
✓
requires tailored output when a brief is stored 0.3ms
✓
onboarding gate blocks tools, never knowledge — direct answers come first 0.7ms
✓
keeps the mandated pre-execution questions carved out (no contradiction with gates) 0.6ms
connectAlias (connect_<name> hallucination guard) · 3 tests
✓
resolves fused connect names with the connector arg 1.3ms
✓
ignores the real tool and unknown suffixes 0.3ms
✓
suffix list stays in sync with connect_connector's enum in V2_TOOLS 0.9ms
find_competitors exposure (cheap competitor discovery) · 2 tests
✓
find_competitors is registered so the LLM can actually call it 0.2ms
✓
routes bare "who are my competitors" to find_competitors, not the expensive aeo_visibility 0.4ms
create_marketing_plan dual registration · 8 tests
✓
is registered in V2_TOOLS so the LLM can call it 0.2ms
✓
is in the planner executable map so dispatch can run it 177.7ms
✓
its description never says free and prices in tokens only 0.5ms
✓
show_marketing_plan is dual-registered too 0.4ms
✓
create_marketing_plan has an LLM-synthesis-class timeout, not the 30s default 0.4ms
✓
B3 routing: ADVISORY asks route to the planner, imperatives to their tool 0.9ms
✓
regression 2026-07-22: "quick wins" must never DUMP a saved plan 0.5ms
✓
RESPONSE SHAPE contract: TL;DR-first exists and exempts short/gate turns 0.2ms
V2_SYSTEM no-ask turns · 1 test
✓
forbids tool calls on gratitude/acknowledgement/greeting turns 0.3ms
V2_SYSTEM out-of-scope asks · 3 tests
✓
instructs a direct, useful answer first — not an immediate redirect 0.2ms
✓
forbids inventing capabilities nqzai does not have when bridging back 0.2ms
✓
does not license skipping a tool call that DOES cover the ask 0.2ms
V2_SYSTEM tabulation rule · 5 tests
✓
scopes tabulation to data the MODEL composed — tool records are rendered for it 0.3ms
✓
forbids the header-and-separator-only table that shipped the 2026-08-28 defect 0.2ms
✓
caps column count so tables do not overflow the chat column 0.2ms
✓
still tells the model when NOT to tabulate 0.1ms
✓
keeps cells free of bold, consistent with the sparing-bold rule 0.2ms
seo_google_merge compare exposure · 4 tests
✓
exposes a compare parameter the model can actually set 0.2ms
✓
the parameter description says a snapshot cannot explain a change 0.2ms
✓
the TOOL makes compare mandatory for change questions 0.2ms
✓
the TOOL forbids escalating to paid tools before running the comparison 0.2ms
tool-name aliases found in the 2026-08-25 sweep · 2 tests
✓
maps the two confirmed misfires to their canonical tool 0.2ms
✓
leaves an unresolved hallucination alone rather than guessing a target 0.2ms
src/seo/panel-segments.vitest.ts
segmentKey · 2 tests
✓
is stable, slugged and namespaced by kind 1.9ms
✓
never yields a bare namespace for unusable input 0.3ms
cleanSeededPrompts — the seed must survive hygiene · 7 tests
✓
keeps the seed and lowercases it 0.3ms
✓
FIRST occurrence wins, so a seeded prompt is not replaced by an unseeded duplicate 0.9ms
✓
drops prompts that are too short or too long rather than truncating them 0.5ms
✓
accepts bare strings as well as objects 0.2ms
✓
normalises whitespace so two spellings of one prompt are one prompt 0.3ms
✓
an empty seed string is null, never the empty string 0.6ms
deriveKeywordSegment — the Q26 primitive · 9 tests
✓
carries the keyword itself, not just the origin label 1.8ms
✓
reuses the registry junk gate rather than inventing a second one 1.3ms
✓
orders by impressions — a weekly charge should measure the terms that carry traffic 0.3ms
✓
keeps terms with no impressions rather than dropping them 0.3ms
✓
is tagged as a keyword segment with no locale 0.2ms
✓
asks an already-question query verbatim instead of wrapping it 0.3ms
✓
never emits a double question mark 0.2ms
✓
the SEED keeps the query exactly as Search Console reported it 0.1ms
seedIndex — the join Q26 performs against rank data · 3 tests
✓
groups prompts by the term they measure 0.3ms
✓
omits unseeded prompts — they cannot be joined to a rank 0.2ms
✓
a keyword named __proto__ cannot reach Object.prototype 0.2ms
segmentBudget — segments are a recurring spend multiplier · 5 tests
✓
multiplies prompts by the engines the run will ACTUALLY use 0.7ms
✓
reports the YEARLY commitment, because weekly is what is being approved 0.1ms
✓
counts distinct engines — a duplicated engine is not a second fan-out 0.2ms
✓
never counts more than the active ceiling 0.2ms
✓
zero engines is zero cells, not a silent fallback to a default fan-out 0.1ms
parseSegments / serializeSegments · 8 tests
✓
round-trips a keyword segment WITH its seeds intact 0.3ms
✓
keeps two audience segments distinct — the Q14 comparison depends on it 0.3ms
✓
drops a duplicate key rather than storing two indistinguishable panels 0.2ms
✓
keeps locale ONLY on a language segment 0.2ms
✓
drops a segment with no usable prompts instead of keeping an empty shell 0.4ms
✓
rejects an unknown kind rather than defaulting it 0.2ms
✓
survives malformed storage without throwing — it is read on a cron 0.2ms
✓
enforces the active ceiling on read, not just on write 0.3ms
segmentPromptTexts · 2 tests
✓
yields exactly what seoGeoVisibility takes 0.2ms
✓
is empty, never undefined, for a missing segment 0.1ms
upsertSegment · 2 tests
✓
replaces by key and keeps the others in order 0.3ms
✓
adds when the key is new 0.2ms
src/seo/traffic-incident.vitest.ts
the two-source rule is structural, not advisory · 3 tests
✓
never returns a confident verdict on one source 3.0ms
✓
every confident verdict in every shape names >= 2 sources 2.1ms
✓
an untested hypothesis always says what would settle it 0.6ms
the rival hypothesis is KILLED by the scan that was ignored · 5 tests
✓
marks it killed, not merely unmentioned 0.5ms
✓
says so out of the tenant's OWN measurements 1.0ms
✓
a scan that never ran is NOT "no competitors" — GS-004 0.5ms
✓
survives when a rival really is ahead, or a new one arrived 0.4ms
✓
does not claim movement it cannot see — a truncated read drops the third source 0.3ms
tracking is the cheapest thing to rule out, so it is tested first · 4 tests
✓
survives when the two systems disagree 1.1ms
✓
is killed when they moved together 0.4ms
✓
names the missing connector when only one system is present 0.3ms
✓
a move smaller than the stated threshold is not a direction 0.2ms
indexation is never KILLED, because we cannot see index coverage · 2 tests
✓
has only two possible verdicts 0.6ms
✓
survives only when the on-page audit and Search Console fell together 0.2ms
breadth separates an update from a local fault · 3 tests
✓
survives when three or more measurements fell together 0.2ms
✓
does NOT kill it when there are too few measurements to judge breadth 0.3ms
✓
is killed when one fell and its neighbours held 0.3ms
seasonality is the question only the user can answer · 1 test
✓
is always untested, in every shape, and always ends in a question 0.3ms
the decision rule produces an instruction, never a summary · 7 tests
✓
names the single survivor to act on 0.6ms
✓
refuses to pick between two survivors, and names the discriminator 0.2ms
✓
SAYS SO when nothing survives — the honest non-answer 0.5ms
✓
STILL stops when nothing at all could be tested 0.3ms
✓
the one-pager is always complete 0.3ms
✓
states the period, because a delta with no period cannot be checked 0.2ms
✓
degrades honestly with no readings at all — GS-009, never padded 0.3ms
no internal vocabulary reaches the reader — GS-005 · 1 test
✓
never names a tool, a field or a vendor 0.5ms
a movement question about search reaches diagnose deterministically · 4 tests
✓
routes on all three conditions, not on the intent alone 2.6ms
✓
runs diagnose and NOTHING else 0.5ms
✓
stands down on a compound ask, asking the SAME registry the AEO shortcut asks 0.7ms
✓
the shape axis is what keeps a STATE question out of it 2.8ms
the brief never misdescribes its own evidence · 4 tests
✓
an AMBIGUOUS spread is not reported as too few measurements 0.3ms
✓
still says "too few" when there genuinely are too few 0.2ms
✓
does not claim there are no readings when other measurements have two 0.2ms
✓
says it plainly when there is genuinely nothing 0.2ms
the second Google-traffic reading can come from Search Console windows ([1.5.2] 2026-09-15) · 4 tests
✓
a single stored snapshot no longer means "no second reading" when the history is on file 0.6ms
✓
a snapshot that already has a direction keeps it — the windows do not override a measured pair 0.2ms
✓
a thin pair of windows states the numbers and the pages but claims no direction 0.4ms
✓
without the history the wording is unchanged 0.2ms
src/adoption/contracts.vitest.ts
adoption contracts · 3 tests
✓
classifies current usage and preserves lapsed state 1.9ms
✓
assigns the same user to the same experiment bucket 1.0ms
✓
blocks unsafe and capped sends with machine-readable reasons 14.8ms
evaluateNudgePolicy — bounced and tool_cooldown in isolation · 4 tests
✓
blocks on bounced alone 0.5ms
✓
blocks on a tool nudged within the last 21 days 0.5ms
✓
does NOT block a tool nudged 21+ days ago 0.3ms
✓
a genuinely clean candidate is eligible 0.5ms
computeConsecutiveIgnored · 5 tests
✓
counts leading sent-but-unopened rows, newest first 0.3ms
✓
stops at the first opened send 0.5ms
✓
stops at the first non-terminal row — a rejected/pending draft says nothing about whether the USER ignored anything 0.2ms
✓
empty history is zero, not ignored 0.2ms
✓
an engaged user (most recent opened) is never in a backoff streak 0.1ms
adoptionAutoSendActive · 3 tests
✓
'1'/'true' = active now; junk/empty = off 0.4ms
✓
date value stays off before the date and turns on from 00:00 UTC that day 0.2ms
✓
malformed dates never activate 0.2ms
isAdoptionUserExcluded · 3 tests
✓
excludes a test tenant by id 0.2ms
✓
excludes an internal account by email (case/space-insensitive) — the newly-honored form 0.2ms
✓
lets a genuine user through 0.1ms
summarizeAdoptionProfile · 3 tests
✓
summarizes an empty profile honestly 0.2ms
✓
names never-used families plainly, without a fabricated count 0.2ms
✓
states an active family with real counts and recency, giving genuine contrast material 1.7ms
extractPreSendCount · 2 tests
✓
reads the invocations value captured at send/assignment time 0.2ms
✓
defaults to 0 for an empty or malformed bundle 0.1ms
buildAccountFactEvidence · 10 tests
✓
cites real contacts for a lead_discovery pitch 0.2ms
✓
cites unsent drafts for an email_generation pitch 0.2ms
✓
combines sent + replied for an outreach pitch 0.1ms
✓
still cites outreach when only replies exist (sent=0 but replied>0 is real signal) 0.2ms
✓
cites tracked keywords for a rank_tracking pitch 0.1ms
✓
cites content pieces for a reporting pitch 0.1ms
✓
returns null rather than a fabricated zero when the fact is empty 0.2ms
✓
returns null for ai_visibility — no bulk-fetchable account table yet, stays honest rather than fabricate one 0.1ms
✓
returns null for an unknown family 0.1ms
✓
floors negative/fractional inputs defensively rather than emitting a nonsense count 0.2ms
detectAdoptionConversion · 4 tests
✓
is a conversion: count increased AND last use postdates the send 0.2ms
✓
is NOT a conversion: no last_invoked_at at all 0.1ms
✓
is NOT a conversion: count did not increase, even with a recent timestamp 0.1ms
✓
is NOT a conversion: count increased but the last-seen timestamp predates the send (stale window recompute, not new activity) 0.1ms
src/chat/message-contract.vitest.ts
layer 2 — the assembled reply, per site-scoped tool · 36 tests
✓
renders something only this tool could have produced 2.2ms
✓
I5 — no JS placeholder reaches the user 0.4ms
✓
I1 — no verdict word survives a degraded sample 0.2ms
✓
I2 — does not disclose a limitation and then act as if it had not 0.4ms
✓
I3 — no status code the outbound guardrail would silently rewrite 0.3ms
✓
I4 — degraded language never leaks into a healthy reply 0.2ms
✓
renders something only this tool could have produced 0.3ms
✓
I5 — no JS placeholder reaches the user 0.2ms
✓
I1 — no verdict word survives a degraded sample 0.5ms
✓
I2 — does not disclose a limitation and then act as if it had not 0.2ms
✓
I3 — no status code the outbound guardrail would silently rewrite 0.2ms
✓
I4 — degraded language never leaks into a healthy reply 0.1ms
✓
renders something only this tool could have produced 0.2ms
✓
I5 — no JS placeholder reaches the user 0.1ms
✓
I1 — no verdict word survives a degraded sample 0.1ms
✓
I2 — does not disclose a limitation and then act as if it had not 0.1ms
✓
I3 — no status code the outbound guardrail would silently rewrite 0.1ms
✓
I4 — degraded language never leaks into a healthy reply 0.1ms
✓
renders something only this tool could have produced 0.3ms
✓
I5 — no JS placeholder reaches the user 0.1ms
✓
I1 — no verdict word survives a degraded sample 0.1ms
✓
I2 — does not disclose a limitation and then act as if it had not 0.0ms
✓
I3 — no status code the outbound guardrail would silently rewrite 0.1ms
✓
I4 — degraded language never leaks into a healthy reply 0.1ms
✓
renders something only this tool could have produced 0.2ms
✓
I5 — no JS placeholder reaches the user 0.1ms
✓
I1 — no verdict word survives a degraded sample 0.1ms
✓
I2 — does not disclose a limitation and then act as if it had not 0.0ms
✓
I3 — no status code the outbound guardrail would silently rewrite 0.1ms
✓
I4 — degraded language never leaks into a healthy reply 0.1ms
✓
renders something only this tool could have produced 0.2ms
✓
I5 — no JS placeholder reaches the user 0.1ms
✓
I1 — no verdict word survives a degraded sample 0.1ms
✓
I2 — does not disclose a limitation and then act as if it had not 0.0ms
✓
I3 — no status code the outbound guardrail would silently rewrite 0.1ms
✓
I4 — degraded language never leaks into a healthy reply 0.1ms
site-scoped tools with NO chat renderer · 1 test
✓
is a known, listed gap 0.8ms
src/db/user-role-token-writes.vitest.ts
preconditions (the committed snapshot, as refreshed 2026-10-18) · 1 test
✓
the user role may update emails_sent subject/body, and not status / sent_at / seq_step / bounce_detail (196) 4.1ms
baseline · 1 test
✓
the clean tree passes and says how many payload writes it compared, user-token and every document 845.2ms
1. a user-token write of a column the user role may not write fails, in every shape (V6-tenancy-F01) · 17 tests
✓
the batch prints exactly the findings its cases expect, each on its own probe, and nothing else 837.6ms
✓
CONTROL (caught before the fix): update_<t>_by_pk _set: exits 1 and names the file, line and column 0.7ms
✓
update_<t>_many updates[0]._set (V6 mutant D8): exits 1 and names the file, line and column 0.4ms
✓
update_<t>_many: only the SECOND element writes it: exits 1 and names the file, line and column 0.4ms
✓
upsert on_conflict.update_columns (V6 mutant D9c): both columns named: exits 1 and names the file, line and column 0.4ms
✓
_one upsert with on_conflict BEFORE object: exits 1 and names the file, line and column 0.3ms
✓
update_columns as a single enum value (GraphQL list coercion): exits 1 and names the file, line and column 0.6ms
✓
_inc: exits 1 and names the file, line and column 0.3ms
✓
jsonb operator _append: exits 1 and names the file, line and column 0.4ms
✓
jsonb operator _prepend: exits 1 and names the file, line and column 0.3ms
✓
jsonb operator _delete_key: exits 1 and names the file, line and column 0.2ms
✓
jsonb operator _delete_elem: exits 1 and names the file, line and column 0.2ms
✓
jsonb operator _delete_at_path: exits 1 and names the file, line and column 0.2ms
✓
update_<t>_many with a jsonb operator: exits 1 and names the file, line and column 0.3ms
✓
a nested relationship insert: the related table's row: exits 1 and names the file, line and column 0.2ms
✓
a nested relationship insert: its on_conflict.update_columns: exits 1 and names the file, line and column 0.2ms
✓
an upsert on a table the user role holds no UPDATE on at all: exits 1 and says so 0.1ms
2. the filters inside those shapes are read-checked too · 3 tests
✓
the batch prints exactly one finding per probe, and nothing else 858.1ms
✓
updates[].where on an unreadable column: exits 1 and names it 0.3ms
✓
on_conflict.where on an unreadable column: exits 1 and names it 0.3ms
3. controls: what the user role MAY write passes, and a payload the guard cannot read is counted, never passed as checked · 10 tests
✓
update_<t>_many writing subject and body: exits 0 851.8ms
✓
an upsert updating subject and body, and one updating nothing: exit 0 0.4ms
✓
a nested insert of columns the role may insert: exits 0 0.2ms
✓
the same status writes on the ADMIN secret pass header item 4 (the admin may write them) 0.3ms
✓
the not-checked total moves by exactly what the probes add, and every other document's count is unchanged 0.5ms
✓
a variable payload (_set: $s) is counted as not checked: 1, and the document passes 0.2ms
✓
a variable payload (updates: $u) is counted as not checked: 1, and the document passes 0.1ms
✓
a variable payload (a variable element) is counted as not checked: 1, and the document passes 0.2ms
✓
a variable payload (on_conflict: $oc) is counted as not checked: 2, and the document passes 0.1ms
✓
a variable payload (update_columns: $c) is counted as not checked: 2, and the document passes 0.1ms
4. header item 1 (the column exists at all) sees the same shapes, on every document · 5 tests
✓
the batch prints exactly one missing-column finding per probe, and nothing else 630.2ms
✓
an ADMIN document writing a column that does not exist through update_<t>_many: exits 1 and names it 0.4ms
✓
an ADMIN document writing a column that does not exist through an upsert's update_columns: exits 1 and names it 0.2ms
✓
an ADMIN document writing a column that does not exist through an insert whose object comes after on_conflict: exits 1 and names it 0.1ms
✓
an ADMIN document writing a column that does not exist through a jsonb operator: exits 1 and names it 0.2ms
src/email/sender-settings.vitest.ts
what is written is sealed · 3 tests
✓
every secret field is sealed; the non-secret fields stay readable for diagnosis 7.8ms
✓
opens back to exactly what was written 1.4ms
✓
with no encryption key a credential is refused, not stored in the clear 1.5ms
rows written before K3 migrate on first read · 4 tests
✓
a plaintext row is read correctly and re-sealed in place 1.2ms
✓
a failed re-seal does not fail the read, and is reported 0.9ms
✓
the admin backfill: dry run counts, apply seals, a second pass finds nothing 3.2ms
✓
the backfill never overwrites a row it cannot round-trip (the only copy of a credential) 0.8ms
an unreadable secret is an error, not an absence · 3 tests
✓
a value sealed under another key throws on read 0.8ms
✓
the send path reports it and treats the tenant as not configured 1.7ms
✓
the send path reads a sealed row 0.7ms
the settings form · 5 tests
✓
GET returns a mask with the last 4 characters and never a secret 23.6ms
✓
GET on an unreadable row is a plain 500, with no error detail 0.8ms
✓
a save that re-sends the mask keeps the stored key, keeps fields the form does not edit, and stores nothing in the clear 6.5ms
✓
a save over an unreadable row changes nothing 2.0ms
✓
the mask of a short secret shows nothing of it 0.4ms
the bounce webhook fails closed on an unreadable signing secret · 4 tests
✓
a signing secret sealed under another key → 404, and reported 3.6ms
✓
a settings row that cannot be read → 404 (was: verification silently skipped) 1.4ms
✓
a sealed signing secret is opened and enforced: an unsigned post is refused 2.0ms
✓
no signing secret stored → the URL token stands alone (unchanged) 1.5ms
provider allowlist, provider switch and field hygiene on save · 17 tests
✓
#15 a provider outside the allowlist is refused and the row is untouched 4.9ms
✓
#16 the normalised provider is what is stored 1.2ms
✓
#17 switching SMTP → Resend without a new key is refused, and the SMTP password never reaches Resend 27.8ms
✓
#17b an SMTP save that changes the server or username without a new password is refused; the saved password never reaches another host 11.0ms
✓
#17c the same SMTP server (host case/spacing, a new port) keeps the saved password; a new server with its own password gets only that password 5.4ms
✓
#18 switching to Mailjet needs a new secret too; with both, the row holds exactly Mailjet fields 9.6ms
✓
#19 leaving SMTP drops every SMTP field and a stray secret 3.9ms
✓
#20 a webhook signing secret does not survive a switch — and does survive a same-provider save 3.9ms
✓
#21 SMTP ports: 25 and non-ports refused; 2525 stored as given 3.4ms
✓
#21b a host naming a private or internal network is refused at save, with a reason the form shows 4.4ms
✓
#21d a host literal that is not canonical dotted-decimal is refused at save, the way the send refuses it 4.4ms
✓
#21c only the SMTP submission ports 465 / 587 / 2525 are accepted at save 5.7ms
✓
#22 from_email must be a plain address 1.7ms
✓
#22b a CR/LF in from_name is flattened, not stored 0.8ms
✓
#23 a stored "gmail" row is not a sending provider: no Gmail API call, refusal counted by class 1.3ms
✓
#24a a stored "mailgun" row: sendEmail refuses at the read, with no network call at all 1.1ms
✓
#24b the same row handed straight to the sender (read-side check bypassed) still reaches no host 0.8ms
a refused send leaves its reason on the row — REST /api/email/send · 1 test
✓
#27 an SMTP server without STARTTLS: the row is failed WITH smtp_tls_required, and nothing authenticated 12.6ms
src/runtime/guardrail.vitest.ts
scanOutbound — BLOCK (fail-closed) · 4 tests
✓
blocks and replaces a message containing the canary 2.6ms
✓
blocks secret-shaped strings (keys, JWTs, PEM) 1.0ms
✓
blocks a LABELED admin secret, but NOT a report hash + the word "admin" 2.2ms
✓
does NOT block reports that embed non-user UUIDs (report_id / run_id) 0.5ms
scanOutbound — REDACT (fail-open) · 9 tests
✓
redacts backend vendor names 0.4ms
✓
keeps user-facing allowlist names (Google products, Apollo picker) 0.3ms
✓
lets the Apollo partner referral link + CTA pass through untouched 0.8ms
✓
redacts USD amounts (token-only billing) 0.5ms
✓
redacts internal tool names and raw error codes 0.7ms
✓
redacts a name-dropped planner tool (live-hit 2026-07-22 regression) 0.3ms
✓
INTERNAL_TOOL_NAMES covers every V2_TOOLS entry (registry drift) 86.9ms
✓
a bare-word tool name is redacted as an IDENTIFIER but not as English 0.8ms
✓
underscore names stay redacted in plain prose — they are never English 0.2ms
scanOutbound — allowCurrency (commerce turns, NQZAI-50/4R regression) · 9 tests
✓
keeps merchant store revenue amounts when allowCurrency is set 0.3ms
✓
still redacts USD by default (platform-cost rule unchanged) 0.3ms
✓
TENANT_CURRENCY_TOOLS covers commerce AND Google revenue-report tools 0.6ms
✓
does not redact a dollar figure the user themselves wrote 2.5ms
✓
still redacts OUR costs on the same turn the user quoted THEIR figure 0.4ms
✓
matches the user echo across formatting differences, not across values 0.3ms
✓
with no userEcho, behaviour is exactly as before 0.2ms
✓
isRedactionBug: usd on a tenant-money turn pages; everything else is telemetry 0.3ms
✓
allowCurrency does NOT weaken vendor/secret rails 0.3ms
scanOutbound — clean replies pass through UNCHANGED (anti-over-blocking) · 1 test
✓
leaves ordinary intelligent replies byte-for-byte identical 0.6ms
a redacted sentence still reads like English · 8 tests
✓
rewrites: The seo_onpage_audit tool could not read your site. 0.5ms
✓
rewrites: the seo_onpage_audit tool could not read your site. 0.2ms
✓
rewrites: I used the search_leads function to find them. 0.1ms
✓
rewrites: The "diagnose" tool needs your domain. 0.1ms
✓
rewrites: Calling the "diagnose" function now. 0.2ms
✓
an unlabelled name still becomes the placeholder, with the frame repaired 0.3ms
✓
keeps a parenthetical that now names the operation, drops one that would be only a placeholder 0.2ms
✓
leaves the ordinary phrase alone when we did not put it there 0.2ms
scanInbound — flag, never block · 2 tests
✓
flags extraction / injection / fishing attempts 1.9ms
✓
does NOT flag normal product questions 0.2ms
free-claim redaction · 4 tests
✓
rewrites a claim that something is free 0.3ms
✓
rewrites the adjective form that names one of our no-extra-cost paths 0.3ms
✓
leaves negations, product nouns and idioms alone 0.2ms
✓
does not rewrite a tenant-money turn or the user's own words 0.3ms
src/observability.vitest.ts
calcLlmCost · 3 tests
✓
prices a known model from its real per-M rates 1.7ms
✓
scales linearly with token counts 0.3ms
✓
returns 0 for a zero-token call 0.3ms
LLM_COST_PER_M coverage — models that were silently mispriced · 4 tests
✓
prices the live CoT reasoning model 0.7ms
✓
prices both router bake-off candidates 0.3ms
✓
prices the AEO engine-probe models and the RCA models 0.5ms
✓
never prices a model below the fallback it would otherwise silently use 1.1ms
LLM price table companions · 4 tests
✓
an unknown id is costed at UNKNOWN_MODEL_FALLBACK_PER_M, not at zero 0.3ms
✓
every cache-read rate belongs to a priced model and sits in (0, that model's input rate] 1.4ms
✓
the invariant rejects a cache rate above the input rate (negative case) 0.4ms
✓
LLM_COST_PER_M_VERIFIED_AT is an ISO date (format only — no clock here) 0.3ms
toLogAttribute · 4 tests
✓
types integers, doubles and strings distinctly 0.3ms
✓
writes booleans as STRINGS so they can actually be read back 0.2ms
✓
every existing reader already string-compares these 0.1ms
✓
stringifies non-finite numbers and objects instead of sending invalid JSON types 0.1ms
buildSentryLogEnvelope · 2 tests
✓
is a 3-line envelope with a log item header Sentry accepts 3.2ms
✓
carries the message contract + typed attributes, and drops null attributes 0.7ms
buildGenAiTransactionEnvelope · 6 tests
✓
emits a transaction whose child span follows the gen_ai convention 0.9ms
✓
never gives the transaction root the same op as the child span 0.7ms
✓
marks a failover attempt internal_error so dashboards separate wasted spend 0.4ms
✓
records finish_reason and tags a truncated completion 0.4ms
✓
tags a clean completion truncated:no so the two are separable, not just absent-vs-present 0.3ms
✓
omits the tag entirely when no finish_reason was reported 0.2ms
isInternalTraffic — our own traffic must be distinguishable in Sentry · 13 tests
✓
tags the eval tenant by email 0.2ms
✓
tags the owner accounts 0.1ms
✓
tags eval-harness sessions with no email at all 0.2ms
✓
leaves a real tenant alone — tagging everything would be the same blindness 0.1ms
✓
matches the harness prefix, not a substring anywhere 0.1ms
✓
is case- and whitespace-insensitive on the email 0.1ms
✓
tags a test tenant whose session prefix no harness owns 0.3ms
✓
tags the exact event the 2026-08-30 weekly RCA called ORGANIC 0.1ms
✓
tags the OWNER by id, which TEST_CAP_USER_IDS alone could not 0.1ms
✓
does NOT tag a real tenant just because the set is present 0.3ms
✓
is inert without a set, rather than tagging everything 0.2ms
✓
is case-insensitive on the id, since UUIDs get written both ways 0.1ms
✓
reads the SAME set the rest of the product calls internal 0.2ms
scripts/lib/admin-paths-scan.vitest.mjs
strayApiLiterals — the fixtures the design names · 7 tests
✓
a stray '/api/admin/x' literal is 1 hit (R1) 3.4ms
✓
a template literal with a query is a hit, and so is a double-quoted one 0.8ms
✓
a comment `// GET /api/admin/x` is 0 hits — no quote before the path 0.4ms
✓
an absolute https://admin.nqz.ai/api/admin/x is an R2 hit — the host hides the path from R1 0.5ms
✓
JSX text `POST /api/admin/user-scores/recompute` is 0 hits (score-panel.tsx prose) 0.3ms
✓
fails closed: a QUOTED path inside a comment is a hit, by design 0.3ms
✓
reports the right line number 0.3ms
strayApiLiterals — a path composed from a registry value, or opened with `/api${` · 6 tests
✓
R3: a segment appended to ADMIN_API.<key> inside a template is a hit 0.4ms
✓
R3: a segment concatenated onto ADMIN_API.<key> is a hit, any quote, any spacing 0.5ms
✓
a query string on a registry value is NOT a hit — that is how parameters ride 0.3ms
✓
R1: a template that opens `/api${…}` is a hit 0.3ms
✓
R1: a quoted 'api/admin/…' with no leading slash is a hit 0.1ms
✓
a quoted word 'api' is not a path (verified_source = 'api') 0.2ms
parseAdminApi — the regex the guard trusts instead of importing .ts · 3 tests
✓
reads only the ADMIN_API object, in order, trailing comments allowed 0.5ms
✓
returns nothing when the object is missing or unterminated 0.3ms
✓
a line it cannot read is surfaced, not dropped — a vanished entry is an unseen proxied path 0.4ms
adminApiRefs / mainRoutes · 4 tests
✓
counts ADMIN_API.<key> references per key 0.5ms
✓
a mention in a comment is not a call — line, block and JSDoc comments count 0 0.2ms
✓
comment markers inside strings and templates do not hide the code after them 1.8ms
✓
names the paths with no exact `path ===` route, and counts the routes 0.3ms
adminHostApiLinks — admin.nqz.ai/api links written outside the SPA · 3 tests
✓
finds the path, trims sentence punctuation, keeps the line 0.3ms
✓
a query string is not part of the path; https:// and a bare /api both count 0.3ms
✓
the console itself (admin.nqz.ai/ga4-landing) and the main worker (nqz.ai/api/…) are not admin API links 0.1ms
check-admin-paths — exit codes against the real defect · 13 tests
✓
the real tree → exit 0, with its counts 0.5ms
✓
an empty --root → exit 2 (blind), never a cheerful pass 161.5ms
✓
an empty --index → exit 2: no main-worker routes to check against 234.4ms
✓
PX1 itself: the pre-fix egress literal restored → exit 1 (R1) 337.2ms
✓
a new file with a stray literal → exit 1 339.1ms
✓
the egress entry deleted from ADMIN_API → exit 1 (a call names a key that does not exist) 333.3ms
✓
a proxied path nobody calls (transactional-emails) → exit 1 (0 references) 327.2ms
✓
a registry path with no main-worker route → exit 1 340.3ms
✓
a registry value with a query string → exit 1 (unparseable line, not a silent drop) 336.5ms
✓
a segment appended to a registry value → exit 1 (R3): the /bug-reports/<uuid> trap 345.2ms
✓
a key whose only remaining mention is a comment → exit 1 (0 references) 330.3ms
✓
the pre-fix judge-report pointer restored (admin.nqz.ai/api/admin/judge-fail-fixtures) → exit 1 389.4ms
✓
an empty --main-src → exit 2 (blind), never a cheerful pass 109.7ms
src/admin/sessions.vitest.ts
a report IS a delivery — the counter and the classifier now agree · 3 tests
✓
counts a session that shipped only a report as delivered 2.2ms
✓
still counts a session that shipped nothing as nothing 0.4ms
✓
and the totals ask that function rather than re-deriving it 1.0ms
the signature that a human found by reading 17 transcripts · 4 tests
✓
flags high score + short session + nothing ran 8.1ms
✓
does NOT flag a session where a tool actually ran 1.2ms
✓
does NOT flag a long session, even with nothing run 1.0ms
✓
does NOT flag a session the judge already marked bad 1.6ms
the signature is what RENDERED, not what dispatched · 4 tests
✓
a tool ran, nothing rendered, judge happy → SILENT FAILURE 1.2ms
✓
a tool ran AND rows reached the screen → not a failure 1.5ms
✓
ABSENT instrumentation falls back — it is never read as zero 0.9ms
✓
and the fallback still catches a no-tool session 0.7ms
onboarding is not an outcome — the ground-truth check that FAILED · 4 tests
✓
a session where only the site scan ran is NOT tool_ran 1.0ms
✓
scan + diagnose together are still only onboarding 0.7ms
✓
onboarding PLUS a real tool is tool_ran 0.7ms
✓
wasted spend counts onboarding-only sessions too 0.4ms
internal matching collapses +tag and gmail-dot variants · 3 tests
✓
a probe address is excluded by the plain entry 0.5ms
✓
gmail dots collapse too 0.4ms
✓
a genuinely different address is NOT swallowed 0.5ms
tool execution is counted from the dispatcher, never from the judge · 1 test
✓
a session with tool_run rows is tool_ran even when the judge says nothing ran 0.6ms
the DETERMINISTIC path is no longer invisible (migration 166) · 2 tests
✓
a shortcut turn with NO llm row still lands on its session 0.7ms
✓
its own session_id WINS over the turn_id fallback 0.6ms
the spine: turn_id joins the ledger to a session · 2 tests
✓
provider and judge spend land on the right session via turn_id 0.6ms
✓
a ledger row whose turn has no session is skipped, never guessed 0.4ms
internal accounts are excluded by default · 1 test
✓
the test tenant does not pollute the real-user picture 1.1ms
the totals that make the case · 2 tests
✓
counts sessions where nothing ran, and what they cost 0.6ms
✓
reports the judge as a share of spend — it was 23.6% of everything 0.4ms
the transcript drill-down · 2 tests
✓
reads the same key the chat writes 0.5ms
✓
returns null rather than throwing on a missing or corrupt entry 0.3ms
outcome reads the render manifest, not just the tool list · 2 tests
✓
a session that rendered an ARTIFACT is tool_ran, whatever tools it used 0.4ms
✓
the tool list survives as the fallback for pre-manifest sessions 0.4ms
reconciliation: the view says what the ledger debited · 3 tests
✓
6d5: llm 152,005 + send fees 22,500 = 174,505 debited; the judge is 174,000 of overhead 16.5ms
✓
3es: 69,895 as the rows are; 36,000 once the refunds name their turns 5.7ms
✓
under BILLING_MODEL=cost the LLM leg is its cost at the basis rate 2.0ms
coverage names the window every table was read over · 2 tests
✓
api_usage at the cap: covered_since is the oldest api row, not the requested window 324.7ms
✓
under the cap, the window is the one asked for 0.8ms
what is debited is billing's rule, imported · 1 test
✓
no prefix rule for overhead, and the overhead list comes from billing 1.1ms
src/chat/monitor-insight.vitest.ts
monitorInsight — "went up" is not "improved" · 4 tests
✓
reads a RISE in pages-not-indexed as a loss 2.5ms
✓
reads a FALL in pages-not-indexed as a win 0.4ms
✓
reads NEW AI answer gaps as a loss and closed ones as a win 0.3ms
✓
reads regressed pages as a loss even though the count is positive 0.2ms
monitorInsight — the verdict is the point · 4 tests
✓
states the count of what improved and what slipped, before naming any of it 0.3ms
✓
says so plainly when everything moved one way 0.2ms
✓
puts a current level with its change on the chips, and nothing else 0.9ms
✓
keeps event counts out of the chips — they are not a reading 0.6ms
monitorInsight — the count must cover every delta the tool reported · 3 tests
✓
counts backlinks and referring domains as two distinct losses 0.5ms
✓
shows both on the chips, each with its own level 0.3ms
✓
does not double-count users against sessions 0.2ms
monitorInsight — display order is declared once · 3 tests
✓
orders traffic, then off-page, then AI, then on-page, then pages 0.3ms
✓
gives every movement a distinct rank 0.3ms
✓
has a written phrase for every declared measure 1.0ms
monitorInsight — link velocity qualifies the verdict, it does not join the count · 5 tests
✓
adds the qualifier as its own sentence, after the verdict 0.2ms
✓
states BOTH periods, because the word alone is not falsifiable 0.2ms
✓
says nothing when velocity is stable 0.1ms
✓
says nothing when the two periods are missing 0.2ms
✓
is not counted as a measure 0.2ms
monitorInsight — Search Console joined with Analytics · 5 tests
✓
counts search clicks and the two underperforming-page counts 0.3ms
✓
prints revenue as a DIRECTION with no figure — it is the tenant's own money, uncurrencied 0.3ms
✓
does not count google_merge sessions against ga_traffic sessions 0.2ms
✓
does not count joined_rows — measurement coverage is not a result 0.2ms
✓
does not count the ambiguous opportunity metric 0.1ms
monitorInsight — takes the tool deltas, never its own · 2 tests
✓
reports the tool delta even when it disagrees with current minus prior 0.2ms
✓
drops a null delta rather than coercing it to a zero movement 0.1ms
monitorInsight — refuses rather than half-claims · 5 tests
✓
returns null when nothing moved 0.1ms
✓
returns null when a section has no prior to compare against 0.1ms
✓
returns null on no history, an error, or no sections at all 0.2ms
✓
names the checks that ran for the first time instead of dropping them silently 0.2ms
✓
carries no caveat when every section had a prior 0.1ms
monitorInsight — reads as English · 2 tests
✓
singularises every unit it prints 0.3ms
✓
never prints a signed magnitude like "down -5" 0.2ms
monitorInsight — a thin AI-visibility delta is qualified · 3 tests
✓
states the movement AND why it cannot be acted on 0.2ms
✓
carries the first-run note and the thin note together 0.2ms
✓
says nothing when the samples carry their own weight 0.2ms
src/seo/ai-search-playbook-wiring.vitest.ts
each AI-search playbook is REACHABLE, not merely built · 6 tests
✓
Q08 → hallucination_recovery: predicate fires, key is registered, both routes carry it 3.4ms
✓
Q11 → ai_search_staffing: predicate fires, key is registered, both routes carry it 1.0ms
✓
Q12 → ai_audit_scope: predicate fires, key is registered, both routes carry it 1.2ms
✓
Q17 → geo_measurement_contract: predicate fires, key is registered, both routes carry it 0.9ms
✓
Q18 → crawler_policy: predicate fires, key is registered, both routes carry it 1.0ms
✓
the isPlaybook expression is one statement — the roster cannot drift apart 0.7ms
each playbook answers ITS question, not its neighbour's · 6 tests
✓
Q08 — hallucination_recovery carries its own template and clears the invariants 1.7ms
✓
Q11 — ai_search_staffing carries its own template and clears the invariants 0.5ms
✓
Q12 — ai_audit_scope carries its own template and clears the invariants 0.7ms
✓
Q17 — geo_measurement_contract carries its own template and clears the invariants 0.5ms
✓
Q18 — crawler_policy carries its own template and clears the invariants 0.6ms
✓
no two of the five produce the same headline 0.2ms
an absence claim names its boundary — the two that did not, live · 6 tests
✓
Q18 anchors on the crawl when one exists, and stops claiming nobody looked 0.6ms
✓
Q18 still says so — with its boundary — when no crawl is on file 0.3ms
✓
Q18 reads blocked bots as blocked, not merely as "checks exist" 0.2ms
✓
`na` is excluded from the access denominator 0.2ms
✓
Q12 stops claiming no content checks exist once it is given them 0.4ms
✓
the dispatcher hands content signals to EVERY playbook that anchors on them 0.3ms
a playbook does not deny a panel the tenant has already run · 7 tests
✓
Q08 anchors on the grounded run instead of denying it 0.5ms
✓
Q08 treats an UNGROUNDED run as no incident log — with a different reason 0.3ms
✓
Q08 still says so plainly when no run exists at all 0.2ms
✓
Q17 anchors on the frozen panel and its baseline 0.3ms
✓
Q17 distinguishes "ran but not frozen" from "never ran" 0.3ms
✓
an EMPTY frozen prompt list is not a frozen panel 0.1ms
✓
the gather reads both, or the anchors above can never fire in production 0.2ms
a coverage anchor never states good news as a double negative · 4 tests
✓
zero on both counts reads as the good news it is 0.2ms
✓
real shortfalls are still counted, on either axis or both 0.3ms
✓
never emits two negations in ONE clause, at any input 0.6ms
✓
every playbook that states coverage uses the shared helper 1.4ms
Q15 rival industrialisation is anchored on the measured shortlist gap · 7 tests
✓
states the gap in the direction it actually runs 0.4ms
✓
reads AHEAD as defending a lead, not as a gap to close 0.3ms
✓
a panel with no comparison prompt is not a gap of zero 0.4ms
✓
no run at all is a third sentence again 0.3ms
✓
warns against out-publishing, which is the expensive wrong answer 0.5ms
✓
prices capacity when initiatives are stacking up unrun 0.3ms
✓
the gather computes the gap from COMPARISON prompts only 0.3ms
src/seo/keyword-evidence.vitest.ts
striking distance — ONE definition, extracted from the planner · 4 tests
✓
takes positions 4-20 and nothing else 2.1ms
✓
is exclusive at 3 and inclusive at 20 — the boundaries the planner set 1.5ms
✓
ranks a distant term with traffic above a close term without 0.2ms
✓
excludes a keyword with no position — unranked is not position zero 0.3ms
the horizon weights a score that already had both halves · 5 tests
✓
is 1:1 when unset — an un-asked tenant sees no behaviour change 0.2ms
✓
favours behaviour for quick wins and estimate for the long game 0.3ms
✓
inverts the ranking between the two horizons 0.4ms
✓
still scores a big unranked term above zero under quick wins 0.3ms
✓
scores an unmeasured keyword at zero rather than inventing a value 0.5ms
the horizon is stated, never applied silently · 4 tests
✓
returns a note naming the ranking AND how to change it 0.4ms
✓
says nothing when unset — there is no preference to disclose 0.2ms
✓
parses only the two real values; everything else is unset, not a default 0.3ms
✓
names the settings key the SETTING_KEYS array must carry 0.3ms
asking — only when the answer would actually change · 4 tests
✓
asks when the two horizons name different leaders 0.4ms
✓
stays silent when both horizons agree — the question would be noise 0.1ms
✓
stays silent with nothing to rank 0.1ms
✓
offers exactly two options and is not a refusal 0.8ms
an uncaptured property is a finding, not an absence · 3 tests
✓
names the gap, the count, and that the figures are estimates 13.3ms
✓
says nothing once behaviour exists 0.1ms
✓
says nothing when there are no keywords at all — that is a different problem 0.1ms
no surface re-forks the definition · 3 tests
✓
the planner calls the shared definition instead of repeating the filter 0.4ms
✓
seo_list_keywords no longer orders the registry by recency 1.6ms
✓
diagnose reads keyword evidence 1.3ms
ensureGscCaptured — auto, but guarded · 7 tests
✓
captures when the property matches and nothing is on file 1.2ms
✓
refuses when Search Console is connected for a DIFFERENT property 0.3ms
✓
refuses when nothing is connected 0.2ms
✓
does not re-ask within a day of the last attempt 0.3ms
✓
tries again once a day has passed 0.5ms
✓
stamps the attempt BEFORE calling, so a failure still counts as an attempt 0.9ms
✓
reports an empty property as no_data, which is a finding rather than an error 0.2ms
gscCaptureNote — provenance is stated in every branch that has one · 3 tests
✓
says a capture just ran, with the count and the window 0.4ms
✓
says so when Search Console is absent or points elsewhere 0.3ms
✓
stays quiet when nothing happened worth reporting 0.2ms
the diagnose renderer shows the keyword half · 3 tests
✓
renders the keyword counts, the striking-distance table, provenance and horizon 0.3ms
✓
renders all four capture outcomes that have something to disclose 0.2ms
✓
flags an unmeasured profile rather than printing a bare zero 0.1ms
src/seo/local-presence.vitest.ts
buildFindings · 8 tests
✓
a complete, consistent, structured site produces NO findings 2.9ms
✓
leads with the address conflict — it is the one that blocks everything downstream 0.8ms
✓
reports a phone conflict separately from an address conflict 0.3ms
✓
escalates the missing-schema finding when there is also no address 0.4ms
✓
discloses when the address is only page text, because that weakens every later comparison 0.2ms
✓
does not raise the text-only disclosure when the address came from structured data 0.2ms
✓
never names a vendor or a schema internal to the user 0.6ms
✓
never quotes a dollar figure — the product bills in tokens 0.3ms
the consistency gate · 2 tests
✓
a self-contradicting site is what stops a paid listing comparison 0.6ms
✓
does not fire on the same address written two ways 0.3ms
buildNotChecked · 4 tests
✓
is never empty — the blind spots are structural, not situational 0.4ms
✓
names the listings explicitly, since that is what users ask about 0.2ms
✓
names the aggregator layer, which is unreachable at any price 0.2ms
✓
keeps the no-vendor-names and no-dollars rules 0.4ms
the tool is reachable for the question a user actually asks · 2 tests
✓
entity_audit advertises the address/phone capability in the words users type 13.1ms
✓
and carries the rule that stops it claiming listings were read 0.2ms
findings are gated on the tenant actually being local · 8 tests
✓
REGRESSION: says nothing local when the answer is unknown 0.1ms
✓
REGRESSION: says nothing local when the tenant serves remotely 0.1ms
✓
says all of it when the tenant IS local 0.3ms
✓
defaults to suppressed when the argument is omitted entirely 0.1ms
✓
a site contradicting ITSELF is universal — never gated 0.3ms
✓
a phone contradiction is universal too 0.2ms
✓
carries the question only while the answer is unknown 0.2ms
✓
and the model is told not to assume the answer from the industry 0.3ms
mergeBusinessLocation · 9 tests
✓
THE REGRESSION: an explicit answer persists, so the question is asked once 0.4ms
✓
stores the address the site states, with which tier it came from 0.3ms
✓
never lets an observation revise the user's own answer 0.2ms
✓
a failed fetch does not erase a good stored address 0.2ms
✓
clears confirmed_at when the site now says something else 0.2ms
✓
KEEPS confirmed_at when the address only changed cosmetically 0.2ms
✓
reports changed=false when nothing moved, so an audit is not a settings write 0.2ms
✓
survives a malformed stored blob instead of throwing 0.3ms
✓
the answer is reachable from chat — entity_audit declares the parameter 0.2ms
mergeBusinessLocation — the write-churn guard · 3 tests
✓
REGRESSION: a reformatted phone is not a change 0.2ms
✓
REGRESSION: a reformatted address is not a change 0.2ms
✓
but a REAL move still writes 0.2ms
src/campaigns/verify-dispatch.vitest.ts
every address already has a verdict → the answer is what is on file · 3 tests
✓
returns nothing_to_check with the stored verdicts, the re-check offer, and no spend 12.1ms
✓
several lists ride filter.in_lists in the offer; explicit ids stay ids 3.9ms
✓
(neg) nothing skipped → no re-check offer 2.3ms
a run hands the caller's clock and signal to the work · 3 tests
✓
verifyContactsByIds receives opts.signal and opts.deadlineAt, and bills only the unchecked 3.7ms
✓
an aborted signal before the spend → nothing is bought 1.6ms
✓
a normal run carries on_file (read after the writes) and the re-check offer for the 24 skipped 3.1ms
the continuation · 2 tests
✓
appears when the deadline stopped the run with work left, priced for exactly what is left 5.5ms
✓
(neg) not when the run finished, and not when it stopped with nothing left 2.1ms
consent is recorded on the ledger row · 5 tests
✓
a chip click that widens the filter is 'chip' 1.4ms
✓
a click (Next action: {"action":"verify_contacts","params":{"list_name":"List A","filter":{"verified":"any"}}}) is 'chip' even after the handler repoints the message to the typed one 2.1ms
✓
a click (Cost confirm:0f0e0d0c-0000-4000-8000-000000000001) is 'chip' even after the handler repoints the message to the typed one 2.8ms
✓
the model's widening that the loop let stand on Jev's reading is 'jev', with Jev's probability 1.0ms
✓
the loop's click consent is 'chip'; the default filter is 'none' whatever the annotation 1.8ms
the central reservation and the dispatch reserve one count between them · 5 tests
✓
70,000 and 25 unchecked addresses: the central check passes and the run is not refused 2.8ms
✓
balance = 1,500·N + 25,000 exactly is accepted end to end (N = 25 → 62,500) 1.4ms
✓
(neg) one token under that is refused — by the central check, before anything is bought 16.1ms
✓
a list that grew between the two reads reserves only the difference at dispatch 1.6ms
✓
(neg) a call that never passed the central preflight reserves its full count at dispatch 0.8ms
a declined valid/invalid re-check spends nothing · 5 tests
✓
the loop narrows it to the 5 it named: no spend, no quote, the 5 on file, a chip for exactly those 5 6.7ms
✓
(neg) the first version's rewrite — 'unchecked' on the list — would have bought all 45 0.8ms
✓
'any' narrows to 'unchecked' on the same target — exactly the intersection 0.3ms
✓
left widened (unread or naming nothing) + the loop said declined → the dispatch answers without spending 2.4ms
✓
a widened request that matches nothing says so — never "all N already have a result" 1.1ms
the continuation of a widened run · 3 tests
✓
a stopped-early 'any' run continues with exactly the addresses it did not reach — nothing it bought 1.6ms
✓
an address the run reached but got no verdict for is continued too (it was never billed) 1.0ms
✓
the unchecked continuation keeps the request's other clauses 5.6ms
a re-check run is described as one · 2 tests
✓
'Re-check all 25 anyway' on the 09-21 list: 24 of the 25 already had a result, and the reply says so 1.0ms
✓
(neg) the default run still says "that had no result", and carries no rechecked count 0.8ms
another clause is not "already had a result" · 1 test
✓
contacted addresses excluded by `contacted: no` are neither "skipped" nor in the re-check offer 2.1ms
verifyHaltContinuation · 4 tests
✓
keeps the limit and every filter key, sized by what the run has not bought 0.4ms
✓
billed, not saved: a verdict whose write is still landing is not offered again 0.2ms
✓
a timed-out re-check continues by id, with its own filter 0.2ms
✓
(neg) no progress: the request as made, unpriced — nothing was checked 0.2ms
nothing named · 1 test
✓
still gets the picker, with no spend 0.4ms
the chips round-trip through the validator the click goes through · 1 test
✓
every offer shape validates, and list_name folds into filter.in_lists 6.4ms
src/chat/diagnose.vitest.ts
one measurement is a point, not a direction · 3 tests
✓
cannot explain a change from a single measurement 1.8ms
✓
can explain once there are two 0.3ms
✓
a delta is null, never 0, when there is no prior 0.3ms
the forensic contract catches a dishonest diagnosis · 5 tests
✓
passes a well-formed one 1.0ms
✓
rejects a delta the two displayed values do not support 0.3ms
✓
rejects claiming a trend when nothing has moved 0.2ms
✓
rejects a thing listed as never-measured that also carries a score 0.3ms
✓
rejects an out-of-range score 0.4ms
it renders INLINE in the chat body, not as another artifact · 5 tests
✓
returns inline:true so the chat renders it in-body with charts 0.5ms
✓
draws an Apex chart of the scores 0.3ms
✓
orders the chart weakest-first — it shows where the problem is, not a victory lap 0.2ms
✓
shows movement only where a comparison exists 0.1ms
✓
names what was never measured, so partial does not read as complete 0.2ms
the model is pointed at it · 2 tests
✓
V2_SYSTEM says call diagnose before any paid audit on a why question 17.2ms
✓
costs nothing, and the registry says so 0.2ms
a WHY question reaches the diagnostic tool · 3 tests
✓
the visibility intent stands down on a why question, via the shared vocabulary 8.0ms
✓
recognises the phrasings people actually use 0.3ms
✓
leaves a MEASUREMENT ask alone — that one still wants the number 0.2ms
the reading names the runs it was built from · 3 tests
✓
cites every dated point, or the contract fails 0.2ms
✓
passes when each one is cited 0.2ms
✓
renders each source with its own date and age 2.1ms
the token meter is never blank · 1 test
✓
the snapshot answer carries the running total like every other exit 3.5ms
every dispatched tool is actually routable · 3 tests
✓
parsed both lists (the assertion is real, not vacuous) 0.2ms
✓
no case is stranded without a routing entry 0.2ms
✓
diagnose specifically 0.8ms
the evidence covers what the platform actually stores · 3 tests
✓
every dashboard pillar is known to the diagnosis 0.5ms
✓
reads the traffic history the diagnostic rule itself names 0.2ms
✓
records WHY the overlapping snapshot types are excluded 0.2ms
the copy says each thing once, and reads rates not counts · 3 tests
✓
does not repeat the staleness number the renderer already prints 0.2ms
✓
diagnoses the reply RATE, not just a zero 0.2ms
✓
separates the open-rate cause from the reply-rate cause 0.2ms
diagnose — a named absence carries the way out of it (GS-006) · 4 tests
✓
every gap label the evidence module can emit has an action 0.7ms
✓
the action is what to ASK FOR, never a tool name (GS-005) 0.3ms
✓
an unknown label returns null rather than an invented next step 0.1ms
✓
the report renders the action beside the gap, and still renders one without 10.9ms
src/chat/tool-surface.vitest.ts
the shortlist question: two optional questions, absent by default · 4 tests
✓
with no options the request is byte-identical to its pre-change snapshot 5.5ms
✓
leads_work is the calibrated wording, verbatim, and only when vetoLeads is set 0.9ms
✓
email_only is the calibrated wording, verbatim, and only when emailOnly is set 0.6ms
✓
the flag keys and thresholds are the ones the rollout and the calibration name 0.3ms
A11 — leadsVetoEligible: a verify/enrich stem and nothing else of leads · 3 tests
✓
an adjective-only mention is eligible 0.9ms
✓
(neg) targeting or link-prospect words keep the preload without asking 0.3ms
✓
the preload itself is unchanged: the split regex still loads leads on every word it did 1.0ms
A11 — decidePreloadVeto · 8 tests
✓
(p 0.05, general) → drop 0.4ms
✓
(p 0.05, family leads) → keep: a leads pick always survives 0.5ms
✓
(pick null — Jev failed or timed out) → keep 0.3ms
✓
(preloadWanted undefined, or an answer that is not a number) → keep 0.2ms
✓
(flag off) → ask false 0.2ms
✓
(not eligible) → ask false 0.2ms
✓
(leads not preloaded) → ask false 0.2ms
A11 — wiring order in runChatV2 · 2 tests
✓
the veto runs after the Jev call and before a shortlist pick adds its family 0.6ms
✓
asks only when the flag is on, the message is eligible and leads was preloaded; a drop is recorded 0.6ms
A7 — the email group and its surface · 4 tests
✓
CORE_EMAIL_GROUP is CORE minus CORE_MIN, and never a loadable family 1.4ms
✓
coreMin + coreGroup resolves to exactly CORE_MIN + the group + search_tools 1.0ms
✓
with 'core' loaded it is the full CORE — the way back is unchanged 0.8ms
✓
the email surface is <= 6,000 schema tokens (same measure as the shortlisted families) 0.3ms
A7 — decideSurface · 7 tests
✓
(general, 0.95, flag) → core_email with the email group 0.2ms
✓
(general, 0.88) → general 0.2ms
✓
(general, 0.95, no flag) → general 0.2ms
✓
(campaigns 0.96, emailOnly 0.99) → shortlist, no coreGroup: a specialist pick ignores email_only 0.2ms
✓
(general, NaN) → general 0.1ms
✓
the moved ternary is unchanged: a specialist family below the confidence floor is low_confidence 0.2ms
A7 — wiring in runChatV2 · 2 tests
✓
every resolveTurnTools(expandedFamilies …) call carries coreGroup 0.9ms
✓
the email flag is asked on the shortlist call and a core_email decision sets coreMin + coreGroup 0.8ms
surface logging in runChatV2 (token-waste audit §6 data gap 3) · 2 tests
✓
records the preload, marks onboarding/machine turns none, labels the decision, and records search_tools loads 1.7ms
✓
startTokenTracking clears every new per-request field — reqCtx is a module global 0.9ms
the rollout matches the calibration (wrangler.toml) · 3 tests
✓
contact_target is listed; tool_shortlist_email is NOT (3 of 6 email-only asks reached 0.9) 0.2ms
✓
preload_veto IS listed, on the owner's sign-off of 2026-09-25 — its one miss (0.36-0.41) keeps the preload 0.3ms
✓
the saved-contact-set arm stays at 0 until the retainly proof 0.1ms
src/ui/panel-structure.vitest.ts
Outbound workspace panel · 4 tests
✓
sidebar opens the hub, not straight into Contacts 2.6ms
✓
only pushes past the hub when a destination is named 0.6ms
✓
#leadView does not carry its own slide transform inside a screen 0.4ms
✓
the lead card is a screen on the stack, not a bespoke .open toggle 0.7ms
Keywords / AI Prompts panel · 4 tests
✓
#kwSelectionBar comes after #keywordsPanelList so sticky-bottom works 0.6ms
✓
#aipSelectionBar comes after #aiPromptsList so sticky-bottom works 0.3ms
✓
filter pills have space before the block beneath them 0.4ms
✓
the bulk bar is a single aligned row 0.4ms
Keywords panel — Track B tiers · 3 tests
✓
uses the shared wide frame, not a bespoke width 1.2ms
✓
Vol and CPC are separately targetable so one tier can drop without the other 0.6ms
✓
drops only P2/P3 columns at the narrow breakpoint 0.6ms
Keywords panel — screen containment · 3 tests
✓
the panel is on the v4 screen stack, with no tabs left 0.5ms
✓
each screen contains its own table, summary and bulk bar 0.4ms
✓
both bulk toolbars offer CSV export 0.2ms
Track B wide frame · 1 test
✓
is a class, not an ID selector 0.3ms
wireframe empty states · 5 tests
✓
the wireframe primitive exists and is inert — no animation on its ghosts 0.4ms
✓
ghost scaffolding is hidden from assistive tech, the caption is not 0.5ms
✓
every dashboard section that can be empty ships a hint and a next step 1.2ms
✓
an empty section renders the wireframe INSTEAD of a row of em-dashes 0.6ms
✓
the wireframe CTA is wired to a handler, not left inert 0.5ms
AI visibility surface · 7 tests
✓
an errored engine is carried as a distinct status, never as a zero 0.7ms
✓
the trend plots real elapsed time and never interpolates 0.6ms
✓
the freshness bar states the shape of the measurement, not just its age 0.5ms
✓
you are always in the competitor table, even at zero 2.4ms
✓
every count in the matrix carries its denominator 0.3ms
✓
the page roll-up leads with the weakest page 0.6ms
✓
detail renders around the AEO section, not stacked before it 0.4ms
prompt library on the panel system · 8 tests
✓
uses the Track B panel shell, and the legacy one is gone from the markup 0.8ms
✓
the legacy shell CSS was deleted, not merely orphaned 1.0ms
✓
is registered as a panel, so the system owns Esc / click-outside / exclusion 0.4ms
✓
opening closes every other panel and records focus for return 0.3ms
✓
search states its denominator while filtering 0.2ms
✓
searching opens matching sections instead of hiding matches behind a closed one 0.3ms
✓
typing survives the re-render — focus and caret are restored 0.3ms
✓
Escape clears the filter before it closes the panel 0.3ms
src/seo/website-health-signals.vitest.ts
external source links · 3 tests
✓
counts pages that link off-origin, and can therefore be non-zero 42.6ms
✓
separates a nofollowed citation from a followed one 4.5ms
✓
still reports honestly when a site genuinely links nowhere 3.8ms
authorship · 2 tests
✓
sees an author declared only in JSON-LD 2.1ms
✓
counts a page with neither a byline nor author schema 1.8ms
internal links that were never fetched · 1 test
✓
does not call an unfetched link broken, and does not charge for it 3.5ms
orphan candidates · 2 tests
✓
does not flag a noindex page as an orphan 2.8ms
✓
still flags a genuinely unlinked indexable page 3.2ms
duplicate content scoring · 3 tests
✓
reports the share of pages involved, not just a quadratic pair count 5.5ms
✓
scales with the SHARE of the site involved, instead of saturating on pair count 32.1ms
✓
a site with no overlap scores full marks 2.7ms
a signal never outruns the population it measured · 4 tests
✓
says what it fetched, not what the site contains, when reporting noindex 4.5ms
✓
distinguishes orphans from pages unreachable from the root 1.8ms
✓
discloses the matcher behind the caveat heuristic 1.4ms
✓
names the slow pages instead of only counting them 1604.5ms
expansion must not corrupt a sitemap-scoped measurement · 2 tests
✓
scores sitemap accuracy over the sitemap, not the whole crawl 2.1ms
✓
names the pages behind a small count instead of only counting them 1.8ms
a file is not a page · 2 tests
✓
does not queue an obvious non-document 3.8ms
✓
does not measure content on a 200 that returned no HTML 1.7ms
the signal cap does not swallow an explanation · 1 test
✓
keeps the orphan/unreachable explanation when architecture is at its busiest 1.6ms
a page that links to itself is not linked-to · 2 tests
✓
counts a self-link as no inbound link at all 1.5ms
✓
still counts a genuine inbound link from another page 1.4ms
response performance states which population it timed · 1 test
✓
times HTML pages and says so 1.3ms
we obey the robots.txt we read · 3 tests
✓
does not fetch a sitemap URL the site disallows, and says it did not 1.6ms
✓
an Allow beats a Disallow of the same or shorter path 1.3ms
✓
an unparseable robots.txt can only ever widen what we crawl, never narrow it 1.7ms
a canonical can live in a header · 1 test
✓
reads rel=canonical from the Link response header 1.8ms
a blocked URL only matters when something links to it · 2 tests
✓
reports a blocked URL that crawled pages link to 2.2ms
✓
stays quiet when a blocked URL has no inbound link 2.1ms
robots patterns, not just prefixes · 3 tests
✓
honours a wildcard in the middle of a pattern 1.7ms
✓
honours a trailing $ anchor 1.5ms
✓
a longer Allow still beats a wildcard Disallow 1.4ms
a robots.txt governs its own origin and nothing else · 3 tests
✓
says nothing about a cross-origin URL that would match if origin were ignored 1.4ms
✓
does not judge a sibling subdomain by the parent origin rules 1.4ms
✓
still blocks a same-origin URL matching the same pattern 2.3ms
src/admin/judge-coverage.vitest.ts
canonicalOperation · 5 tests
✓
folds a retired name into its replacement 1.8ms
✓
keeps a variant visible but canonicalises its base 0.3ms
✓
leaves a live tool name alone 0.2ms
✓
does not inherit the rate-cap alias that merges two LIVE tools 0.3ms
✓
maps only retired names, and only onto live tools 0.7ms
computeJudgeCoverage · 6 tests
✓
names what was NEVER judged — absent is not healthy 1.0ms
✓
flags a score built on too few samples 1.2ms
✓
counts a retired name toward its replacement, not as its own tool 0.5ms
✓
counts a variant toward its parent tool for coverage 0.6ms
✓
surfaces an operation that is not a registered tool at all 0.3ms
✓
never counts judge_failure rows as coverage 0.5ms
computeQualityTrend · 3 tests
✓
reports sample counts so n=1 cannot pass for a rating 0.4ms
✓
draws one series for a capability, not one per historical name 7.5ms
✓
still averages within a day 0.2ms
judge coverage — the 2026-08-19 wiring defects · 3 tests
✓
does not count operational telemetry as a judged capability 0.4ms
✓
credits an async job to its TOOL, not to a capability called async_job 0.3ms
✓
still flags a genuinely unknown name — the alarm must not be disabled, only de-noised 0.2ms
chat as a shortcut capability · 2 tests
✓
does not report a no-tool conversation turn as an unrecognised id 0.2ms
✓
does not report the shortcut-owned Google composite as an unrecognised id 0.4ms
quality rows that are counters, not judgements · 3 tests
✓
does not report a report-render counter as a judged capability 0.2ms
✓
excludes a counter nobody has declared yet, because it carries no score 0.2ms
✓
still flags a scored row under an unknown name 0.1ms
invoked-but-unjudged vs never-invoked · 5 tests
✓
separates a tool that ran and was never judged from one nobody ran 0.4ms
✓
reports the run count, so the bucket can be ranked by how much went ungraded 0.3ms
✓
refuses to split when there are no run counts, and says so 0.2ms
✓
treats an omitted run list the same as an empty one — never as "nothing ran" 0.2ms
✓
credits a variant run row to its parent tool 0.2ms
runs the platform refused · 3 tests
✓
does not count a rejected or capped run as something the judge could have graded 0.2ms
✓
counts the executions and ignores the refusals, in the same window 0.2ms
✓
treats a run with no recorded status as an execution 0.2ms
a mismatched window manufactures coverage gaps · 3 tests
✓
does not call a tool unjudged when its judged row is in the same window as its runs 0.2ms
✓
reports it as unjudged when the judged rows are missing from the set it was given 0.2ms
✓
carries the truncation flag through so a paging cap cannot read as a coverage gap 0.2ms
no code claims a sampler that does not exist · 1 test
✓
has scrubbed the 1-in-5 claim from this module 0.8ms
src/chat/canonical-question-routing.vitest.ts
every canonical question routes to at most ONE predicate · 31 tests
✓
the fixture still holds all 28 AI questions 2.2ms
✓
the SEO 30 are still readable from the pillar page 0.7ms
✓
Q01 is not ambiguous 13.5ms
✓
Q02 is not ambiguous 5.8ms
✓
Q03 is not ambiguous 1.2ms
✓
Q04 is not ambiguous 1.0ms
✓
Q05 is not ambiguous 0.5ms
✓
Q06 is not ambiguous 0.8ms
✓
Q07 is not ambiguous 0.8ms
✓
Q08 is not ambiguous 0.6ms
✓
Q09 is not ambiguous 2.3ms
✓
Q10 is not ambiguous 0.4ms
✓
Q11 is not ambiguous 0.6ms
✓
Q12 is not ambiguous 0.7ms
✓
Q13 is not ambiguous 0.5ms
✓
Q14 is not ambiguous 0.7ms
✓
Q15 is not ambiguous 1.3ms
✓
Q16 is not ambiguous 0.5ms
✓
Q17 is not ambiguous 0.2ms
✓
Q18 is not ambiguous 5.5ms
✓
Q19 is not ambiguous 0.6ms
✓
Q20 is not ambiguous 0.7ms
✓
Q21 is not ambiguous 0.5ms
✓
Q22 is not ambiguous 0.4ms
✓
Q23 is not ambiguous 0.2ms
✓
Q24 is not ambiguous 1.1ms
✓
Q25 is not ambiguous 0.7ms
✓
Q26 is not ambiguous 0.5ms
✓
Q27 is not ambiguous 0.2ms
✓
Q28 is not ambiguous 0.6ms
✓
no SEO question is ambiguous either 9.8ms
the two that were live, pinned by name · 3 tests
✓
Q08 goes to the hallucination playbook, not the core-update recovery brief 0.3ms
✓
Q18 goes to the crawler-policy playbook, not the AI-content-policy brief 0.4ms
✓
and the carve-outs did not steal the incumbents 0.7ms
src/email/send-security.vitest.ts
SMTP: TLS before any AUTH · 7 tests
✓
#1 port 587: opened as starttls, upgraded, and every credential line went out on the TLS socket 49.6ms
✓
#2 port 2525 with STARTTLS advertised: same as 587 8.6ms
✓
#3a refuses with the STARTTLS reason (the first lock) 1.7ms
✓
#3b no AUTH line and no credential is written anywhere 1.5ms
✓
#4 port 465: implicit TLS, no STARTTLS command, AUTH allowed 2.3ms
✓
#5 a stored port 25 (or garbage) is refused without connecting 0.6ms
✓
#6 PLAIN rejected (535) on 587: the AUTH LOGIN fallback lines are on the TLS socket only 1.6ms
SMTP: command framing · 4 tests
✓
#7 a CR/LF-bearing from_email never opens a socket 0.4ms
✓
#8 a CR/LF-bearing recipient never opens a socket 0.7ms
✓
#9 exactly one MAIL FROM and one RCPT TO — on a valid run, and never more on an injection attempt 1.5ms
✓
#10 a bare CR before a dot cannot end DATA early (465) 1.5ms
SMTP: the From header · 2 tests
✓
#11 a display name with specials is quoted — one address, not two 1.4ms
✓
#12 a non-ASCII display name is an RFC 2047 encoded-word 1.1ms
the From value on the Resend and Gmail branches · 3 tests
✓
#28 Resend: a display name that could read as a second address is quoted — one address 0.8ms
✓
#28b Resend: a name with only "@" or "." (no address-changing character) keeps the unquoted wire format 0.4ms
✓
#29 Gmail: the raw From header is quoted for specials and an encoded-word for non-ASCII 1.4ms
#13 host-table sweep: a credential only ever goes to its own provider · 13 tests
✓
mailjet → api.mailjet.com, exactly one request, and the credential is in it 0.6ms
✓
resend → api.resend.com, exactly one request, and the credential is in it 0.4ms
✓
sendgrid → api.sendgrid.com, exactly one request, and the credential is in it 0.4ms
✓
mailtrap → send.api.mailtrap.io, exactly one request, and the credential is in it 0.4ms
✓
gmail → gmail.googleapis.com, exactly one request, and the credential is in it 0.4ms
✓
"mailgun" reaches neither fetch nor connect 0.4ms
✓
"Mailgun" reaches neither fetch nor connect 0.2ms
✓
"smtp " reaches neither fetch nor connect 0.2ms
✓
"cloudflare" reaches neither fetch nor connect 0.2ms
✓
"postmark" reaches neither fetch nor connect 0.2ms
✓
"ses" reaches neither fetch nor connect 0.2ms
✓
"" reaches neither fetch nor connect 0.2ms
✓
"GMAIL" reaches neither fetch nor connect 0.2ms
#14 formatDisplayFrom · 5 tests
✓
a plain name is unquoted 0.2ms
✓
specials are quoted, with backslash and double quote escaped 0.2ms
✓
an empty name gives the bare address 0.2ms
✓
CR/LF in a name is flattened; non-ASCII goes raw to an API that encodes it 0.2ms
✓
'quoted' changes the string only for a character that can move the parsed address; 'mime' quotes every special 0.7ms
src/guard-proofs/cited-coverage.vitest.ts
G8(c) — every cited guard has an executing mutation proof · 34 tests
✓
the enumeration is not empty (32 cited guards on 2026-10-30; a parse that finds none is blind, not green) 1.6ms
✓
check-standing-instructions checks at least every guard counted here (one definition, not two) 47.6ms
✓
check-audit-freeze 0.9ms
✓
check-block-invariant 0.4ms
✓
check-confirm-surface 0.3ms
✓
check-connector-degrade 0.3ms
✓
check-doc-freshness 0.6ms
✓
check-draft-sendable 0.4ms
✓
check-graphql-schema 0.5ms
✓
check-graphql-seams 0.2ms
✓
check-guard-integrity 0.2ms
✓
check-keyword-attribution 0.2ms
✓
check-live-path-render 0.2ms
✓
check-model-pricing 0.2ms
✓
check-plan-coverage 0.2ms
✓
check-preflight-coverage 0.2ms
✓
check-preflight-gates 0.2ms
✓
check-presenter-coverage 0.2ms
✓
check-product-invariants 0.2ms
✓
check-prompt-attribution 0.2ms
✓
check-provider-registry 0.2ms
✓
check-report-families 0.2ms
✓
check-schema-producers 0.2ms
✓
check-schema-tools 0.2ms
✓
check-standing-instructions 0.2ms
✓
check-tag-provenance 0.2ms
✓
check-tenant-scoping 0.2ms
✓
check-test-spend-ceiling 0.2ms
✓
check-tool-registry 1.4ms
✓
check-truncation-gate 0.2ms
✓
check-version-forward 0.3ms
src/seo/crawl-vitals.vitest.ts
Q22: the never-cut list protects the site from this brief · 13 tests
✓
never recommends cutting /assets, whatever the numbers say 2.0ms
✓
never recommends cutting /static, whatever the numbers say 0.4ms
✓
never recommends cutting /_next, whatever the numbers say 0.2ms
✓
never recommends cutting /js, whatever the numbers say 0.2ms
✓
never recommends cutting /css, whatever the numbers say 0.3ms
✓
never recommends cutting /images, whatever the numbers say 0.2ms
✓
never recommends cutting /api, whatever the numbers say 0.2ms
✓
never recommends cutting /checkout, whatever the numbers say 0.2ms
✓
never recommends cutting /cart, whatever the numbers say 0.5ms
✓
never recommends cutting /pricing, whatever the numbers say 0.2ms
✓
still flags an ordinary pattern with the same numbers 0.2ms
✓
carries both safety clauses in the decision whenever a cut is proposed 0.9ms
✓
refuses to cut anything when no pattern is being declined 0.3ms
Q22: it never claims to have seen the crawler · 5 tests
✓
keeps the log-based hypotheses untested 0.3ms
✓
says outright that this is read from what the site advertises, not what was fetched 0.4ms
✓
requires a real population before calling something a pattern 0.3ms
✓
flags a pattern only when the index declines most of it 0.2ms
✓
surfaces a blocked-and-indexed contradiction before recommending more rules 0.2ms
pathPrefix and pattern folding — the derivation, tested directly · 2 tests
✓
groups on the first path segment 0.3ms
✓
folds URLs into patterns with their sitemap and index state 1.3ms
Q23: no field data is an ANSWER, not a missing measurement · 4 tests
✓
says do not spend a sprint, in as many words 2.2ms
✓
applies the rule rather than refusing to answer 0.3ms
✓
names the traffic as the finding, not the speed 0.3ms
✓
the ask says there is nothing to approve, and why that is useful 0.2ms
Q23: the crawler fetch time is never allowed to stand in for field data · 3 tests
✓
states what the lab number is and is not 0.4ms
✓
keeps lab-versus-field untested, because there is nothing to disagree with 0.4ms
✓
never promotes the lab number to a verdict, and never RULES OUT a field failure it could not see 0.4ms
Q23: when field data exists, the earning pages decide the sprint · 4 tests
✓
confirms the overlap between failing and earning 0.3ms
✓
takes one template and names the element 0.3ms
✓
says re-measure after weeks of traffic, not the next morning 0.2ms
✓
never claims to know which element is responsible 0.2ms
Q22 and Q23: no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps field and table names out of the prose 0.7ms
Q23: nothing checked is not nothing failing · 2 tests
✓
does not claim a clean result when no page was checked 0.3ms
✓
still says nothing to schedule when pages WERE checked and passed 0.2ms
src/admin/rca-evidence-quality.vitest.ts
the minority population cannot be crowded out · 7 tests
✓
reserves the organic floor when internal traffic dominates 2.9ms
✓
caps organic at the floor when BOTH populations are plentiful 0.6ms
✓
gives organic the whole budget when internal traffic is light 0.3ms
✓
never exceeds the cap, on any mix 1.5ms
✓
reports both totals so truncation can be read per population 1.3ms
✓
degrades to a plain cap when the floor is absurd 0.7ms
✓
an empty window produces an empty sample, not a throw 0.5ms
full-population counts, so absence means something · 3 tests
✓
counts every row, not just the sampled ones 0.6ms
✓
splits operations by traffic type 0.7ms
✓
an operation with zero organic rows is ABSENT from the organic map 0.3ms
the build join is arithmetic, not prose · 4 tests
✓
picks the release that was live at the timestamp 0.3ms
✓
a timestamp exactly at a deploy belongs to that deploy 0.1ms
✓
returns null — never the oldest build — for undatable observations 0.2ms
✓
returns null for a missing timestamp and survives an empty timeline 0.2ms
the writer records what it already knew · 4 tests
✓
BOTH judge paths write all five fields — ensemble and single 1.6ms
✓
reads reqCtx.toolCalls SYNCHRONOUSLY, before the detached judge 0.3ms
✓
counts top-level tools only, on the same branch that mints the run id 0.7ms
✓
the counter is zeroed per unit of work at BOTH boundaries 0.6ms
the reader treats a missing field as unknown, not false · 4 tests
✓
absent tool-outcome keys read as null 0.3ms
✓
rows are tagged BEFORE they are sampled 0.3ms
✓
judge health is reported per traffic population, not only in aggregate 0.2ms
✓
full-population counts ship alongside the sample 0.2ms
a fix verdict needs an exercise denominator · 8 tests
✓
counts only runs at or after the fix date 0.4ms
✓
matches the CANONICAL operation, not the raw ledger variant 0.2ms
✓
separates organic runs from internal ones 0.2ms
✓
reports zero for a path nothing exercised 0.2ms
✓
returns one row per fix, in order, even with no traffic at all 0.2ms
✓
the prompt states the count inline and forbids a bare "unproven" 4.1ms
✓
the sweep agenda is asked for by name 5.9ms
✓
still renders without coverage, so the old call shape cannot crash a run 2.6ms
an infrastructure change is not a sweep item · 3 tests
✓
an entry with only pseudo-operations is not applicable 0.2ms
✓
a marker mixed with a REAL operation stays applicable and counts the real one 0.2ms
✓
the prompt says n/a rather than 0 for those entries 2.5ms
src/chat/present-wave5.vitest.ts
web_search — a ranked list is records · 4 tests
✓
renders every result as a row 2.4ms
✓
position is a NUMBER, so the table sorts by rank rather than by string 0.5ms
✓
the model no longer receives the rows it used to re-type 0.8ms
✓
a zero-result search presents nothing — that case is an ANSWER, and prose says it 0.3ms
diagnose — the measurements behind the diagnosis · 4 tests
✓
shows previous NEXT TO the change — a drop of 12 differs from 90 and from 20 0.4ms
✓
a first measurement has a null change, never a zero 0.2ms
✓
gaps stay with the model — an absence stripped of its remedy is worse than the sentence 0.4ms
✓
nothing measured yet presents nothing rather than an empty frame 0.2ms
enrich_contacts — all of the research, not the first three · 3 tests
✓
every enriched contact reaches the screen 0.9ms
✓
falls back to the company one-liner when there is no per-person signal 0.3ms
✓
five columns: the note is "Why they may fit", and Source says what it rests on 0.4ms
send_emails — the recipients that did NOT get it · 3 tests
✓
one row per failure, so a reason can be traced to an address 0.3ms
✓
a clean send presents nothing — a table of addresses that worked tells nobody anything 0.2ms
✓
the confirm gate is left alone — it has its own preview table 0.2ms
seo_serp_spider — one table over every problem URL · 3 tests
✓
classifies each problem and drops the healthy pages 0.3ms
✓
says whether the verdict was CONFIRMED — unverified is not the same claim 0.1ms
✓
a fully healthy site presents nothing 0.1ms
seo_monitor — what moved, flattened out of the prose · 3 tests
✓
reads every section, including the aeo_visibility the formatter never had a branch for 0.4ms
✓
a metric with no value at all is omitted rather than shown as a blank row 0.2ms
✓
no history presents nothing 0.2ms
seo_keyword_metrics read a key that is never returned · 3 tests
✓
presents who currently ranks — the half of a difficulty score that means something 0.3ms
✓
the formatter no longer reads related_keywords 17.2ms
✓
and now shows the score, intent and batch that were computed and dropped 0.2ms
seo_aeo_check shared a case body with two tools that return something else · 3 tests
✓
no longer prints undefined over a result that is entirely present 0.3ms
✓
presents the nine checks, with the fix on the row that failed 0.3ms
✓
the RAG-shaped siblings still take the RAG branch 0.2ms
the invariant every presenter inherits · 3 tests
✓
no presenter can build a rowless block 0.9ms
✓
rows are capped at BLOCK_ROW_CAP, not at the tool's own slice 0.4ms
✓
an errored result is never presented 0.1ms
a presenter that takes the rows away says so, and says what that forbids · 4 tests
✓
the model does not receive the rows it must not transcribe 0.4ms
✓
and is told explicitly that it cannot know what any row says 0.2ms
✓
the counts and column names ARE given, so the intro can be true 0.2ms
✓
a report tool keeps the ORIGINAL note — it still has to read the rows 0.5ms
src/email/smtp-target-gate.vitest.ts
a host that is private by its own name or address is refused before connect · 14 tests
✓
10.0.0.5: no socket, no password, a plain-words reason, a Sentry line 6.4ms
✓
127.0.0.1: no socket, no password, a plain-words reason, a Sentry line 1.2ms
✓
169.254.169.254: no socket, no password, a plain-words reason, a Sentry line 0.8ms
✓
100.100.100.200: no socket, no password, a plain-words reason, a Sentry line 0.7ms
✓
192.168.1.10: no socket, no password, a plain-words reason, a Sentry line 0.7ms
✓
172.16.0.1: no socket, no password, a plain-words reason, a Sentry line 0.6ms
✓
0.0.0.0: no socket, no password, a plain-words reason, a Sentry line 0.5ms
✓
localhost: no socket, no password, a plain-words reason, a Sentry line 0.7ms
✓
mail.local: no socket, no password, a plain-words reason, a Sentry line 1.2ms
✓
metadata.google.internal: no socket, no password, a plain-words reason, a Sentry line 0.7ms
✓
[::1]: no socket, no password, a plain-words reason, a Sentry line 1.3ms
✓
[fd00::25]: no socket, no password, a plain-words reason, a Sentry line 0.6ms
✓
[::ffff:7f00:1]: no socket, no password, a plain-words reason, a Sentry line 0.6ms
✓
2130706433: no socket, no password, a plain-words reason, a Sentry line 0.5ms
a PUBLIC-LOOKING name that RESOLVES inward is refused before connect · 5 tests
✓
a name whose A record is the metadata address 31.3ms
✓
a name with one public and one private address (connect could pick either) 1.1ms
✓
a name resolving to loopback (127.0.0.53) 0.9ms
✓
a name resolving to RFC1918 (10.1.2.3) 0.6ms
✓
a name resolving to CGNAT metadata (100.100.100.200) 1.5ms
fail closed: no answer is never "connect and see" · 3 tests
✓
NXDOMAIN → refused, nothing connects 0.8ms
✓
a name with no A or AAAA record → refused 0.5ms
✓
the lookup itself fails (resolver down, unreadable answer, SERVFAIL) → refused, retryable copy 1.3ms
the port is an SMTP submission port, at the socket as well as at save · 6 tests
✓
the allow-list is exactly 465/587/2525 (25 is refused: Workers cannot open it) 0.6ms
✓
a stored port 22 reaches neither DNS nor the socket 0.4ms
✓
a stored port 6379 reaches neither DNS nor the socket 0.4ms
✓
a stored port 8025 reaches neither DNS nor the socket 0.3ms
✓
a stored port 5432 reaches neither DNS nor the socket 0.3ms
✓
the socket gate holds the list on its own (a caller that skipped parseSmtpPort is still refused) 0.3ms
controls: a public mail server still works, and the query is ours · 5 tests
✓
a name resolving only to public addresses connects on 587 15.8ms
✓
a name resolving only to public addresses connects on 465 1.7ms
✓
a name resolving only to public addresses connects on 2525 1.4ms
✓
the lookup goes to the constant resolver host, with the name encoded and nothing else 2.1ms
✓
the person reads plain words: no code prefix, no vendor, no host 7.0ms
src/tools/contact-filter.vitest.ts
the operator is a field, not a parsed token · 4 tests
✓
compiles the owner's minus — "the ones not already enriched" 3.1ms
✓
compiles its INVERSE — "including the ones already enriched" — to no clause at all 0.5ms
✓
distinguishes "any" from omitted at the TOOL level, which is where it matters 1.4ms
✓
compiles union, intersection and subtraction without a new pattern for each 0.4ms
verification is four-state because yes/no would have to guess · 3 tests
✓
separates "never checked" from "checked and bad" — the pair that decides spend 0.6ms
✓
"valid" means WE confirmed it — a provider claim never qualifies 0.3ms
✓
offers a deliberate "any" so a re-verify is expressible 1.0ms
contacted reads lead_status through the one helper · 2 tests
✓
treats NULL and "new" as not contacted, matching every other read in the codebase 0.4ms
✓
expresses "already contacted" as the exact complement, so the two cannot drift 0.6ms
a filter the dispatch cannot honour is a rejection, never a silent drop · 3 tests
✓
throws when a list field was set and no ids were resolved for it 0.5ms
✓
names the offending field so the caller can say which part it could not honour 0.3ms
✓
treats an EMPTY resolution as a real answer, not a missing one 0.2ms
the filter discloses itself · 2 tests
✓
produces the sentence fragment the formatter renders 0.3ms
✓
says nothing when nothing was asked 0.4ms
the validator enforces the filter, it does not merely carry it · 12 tests
✓
enrich_contacts declares the shared filter 0.2ms
✓
enrich_contacts accepts every legal predicate 0.2ms
✓
enrich_contacts REJECTS a value outside the vocabulary rather than dropping it 0.6ms
✓
enrich_contacts rejects an invented predicate — the ceiling is the point 0.5ms
✓
enrich_contacts rejects an operator STRING — no expression language grows here 0.3ms
✓
list_contacts declares the shared filter 0.1ms
✓
list_contacts accepts every legal predicate 0.3ms
✓
list_contacts REJECTS a value outside the vocabulary rather than dropping it 0.3ms
✓
list_contacts rejects an invented predicate — the ceiling is the point 0.3ms
✓
list_contacts rejects an operator STRING — no expression language grows here 0.2ms
✓
a bad predicate is never DROPPED to keep the turn alive 0.3ms
✓
keeps list names inside the filter within the same bounds as the legacy field 0.3ms
model-facing copy · 3 tests
✓
tells the model the inverse is a thing it can ask for 0.5ms
✓
states the redo rule so a "refresh everything" ask cannot be silently narrowed 0.2ms
✓
names no vendor and no USD price 0.4ms
verify_contacts does not re-check what it already checked · 4 tests
✓
defaults an unspecified filter to the addresses nothing has actually probed 0.2ms
✓
leaves an explicit choice alone, including the re-check-everything one 0.2ms
✓
touches nothing else on the filter, and no other tool 0.3ms
✓
the default it sets is a state the compiler actually honours 0.4ms
src/seo/answer-completeness.vitest.ts
readAnswerCompleteness — the denominator (AEO-001) · 5 tests
✓
counts answers RECEIVED, not executions sent 2.6ms
✓
separates an engine that answered nothing from one that answered some (AEO-002) 1.4ms
✓
works on artifacts stored long before the field existed 0.5ms
✓
a complete run needs no caveat, and printing one anyway trains readers to skip them 0.2ms
✓
names the silent engines rather than counting them 0.7ms
costPerAnswer (AEO-012) · 2 tests
✓
divides by answers received, not by queries sent 0.6ms
✓
is null rather than Infinity when nothing came back 0.4ms
engine labels — one definition (trap 4) · 2 tests
✓
knows the surfaces that only the client copy used to know 0.2ms
✓
an unknown engine reads like a name, never like a column 0.5ms
the artifact states its denominator (R-C acceptance) · 5 tests
✓
the SPEC acceptance case: "0 of 27 answers", never a bare 0% over 45 0.4ms
✓
names both silent engines instead of dropping them off the chart 0.3ms
✓
a count and the list beside it describe the SAME population 0.2ms
✓
reports cost per answer received 0.2ms
✓
a fully-answered run carries no coverage banner 0.6ms
sample adequacy — a rate over n=1 (AEO-001, magnitude) · 10 tests
✓
THE REGRESSION: the completeness layer reports a 1-of-1 run as perfectly complete 0.2ms
✓
reads the shape off the matrix, counting answers received 0.2ms
✓
names the single engine rather than counting to one 0.1ms
✓
says a single answer can only score 0% or 100%, and what to do about it 0.2ms
✓
fires on the ENGINE axis alone — 8 answers, all from one engine 0.3ms
✓
fires on the ANSWERS axis alone — 3 answers across 3 engines 0.2ms
✓
stays silent on a sample that carries its own weight 0.3ms
✓
counts answers RECEIVED, so silent engines cannot pad the sample past the threshold 0.3ms
✓
an unknown shape makes no thin-sample claim (GS-004 — never looked is not a finding) 0.2ms
✓
makeSampleShape carries the trend points, which have no matrix to count 0.2ms
a stored sov row states the request, not the run · 7 tests
✓
THE REGRESSION: never claims prompts that were never sent 0.3ms
✓
THE OTHER DIRECTION: a defaulted engine list must not suppress the single-engine caveat 0.3ms
✓
an unknown engine count neither raises the caveat nor clears it 0.3ms
✓
an empty engine_names array is an absence, not zero engines 0.2ms
✓
THE SELF-CONTRADICTION: no step arithmetic when the rate is not over these answers 0.4ms
✓
n=1 drops the 0%-or-100% claim when the number is a blend 0.2ms
✓
the matrix path is unaffected — it counts the run and keeps the full basis 0.2ms
the artifact discloses the sample (AEO-001 on the report surface) · 2 tests
✓
states the basis beside the headline, not two sections below it 0.1ms
✓
warns that the number cannot be acted on 0.2ms
client/set-site-form.vitest.ts
the rendered field · 2 tests
✓
is a text field and a submit button — not a chat command 35.3ms
normalizeSiteInput · 10 tests
✓
acme.com → https://acme.com 2.5ms
✓
www.acme.co.uk/pricing → https://www.acme.co.uk/pricing 2.6ms
✓
https://acme.com → https://acme.com 1.8ms
✓
http://shop.acme.io/ → http://shop.acme.io/ 1.6ms
submitting · 11 tests
✓
reports outcome invalid once 7.9ms
✓
reports outcome scanned once 4.1ms
✓
reports outcome saved_unread once 1.8ms
✓
reports outcome refused once 2.0ms
✓
reports outcome network_error once 2.3ms
✓
a bad entry is answered in place and nothing is sent 2.4ms
✓
saved and scanned: posts the normalised URL, reports it, and refreshes the dashboard 2.3ms
✓
saved but the page could not be read: still saved, says so, still refreshes 1.7ms
✓
a refusal is shown, nothing refreshes, and the button comes back 2.1ms
✓
a network failure is shown, never swallowed 1.7ms
✓
wiring listens for the real submit event, once per form 55.2ms
wiring in client/main.ts · 2 tests
✓
a set_site section gets the field and no data-dash-empty-cmd button 1.3ms
✓
the field is wired to /api/product/scan and reloads the dashboard 1.1ms
mountSiteAsk — the website field at the top of a chat reply · 7 tests
✓
renders ABOVE the reply text — the question leads 4.3ms
✓
nothing to ask → nothing rendered 1.6ms
✓
escapes the question 2.8ms
✓
scanned → the original question is re-sent once, and the form locks 54.8ms
✓
saved but unread → no re-send (no brief yet, the answer would be the same generic one) 54.3ms
✓
no resend on the payload (the scan WAS the ask) → saving re-sends nothing 54.7ms
✓
client/main.ts mounts it on the agent reply, wired to the scan route and the chat sender 3.3ms
src/admin/ai-discovery-reddit.vitest.ts
thread identity · 2 tests
✓
takes the id from any reddit thread URL and refuses everything else 2.3ms
✓
normalises the permalink to www.reddit.com without query or hash 0.4ms
reading a thread · 5 tests
✓
keeps the flags that decide whether a reply is possible 1.2ms
✓
flattens nested replies, drops deleted bodies, highest score first 0.5ms
✓
indexes every comment id, marking deleted ones 0.4ms
✓
a deleted post reads as removed; no post at all is null 0.3ms
✓
subreddit rules are kept as text 0.3ms
gates — before any spend on rules or a draft · 4 tests
✓
an open community thread passes 0.4ms
✓
archived, locked, removed and profile posts are refused 0.7ms
✓
a thread we already replied in is refused 0.3ms
✓
a reply in the same community within 24 hours warns but does not block 0.4ms
reading the plan · 3 tests
✓
survives literal line breaks inside the draft — 2 of 3 text drafts broke on this live 1.2ms
✓
an empty draft means no draft; unknown rule values read as unclear; garbage is null 0.3ms
✓
the structured-output schema meets the API rules: every object closed and fully required 0.4ms
policy the code enforces · 4 tests
✓
names nqzai without saying so → the disclosure line is added, and says it was 0.8ms
✓
an existing disclosure is left alone 0.3ms
✓
no draft where self-promotion is banned and the draft names nqzai 0.2ms
✓
no draft where AI-written comments are banned, or the thread is off-topic 0.2ms
repeat warning · 2 tests
✓
warns on a near-identical draft for another thread in the last 24 hours 0.4ms
✓
is quiet for the same thread, an old draft, or a different text 0.3ms
checking the posted comment · 2 tests
✓
reads the comment id from both link shapes 0.4ms
✓
up, removed, or not found — and not-found is never reported as removed 0.4ms
the prompt · 1 test
✓
carries the question, the rules, and the hard instructions 0.3ms
brand named in the answer — what a Reddit reply can move · 2 tests
✓
is read on the full answer text, apart from citation 0.6ms
✓
the citation gap lists the engines that named us 0.4ms
pilot records · 2 tests
✓
feed the pace and repeat checks 0.2ms
✓
summarise to the latest comment check 0.3ms
Reddit actions — validation before any spend · 3 tests
✓
refuses a URL that is not a reddit thread 26.7ms
✓
refuses a "posted" link that is not a comment in this thread 1.5ms
✓
a held-out control cannot be marked posted 0.9ms
the draft model when the direct Claude call is refused · 2 tests
✓
reaches the same Claude through the router before any weaker model — production's first draft fell to gpt-5-mini 0.3ms
✓
every router draft model has a list price, so its cost line is not the unknown-model guess 0.2ms
src/admin/visibility-tracker.vitest.ts
cells · 2 tests
✓
a probe result becomes a cell with cited and named kept apart 3.0ms
✓
a thrown probe is failed and an empty search is empty — neither is a "no" 0.5ms
rates · 4 tests
✓
the denominator is answers received (AEO-001): a failure is counted apart, not as a miss 0.6ms
✓
nothing received is a gap (null), never 0% 0.2ms
✓
the trend is the last four runs 0.5ms
✓
weeks start on Monday (UTC) 0.2ms
actions from a run · 5 tests
✓
one round-up that won two questions is ONE outreach, linked to both 1.1ms
✓
a post on someone's own profile is never a reply action (first production run suggested r/u_mohdamir077) 0.4ms
✓
two listings on the same host get titles that say which page 0.9ms
✓
a cited Reddit thread becomes a reply action checked against the Reddit pilot 0.3ms
✓
the searches the engines ran become a "cover the searches" action for the target page — only when it was not cited 0.4ms
merging into stored actions · 2 tests
✓
the same recommendation next week lands on the same record 0.3ms
✓
a dismissed action is never resurrected — it only gains questions 0.4ms
verifiers (pure parts) · 2 tests
✓
page coverage names the missing words, and a stem match counts ("prompts" covers "prompt") 0.7ms
✓
a link to nqz.ai or the brand in the text both count as listed 0.8ms
outcome · 2 tests
✓
compares the linked questions with the untouched ones, four runs either side 1.2ms
✓
is "too early" without three runs on each side, and silent before verification 0.2ms
panel and handler · 4 tests
✓
validates questions, keeps a question id while its text and page are unchanged 2.8ms
✓
the estimate is per question × engine, in tokens too 0.4ms
✓
candidate pages are the public tool and guide pages, not legal pages 0.5ms
✓
refuses without the admin secret, and validates ids before any spend 27.4ms
automatic indexing submissions (nqzai does it) · 3 tests
✓
never submits a page an engine already cites, or one it could not read 0.4ms
✓
submits a never-submitted page, a changed page, and one not submitted for 28 days — and says why 0.2ms
✓
an unchanged page submitted recently is left alone 0.2ms
Copilot share actions · 5 tests
✓
groups low-share queries by the page that should win them, ranked by citations going elsewhere 1.6ms
✓
a Jev "none fits" keeps a query out of an action even when the slug would match 0.5ms
✓
links the action to Bing-sourced panel questions for the same query 0.5ms
✓
the outcome is the next Bing export whose range starts after the verified day — never an overlapping one 0.9ms
✓
a suggested share action follows the newest export; an accepted one keeps its baseline 0.6ms
one table across engines · 2 tests
✓
Copilot is Bing's measured count; the sampled rows report "any nqz.ai page cited" as the shared unit 0.6ms
✓
without a Bing export the Copilot row says so instead of showing zero 0.2ms
panel: Bing-sourced questions · 1 test
✓
keeps a Bing origin, rebuilt field by field, and refuses to call a question "bing" without one 0.8ms
src/chat/stream-guard.vitest.ts
stream-guard — the property that decides whether streaming ships · 21 tests
✓
is byte-identical to scanOutbound across every chunking: canary 69.5ms
✓
is byte-identical to scanOutbound across every chunking: openai key 69.7ms
✓
is byte-identical to scanOutbound across every chunking: jwt 55.4ms
✓
is byte-identical to scanOutbound across every chunking: bearer 63.4ms
✓
is byte-identical to scanOutbound across every chunking: aws key 32.2ms
✓
is byte-identical to scanOutbound across every chunking: google key 35.5ms
✓
is byte-identical to scanOutbound across every chunking: testomat 35.0ms
✓
is byte-identical to scanOutbound across every chunking: pem 40.2ms
✓
is byte-identical to scanOutbound across every chunking: admin secret 44.5ms
✓
is byte-identical to scanOutbound across every chunking: vendor 50.8ms
✓
is byte-identical to scanOutbound across every chunking: vendor 2 51.7ms
✓
is byte-identical to scanOutbound across every chunking: usd 57.2ms
✓
is byte-identical to scanOutbound across every chunking: usd words 40.6ms
✓
is byte-identical to scanOutbound across every chunking: raw error 60.4ms
✓
is byte-identical to scanOutbound across every chunking: internal tool 54.9ms
✓
is byte-identical to scanOutbound across every chunking: bare tool 59.5ms
✓
is byte-identical to scanOutbound across every chunking: prompt internals 63.1ms
✓
is byte-identical to scanOutbound across every chunking: schema assign 44.8ms
✓
is byte-identical to scanOutbound across every chunking: internal directive 86.3ms
✓
never releases the redacted form of a span it has not finished reading 65.6ms
✓
does not cut inside a dotted span that a rule is still matching 69.6ms
stream-guard — retraction, and the direction it fails in · 2 tests
✓
reports retract only when a BLOCK lands after bytes were already shown 11.9ms
✓
emits nothing further once blocked, however much more arrives 0.3ms
stream-guard — word-level cadence · 9 tests
✓
advances a word at a time, not a sentence and not a paragraph 0.5ms
✓
never cuts mid-word 0.8ms
✓
holds everything back until there is more than the character holdback 0.2ms
✓
stalls rather than guessing while an unbounded rule is still arriving 0.2ms
✓
an open INTERNAL directive falls back to sentence granularity 0.2ms
✓
sentenceBoundary still describes the worst case honestly 0.3ms
✓
is a no-op on empty and whitespace input 0.2ms
✓
delivers the whole answer at end() even if nothing ever streamed 0.2ms
✓
passes turn options through to the rail unchanged 4.3ms
src/drip/start-gate.vitest.ts
the cron sends only what a person started · 2 tests
✓
refuses a model-armed enrolment and sends the human-started one 13.8ms
✓
says so, with the chip that starts it — never silence 2.0ms
the reminder names only the tenant's own sequences · 2 tests
✓
an enrolment pointing at another tenant's sequence never shows that sequence in this tenant's feed 1.1ms
✓
a feed whose only held rows point at foreign sequences says nothing 0.5ms
the reminder is said once a day per held set, never hourly · 1 test
✓
a second tick the same day is silent; a newly armed sequence is not 3.9ms
the gate does not rest on one filter in one document · 2 tests
✓
a row handed back without a confirmation is held by the cron's own check 1.3ms
✓
the due query itself asks only for confirmed rows, so armed rows never crowd the batch 0.5ms
a model start arms; it does not confirm · 4 tests
✓
start_sequence from the model makes the rows live but unconfirmed, and the cron holds them 35.5ms
✓
cannot ride an earlier human start: a paused sequence the model restarts loses its confirmation 1.2ms
✓
a start on an already-armed sequence is not "already running" 0.8ms
✓
a human scope for one tenant confirms nothing for another 1.2ms
a person starting it is recorded — who, when, and through which surface · 6 tests
✓
the panel Start records the confirmation, and the cron then sends 2.4ms
✓
the panel Start also confirms rows the model had already armed 0.9ms
✓
the panel Pause records nothing and clears nothing 0.5ms
✓
the chat chip records the confirmation through chat_chip 2.1ms
✓
the chat chip names a sequence the tenant does not have: an error, nothing started 0.4ms
✓
handleSequenceStatus alone — the shared writer the tool also uses — confirms nothing 0.9ms
a start chip starts the rows on its card and no others · 3 tests
✓
the reminder's chip carries a card over exactly the held rows it counted 6.3ms
✓
the person's chip start names its rows: a row enrolled after the card stays unconfirmed 1.2ms
✓
an empty card starts nothing — it never falls back to "everyone waiting" 0.3ms
resume_campaign restarts mail only on the person's chip · 3 tests
✓
a model confirm:true on a later turn resumes nothing: the card comes back, and the cron sends nothing 2.9ms
✓
the second rail still holds: an authorised resume outside a person's start clears the old start, and the cron holds the rows 9.3ms
✓
the "Yes, resume it" chip is the person: it records chat_chip and the cron sends 9.1ms
what the person sees: armed is not running · 2 tests
✓
the panel list counts armed rows apart from sending ones, so its button says Start 1.8ms
✓
list_sequences shows a waiting column only when something is waiting 0.7ms
the chip is a sentence a person sends, matched exactly · 2 tests
✓
routes the chip to its handler 1.5ms
✓
a bare affirmative starts nothing 75.2ms
wiring · 5 tests
✓
the Sequences panel route goes through the human-start handler 0.6ms
✓
the chip handler exists and calls the chip start 0.5ms
✓
a human start is opened only by the three sanctioned surfaces, never by a tool dispatcher 116.3ms
✓
every drip_enrollments writer is accounted for, and each activation handles the confirmation 85.0ms
✓
the resume confirm chip is the one CONFIRM_GATES call that opens a human start 0.6ms
src/email/send-residuals.vitest.ts
V7-send-F03: a 408, or a 409 with or without a key, after acceptance is held — never a refusal that is retried · 10 tests
✓
the classification: 408 and 409 unconfirmed; a rate limit and the other 4xx stay refusals 3.5ms
✓
resend 408 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 36.7ms
✓
resend 409 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 6.2ms
✓
sendgrid 408 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 5.7ms
✓
sendgrid 409 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 2.9ms
✓
mailjet 408 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 4.0ms
✓
mailjet 409 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 2.9ms
✓
mailtrap 408 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 2.5ms
✓
mailtrap 409 after accepting: held as Delivery unconfirmed, not billed, and the same batch posted again mails nobody twice 2.8ms
✓
the unkeyed 409 on a retry of a refused row (the retry carries no key) is held too 3.6ms
V7-send-F04: a 2xx whose body reports an error is never recorded sent, and never billed · 9 tests
✓
mailjet 200 {"Messages":[{"Status":"error","Errors":: failed, 0 fees 4.5ms
✓
mailtrap 200 {"success":false,"errors":["x"]}: failed, 0 fees 2.0ms
✓
resend 200 {"error":"message rejected"}: unconfirmed, 0 fees 1.5ms
✓
sendgrid 202 {"errors":[{"message":"x"}]}: unconfirmed, 0 fees 1.4ms
✓
mailjet 200 {"error":"message rejected"}: unconfirmed, 0 fees 1.4ms
✓
mailtrap 200 {"error":"message rejected"}: unconfirmed, 0 fees 1.4ms
✓
CONTROL: every provider's own success answer is a delivery, billed once 2.1ms
✓
the connected-Gmail branch reads its 2xx body too 2.5ms
✓
the rule itself: only a reported error changes a 2xx; an empty or unparseable body stays an acceptance 0.5ms
V7-send-F02: a release never meets a live provider call — the call is ended before the claim can settle · 5 tests
✓
a call that never answers is aborted at its deadline; at ten minutes the release finds it over 8.1ms
✓
at every minute of a call that never answers, a claim old enough to release has no open call 2.8ms
✓
a deadline that passed before the call is a refusal: nothing is handed to the email service 1.6ms
✓
the bound is below the settle window, with room for the abort to land 0.5ms
✓
CONTROL: an ordinary send is not cut short, and leaves no timer behind 2.1ms
V7-send-F01: a stale attempts read cannot resend a drip step — the database refuses the second row · 6 tests
✓
tick 1 sends but its advance fails; tick 2's read answers []: the insert is refused, nothing is sent, the step advances 6.1ms
✓
tick 1 sends but its advance fails; tick 2's read answers ["failed"]: the insert is refused, nothing is sent, the step advances 2.3ms
✓
a held step (no answer) read stale is refused the same way 2.9ms
✓
CONTROL: up to three refused attempts still retry — failed rows are outside the index 5.4ms
✓
the migration's index and the drip agree: name, key columns, and exactly the statuses the read advances past 2.1ms
✓
only this index's refusal is read as "already sent" 0.5ms
G5(b): a send with no deadline of its own still ends, as held — never as a failure, never twice · 2 tests
✓
sendEmail without deadlineAtMs (the drip's shape) against a provider that never answers: unconfirmed at SEND_CALL_DEADLINE_MS, one provider call, none open after 2.4ms
✓
CONTROL: a send with no deadline that is answered is sent, and leaves no timer behind 1.5ms
src/leads/icp-extract.vitest.ts
the evidence check · 5 tests
✓
accepts a quote that occurs in the brief 1.9ms
✓
REJECTS a paraphrase — the most common and most convincing fabrication 0.3ms
✓
survives curly quotes, dashes and re-wrapped whitespace 0.3ms
✓
rejects a span too short to distinguish one claim from another 0.3ms
✓
accepts a four-character noun, because that IS the evidence for a title 0.2ms
a field with no valid evidence does not exist · 3 tests
✓
drops a value whose quote is absent from the brief, and names the axis as silent 2.8ms
✓
drops a field with a perfect quote but no values 0.9ms
✓
returns nothing at all rather than guessing when the response is not JSON 0.2ms
confidence is derived from the quote, not reported by the model · 3 tests
✓
marks a value the brief names as STATED 0.8ms
✓
marks a value we inferred as IMPLIED, even when the quote is real 0.7ms
✓
does not read "farm" as stated because the quote says "farmingdale" 0.6ms
values are coerced onto the vocabulary the rest of the system speaks · 3 tests
✓
maps the model’s LinkedIn band onto OUR enum, wider rather than narrower 1.1ms
✓
keeps an ISO country code and drops a country NAME 1.3ms
✓
caps a runaway list instead of widening the search the user pays for 0.8ms
the output is executable, and goes through the same translation a typed request does · 3 tests
✓
translates the industry into what the corpus actually stores 0.8ms
✓
carries an industry the corpus has never heard of as unmatched, never as a silent drop 1.0ms
✓
sets no argument for an axis the brief is silent on 0.5ms
a thin brief is an answer, not a failure · 2 tests
✓
refuses to extract below the shared floor 0.2ms
✓
says what to add rather than inventing a plausible buyer 0.4ms
what the user reads · 3 tests
✓
shows the quote beside every reading, so a wrong one is correctable 0.8ms
✓
names the axes the brief was silent on instead of quietly leaving them out 0.4ms
✓
says so plainly when nothing survived 0.1ms
the brief the extractor is allowed to read · 6 tests
✓
passes a normal brief through untouched 0.2ms
✓
KEEPS THE TAIL when a brief is too long — that is where the buyer map lives 0.2ms
✓
keeps the head too — an industry inferred with no idea what the product is is a guess 0.1ms
✓
marks the join, so the model cannot quote across the seam 0.2ms
✓
stays within the stated cap 0.2ms
a headcount range keeps its top end · 4 tests
✓
keeps the band covering the TOP of the stated range 0.7ms
✓
covers the whole range, not a prefix of it 0.4ms
✓
errs WIDER, never narrower — the direction numeric-band exists to guarantee 0.3ms
✓
still bounds the payload — you cannot name more bands than exist 0.4ms
src/seo/page-visibility.vitest.ts
the two-source rule holds here too · 3 tests
✓
no confident verdict rests on fewer than two named sources, in any shape 3.0ms
✓
CTR alone never confirms the snippet — that would be one system twice 0.9ms
✓
every untested hypothesis says what would settle it 0.5ms
the snippet hypothesis · 3 tests
✓
survives when the click gap and a title/description fault land on the SAME page 0.3ms
✓
is KILLED when the clicks are missing and the crawl finds no snippet fault 0.4ms
✓
joins on a NORMALISED url — scheme, www and trailing slash must not break the match 0.2ms
the hypotheses that can never be killed here · 3 tests
✓
query mismatch is never killed — settling it needs a per-query reading 0.7ms
✓
thin variant is never killed — the crawl finding nothing is not proof of nothing 0.4ms
✓
depth is ALWAYS untested — there is no internal-link graph in this codebase 0.7ms
the SERP-feature hypothesis needs the AI reading as its second source · 2 tests
✓
survives only when a click gap AND an AI visibility reading both exist 0.2ms
✓
is untested when the AI reading is missing, and says which reading is missing 0.3ms
the premise not holding is an ANSWER, not an empty report · 2 tests
✓
says so plainly when no page is indexed-and-invisible 0.9ms
✓
NEVER MEASURED and MEASURED-AND-CLEAN do not render alike — GS-004 0.3ms
the subjects are the question · 2 tests
✓
covers BOTH failure kinds — selection and click 0.2ms
✓
de-duplicates a page that fails both ways 0.2ms
the decision rule follows the template, not the list order · 3 tests
✓
a mismatch says retarget, never "polish it" 0.3ms
✓
says STOP and names the next pull when nothing survives 0.2ms
✓
the one-pager is always complete 0.3ms
no internal vocabulary reaches the reader — GS-005 · 1 test
✓
never names a tool, a field, an issue code or a vendor 0.5ms
Q14 is reachable and rendered · 5 tests
✓
routes from the SENTENCE, not from an intent that cannot be trusted with it 2.3ms
✓
is distinguishable in the trace from Q01 0.2ms
✓
the dispatch attaches the brief and gathers its own evidence 0.3ms
✓
ONE renderer serves both briefs 0.4ms
✓
does not steal the turn from the index checker 0.5ms
Q14 survives a tenant with no pillar evidence · 3 tests
✓
is computed BEFORE the empty-evidence gate 0.4ms
✓
the empty-evidence branch returns the brief rather than a generic refusal 0.6ms
✓
is computed ONCE — two copies is the defect brief-kit was extracted to prevent 0.3ms
a clean reading is an ANSWER, not an absence · 5 tests
✓
kills the snippet hypothesis when the clicks were read and are healthy 0.4ms
✓
kills the thin-variant hypothesis when the crawl ran and flagged nothing 0.2ms
✓
kills the serp-feature hypothesis when the AI check ran and there is no click gap 0.1ms
✓
does NOT report five-of-five untested on a site that was fully measured 0.1ms
✓
still reports untested when Search Console reported no impressions at all 0.1ms
src/seo/rank-vs-citation.vitest.ts
bandFor · 1 test
✓
bands by position, with unranked as its own state not a worst band 2.1ms
joinRows — the join is exact, or it is nothing · 6 tests
✓
joins on the seed, normalised for case and whitespace only 1.1ms
✓
refuses a NEAR match rather than pairing two different questions 0.8ms
✓
counts unseeded prompts separately — they are not failures, they are unjoinable 0.3ms
✓
drops a prompt NO engine answered — silence is not "not cited" 0.7ms
✓
an errored engine does not dilute a prompt another engine answered 0.3ms
✓
the FIRST ranking row for a term wins, so a duplicate cannot flip the band 0.2ms
bandStats — a rate below MIN_BAND is suppressed, not rounded · 3 tests
✓
reports counts and a null rate under the floor 0.3ms
✓
reports a rate once the band clears the floor 0.6ms
✓
bandLine never prints a blank where a rate was suppressed 0.4ms
the rank-lifts-citation hypothesis refuses a comparison it cannot make · 3 tests
✓
is UNTESTED when either band is under the floor, and says which 0.4ms
✓
survives when both bands clear the floor AND the gradient runs the right way 0.4ms
✓
is KILLED when the gradient runs the wrong way — ranking did not lift citation 0.3ms
the findings a reader acts on · 3 tests
✓
names the terms that rank 1-3 and are still not quoted 0.3ms
✓
counts citations won outside the classic top 10 0.2ms
✓
the decision names the passage work, not a generic next step 0.2ms
the commercial trade-off is never argued from data we do not have · 1 test
✓
stays untested and names what it would need, whatever the panel says 0.4ms
an unseeded panel cannot answer this at all, and says so · 3 tests
✓
joins nothing and reports the unseeded count rather than a zero rate 0.2ms
✓
every evidence-bearing hypothesis is untested, none are killed 0.2ms
✓
the untested reasons name the missing panel, not a missing number 0.2ms
the situation line distinguishes NO RUN from AN UNJOINABLE RUN · 2 tests
✓
names the unjoinable run and why it cannot be paired 0.4ms
✓
says plainly when there is no run at all 0.2ms
an ungrounded run is labelled as recall, not retrieval · 2 tests
✓
says so in the situation line 0.2ms
✓
a grounded run carries no such caveat 0.2ms
the brief holds the contract every brief holds · 3 tests
✓
owns its own headline 0.3ms
✓
carries situation, so_what, ask and owner 0.2ms
✓
names no tool and no field name in the claims 0.3ms
Q26 is wired everywhere a brief has to be wired · 5 tests
✓
the dispatcher builds it 0.2ms
✓
it is in the answer chain, so the turn can select it 0.2ms
✓
it is in BOTH payload lists 0.2ms
✓
the router recognises it and labels the intent 0.4ms
✓
the renderer picks it up BEFORE the incident fallback 0.4ms
src/chat/claim-grounding.vitest.ts
the shipped defect · 3 tests
✓
marks the assertion about a page it could not read 3.2ms
✓
leaves the page it DID read completely alone 0.4ms
✓
separates "could not read" from "never opened" 0.5ms
what does NOT ground a claim · 2 tests
✓
a search result is a snippet, not a page read 0.4ms
✓
an own-site refusal is grounded once diagnose actually runs 0.4ms
the false positives the catalog eval caught (2026-08-11) · 3 tests
✓
does NOT mark a page that aeo_page_check examined 0.2ms
✓
does NOT mark the tenant OWN site, whose read_url refusal is our own routing rule 0.3ms
✓
still marks a THIRD-PARTY page that genuinely could not be read 0.3ms
it must not cry wolf · 7 tests
✓
says nothing on a turn that gathered no evidence at all 0.6ms
✓
does not mark a sentence that is already honest about its footing 0.4ms
✓
ignores reference hosts — "Google shows an AI Overview" is not a page claim 0.3ms
✓
ignores a bare citation line — a link list asserts nothing 0.5ms
✓
marks once per page, not once per sentence 0.9ms
✓
caps the total number of marks 0.3ms
✓
rebuilds the text byte-exact apart from the marks 0.2ms
host extraction · 3 tests
✓
reads a host from a URL, a bare domain and a port 0.3ms
✓
finds every host named in prose, in order, deduped 0.6ms
✓
does not read a FILENAME as a host — SEO prose is full of them 0.2ms
evidenceSummary · 7 tests
✓
is null on a turn that gathered no evidence 0.3ms
✓
splits what it read from what it could not, and keeps the URL it opened 1.9ms
✓
keeps the FIRST url per host, not the last 0.2ms
✓
marks the tenant's own site as read, never as a gap 0.2ms
✓
adds hosts the ANSWER names that nobody opened, as "not checked" 0.2ms
✓
does not list a host twice when it was both tried and named 0.2ms
✓
never lists a search result as read — a snippet is not a page 0.2ms
www/apex are the same source · 6 tests
✓
does not mark a page it read because the prose dropped the www 0.2ms
✓
does not mark it the other way round either 0.1ms
✓
never reports the same source as BOTH read and unread 0.3ms
✓
lists one source when both spellings were read 0.3ms
✓
still marks a host nobody opened, www or not 0.2ms
✓
a host we tried and failed is not re-listed when the prose uses the other spelling 0.2ms
src/chat/diagnose-focus.vitest.ts
focusOf — the question names the subject · 4 tests
✓
reads the two phrasings that collided live as DIFFERENT questions 3.0ms
✓
separates the four subjects nqzai actually measures 0.4ms
✓
lets the specific subject win over the broad one 0.2ms
✓
falls back to general — the previous behaviour — when it recognises nothing 0.3ms
orderForFocus — reorders, never filters · 7 tests
✓
leads a traffic question with the search facts 0.3ms
✓
leads a reply question with outbound 0.3ms
✓
keeps the original movement-then-weakest order for a general question 1.2ms
✓
returns every fragment whatever the focus 1.7ms
✓
pins the staleness caveat last, whatever was asked 0.6ms
✓
is stable — same-rank fragments keep the order they were composed in 0.3ms
✓
gives the two colliding questions different leading facts 0.3ms
headlineFor — the title cannot disagree with the ordering · 3 tests
✓
quotes the question when there is one 0.2ms
✓
names the subject when there is no question 0.3ms
✓
truncates a long question instead of spilling it 0.2ms
diagnose hands over an exact content prompt · 5 tests
✓
offers a QUALITY CHECK for a term whose page already ranks 1.2ms
✓
offers a BRIEF for a term with no presence 0.2ms
✓
does not offer a brief for the same term the quality check covers 0.3ms
✓
still leads with the tool's own chips when it asked a question 0.1ms
✓
falls back cleanly when no keywords were measured 0.2ms
shapeOf — is this about a CHANGE or a STATE · 6 tests
✓
reads Q01, the most-asked question in the set, as movement 1.8ms
✓
reads a RISE as movement too — same shape, same lead 0.2ms
✓
reads a comparison with no verb of motion as movement 0.3ms
✓
reads a STATE question as state — Q03 and Q14 must not be re-ordered 0.2ms
✓
does not read the IDIOMATIC down/up as movement 0.4ms
✓
an empty or unrecognised question stays state — the conservative fallback 0.1ms
a movement question leads with what moved · 5 tests
✓
hoists movement above the search facts for a decline question 0.2ms
✓
leaves a STATE question exactly as it was — no regression 0.2ms
✓
never hoists movement above provenance 0.1ms
✓
hoists to the front when the topic has no provenance in its list 0.1ms
✓
still drops nothing, whatever the shape 0.2ms
the diagnose dispatch consults both axes · 1 test
✓
passes the shape through, rather than computing focus and forgetting it 1.7ms
src/chat/onboarding-gates.vitest.ts
the shortcut gate reads the sentence, not just the URL · 3 tests
✓
scan_product is not dispatched on URL-presence alone 11.6ms
✓
and that check sits on the SAME condition as the scan, not after it 7.3ms
✓
does NOT restrict onboarding to the first turn 11.1ms
the agent-loop surface reads it too, and does not strand a task · 5 tests
✓
a first-turn OFFER still gets the cheap single-tool surface 6.7ms
✓
a first-turn TASK gets the full surface, not an empty one 14.5ms
✓
a first turn with NO url that asks for work also gets the full surface 7.5ms
✓
and "asks for work" is the intent registry, not a new heuristic 6.7ms
✓
a first turn that asks for NOTHING still gets only the account reads 14.5ms
the ownership question is attached, and yields to anything already asked · 4 tests
✓
fires for a first-turn task that named a URL — OR for any scan that claimed a site 6.8ms
✓
never replaces a gate, a picker, or chips the turn already produced 8.0ms
✓
the chips name all three real answers, including "not my site" 1.2ms
✓
is asked AFTER the work, not as a precondition 6.4ms
the first turn reports what it cost · 1 test
✓
the onboarding scan return carries cumulative, like every other return on its path 6.6ms
the trace does not claim a page belongs to the user · 1 test
✓
scan_product names the host it is fetching, not "your website" 2.6ms
the ownership chips have handlers, and only one of them writes identity · 5 tests
✓
all three chips route somewhere — none is decorative text 11.7ms
✓
the URL comes from KV, never from re-reading the message 6.4ms
✓
only the "my company" branch scans; the other two write nothing 6.8ms
✓
a missing or expired pending ask falls through rather than guessing a domain 8.0ms
✓
answering clears the pending ask, so it cannot be re-answered later 6.6ms
the scan reply itemises what the turn actually did · 3 tests
✓
reads the seed back rather than claiming numbers it cannot know 1.9ms
✓
names the keywords, the competitors and where to find them 2.2ms
✓
a zero count is omitted, never announced as an absence 2.1ms
the gate blocks tailoring, not the tenant's own data · 4 tests
✓
still blocks the tools that need product context 0.2ms
✓
names the account reads that are NOT gated 0.3ms
✓
no longer claims to apply to EVERY request without exception 0.2ms
✓
every tool it exempts is a real registered tool 0.3ms
the prompt may not promise a tool the surface does not carry · 5 tests
✓
the ungated list in V2_SYSTEM is BUILT from the constant, not retyped 0.5ms
✓
and the surface filters on that same constant 8.3ms
✓
every ungated tool is a real registered tool 0.4ms
✓
every ungated tool is FREE — a gated surface must not smuggle in spend 0.2ms
✓
the account reads ride the scan-only arm too 6.4ms
src/seo/prompt-library-guard.vitest.ts
whose words are in a prompt · 7 tests
✓
a model's prompt, and a search page's question, are read in full: a supplier, a price or "free" withholds it 5.6ms
✓
the tenant's own record keeps the vendor exemption, only where the product drew it 3.0ms
✓
only the vendor check is lifted: a price inside the tenant's span is still caught 0.4ms
✓
"exactly as written" means the text, not only the violations: a rewrite with none still withholds 0.7ms
✓
a buyer's budget is the tenant's market (DECISIONS #51): marketCurrency lifts the price check and nothing else 1.6ms
✓
the exit's own options apply: a tenant-money exit reads no price 0.2ms
✓
a product command quoting a prompt keeps the prompt's exemption where it sits 0.5ms
the library as the person may see it · 4 tests
✓
withholds what the guardrail would alter, keeps order, and keeps origins aligned 0.9ms
✓
a legacy library with no origins is a model's words throughout 1.1ms
✓
origins that no longer line up are not trusted 0.4ms
✓
product copy controls: a clean library passes untouched 0.4ms
visibility signals: the action is never a prompt the guardrail would alter · 4 tests
✓
skips a vendor-naming model prompt and acts on the first clean one 0.9ms
✓
the tenant's own competitor prompt keeps its action 0.2ms
✓
a buyer's budget keeps its action (DECISIONS #51): nothing re-scans this card 0.2ms
✓
with no clean prompt the card states the count and offers no action 0.3ms
the AI-visibility report: no write button sends a rewritten command · 3 tests
✓
a gap prompt naming a supplier keeps its row and loses its button; a clean one keeps both 32.4ms
✓
read with the exit's own options: this report is not a tenant-money one, so a price loses its button too 0.5ms
✓
control: every clean gap keeps its button 0.8ms
the wiring · 3 tests
✓
generateAeoPromptLibrary returns only the shown library on both of its returns, and stores the whole one 1.3ms
✓
the Keywords & AI Prompts listing reads the stored library through the same guard 11.6ms
✓
the dashboard serves the signals exactly as built 1.0ms
withholdRunPrompts · 5 tests
✓
withholds what the guardrail would alter; keeps the clean prompt and the buyer's budget, in order 0.7ms
✓
a prompt the person typed whole is theirs (#621's typedByPerson); a fragment or a re-casing is not 1.0ms
✓
a prompt copied from the library keeps the origin it was stored with 0.3ms
✓
a call left with nothing to measure says so; one with nothing withheld is passed on untouched 0.8ms
✓
reads each argument the way its dispatch does 0.3ms
the sentence the reply carries · 1 test
✓
how many and why, one sentence, no prompt text and nothing the guardrail would change 0.4ms
the wiring of DECISIONS #51 · 4 tests
✓
the agent loop narrows a model's call before anything prices, stages or runs it 1.2ms
✓
plan-execute narrows the ledgered call before it is priced 0.3ms
✓
the person's own turns and the chat exit's options are what a run's prompts are read against 0.2ms
✓
finishChatReply states the count before the reply is judged 0.2ms
src/seo/sov.vitest.ts
makeSovEntity · 2 tests
✓
builds aliases and domain tokens from name + domain 2.4ms
✓
normalizes domains 0.4ms
extractMentions — kinds and prominence · 7 tests
✓
classifies a recommendation as recommended with weight 3 (+ early bonus) 0.9ms
✓
classifies a bullet-list item as listed 0.6ms
✓
classifies passing prose as mentioned 0.3ms
✓
falls back to cited_only when the entity appears only in citation URLs 0.4ms
✓
is word-bounded — "personal" does not match Persona 0.3ms
✓
matches bare-domain citations (AI Overview leaderboard style) 0.3ms
✓
does NOT match citation domains via a generic first word of a multi-word brand 0.8ms
computeSov — aggregation · 9 tests
✓
aggregates raw counts across engines before dividing 1.1ms
✓
excludes errored cells from every denominator 0.4ms
✓
citation rate counts cells whose citations include our domain 0.4ms
✓
weighted SOV favors the recommended slot 0.4ms
✓
reports per-engine breakdown 0.3ms
✓
computes HHI and concentration band 0.3ms
✓
synthetic cells count toward shares but not mention/citation rates 0.4ms
✓
handles the empty matrix without NaN 0.2ms
✓
flags low confidence on tiny samples and thin auto competitor sets 0.5ms
classifyPromptType · 3 tests
✓
detects comparison prompts 0.5ms
✓
detects branded prompts 0.2ms
✓
defaults to category 0.1ms
computeSov — prompt-type cut · 1 test
✓
breaks SOV down by prompt type when cells carry it 0.3ms
isReferenceHost — auto-derive junk filter · 2 tests
✓
filters reference/authority hosts that are never competitors 0.5ms
✓
keeps plausible commercial rivals 0.2ms
competitor set persistence helpers · 3 tests
✓
parses stored JSON and drops junk entries 0.6ms
✓
returns [] on malformed input 0.7ms
✓
set signature is order-independent and change-sensitive 0.4ms
orderStoredCompetitors — user-first, honor full set · 4 tests
✓
orders user entries before auto and never drops a user pick for an auto one 0.4ms
✓
honors up to 12 (the modal cap), not the old 5 0.4ms
✓
respects an explicit smaller limit and re-screens auto entries against the reference filter 0.4ms
✓
a user-entered reference host is taken at face value (never second-guessed) 0.2ms
client/approval-card.vitest.ts
"Not now" is an answer, and it has to reach the server · 3 tests
✓
posts a message the server recognises as a cancellation 40.0ms
✓
is inert while a turn is running, exactly like Confirm 7.4ms
✓
still dims the card, so the click is visibly acknowledged 5.8ms
the jsdom environment is actually present · 1 test
✓
has a document and a mount point 1.5ms
CLAUDE.md §4 — what the card may say about money · 6 tests
✓
never renders a currency symbol or the word dollar 6.0ms
✓
never names a backend vendor 6.1ms
✓
never says "free" — it says "No extra cost" 7.9ms
✓
renders a RANGE when the maximum exceeds the estimate 9.2ms
✓
renders a single figure when there is no range, not "X to X" 8.0ms
✓
labels the mode: paid operation vs confirmation gate 4.2ms
the advisory block · 7 tests
✓
renders ABOVE the cost summary — advice before price 3.7ms
✓
strips markdown from chip labels 7.0ms
✓
POPULATES the composer and does NOT send — the whole point of an alternative 4.6ms
✓
sends each chip its OWN text when several are present 2.4ms
✓
renders no advisory block when there is no note, even if chips are present 1.6ms
✓
drops empty chips rather than rendering blank buttons 1.7ms
✓
survives a telemetry callback that throws 2.7ms
Confirm · 4 tests
✓
sends the confirm prompt and locks itself 1.7ms
✓
does nothing while a send is already in flight 1.3ms
✓
cannot be double-fired by two fast clicks 1.7ms
✓
falls back to defaults when the server sends no labels 1.6ms
supersession — two live Confirm buttons is a way to pay for the wrong quote · 4 tests
✓
disables the older card when a newer one arrives 2.6ms
✓
refuses to send from a superseded card even if its button is re-enabled 3.2ms
✓
leaves an already-dismissed card alone rather than relabelling it 2.7ms
✓
is a no-op with no cards 0.8ms
refuses to render rather than rendering something wrong · 5 tests
✓
does nothing without a wrapper, an approval, or a .msg-text host 1.1ms
✓
treats a server-supplied title and message as TEXT, never as markup 3.3ms
✓
escapes a tool label, which goes through innerHTML 2.9ms
✓
names an unlabelled tool "Operation" rather than leaving it blank 1.5ms
✓
renders with no tools at all 2.1ms
src/connectors/oauth-state-coverage.vitest.ts
every provider authorize URL carries a bound state · 6 tests
✓
the population is the six known flows (a seventh must be added here AND bound) 2.2ms
✓
src/admin/ga4-landing.ts: one mintOAuthState and one withStateCookie per authorize URL 0.6ms
✓
src/admin/gsc.ts: one mintOAuthState and one withStateCookie per authorize URL 0.3ms
✓
src/commerce/shopify-oauth.ts: one mintOAuthState and one withStateCookie per authorize URL 0.3ms
✓
src/connectors/gmail-oauth.ts: one mintOAuthState and one withStateCookie per authorize URL 0.3ms
✓
src/connectors/oauth.ts: one mintOAuthState and one withStateCookie per authorize URL 0.3ms
every OAuth callback verifies the binding before it saves anything · 12 tests
✓
the population is the six known callbacks 17.5ms
✓
handleGoogleOAuthCallback consumes a 'google' state before any save 1.1ms
✓
handleGoogleOAuthCallback does not redeem the code before the binding is verified 0.7ms
✓
handleNotionOAuthCallback consumes a 'notion' state before any save 0.5ms
✓
handleNotionOAuthCallback does not redeem the code before the binding is verified 0.3ms
✓
handleGmailOAuthCallback consumes a 'gmail' state before any save 0.4ms
✓
handleGmailOAuthCallback does not redeem the code before the binding is verified 0.1ms
✓
handleShopifyOAuthCallback consumes a 'shopify' state before any save 0.3ms
✓
maybeHandleAdminGscOAuthCallback consumes a 'admin-gsc' state before any save 0.4ms
✓
maybeHandleAdminGscOAuthCallback does not redeem the code before the binding is verified 0.3ms
✓
maybeHandleAdminGa4OAuthCallback consumes a 'admin-ga4' state before any save 0.3ms
✓
maybeHandleAdminGa4OAuthCallback does not redeem the code before the binding is verified 0.2ms
the public callback routes reach binding-aware handlers · 5 tests
✓
the shared Google callback dispatches admin GSC, then admin GA4, then the tenant handler 0.5ms
✓
Notion and Gmail callbacks route straight to their handlers 0.2ms
✓
the Shopify callback routes to its handler 0.3ms
✓
every public /callback path is one of the four above 0.3ms
✓
the start routes hand the request to the start handlers (the cookie needs it) 0.5ms
every vendor-hosted consent link is bound to the browser that started it · 6 tests
✓
the population is the Google bridge start (a second one must be added here AND bound) 6.8ms
✓
the bridge start binds the browser before it mints any consent link, and sets the cookie 0.5ms
✓
the verify route redeems a session only for the bound account, and burns it otherwise 0.4ms
✓
the vendor session is redeemed from the verify module and nowhere else 5.1ms
✓
finalize requires both legs verified before it activates anything 0.5ms
✓
the verify route is public, ahead of the session gate, and routed to its handler 3.4ms
the never-expiring timestamp cannot come back · 1 test
✓
no state parser under src/ reads a ':'-split timestamp with Number() 3.9ms
src/tools/scheduled-scans.vitest.ts
stop switches round-trip through settings · 4 tests
✓
every stop key is in SETTING_KEYS, or getAllSettings could never read it back 2.8ms
✓
absent means on for the default-on scans; only an explicit 0 is off 0.6ms
✓
a stop from chat is what the cron reads, for that tenant only 194.1ms
✓
tenantsWhoStopped throws on a failed read, so crons can fail closed 1.4ms
list_scheduled_scans · 9 tests
✓
reports the rank scan as running only when the cron would scan: opted in, keywords, plan, balance 1.0ms
✓
a balance the cron guard would refuse reads as paused, with no next run 0.6ms
✓
checks the balance against the run the card quotes, not the keyword-research catalogue row 1.0ms
✓
a failed balance lookup is "could not check", never a balance problem the user does not have 0.6ms
✓
a test tenant is shown as excluded, matching the cron skip 0.7ms
✓
no keywords, no store and nothing unpublished read as idle, not running 0.7ms
✓
AI visibility follows the opt-in and the tenant's chosen day 0.8ms
✓
lists email sequences and the plan check only when they have work, and never offers to stop them here 0.6ms
✓
never states a cost in currency or calls anything free 0.5ms
stop_scheduled_scan · 4 tests
✓
"all" switches off every scan that was on and leaves opt-in AI visibility alone when it was off 214.3ms
✓
stops weekly AI visibility through the same switch sov_trend uses 140.3ms
✓
stopping twice writes nothing the second time and says it was already off 244.7ms
✓
"all" names the email sequences it did not touch 143.3ms
resume_scheduled_scan · 9 tests
✓
the rank scan is a weekly spend: the first call stages a quote and writes nothing 130.2ms
✓
the confirm chip after the quote switches it back on 242.9ms
✓
resuming an auto-paused rank scan clears its refusal streak 144.6ms
✓
a scan the person stopped still reads "You stopped it" 108.2ms
✓
a confirm from outside the chip (the model's own) re-quotes and switches nothing on 118.9ms
✓
a confirm nobody was quoted for does not resume: it stages a fresh quote instead 113.2ms
✓
the no-cost jobs resume at once 248.1ms
✓
AI visibility is sent to sov_trend, which owns its quote, and nothing is written 0.5ms
✓
a scan that is already on says so 0.3ms
nextWeeklyRunUtc · 2 tests
✓
finds the next occurrence strictly after now 0.5ms
✓
covers every scan id the tools accept 0.4ms
the rank-scan reservation prices a capped number of fallbacks · 2 tests
✓
200 keywords reserve ~350K: 200 x 750 + 20 x 10,000 0.3ms
✓
a scan smaller than the cap prices one fallback per keyword, never more fallbacks than keywords 0.3ms
scripts/lib/ops-env.vitest.mjs
loadOpsEnv — env first, then the first .dev.vars that has the key · 4 tests
✓
an environment variable wins over a file (a cloud session sets these) 2.4ms
✓
falls back through files in order and strips quotes 0.4ms
✓
a blank env value does not mask the file, and a missing key is absent, not empty 0.4ms
✓
parseDevVars ignores comments and lowercase lines 0.3ms
isReadOnlySelect — the first of two locks on ro-sql · 18 tests
✓
allows select count(*) from users 0.6ms
✓
allows SELECT status, count(*) FROM emails_sent GROUP BY 1 0.4ms
✓
allows select comment, reset_at from feedback 0.2ms
✓
refuses with x as (delete from users returning 1) select * from x 0.3ms
✓
refuses select 1; delete from users 0.4ms
✓
refuses delete from users 0.2ms
✓
refuses update users set x = 1 0.2ms
✓
refuses select * from users where id in (select id from t); drop table t 0.2ms
✓
refuses select pg_sleep(1); truncate t 0.1ms
✓
refuses SELECT 1 FROM t WHERE false; INSERT INTO t VALUES (1) 0.1ms
✓
refuses select * into newtbl from users; create table y() 0.1ms
✓
refuses select * into newtbl from users 0.1ms
✓
refuses select 1; select 2 0.1ms
✓
refuses select pg_terminate_backend(123) 0.1ms
✓
refuses SELECT pg_read_file('/etc/passwd') 0.1ms
✓
refuses select pg_sleep(30) 0.1ms
✓
refuses select dblink_exec('x', 'delete from t') 0.1ms
✓
a trailing semicolon alone is fine 0.1ms
isReadOnlyGraphql · 1 test
✓
refuses mutations and subscriptions, allows queries 1.8ms
jev-eval.mjs calls the endpoint production calls · 1 test
✓
JEV_ENDPOINT matches src/llm/jev.ts 0.3ms
jev-eval.mjs sends the payload production sends · 3 tests
✓
production passes questions as a map of id → question 0.3ms
✓
accepts that map, and refuses the array the tool used to demand 0.3ms
✓
refuses what the API would reject, before spending a call 0.3ms
resolveFixlogConflict — both entries survive whole · 2 tests
✓
keeps ours then theirs, each in its own object 0.2ms
✓
refuses zero or two conflict blocks rather than guessing 0.9ms
src/admin/readiness.vitest.ts
auth — header only, checked before any read · 4 tests
✓
1. no header → 403 and 0 fetches 26.8ms
✓
2. a CORRECT ?secret= with no header → 403 and 0 fetches (header-only) 0.9ms
✓
a ?secret= beside a valid header is still refused 0.9ms
✓
a wrong header → 403, never a 401 with a ?secret= hint 1.8ms
3. page load: exactly 2 Nhost round trips, every host is NHOST_URL's · 3 tests
✓
200 JSON, 2 fetches, all to the Nhost host (S18) 8.2ms
✓
live_build_id is env.APP_BUILD_ID when set, and null when not (never APP_VERSION) 7.7ms
✓
the Nhost admin secret also opens it, by header (checkAdminSecret accepts both) 1.9ms
4. a failed release-ledger read degrades, it never shows zeros · 2 tests
✓
ReleaseHealth 500 → still 200, release null, degraded names it; hosts only Nhost + the Sentry DSN host 14.1ms
✓
a failed token-efficiency read degrades the tile, not the page 3.9ms
5. the built response · 5 tests
✓
holds every invariant: each FAIL-unmeasurable sub names an unlock 5.0ms
✓
contains no secret and no email address — the fixture carries one in a judge reason and in a release note 2.9ms
✓
joins each K-fix to its deploy by build_id prefix: K1 → 2.681.89 2.6ms
✓
B1 leaves the later slices empty, and says so with nulls rather than zeros 2.4ms
✓
the gate states equal the offline scorer run over the same seed at the same instant 2.8ms
6. foldTokenEfficiency · 8 tests
✓
judge_model_health [] → no_attempts, never ok (the 09-23 row) 0.5ms
✓
no report at all → no_report 0.3ms
✓
a model at 0.25 over 8 attempts → failing; 0.08 over 12 → elevated; 0.08 over 9 → ok 0.3ms
✓
a report older than yesterday is not fresh 0.2ms
✓
no drift_runs row → last_run 'unknown' 0.3ms
✓
a 30-hour-old run is stale; a 25-hour-old run is fresh 0.4ms
✓
findings parse their meta, and 50 rows mark the list truncated 0.4ms
✓
safeReason redacts an address BEFORE cutting to 80 characters 0.4ms
7. SYMPTOM_CLASSES parity — the admin-app mirror and src/admin/defect-class.ts · 2 tests
✓
the SymptomClass union lists exactly SYMPTOM_CLASSES (0 literals parsed fails, never passes vacuously) 0.5ms
✓
DEFECT_TONE colours every class (a missing key renders DEFECT_TONE[undefined]) 0.4ms
wiring — src/index.ts dispatches the route ahead of the JWT gate · 1 test
✓
GET /api/admin/readiness → handleAdminReadiness(request, env, json), ahead of the Nhost session gate 1.1ms
drill links — every catalogue drill path is a real admin-app route · 2 tests
✓
parses the route tree (0 routes fails, never passes vacuously) 0.2ms
✓
no drill path points at a missing page 0.4ms
admin-app hooks — one bounded read per click or visit · 2 tests
✓
useReadiness: retry false, a 10-minute staleTime, no refetch on focus 0.6ms
✓
useWasteRollup: retry false, a 10-minute staleTime, no refetch on focus 0.4ms
src/chat/speech-act.vitest.ts
a question about the world is not a command, however the topic reads · 6 tests
✓
the incident: Explain how AI search engines decide which sit 5.5ms
✓
a definition ask: What is the difference between SPF and DKIM, a 0.5ms
✓
out of domain entirely: What is a good recipe for chicken biryani? 0.3ms
✓
a comparison of concepts: How does answer engine optimisation differ fro 0.2ms
✓
a phrasing nobody listed: Curious whether backlinks still matter as much 8.7ms
✓
a bare topic: thoughts on programmatic SEO 0.2ms
a question about THEIR data is still a question, but not a general one · 5 tests
✓
not general: Am I visible in AI search? 0.3ms
✓
not general: my numbers dropped 0.3ms
✓
not general: how do I improve my seo 0.5ms
✓
not general: why is our traffic down 0.3ms
✓
not general: We have 200 tokens of budget and one week. Is 0.2ms
a command is recognised wherever in the sentence it appears · 5 tests
✓
IN A LATER CLAUSE — the regression that first-token-only testing caused 2.6ms
✓
but NOT a work verb that is merely being discussed 0.2ms
✓
and NOT an explanation verb, which is imperative in form only 1.9ms
naming a specific page makes a question specific, not general · 2 tests
✓
a comparison of two named URLs needs evidence, not prose 0.1ms
✓
a bare domain counts too 0.1ms
the defaults, and why they lean the way they do · 2 tests
✓
empty input is neither a command nor a general question 0.2ms
✓
an unrecognised sentence defaults to QUESTION, and that is the cheap failure 0.1ms
the predicate decides whether a PICKER opens, and nothing else · 4 tests
✓
a noun-phrase data request is called "general" — which is why it must not gate tools 0.1ms
✓
the tool surface no longer consults it 9.8ms
✓
the guard has no `answer` rung to drop a data request into 0.5ms
✓
what still protects an explanatory turn is the COST GATE, which the user can see 0.4ms
an advisory ask still reaches the planner · 3 tests
✓
the planner tools are exempt from the evidence-first redirect 216.0ms
✓
and a genuinely paid report is still gated 0.4ms
✓
the exemption reads the canonical planner set, not a second list 0.3ms
the planner is not augmented with a competing answer · 2 tests
✓
the guard stands down once the model has chosen a planner tool 0.5ms
✓
and still fires when the model reached for a paid report instead 1.2ms
src/chat/write-intent.vitest.ts
asksForAWrite · 7 tests
✓
recognises the sentences that actually failed 7.5ms
✓
leaves read requests alone — the shortcut exists for these 0.6ms
✓
does not fire on a write verb buried inside a read request 0.5ms
✓
is not fooled by substrings 0.3ms
✓
reads polite and compound phrasings 0.3ms
✓
ignores control tokens, which the shortcut also excludes 0.2ms
shouldKeepGoingAfterLookup · 2 tests
✓
needs BOTH a lookup and a write request 3.9ms
✓
does not cover the expensive audit whose render really is the answer 0.5ms
the loop honours it · 2 tests
✓
the shortcut stands down when the helper says keep going 0.6ms
✓
and the stand-down is counted, so the rate is measurable rather than assumed 0.6ms
writeInstructionCount · 5 tests
✓
counts the two-instruction sentence that failed 0.2ms
✓
counts one instruction as one 0.2ms
✓
counts a read as zero, so a plain question never keeps the loop alive 0.1ms
✓
does not count a verb inside a noun phrase 0.2ms
✓
KNOWN FALSE POSITIVE: "and <verb>" in a noun phrase counts as an instruction 0.2ms
shouldKeepGoingAfterLookup — the second reason · 3 tests
✓
keeps going after ONE write tool when the message asked for two things 0.2ms
✓
still halts after one write tool for a single instruction 0.1ms
✓
is unchanged for lookups 0.2ms
singleToolRenderPath · 9 tests
✓
the first tool of the turn, alone in its round, is 'first' — exactly the old toolCallCount === 1 0.3ms
✓
clean lookups, then one write alone in its round, is 'after_lookup' 0.2ms
✓
(neg) a read or audit tool after clean lookups narrates as today 0.6ms
✓
the allowlist is outbound writes only: each changes state, none is a lookup, each has a formatter 3.2ms
✓
(neg) lookup then lookup narrates as today 0.1ms
✓
(neg) write then write narrates as today 0.2ms
✓
(neg) two tools in the round keep the synthesis pass 0.1ms
✓
(neg) a round that ran only search_tools (0 real calls) is not a render round 0.2ms
✓
(neg) an errored lookup earlier in the turn makes the round ineligible 0.1ms
the loop computes the path from the round · 1 test
✓
snapshots the turn before the round and counts dirty calls after the blocked classifier 1.7ms
src/email/refund-reason-email.vitest.ts
refund_tokens_issued never prints a raw error · 21 tests
✓
APIFY_BACKLINKS_ERROR_403: { "error": { "type": "platform-feature-disabled", "message": "Monthly usage hard limit exceeded" } } 16.5ms
✓
Search Console returned 403/404 for every detected property. Tried: sc-domain:example.com. 3.7ms
✓
DFS_TASK_POST_HTTP_401 0.3ms
✓
DFS_TASK_POST_ERROR_40201: We noticed some unusual activity in your DataForSEO account, so we’ve temporarily paused access as a precaution. Please, reach out to our support team at support@dataforseo. 0.5ms
✓
DFS_TASK_POST_ERROR_40501: Invalid Field: 'target - Domain Not Found'. 0.3ms
✓
Could not identify any companies to search on Apollo for this query — try naming specific companies or a narrower industry. 2.5ms
✓
each step needs delay_days (number) 0.4ms
✓
No contacts found in list(s): Q3 founders. No contact lists exist yet — search for leads first. 0.4ms
✓
tool 'create_marketing_plan' timed out after 30000ms 0.6ms
✓
Plan generation failed — the strategy model returned no usable initiatives. Try again in a moment. 0.4ms
✓
I couldn't draft emails for that contact — the drafting step failed, not your list. (The operation was aborted) Try again; if it keeps happening the contacts are fine and the problem is on our side. 0.5ms
✓
Those arguments can't run as given. email_ids must be an array. 0.3ms
✓
I couldn't run that — the url you gave me isn't something I can search on. Try rephrasing it, or tell me what you're after in your own words. 0.3ms
✓
Failed to fetch URL: a temporary error 1.0ms
✓
I couldn't run that — the industry you gave me isn't something I can search on. Try rephrasing it, or tell me what you're after in your own words. 0.6ms
✓
I couldn't run that — the domain you gave me isn't something I can search on. Try rephrasing it, or tell me what you're after in your own words. 0.6ms
✓
This is the last run included on your current plan. Top up to keep going. 0.5ms
✓
I couldn't find a list called "Example Dealerships". You have no contact lists yet — find some leads first. 0.5ms
✓
Your plan includes 3 search leads runs in total, and that has been used. It does not reset — topping up your balance removes the limit. 0.5ms
✓
Insufficient token balance for contact email verification (~750K tokens). Your balance is 395,316 tokens. Top up to continue. 0.3ms
✓
tool 'contact email verification' timed out after 30000ms 0.2ms
a reason that is already a plain sentence keeps its meaning · 6 tests
✓
I couldn't find a list called "Example Dealerships" 0.3ms
✓
No contacts found in list(s): Q3 founders. 0.1ms
✓
This is the last run included on your current plan. 0.1ms
✓
Could not identify any companies to search on Apollo for this query 0.1ms
✓
a raw error still tells the user something true, in one sentence 0.3ms
✓
no reason prints no reason line 2.6ms
manual_topup_receipt goes through the same rail · 2 tests
✓
an operator reason naming a vendor does not reach the user 0.4ms
✓
the Stripe receipt line is unchanged 0.2ms
src/email/smtp-canonical-host.vitest.ts
the V12-edge-F01 reproduction: 010.0.0.5 is 10.0.0.5 to the socket · 2 tests
✓
is refused as private before connect: no socket, no password, no lookup 5.4ms
✓
isPrivateHost itself reads a leading-zero quad both ways and refuses if either is private 1.4ms
every non-canonical IPv4 form is refused at the socket — none connects · 19 tests
✓
010.0.0.5 → private_host, nothing connects 1.1ms
✓
010.8.8.8 → private_host, nothing connects 0.7ms
✓
08.8.8.8 → ambiguous_address, nothing connects 0.8ms
✓
8.8.8.08 → ambiguous_address, nothing connects 0.8ms
✓
0203.0.113.25 → ambiguous_address, nothing connects 0.6ms
✓
127.0.0.01 → private_host, nothing connects 0.5ms
✓
0127.0.0.1 → private_host, nothing connects 0.7ms
✓
0x7f.0.0.1 → private_host, nothing connects 0.7ms
✓
0x7f.1 → private_host, nothing connects 0.6ms
✓
127.1 → private_host, nothing connects 0.6ms
✓
10.1 → private_host, nothing connects 0.4ms
✓
8.8.2056 → ambiguous_address, nothing connects 0.4ms
✓
2130706433 → private_host, nothing connects 0.4ms
✓
134744072 → ambiguous_address, nothing connects 3.2ms
✓
0x08080808 → ambiguous_address, nothing connects 0.5ms
✓
1.2.3.4.5 → ambiguous_address, nothing connects 0.4ms
✓
[::ffff:010.0.0.5] → private_host, nothing connects 1.0ms
✓
[::ffff:08.8.8.8] → ambiguous_address, nothing connects 0.5ms
✓
the ambiguous refusal reads in plain words with no code prefix leaking to the person 0.4ms
controls: what connects is exactly the canonical form the screen judged · 8 tests
✓
203.0.113.25 dials 203.0.113.25 18.2ms
✓
198.51.100.7 dials 198.51.100.7 1.8ms
✓
SMTP.Example.TEST. dials smtp.example.test 30.9ms
✓
[2001:DB8:0:0:0:0:0:25] dials [2001:db8::25] 1.1ms
✓
2001:db8::25 dials [2001:db8::25] 1.2ms
✓
[::ffff:203.0.113.25] dials [::ffff:cb00:7119] 1.3ms
✓
1.2.3.4.example.test dials 1.2.3.4.example.test 1.5ms
✓
a refused screen carries no host to dial 0.3ms
src/tools/aeo-wave5.vitest.ts
the AEO cluster · 15 tests
✓
entity_audit accepts the empty call 2.0ms
✓
aeo_full_audit accepts the empty call 0.3ms
✓
sov_trend accepts the empty call 0.2ms
✓
tap_volume accepts the empty call 0.2ms
✓
seo_generate_llms_txt accepts the empty call 0.2ms
✓
entity_audit rejects the retired domain alias 0.3ms
✓
aeo_full_audit rejects the retired domain alias 0.3ms
✓
sov_trend rejects the retired domain alias 0.2ms
✓
tap_volume rejects the retired domain alias 0.6ms
✓
seo_generate_llms_txt rejects the retired domain alias 0.2ms
✓
entity_audit accepts a named site 0.5ms
✓
aeo_full_audit accepts a named site 0.1ms
✓
sov_trend accepts a named site 0.1ms
✓
tap_volume accepts a named site 0.1ms
✓
seo_generate_llms_txt accepts a named site 0.1ms
aeo_page_check: one name, both forms · 3 tests
✓
takes a full page URL 0.1ms
✓
takes a bare domain under the same field 0.1ms
✓
rejects site, which was the alias on this tool 0.1ms
type tolerance is gone · 3 tests
✓
sov_trend engines must be an array of known engines 1.4ms
✓
tap_volume queries must be an array 0.2ms
✓
entity_audit execs must be an array 0.1ms
fallbacks go only where validation replaced them · 8 tests
✓
entity_audit no longer reads tool.domain 0.4ms
✓
tap_volume no longer reads tool.domain 0.2ms
✓
sov_trend no longer reads tool.domain 0.2ms
✓
seo_generate_llms_txt no longer reads tool.domain 0.1ms
✓
aeo_page_check no longer reads tool.site 0.2ms
✓
the scalar branches are gone 0.3ms
✓
still-legacy full_seo_audit KEEPS its fallback 0.1ms
✓
still-legacy share_of_model KEEPS its fallback 0.1ms
src/tools/primitives.vitest.ts
web_search · 7 tests
✓
passes `site` through so a competitor-scoped lookup needs no new code 2.2ms
✓
normalises results to a stable shape 1.0ms
✓
treats a ZERO-result search as a finding, not a silent empty 0.5ms
✓
caps the result count no matter what is asked for 0.5ms
✓
returns an error rather than throwing when search is down — a dead tool must not kill the turn 1.1ms
✓
reads the failure class whatever the provider is called, never hands the model a status or the key name 1.3ms
✓
refuses an empty query without calling the provider 0.5ms
read_url — the skeleton · 18 tests
✓
extracts the fields a ranking comparison turns on 2.5ms
✓
ignores script and style content — a <h1> inside a script is not a heading 1.2ms
✓
separates internal from external links, and skips mailto 1.1ms
✓
counts words on the FULL text even when the text is truncated 1.5ms
✓
surfaces the egress layer's OWN refusal rather than paraphrasing it 0.3ms
✓
goes through the egress choke point, never a bare fetch 0.3ms
✓
reports a redirect target so the model knows what it actually read 0.4ms
✓
reports a non-2xx as a FAILURE TO READ, never as a measurement 0.4ms
✓
says a 403 REFUSED the research, rather than implying the page is broken 0.3ms
✓
distinguishes rate-limiting from refusal — one is temporary 0.3ms
✓
blames US, not the site, for a timeout or an oversized page 0.3ms
✓
a page refused MID-READ by the streamed cap is "too large", not "no readable content" (V1-egress-F01) 0.4ms
✓
names the loopback case on a 52x instead of letting it read as an outage 0.3ms
✓
READS the tenant's own site — the refusal is gone (2026-09-23) 0.3ms
✓
reads OUR OWN host through the SELF binding, never over the network — [5.0.2] 25.9ms
✓
the owner's own tenant (site = our host) reads its page through SELF too 0.8ms
✓
says so when a page returns nothing readable, instead of an empty skeleton 0.4ms
✓
echoes the extract hint without letting it change what was measured 0.4ms
a primitive result must have a VOICE, not a JSON dump · 4 tests
✓
renders search results as prose 123.0ms
✓
says plainly when a search found nothing — that is an answer, not an empty render 0.5ms
✓
renders a page as a comparable summary, not a blob 0.6ms
✓
surfaces an error as the message rather than rendering an empty skeleton 0.3ms
src/tools/tool-tiers.vitest.ts
tool-tiers — coverage stays in sync with V2_TOOLS · 3 tests
✓
every V2_TOOLS entry is covered by CORE or a family 2.0ms
✓
no tiered name references a tool that does not exist in V2_TOOLS 0.4ms
✓
no tool appears in more than one family (each has exactly one home) 0.3ms
resolveTurnTools · 4 tests
✓
'all' returns V2_TOOLS unchanged (safe default, today's live behavior) 0.4ms
✓
empty family set returns exactly the CORE tools plus the search_tools meta-tool 1.9ms
✓
requesting a family adds its tools on top of CORE 1.8ms
✓
an unknown family key is ignored, not thrown 0.7ms
listToolFamilies · 1 test
✓
lists every family with a non-empty tool list 0.5ms
search_tools meta-tool · 5 tests
✓
is appended to every tiered tool list, so the long tail is always reachable 0.6ms
✓
is NOT added to the untiered full list (flag off = today's surface, unchanged) 0.3ms
✓
enumerates the real families in its schema, so the model cannot invent one 0.3ms
✓
returns the family's tool names on a valid call 0.3ms
✓
returns a self-correcting error naming the real families on an unknown one 0.2ms
tieringEnabled — rollout gate · 2 tests
✓
defaults to off for unset/off/garbage 0.2ms
✓
accepts the documented on values 0.2ms
family hints — a bare family name is not an index · 7 tests
✓
every family has a hint, so the rendered list can never be half-annotated 0.3ms
✓
no hint exists for a family that does not 0.3ms
✓
the meta-tool description carries the hints, not just the names 0.5ms
✓
names PANELS in the AI-search hint — the exact word that failed 0.3ms
✓
preloads campaigns for a drip/sequence ask ([6.2.1] 2026-09-15) and seo for backlinks, nothing else 4.7ms
✓
loads the family a sentence names, and nothing else (widened 2026-09-17 on a measured 19K-per-turn cost) 1.9ms
✓
tells the model to load a family before denying the capability 0.2ms
the Jev tool shortlist (2026-09-19): CORE_MIN + one family, and the way back · 7 tests
✓
CORE_MIN is a strict subset of CORE and keeps both research primitives 0.4ms
✓
coreMin with a family resolves to CORE_MIN + that family + search_tools, and nothing else 1.1ms
✓
coreMin without a family, or with the core family loaded, is the full CORE (never a smaller surface than today) 1.1ms
✓
search_tools('core') loads the full CORE list, so a shortlisted turn can always get back 0.2ms
✓
every tool of a sub-grouped family is in at least one sub-group, every sub-group has a hint, and no group is the whole family 3.0ms
✓
a sub-group narrows the family; a family with no sub-groups is loaded whole 0.5ms
✓
the shortlisted surface is small enough to be worth it: every family, narrowed where it has sub-groups, ≤ 6,000 schema tokens 4.7ms
src/seo/ai-policy-playbooks.vitest.ts
all four are registered and hold the shared invariant in every input state · 8 tests
✓
kpi_contract is registered 1.7ms
✓
kpi_contract passes the invariant empty and populated 1.5ms
✓
ai_cannibalisation is registered 0.2ms
✓
ai_cannibalisation passes the invariant empty and populated 0.4ms
✓
ai_pipeline_attribution is registered 0.2ms
✓
ai_pipeline_attribution passes the invariant empty and populated 0.4ms
✓
multi_market_language is registered 0.2ms
✓
multi_market_language passes the invariant empty and populated 0.4ms
Q01 — the scoreboard, not the click loss · 5 tests
✓
names four layers rather than a number 0.7ms
✓
anchors on the frozen panel when one exists — that is layer 2 0.3ms
✓
an EMPTY frozen panel is not a frozen panel 0.3ms
✓
with no panel it still says the contract can be signed first 0.1ms
✓
refuses a single blended visibility score as the scoreboard 0.2ms
Q13 — one backlog, and capacity is the anchor · 4 tests
✓
anchors on recommendations never run 0.3ms
✓
does not anchor on a backlog of zero — nothing unrun is not a finding 0.2ms
✓
refuses a second content workstream outright 0.1ms
✓
treats chat-only tactics as off-page rather than a replacement 0.1ms
Q22 — three layers, and no invented revenue · 4 tests
✓
forbids converting a visibility score into revenue 0.1ms
✓
requires the citation series to move FIRST before brand lift counts 0.1ms
✓
anchors on a real run when one exists, and quotes its citation rate 0.2ms
✓
with no run, it says the money layer has no instrument here AT ALL 0.1ms
Q24 — language is the subject, and the tracked market is the anchor · 4 tests
✓
anchors on the single tracked market, which IS the finding 0.2ms
✓
with no market set, says so rather than assuming one 0.2ms
✓
NEVER claims to have checked hreflang — nothing in this codebase reads it 0.2ms
✓
localises the third-party graph, not only the site 0.2ms
all four are routed and labelled · 4 tests
✓
kpi_contract is selected by its predicate and labelled in the turn 0.4ms
✓
ai_cannibalisation is selected by its predicate and labelled in the turn 0.2ms
✓
ai_pipeline_attribution is selected by its predicate and labelled in the turn 0.2ms
✓
multi_market_language is selected by its predicate and labelled in the turn 0.2ms
src/seo/nap.vitest.ts
normAddress · 6 tests
✓
REGRESSION: folds "Ste B" as a suite, never as street + stray letter 5.0ms
✓
REGRESSION: "201 W 5th St" equals "201 West 5th Street" 0.3ms
✓
folds spelled-out states to their abbreviation 0.2ms
✓
treats # and Suite as the same unit marker 0.2ms
✓
is punctuation- and case-insensitive 0.3ms
✓
does NOT collapse genuinely different addresses 0.9ms
normPhone · 3 tests
✓
ignores formatting and country code 0.3ms
✓
distinguishes genuinely different numbers 0.2ms
✓
returns empty for junk rather than a partial match 0.6ms
normName · 2 tests
✓
folds legal suffixes so they never read as a conflict 0.5ms
✓
keeps distinct businesses distinct 0.3ms
walkJsonLd · 3 tests
✓
REGRESSION: finds an address nested on parentOrganization 1.2ms
✓
terminates on a self-referential graph instead of hanging 0.8ms
extractNapClaims · 5 tests
✓
reads structured data and records its provenance 0.9ms
✓
falls back to footer text when there is no JSON-LD 0.4ms
✓
does not crash on malformed JSON-LD, and degrades to the text tier 0.2ms
✓
reports no LocalBusiness when only a generic Organization is present 0.3ms
✓
ignores phone-shaped strings inside scripts and markup 0.2ms
htmlToText · 1 test
✓
drops tags, scripts and styles 0.3ms
napConsistency · 5 tests
✓
REGRESSION: cosmetic differences across pages are NOT a conflict 1.9ms
✓
flags a genuine two-address conflict 0.2ms
✓
flags a genuine phone conflict but not a reformatted one 0.2ms
✓
treats a brand and its parent legal entity as two names, without calling it a conflict 0.3ms
✓
is empty and conflict-free for a site that states nothing 0.8ms
bestNap · 4 tests
✓
prefers structured data over footer text and reports which it used 0.3ms
✓
falls back to text and SAYS so, so the caller can disclose the weaker claim 0.1ms
✓
returns nulls when nothing was found 0.2ms
✓
ranks sources jsonld > microdata > text 0.1ms
src/seo/tech-briefs.vitest.ts
Q05 — unverified is not absent · 4 tests
✓
never counts an unchecked URL as one Google refused 24.2ms
✓
the gatherer counts ONLY exact_absent as refused 0.8ms
✓
kills the hypothesis when nothing submitted was refused 0.4ms
✓
finds orphans — in the index, absent from the sitemap 0.3ms
Q05 — the health verdict is a definition, evaluated · 4 tests
✓
is FALSE when submitted far exceeds indexed 0.5ms
✓
is TRUE only when nothing is refused and nothing is broken 2.6ms
✓
NOT HEALTHY and NOT MEASURED are different — null, never false 0.6ms
✓
the ratio threshold is stated, not buried 0.5ms
Q05 — what cannot be seen is named, not dropped · 3 tests
✓
render comparison is always untested — there is no second render to diff 0.8ms
✓
says language-alternate tags are read by nothing available today 0.3ms
✓
never-checked and checked-and-clean do not render alike 0.9ms
Q02 — Impact is measured, never page count · 5 tests
✓
ranks by share of impressions, not by how many pages a crawler flagged 0.7ms
✓
divides by effort, and the weights are stated 0.3ms
✓
halves confidence when the affected pages earn nothing 0.3ms
✓
says Impact is UNKNOWN rather than substituting page count 0.4ms
✓
calls the order PROVISIONAL when a fault survives but impact is unmeasured 0.3ms
Q02 — cosmetic work WAITS, it is not merely ranked lower · 4 tests
✓
holds cosmetic items while a blocking issue exists 0.9ms
✓
a 90%-impact cosmetic item still waits — the rule beats the score 0.2ms
✓
releases cosmetic work only when index is CLEAN and nothing blocks 0.5ms
✓
UNKNOWN is not green — with no index check the hold stays on 0.3ms
Q02 — an unmapped issue code is listed, never dropped · 1 test
✓
keeps it with a readable name and no invented severity 0.4ms
both briefs — the shared rules still hold · 3 tests
✓
no confident verdict on fewer than two sources 0.6ms
✓
every untested hypothesis says what would settle it 0.3ms
✓
no internal vocabulary reaches the reader — GS-005 0.8ms
Q02 and Q05 are reachable and rendered · 5 tests
✓
route on the sentence, and are traceable apart 2.6ms
✓
share ONE gatherer 0.2ms
✓
are built before the empty-evidence gate that swallowed Q14 0.5ms
✓
ONE renderer serves all five briefs 0.7ms
✓
do not steal the tools they sit next to 1.1ms
scripts/lib/commit-diff.vitest.mjs
compareCommitFiles · 7 tests
✓
THE 2026-08-22 INCIDENT: 30 declared, 31 committed 2.4ms
✓
catches the quieter twin: a file you named that never made it in 0.4ms
✓
passes only on an exact match 0.4ms
✓
normalises ./ and trailing slashes rather than reporting them as mismatches 0.3ms
✓
collapses a duplicated declaration instead of failing on it 0.3ms
✓
an EMPTY declaration does not silently pass a real commit 0.2ms
✓
ignores blank and whitespace-only paths in either list 0.3ms
parseNumstat · 4 tests
✓
reads added/deleted counts per file 0.6ms
✓
keeps a binary file as null counts, NOT as zero 0.6ms
✓
returns nothing for empty or non-numstat input rather than inventing rows 0.3ms
✓
handles paths containing spaces 0.4ms
summarise · 2 tests
✓
puts the biggest change first, because the stray hunk is usually the small one 0.3ms
✓
labels binaries instead of printing +null -null 0.1ms
renames · 8 tests
✓
parses the -z rename record as ONE row carrying both names 1.0ms
✓
consumes exactly two extra fields, so neighbours are not swallowed 0.3ms
✓
a pure rename is declared by EITHER name 0.3ms
✓
declaring BOTH names is not a mismatch 0.2ms
✓
declaring NEITHER name still fails, by the real destination path 0.3ms
✓
a rename WITH content edits reports its real line counts 0.8ms
✓
summarise shows both names so a move does not read as a new file 0.2ms
✓
a renamed BINARY file keeps null counts 0.3ms
commits with no renames are unaffected · 3 tests
✓
-z output without any rename parses exactly as the newline form does 0.4ms
✓
plain string entries still work — the old call shape is not broken 0.3ms
✓
a NUL-free stream never enters the -z branch 0.1ms
the caller cannot quietly drop -z · 4 tests
✓
throws on a brace-compressed rename instead of treating it as a path 0.7ms
✓
names the fix in the error, not just the problem 0.3ms
✓
catches the un-braced form too — git omits braces when there is no common prefix 0.2ms
✓
an ordinary path is not mistaken for one 0.4ms
src/admin/readiness-build-band.vitest.ts
G8(a) completeness: the multi form · 6 tests
✓
control: multi with the exact range on a window that spans B0–B4 is complete 2.3ms
✓
REFUSED: 'multi' on a window that lies inside one band 0.5ms
✓
REFUSED: a multi range that is not the range the window spans 0.4ms
✓
REFUSED: a bare 'multi', or the range in any other spelling (the one accepted id is multiBandId's) 0.8ms
✓
the basis says how the band was assigned; a build-id reading of the same span holds too 0.3ms
✓
REFUSED: multi on a window with no since or no days (nothing to check it against) 0.8ms
G8(a) completeness: one named band · 3 tests
✓
control: B4_K2 on a window inside B4 is complete 0.3ms
✓
REFUSED: one band named on a window that spans several (the pooled figure wearing one label) 0.2ms
✓
REFUSED: a band the window does not touch 0.5ms
a multi-band figure cannot score a per-band gate (G1, G2) · 2 tests
✓
a valid multi band is off_scope, naming the pooled range 0.9ms
✓
a band that does not hold is off_scope too 0.3ms
the band table and the helpers the register builder uses · 4 tests
✓
BUILD_BANDS is the P0-07a cut table, in order 0.2ms
✓
bandsSpanned: half-open window against half-open bands; B0 open to the left, B4 to the right 0.3ms
✓
bandForWindow / multiBandId give exactly the form bandProblem accepts 0.6ms
✓
an id the table does not list (a build id) is taken as recorded, as before 0.1ms
the recon seed bands are checked, not trusted · 2 tests
✓
the 7 bounded and 4 all-history production windows carry B0_pre_K1, and each holds against its own window 0.7ms
✓
no P_code seed figure carries a band 0.6ms
declared pooled / all_history / point_in_time (DECISIONS #123) · 9 tests
✓
an explicit pooled population on a bounded, banded window is complete 0.2ms
✓
an absent population still fails 0.1ms
✓
a declared all-history window, banded to the read, is complete 0.2ms
✓
all history read before B1 lies inside B0: multi is refused there, B0_pre_K1 holds 0.2ms
✓
a declared point in time, banded to the band it falls in, is complete 0.2ms
✓
REFUSED: 'multi' on a point in time (an instant lies in one band) 0.2ms
✓
REFUSED: a point in time with no parseable read date 0.2ms
✓
REFUSED: an undeclared window is not all history — absent or false, it still needs days and since 0.2ms
✓
pooled cannot score G1 or G2 0.5ms
the G3(e) seed census carries the sweep that counted it; the two retired ratios are gone · 2 tests
✓
the seven-tool census: P_code at the tree it was counted on, b6f64d8c — complete 0.3ms
✓
the retired demand ratios are not in the seed (G3(e) context is the census alone) 0.3ms
src/campaigns/backlink-wall-clock.vitest.ts
1. one deadline, taken once, spent by every leg · 7 tests
✓
the whole-run deadline fits inside the tool budget with real slack 1.8ms
✓
the deadline is taken ONCE, before any leg spends against it 0.5ms
✓
discovery stops starting new SERP queries past its share 0.3ms
✓
the harvest gets the REMAINDER, not a flat number 0.5ms
✓
a spent budget skips the harvest instead of starting it with nothing left 0.3ms
✓
storage keeps a reserve, so the last leg is not the one that overruns 0.2ms
✓
a budget-truncated run SAYS SO 0.3ms
2. the abort actually cancels something · 4 tests
✓
the shared actor poll honours a signal 0.3ms
✓
apifyDomainContacts accepts one and forwards it to the poll 0.5ms
✓
the dispatch passes the turn signal into BOTH legs 0.3ms
✓
withTimeout still aborts AND rejects — the fix is downstream, not here 0.3ms
3. the budget is measurable now · 3 tests
✓
every tool run records its wall-clock 0.3ms
✓
the duration is on the tool_run marker, beside status 0.4ms
✓
it is a STRING, so a fast run recording 0 survives 0.4ms
the guard now covers the tool it was written for · 2 tests
✓
backlink_outreach_search is in DEADLINES 0.2ms
✓
it still covers the original tool too 0.1ms
the WORK is sized to the budget, not just the clock · 6 tests
✓
derives how many domains the remaining budget can finish 0.1ms
✓
the pick takes the MINIMUM of what was asked, what the plan allows, and what fits 0.1ms
✓
always attempts at least one domain 0.1ms
✓
the harvest budget is computed BEFORE the domain count that depends on it 0.2ms
✓
a clock-capped run says so, and says it DIFFERENTLY from a truncated one 0.2ms
✓
the per-domain estimate is stated as measured, with margin 0.1ms
the Apify sweep: every leg states a bound inside its tool budget · 6 tests
✓
seo_offpage_audit declares a budget instead of inheriting 30s 0.2ms
✓
no longer contains an authority leg to bound 0.3ms
✓
every apifyRunSync leg that remains still fits inside its tool budget 0.3ms
✓
apifyRunSync REQUIRES a wait bound — no default to inherit 0.3ms
✓
every call site passes a bound 0.6ms
✓
the guard asserts the signature BEFORE it decides to pass 0.2ms
src/chat/capability-suite-2026-09-18.vitest.ts
capability suite 2026-09-18 — connector slice · 4 tests
✓
cap-conn-diagnose-nudge: a diagnosis whose gaps are closed by Google carries a Connect Google chip 3.5ms
✓
cap-conn-backlink-value-nudge: "nothing on file" hands the user the scan as a chip 0.3ms
✓
cap-conn-rank-track-nudge: the manual-registration result renders no blank "for :" 4.4ms
✓
cap-list-connectors-direct: dormant connectors (Shopify, Gmail-send) are not in the catalog 1.2ms
capability suite 2026-09-18 — core slice · 11 tests
✓
cap-read-url-nc: a recited INTERNAL refusal is removed whole, and a domain dot is not a sentence end 3.3ms
✓
cap-read-url-direct: the egress fetch identifies itself (Wikipedia answers a bare fetch with 403) 0.3ms
✓
cap-web-search-direct: read_url is told never to guess an address 0.9ms
✓
cap-add-contacts-direct: a saved contact offers the contacts panel and the next use 0.4ms
✓
cap-generate-emails-direct: a named list is a complete draft ask and routes deterministically 38.5ms
✓
cap-generate-emails-nc: nobody named → the lists as a picker, chips carry the names, no parameter names in prose 0.7ms
✓
cap-campaign-stats-nc: a named campaign that does not exist is named back, with the ones that do 1.1ms
✓
cap-create-campaign-direct: a campaign created "for the dentist list" is filled at creation 1.7ms
✓
cap-scan-product-nc: a failed scan offers the saved site as a click 0.2ms
✓
cap-list-contacts-nc: a list that does not exist offers the ones that do as chips 0.3ms
✓
cap-scan-product-nc: a domain that does not resolve is named as such, not as a temporary error 0.4ms
capability suite 2026-09-19 — leads + campaigns slice · 13 tests
✓
cap-enroll-sequence-gate: an enrolment says it is paused, renders verbatim, and offers the start 1.2ms
✓
cap-enrich-direct: "the dentist list" finds the list called dentist 0.6ms
✓
cap-backlink-outreach: a linking-sites ask is not the saved-contacts disambiguation, and preloads leads 4.6ms
✓
cap-pause-nc: pausing with no name lists the campaigns instead of "Campaign not found." 0.9ms
✓
cap-backlinks-nc-own-site: a backlink report on the saved site carries the deep-scan door on its card 0.7ms
✓
cap-keyword-metrics-direct: a search-volume ask preloads seo 0.2ms
✓
cap-find-competitors-direct / cap-competitor-gap-nc-own-site: platforms are screened before display; the own-site gap is a stop with chips 1.6ms
✓
cap-sov-weekly-commit: switching weekly tracking on is a two-step confirm with the quote, never a same-turn write 14.3ms
✓
cap-aeo-visibility-selector: "check my AI visibility" reaches the AEO shortcut — the classifier calls the same ask aeo_check 4.9ms
✓
cap-aeo-visibility-nc-cited: an adverb between the engine and the verb still reads as a visibility ask 0.6ms
✓
cap-aeo-visibility-nc-cited (second run): "backlink tools" in a visibility question is not a second request 0.5ms
✓
jev-content-fact-check: "write a 700-word article about <topic>" reaches the writer deterministically 6.7ms
✓
cap-aeo-visibility-card-not-now: the engine picker's Run message is a protocol message — its prompts payload is never read as a question 1.1ms
src/chat/false-shortfall.vitest.ts
parseTokenFigure · 2 tests
✓
reads the three shapes the agent writes 2.1ms
✓
returns null rather than a wrong number on junk 0.4ms
assertedBalances — against the real sentences · 9 tests
✓
finds 666,139 in production message 0 1.3ms
✓
finds 666,139 in production message 1 0.5ms
✓
finds 666,139 in production message 2 0.3ms
✓
finds 666,139 in production message 3 0.2ms
✓
finds 666,139 in production message 4 0.3ms
✓
finds 666,139 in production message 5 0.2ms
✓
does NOT mistake the price for the balance 0.7ms
✓
ignores small numbers that are counts, not balances 1.0ms
✓
finds nothing in a reply that asserts no balance 0.2ms
contradictsLedger · 5 tests
✓
FIRES on the incident: 666,139 claimed against a real 1,538,869 0.5ms
✓
stays QUIET when the refusal is honest — the figure matches the ledger 0.2ms
✓
tolerates rounding — "about 1.5M" against 1,538,869 is not a lie 0.2ms
✓
stays quiet when the balance read FAILED — we have nothing to contradict 0.2ms
✓
stays quiet on a reply that quotes no balance at all 0.1ms
redactStaleBalances — stopping the number compounding · 4 tests
✓
removes the figure from every real sentence 0.6ms
✓
leaves the PRICE intact — a quoted cost is not a balance 0.2ms
✓
leaves a reply with no balance completely untouched 0.1ms
✓
a redacted message no longer contradicts the ledger — the loop is broken 0.3ms
redactHistoryForModel · 4 tests
✓
cleans assistant turns and leaves USER turns exactly as typed 0.2ms
✓
returns untouched messages BY REFERENCE so a clean turn allocates nothing 0.2ms
✓
handles the full six-message poisoned history 0.2ms
✓
survives a malformed entry rather than throwing mid-turn 0.8ms
wired into the chat loop · 4 tests
✓
the model's copy of history is redacted before the model sees it 0.4ms
✓
does NOT redact on the way to storage 0.8ms
✓
the false-balance probe runs against the turn balance 0.8ms
✓
the balance read reports its failure instead of swallowing it 1.0ms
src/email/suppression-ledger.vitest.ts
suppressionKey — the TS half of the key contract · 18 tests
✓
has a real population of shared cases 1.8ms
✓
"bob@example.com" -> "bob@example.com" 0.5ms
✓
" Bob@Example.COM\t" -> "bob@example.com" 0.2ms
✓
"bob+newsletter@example.com" -> "bob@example.com" 0.2ms
✓
"bob+a+b@example.com" -> "bob@example.com" 0.2ms
✓
"b.o.b@example.com" -> "b.o.b@example.com" 0.2ms
✓
"B.O.B+x@Gmail.com" -> "bob@gmail.com" 0.2ms
✓
"b.o.b@googlemail.com" -> "bob@gmail.com" 0.1ms
✓
"first.last@sub.example.co.uk" -> "first.last@sub.example.co.uk" 0.5ms
✓
"\"weird@local\"@example.com" -> "\"weird@local\"@example.com" 0.3ms
✓
"+tag@example.com" -> "@example.com" 0.2ms
✓
"no-at-sign" -> "no-at-sign" 0.1ms
✓
"\n bob@example.com \r\n" -> "bob@example.com" 0.1ms
✓
"ÉLODIE@example.com" -> "Élodie@example.com" 0.1ms
✓
null and undefined have no key 0.2ms
✓
the SQL twin uses the same transforms (trim set, ASCII-only lowercasing, +tag, Gmail fold) 0.4ms
suppressionVerdict — one address's rows, in insertion order · 6 tests
✓
no rows, or only a clear, is not suppressed 0.3ms
✓
unsubscribe, complaint and hard bounce each block, and nothing clears them 0.2ms
✓
invalid blocks until a LATER verification clears it, and a later invalid blocks again 0.2ms
✓
the reason the recipient chose wins the message 0.2ms
✓
a reason this code does not know blocks (fails closed) 0.2ms
✓
every refusal is a sentence that names no vendor and no dollar 0.6ms
the send_emails preview counts a ledger-suppressed recipient, exactly as the send loop skips it · 2 tests
✓
a clean row whose address is on the ledger is blocked 1.1ms
✓
the loop's skip and the assessor's count read the same three facts 1.1ms
src/index.ts sites (not importable under vitest — pinned by wiring) · 2 tests
✓
handleSendSingleEmail reads the ledger and cancels a suppressed draft with the refusal sentence 1.1ms
✓
"mark unsubscribed" also writes the ledger, and says so when that write fails 0.5ms
src/routes/waitlist-retired.vitest.ts
every retired waitlist URL answers 410 Gone and does no work · 10 tests
✓
GET /waitlist is a static 410 page that reads nothing 25.6ms
✓
GET /waitlist/ is a static 410 page that reads nothing 2.6ms
✓
HEAD /waitlist is a static 410 page that reads nothing 1.9ms
✓
HEAD /waitlist/ is a static 410 page that reads nothing 2.0ms
✓
POST /api/waitlist/signup answers 410 before touching Hasura, KV, the verifier or the mailer 5.3ms
✓
GET /api/waitlist/leaderboard?limit=100 answers 410 before touching Hasura, KV, the verifier or the mailer 1.9ms
✓
GET /api/waitlist/me?code=ABCDEFGH answers 410 before touching Hasura, KV, the verifier or the mailer 1.6ms
✓
GET /api/waitlist/me?email=victim%40example.com answers 410 before touching Hasura, KV, the verifier or the mailer 3.5ms
✓
GET /api/waitlist answers 410 before touching Hasura, KV, the verifier or the mailer 9.1ms
✓
PUT /api/waitlist/anything-else answers 410 before touching Hasura, KV, the verifier or the mailer 1.7ms
the admin waitlist endpoint is retired as well · 4 tests
✓
POST /api/admin/waitlist answers 410 and touches nothing, even for an authenticated admin 1.9ms
✓
GET /api/admin/waitlist?view=list answers 410 and touches nothing, even for an authenticated admin 1.2ms
✓
GET /api/admin/waitlist?view=metrics answers 410 and touches nothing, even for an authenticated admin 1.5ms
✓
an anonymous caller gets the same 410, and no data 2.6ms
the */15 waitlist reconcile cron is retired · 2 tests
✓
is no longer registered in wrangler.toml 1.9ms
✓
a stray */15 tick does nothing — not the waitlist reconcile, and not the hourly fallback either 2.9ms
the waitlist emails cannot be sent by any path · 8 tests
✓
none of the three is a registered template 0.9ms
✓
a template send of waitlist_confirmation is refused with no call 0.7ms
✓
a raw send of waitlist_confirmation is refused with no call 0.9ms
✓
a template send of waitlist_referred_notice is refused with no call 2.8ms
✓
a raw send of waitlist_referred_notice is refused with no call 0.4ms
✓
a template send of waitlist_access_granted is refused with no call 0.5ms
✓
a raw send of waitlist_access_granted is refused with no call 0.5ms
✓
a stored pre-retirement waitlist email is not resent: one lookup, no write, no provider call 2.0ms
discovery surfaces no longer advertise /waitlist · 1 test
✓
sitemap, llms.txt and llms-full.txt 2.7ms
the waitlist data is KEPT — no migration drops it · 3 tests
✓
reads a real population 0.7ms
✓
no migration drops, truncates, deletes from, renames or untracks a waitlist table 33.9ms
✓
the schema snapshot still carries all three tables 0.5ms
src/runtime/deploy-path-guard.vitest.ts
a response that cannot name its own build cannot verify a deploy · 4 tests
✓
passes on the current tree 45.9ms
✓
catches the SSE terminal frame losing its build id 105.1ms
✓
catches the shared json() helper losing its build id 101.3ms
✓
refuses to scan nothing — a lost matcher is not a pass 102.2ms
one resolver for both CI providers · 3 tests
✓
passes on the current tree 47.5ms
✓
catches the Workers Builds sha being dropped 93.2ms
✓
catches the Actions path ceasing to use the same resolver 93.8ms
the build time is read, never invented · 2 tests
✓
catches a fallback to the current time 95.7ms
✓
catches the committer date being swapped for the author date 97.9ms
the cutover switch, and the skip that strands a Worker · 2 tests
✓
catches a deployer switch being removed 95.9ms
✓
catches deploy-admin depending on `deploy` alone — the skip-strands-a-Worker trap 95.7ms
a retry is the same deployer, never a second one · 5 tests
✓
catches the retry pushing a commit to provoke a rebuild 97.5ms
✓
catches the retry deploying on its own 94.5ms
✓
catches the Workers Builds trigger endpoint disappearing 95.3ms
✓
catches the rollback refusal being unwired 95.8ms
✓
is not fooled by the forbidden shapes named in a comment 95.0ms
merged is not live — pr:merge keeps watching the deploy · 3 tests
✓
catches the post-merge verifyCommit() call being deleted 96.0ms
✓
a call left only in a comment does not count 98.0ms
✓
catches the merge itself disappearing from where the guard looks — blind is a failure, not a pass 96.6ms
the path no npm script can guard · 2 tests
✓
catches postinstall dropping the wrangler shim installer 94.0ms
✓
both guards are wired into the gate 0.4ms
the deploy never re-runs the test suite (DECISIONS #108) · 7 tests
✓
catches the report step running vitest again — the exact pre-fix line 93.8ms
✓
catches a module the report imports starting the suite through npm 99.9ms
✓
catches `npm test` added to the deploy script chain itself 95.4ms
✓
a vitest run named only in a comment is not an invocation 98.2ms
✓
catches the PR check job no longer uploading the results the deploy reads 96.5ms
✓
catches vitest.config.ts losing the JSON hook 97.8ms
✓
catches the Actions deployer no longer handing the step its token 97.3ms
src/runtime/zero-yield.vitest.ts
resultYield · 3 tests
✓
reads the common count and array shapes 2.2ms
✓
returns null — not zero — when it cannot tell 0.6ms
✓
refuses to read a yield from a run that never delivered 0.4ms
the breaker · 9 tests
✓
opens on the Nth consecutive measured zero, and not before 0.9ms
✓
would have stopped the 2026-07-29 incident at the threshold 0.4ms
✓
resets completely on any successful run 0.4ms
✓
re-closes once a run delivers again 0.3ms
✓
reports the trip ONCE, not on every subsequent refusal 0.2ms
✓
never counts a null reading toward the streak 0.6ms
✓
does nothing for a tool that is not armed 0.3ms
✓
is inactive when KV is unbound, like every other gate here 0.3ms
✓
names the operation, never the provider 0.5ms
an async run in flight is not a yield measurement · 2 tests
✓
returns null while the provider run is still in flight 0.2ms
✓
still measures a completed run honestly, including a real zero 0.2ms
resultYield reads the SEO shapes, not just the outbound ones · 11 tests
✓
measures an empty keywords result as 0, not as "no reading" 0.2ms
✓
measures an empty competitors result as 0, not as "no reading" 0.1ms
✓
measures an empty gaps result as 0, not as "no reading" 0.1ms
✓
measures an empty ideas result as 0, not as "no reading" 0.1ms
✓
measures an empty pages result as 0, not as "no reading" 0.1ms
✓
measures an empty issues result as 0, not as "no reading" 0.1ms
✓
measures an empty backlinks result as 0, not as "no reading" 0.1ms
✓
counts a non-empty SEO result 0.1ms
✓
still returns null for a shape it was never taught 0.1ms
✓
does not disturb the existing precedence 0.2ms
✓
arms no new circuit breaker 0.6ms
an honest SEO zero is expected, not a Sentry fault · 1 test
✓
classifies the zero-yield phrase as an expected outcome 1.0ms
a verify that had nothing to check is not a zero · 2 tests
✓
nothing_to_check → null (no reading) 0.1ms
✓
(neg) a run that asked and got no verdict is still a real zero 0.1ms
src/tools/outbound-wave8.vitest.ts
zero-argument tools reject invented narrowing · 8 tests
✓
list_campaigns accepts the empty call 2.0ms
✓
list_sequences accepts the empty call 0.2ms
✓
list_connectors accepts the empty call 0.2ms
✓
show_marketing_plan accepts the empty call 0.2ms
✓
list_campaigns rejects an invented filter instead of ignoring it 0.4ms
✓
list_sequences rejects an invented filter instead of ignoring it 0.3ms
✓
list_connectors rejects an invented filter instead of ignoring it 0.3ms
✓
show_marketing_plan rejects an invented filter instead of ignoring it 0.2ms
the three undeclared aliases · 3 tests
✓
campaign_stats takes campaign, not name 1.0ms
✓
set_standing_instruction takes text, not instruction 0.3ms
✓
backlink_outreach_search takes topic, not query 0.3ms
create_marketing_plan — declared, and genuinely read · 2 tests
✓
accepts both fields the callee consumes 0.2ms
✓
constrains horizon to the values the implementation honours 0.7ms
create_sequence keeps its typed step item · 3 tests
✓
accepts a well-formed step 0.4ms
✓
still requires a name 0.1ms
✓
accepts omitted steps — they are generated from the brief 0.1ms
connect_connector · 2 tests
✓
takes a known connector 0.1ms
✓
rejects an unknown one rather than opening a panel for nothing 0.2ms
the dispatch no longer reads what it does not declare · 4 tests
✓
campaign_stats no longer coalesces name 0.3ms
✓
set_standing_instruction no longer coalesces instruction 0.1ms
✓
backlink_outreach_search no longer coalesces query 0.1ms
✓
leaves the unregistered delete_campaign its fallback 0.1ms
the migration is complete outside commerce · 3 tests
✓
every tool is still registered 0.9ms
✓
NOTHING remains unschematised — the last 7 went by deregistration, not migration 0.3ms
✓
the drift ledger holds nothing but the verified dormant entry 0.9ms
typed object items in arrays · 3 tests
✓
enforces the item required-fields, not just the item type 0.2ms
✓
rejects a non-object element 0.1ms
✓
still validates string-item arrays the old way 0.2ms
src/seo/brand-platform-name.vitest.ts
the generator rule — evidence from the page, not a list · 4 tests
✓
rejects the exact page that produced the incident 3.0ms
✓
needs no entry for the NEXT builder 1.3ms
✓
does NOT reject a real brand merely because a generator is present 0.5ms
✓
falls through to a better tier rather than giving up 0.3ms
the platform denylist — for builders that set no generator · 15 tests
✓
rejects Hostinger Horizons as a whole-string brand 0.2ms
✓
rejects Wix as a whole-string brand 0.2ms
✓
rejects Squarespace as a whole-string brand 0.2ms
✓
rejects Shopify as a whole-string brand 0.1ms
✓
rejects Webflow as a whole-string brand 0.5ms
✓
rejects WordPress as a whole-string brand 0.2ms
✓
rejects Blogger as a whole-string brand 0.2ms
✓
rejects Weebly as a whole-string brand 0.1ms
✓
rejects Carrd as a whole-string brand 0.1ms
✓
rejects Linktree as a whole-string brand 0.1ms
✓
rejects GoDaddy as a whole-string brand 0.1ms
✓
rejects Facebook as a whole-string brand 0.1ms
✓
rejects Instagram as a whole-string brand 0.1ms
✓
rejects LinkedIn as a whole-string brand 0.1ms
✓
catches the Facebook case with no generator present 0.2ms
real brands that merely CONTAIN a platform word — the discipline of this file · 9 tests
✓
keeps Wix Filtration Products 0.1ms
✓
keeps Shopify Plus Agency 0.1ms
✓
keeps WordPress Maintenance Co 0.1ms
✓
keeps Facebook Marketing Partners LLC 0.1ms
✓
keeps Squarespace Circle Consultants 0.1ms
✓
keeps Hostinger Reseller Group 0.1ms
✓
keeps X-Ray Diagnostics 0.1ms
✓
keeps Blogger Outreach Ltd 0.1ms
✓
names with a plausible non-platform reading are deliberately NOT listed 0.2ms
scripts/lib/version-order.vitest.mjs
version-order — the bug this replaces · 3 tests
✓
rejects the exact pair the old inequality certified 2.1ms
✓
still rejects an unchanged version, which inequality also caught 0.4ms
✓
accepts a genuine forward move 1.0ms
version-order — numeric, never lexicographic · 2 tests
✓
compares each component as a number, where string comparison gets it wrong 0.3ms
✓
orders across every component 0.2ms
version-order — unreadable input is not a pass · 7 tests
✓
returns null / not-forward for 2.491 vs 2.491.0 0.2ms
✓
returns null / not-forward for v2.491.0 vs 2.491.0 0.2ms
✓
returns null / not-forward for vs 2.491.0 0.2ms
✓
returns null / not-forward for null vs 2.491.0 0.5ms
✓
returns null / not-forward for 2.491.0 vs undefined 0.2ms
✓
returns null / not-forward for 2.a.0 vs 2.491.0 0.2ms
✓
names it unreadable rather than calling it backwards 0.1ms
parseVersion · 1 test
✓
parses three plain integers and nothing else 0.4ms
version-order — the four merge cases · 2 tests
✓
row 4 — branch bumped against a quiet main — is HEALTHY and clean 0.1ms
✓
row 3 — both sides landed on the same number — is a FAILURE despite merging clean 0.1ms
isReleaseWorthy — a test file is not a release · 4 tests
✓
counts shipped code 0.4ms
✓
does NOT count tests, even under client/ and src/ 0.2ms
✓
does not count docs, scripts or CI 0.2ms
✓
is safe on empty input 0.1ms
bumpVersion · 3 tests
✓
moves the component it is asked to move and zeroes the ones below 0.2ms
✓
carries past 9 rather than wrapping — the repo lives at 2.6xx with two-digit patches 0.1ms
✓
returns null rather than a plausible string on bad input 0.2ms
allocateVersion — the collision this repo actually had · 5 tests
✓
two branches from the same base no longer compute the same number 0.5ms
✓
bumps from the BRANCH when the branch is the one that is ahead 0.3ms
✓
never returns a number that is behind either side 0.3ms
✓
refuses rather than guessing when either side is unreadable 0.3ms
✓
crosses a minor boundary correctly when main has moved a long way 0.2ms
src/admin/llm-price-drift.vitest.ts
under_priced — reported ÷ table (raw) above 1.15, on enough traffic to mean it · 3 tests
✓
fires at ratio 1.2 with n=25 and $0.02 predicted 2.6ms
✓
does not fire at n=19 0.3ms
✓
does not fire at $0.009 predicted 0.2ms
rising / falling — cache-adjusted recent ÷ baseline · 4 tests
✓
a hit rate moving 34% → 68% at an UNCHANGED price fires neither rule 0.5ms
✓
1.2x the baseline effective price is rising 1.1ms
✓
a model with no prompt-cache rows in a window reads 0% and says so 0.4ms
cache 'unavailable' · 1 test
✓
skips the rising/falling rules, records why, and still evaluates under_priced 0.6ms
unpriced and stale_table · 2 tests
✓
unpriced fires for an estimated-row model the table does not know, and only for it 0.5ms
✓
stale_table fires at VERIFIED_AT + 46 days and not at + 44 0.4ms
the ledger query · 3 tests
✓
excludes free (0/0) entries and TypeSafe models 1.1ms
✓
filters reported openrouter rows, one recent/prior/baseline alias triple per model 1.7ms
✓
carries the tenant-scope marker within 12 lines above the admin call 0.4ms
backtest — deepseek and gemini from bt1.json (2026-09-24, table as shipped) · 1 test
✓
produces no under_priced finding 0.4ms
runLlmPriceDriftCron — outputs · 7 tests
✓
rising is an Issue fingerprinted per model and kind, plus a ledger row and a summary 3.1ms
✓
falling is a Log only — reportError is never called 0.8ms
✓
an Analytics Engine failure still evaluates under_priced and reports cache unavailable 1.8ms
✓
a quiet day still writes the summary — "looked, found nothing" is not "did not look" 0.8ms
✓
every run writes exactly one heartbeat row, a quiet day included 0.6ms
✓
the heartbeat counts the findings and Issues of the run it closes 0.7ms
✓
a ledger read that fails throws, so the check-in records the error 2.0ms
review — persistence and holds decide Issue vs Log · 6 tests
✓
under_priced in the recent week only is a watch Log, never an Issue 0.9ms
✓
under_priced in the recent AND the prior week is an Issue 0.6ms
✓
a HELD model never raises an Issue, even persistent (llama 1.55 then 1.33) 0.9ms
✓
gemini-shaped rising (recent 0.99, prior 0.85, baseline 0.82 at h=0.3) is a watch Log, not an Issue 1.1ms
✓
rising in both the recent and the prior week is an Issue 0.8ms
✓
stale_table names the command that actually moves VERIFIED_AT, and says it merges in a PR 0.5ms
src/chat/table-columns.vitest.ts
classifyColumn · 5 tests
✓
needs EVERY cell to parse, not most 2.6ms
✓
ignores empty cells when deciding, but not when they are all there is 0.4ms
✓
calls a column prose only when it is genuinely paragraphs 0.5ms
✓
does not mistake a percentage or a thousands separator for text 0.2ms
✓
only calls a column url when every cell is an absolute url 0.2ms
compareCells · 4 tests
✓
sinks empty cells in BOTH directions 0.4ms
✓
orders numbers numerically, not lexically 7.3ms
✓
is case-insensitive on text, so Acme and acme do not split the sort 0.2ms
✓
reverses on descending 0.6ms
numericValue · 2 tests
✓
strips separators and percent signs 0.3ms
✓
sorts unparseable values to the bottom rather than to zero 0.2ms
chat table sorting binds to live column position · 3 tests
✓
has a makeSortable to check 0.1ms
✓
reads th.cellIndex at click time 0.2ms
✓
does not address rows through the captured loop index 0.2ms
statusTone — a pill that lies about a verdict is worse than no pill · 4 tests
✓
reads the many words a dozen tools use for the same verdict 0.5ms
✓
is NEUTRAL on anything it does not recognise, never a guess 0.2ms
✓
never confuses the two halves of a catch-all 0.6ms
✓
styles every verdict entity_audit issues 0.3ms
classifyColumn — status is inferred, severity never is · 4 tests
✓
infers a status column so a MODEL-authored table gets pills too 0.2ms
✓
requires EVERY cell to be a known verdict — one stranger and it is text 0.2ms
✓
NEVER infers severity — high is bad here and good in an authority column 1.7ms
✓
does not steal a column that a stronger kind already claims 0.1ms
severityTone — a separate vocabulary, because "high" means both things · 5 tests
✓
ranks severity words 0.5ms
✓
does NOT leak severity into the status vocabulary 0.1ms
✓
dispatches on the DECLARED kind, not the word 0.2ms
✓
sorts severity by RANK, never alphabetically 0.4ms
✓
sinks an unknown severity below every known one instead of guessing a rank 0.2ms
src/connectors/oauth-state-binding.vitest.ts
google: the connect state is bound to the browser that started it · 6 tests
✓
a normal flow still connects — start sets a short-lived HttpOnly, SameSite=Lax binding cookie and the callback saves under the starter 46.6ms
✓
a state started by user A, completed in a browser WITHOUT A's cookie, saves nothing and never redeems the code 7.1ms
✓
…nor in a browser holding a DIFFERENT session's binding cookie for the same flow 4.5ms
✓
a replayed state is refused — the first callback connects, the second saves nothing 10.3ms
✓
an expired state is refused, even from the browser that started it 3.9ms
✓
a restarted flow connects (re-connect is not broken by the binding) 4.9ms
notion: the connect state is bound to the browser that started it · 6 tests
✓
a normal flow still connects — start sets a short-lived HttpOnly, SameSite=Lax binding cookie and the callback saves under the starter 3.6ms
✓
a state started by user A, completed in a browser WITHOUT A's cookie, saves nothing and never redeems the code 3.8ms
✓
…nor in a browser holding a DIFFERENT session's binding cookie for the same flow 3.1ms
✓
a replayed state is refused — the first callback connects, the second saves nothing 2.9ms
✓
an expired state is refused, even from the browser that started it 2.1ms
✓
a restarted flow connects (re-connect is not broken by the binding) 3.4ms
shopify: the connect state is bound to the browser that started it · 6 tests
✓
a normal flow still connects — start sets a short-lived HttpOnly, SameSite=Lax binding cookie and the callback saves under the starter 7.4ms
✓
a state started by user A, completed in a browser WITHOUT A's cookie, saves nothing and never redeems the code 3.1ms
✓
…nor in a browser holding a DIFFERENT session's binding cookie for the same flow 6.9ms
✓
a replayed state is refused — the first callback connects, the second saves nothing 4.4ms
✓
an expired state is refused, even from the browser that started it 2.1ms
✓
a restarted flow connects (re-connect is not broken by the binding) 4.0ms
a state that never expired (the NaN timestamp) is refused · 2 tests
✓
google: a 30-day-old "uid:shop:ts" state saves nothing 9.7ms
✓
notion: a 30-day-old "uid:shop:ts" state saves nothing 0.9ms
a state minted for one flow is refused by another · 1 test
✓
a Notion state — with Notion's own binding cookie — does not connect Google 3.8ms
admin GSC: the connect state is bound to the admin's browser · 3 tests
✓
a normal flow still connects — the cookie reaches the shared callback on the app host 4.3ms
✓
completed in a browser without the admin's cookie, it saves nothing 2.4ms
✓
a replayed admin state is refused 2.6ms
admin GA4: the connect state is bound to the admin's browser · 3 tests
✓
a normal flow still connects — the cookie reaches the shared callback on the app host 6.9ms
✓
completed in a browser without the admin's cookie, it saves nothing 4.1ms
✓
a replayed admin state is refused 7.8ms
src/seo/docs-citation.vitest.ts
ownPageKind — a path heuristic that admits what it cannot tell · 3 tests
✓
recognises the shelves docs actually live on 2.3ms
✓
recognises the marketing site, including the root 0.8ms
✓
an unrecognised path is UNKNOWN, never quietly counted as marketing 0.2ms
ownCitedPages — OURS only · 2 tests
✓
classifies our pages and ignores everyone else's 0.4ms
✓
keeps sample URLs so the classifier can be audited against the reader's own IA 0.8ms
retrievalBlockers · 2 tests
✓
keeps only failures that would stop a bot READING the page 0.4ms
✓
a passing check is never a blocker 0.9ms
what it can answer WITHOUT a docs panel · 3 tests
✓
names marketing-instead-of-docs when every quoted page of ours is marketing 0.5ms
✓
kills it when documentation IS reaching the answer 0.6ms
✓
reports bot-access blockers from the crawl alone 0.4ms
what it REFUSES to answer without a docs panel · 4 tests
✓
will not judge constrained how-to prompts from a buyer panel 0.4ms
✓
distinguishes a docs panel that is CONFIGURED but unmeasured from one that does not exist 0.3ms
✓
answers it once the docs panel HAS been measured 0.3ms
✓
page SHAPE and versioned canonicals stay untested — nothing here reads a page 0.3ms
no citations of ours is not a finding about documentation · 2 tests
✓
does not claim marketing is being cited instead 0.2ms
✓
the situation line says the run quoted nothing of ours 0.1ms
the brief holds the contract · 3 tests
✓
owns a headline and the one-pager fields 0.4ms
✓
names no tool or field name in a claim 0.4ms
✓
an ungrounded run is labelled as recall 0.2ms
Q16 and Q14 are wired everywhere a brief has to be wired · 8 tests
✓
Q16: dispatcher builds it and it is in the answer chain 0.4ms
✓
Q16: in BOTH payload lists 0.2ms
✓
Q16: routed and labelled in the turn 0.2ms
✓
Q16: rendered before the incident fallback 0.4ms
✓
Q14: dispatcher builds it and it is in the answer chain 0.3ms
✓
Q14: in BOTH payload lists 0.2ms
✓
Q14: routed and labelled in the turn 0.2ms
✓
Q14: rendered before the incident fallback 0.3ms
src/leads/shared/email-pattern-lead.vitest.ts
a constructed address is priced down, never at the verified rate · 3 tests
✓
sells at the unverified tier 2.3ms
✓
is a QUARTER of a verified lead, not a whole one 0.5ms
✓
never claims the verified tier 0.8ms
provenance keeps a guess apart from an observation · 3 tests
✓
travels as its own source, not as corpus 0.4ms
✓
never claims a verified status 0.3ms
✓
is spelled out for the reader, because "unverified" is the same word for both 0.7ms
the address is built from normalized_name, and only when the name can carry the shape · 3 tests
✓
applies the pattern 0.6ms
✓
returns null for a name that cannot be split — a mononym or an initial 0.3ms
✓
returns null for a shape it does not know 0.5ms
the corpus call · 7 tests
✓
is a MUTATION and passes args as the generated wrapper, not raw jsonb 0.5ms
✓
asks for BOTH floors, and they are stricter than the inference pass stores at 0.3ms
✓
the evidence floor is not redundant with confidence 0.3ms
✓
sends the confidence floor and de-duplicates the ids 0.8ms
✓
drops a row the corpus returned without every ingredient 0.3ms
✓
returns nothing rather than throwing when the corpus cannot answer 1.1ms
✓
makes no round trip for an empty id list 0.5ms
disclosure is ledgered before it is charged · 7 tests
✓
bills once and reports the disclosure 1.2ms
✓
does NOT bill a repeat — the ledger row carries a revealed_at we did not just write 0.4ms
✓
delivers NOTHING when the ledger write returns no row — an unrecorded sale cannot be refunded 0.4ms
✓
records what produced the address, so a bad pattern is findable from its refunds 0.3ms
✓
is idempotent on the PERSON, not the address — the same human must not be sold twice 0.3ms
✓
uses a no-op update on conflict, because DO NOTHING returns no row 0.5ms
✓
does not charge when billing is disarmed, but still ledgers the disclosure 0.5ms
the corpus refuses to shadow a real address, and says so in SQL · 4 tests
✓
enforces the evidence floor in the RPC, not only in the caller 0.4ms
✓
excludes anyone holding an active business email 0.3ms
✓
treats a consumer mailbox as NOT a business address 0.2ms
✓
is VOLATILE, so Hasura exposes it under mutation_root like every other corpus RPC 0.2ms
src/leads/shared/search.vitest.ts
shared catalog search · 20 tests
✓
runs the vector stage for a TITLES-ONLY request (no query text) 5.0ms
✓
with neither query nor titles, only the browse branch runs 0.6ms
✓
ranks deterministically using the versioned hybrid weights 7.4ms
✓
unions duplicate retrieval candidates by canonical entity and retains signals/citations 1.4ms
✓
never exposes mutable facts without their field citation 1.0ms
✓
falls back to exact and lexical candidates when vector retrieval fails 1.0ms
✓
runs all three stages concurrently, not sequentially — a hung stage never blocks the others 30.7ms
✓
a throwing exact stage degrades on its own, without taking down lexical/vector 0.6ms
✓
skips the exact stage on prose — it cannot match, and it costs a 12.6M-row scan 0.7ms
✓
still runs exact for the shapes it CAN match 0.4ms
✓
the empty-query browse path still reaches exact — that is a different branch entirely 0.3ms
✓
vector is ON now that the corpus is embedded and 087 gave the function a real branch 0.1ms
✓
SKIPS vector — not degrades it — when the caller injects no embedder 0.3ms
✓
DEGRADES vector when the embedder is present but cannot answer 0.4ms
✓
does NOT fall back to trigram retrieval when the embedding is unavailable 0.3ms
✓
sends the embedding and K to the RPC, and only on the vector stage 0.4ms
✓
a slow embedder degrades the vector stage without delaying the others 20.3ms
✓
a SKIPPED stage is not a DEGRADED one 0.3ms
✓
uses an injected parameterized RPC contract and forces US/policy inputs 0.3ms
✓
filters non-US, disallowed sources, suppressed entities, and invalid identifiers defensively 0.5ms
the lexical stage yields once the other stages have filled the ask · 4 tests
✓
supersedes a lexical stage still running after the grace when vector already filled the ask 21.1ms
✓
waits for lexical in full when the other stages came back short 120.0ms
✓
keeps a lexical stage that finished inside the grace 4.8ms
✓
lexicalGraceMs: null restores the full wait regardless 121.4ms
a titles-only request does not wait for the browse-by-filters scan once vector has filled the ask · 3 tests
✓
supersedes a slow exact stage on the browse branch (no free text) 21.0ms
✓
a domain query still waits for exact in full — there it is the indexed, authoritative stage 120.0ms
✓
a browse request whose vector stage came back short waits for exact in full 120.6ms
src/chat/block-guard.vitest.ts
guardBlocks: each cell is read like the reply, and the row stays · 10 tests
✓
a supplier's name, a price and a "free" claim are rewritten in their cell; every other cell is untouched 5.4ms
✓
a key or the canary withholds the WHOLE cell, never part of it, and is reported as blocked 1.0ms
✓
a cell that WAS an internal directive is withheld, not filled with the guardrail's "ask again" sentence 0.6ms
✓
a number is never read as text, whatever its column's costume says 0.5ms
✓
a currency costume on a block that may not show currency withholds its numbers and is reported as copy 0.7ms
✓
the block's own tool decides the currency exemption alongside the exit's (the DATA, not the last tool) 0.4ms
✓
a label the guardrail alters is product copy: changed, and reported as a copy bug 0.4ms
✓
the scope line is read too, and counted apart: nothing draws it, so it is never stated 0.4ms
✓
the provenance never ships, and anything that is not a records block is dropped 0.7ms
✓
a clean block comes back as it was, with nothing counted 0.4ms
only the vendor check is lifted, and only for a cell that IS the tenant's · 6 tests
✓
a record: the name shows; the same name in an undeclared column does not 0.7ms
✓
a price inside the tenant's record is still redacted; a key inside it still withholds the cell 0.3ms
✓
a site: the tenant's only when it is their own saved site 0.7ms
✓
a model's words: the person's only when they typed the whole cell 1.1ms
✓
a forged placeholder in a tenant cell exempts nothing, and is not counted as the exemption 0.9ms
✓
a tenant span in the scope line keeps the vendor exemption there too 0.3ms
blockGuardNote: what the check did, in counts, never silent · 1 test
✓
names counts and where, and says nothing when nothing a person can see changed 0.4ms
blockOwners / withBlockProvenance: the presenter's own build pins the tenant's columns · 9 tests
✓
contacts: name, title, company and address are the contacts row; the status column is ours 1.4ms
✓
the send log: the recipient and the campaign are the tenant's, the subject a model wrote is not, and the scope's filter is the person's only if typed 1.1ms
✓
a saved sequence is the tenant's; a lead from the shared corpus is not anyone's record 0.8ms
✓
a page on the tenant's site is a SITE column: theirs only when it is their own saved site 0.5ms
✓
a tool with nothing declared still records whose data the block is (its tool), with no columns 0.2ms
✓
FAIL-SAFE: a presenter that composes, sorts or branches on the value pins nothing; a probe that throws pins nothing 7.9ms
✓
a column that mixes a declared value with our own copy pins nothing 0.2ms
✓
a column that mixes two parts pins nothing: one column, one part 0.4ms
✓
every declared part says whose it is, where it lives, and — once saved — which count proves it 0.5ms
src/chat/delivery-verdict.vitest.ts
judgeDelivery — the real call, Jev mocked at fetch · 5 tests
✓
returns the choice and its confidence 28.3ms
✓
not rolled out → null, Jev not called 1.4ms
✓
Jev failing → null, and reported 1.0ms
✓
an answer with no confidence is a failure, never a silent clamp 0.7ms
✓
an unknown choice is "other" and never clamps 1.0ms
the clamp — only a confident generic / nothing moves a score · 12 tests
✓
generic @ 0.9 → clamps=true 0.4ms
✓
nothing @ 0.85 → clamps=true 0.3ms
✓
generic @ 0.79 → clamps=false 0.2ms
✓
nothing @ 0.46 → clamps=false 0.5ms
✓
one_question @ 1 → clamps=false 0.3ms
✓
pending_decision @ 1 → clamps=false 0.3ms
✓
honest_empty @ 1 → clamps=false 0.2ms
✓
delivered @ 1 → clamps=false 0.2ms
✓
null (Jev off or failed) → the judge stands 0.3ms
✓
THE BUG: a generic reply the judge scored 1.00 is capped 0.2ms
✓
never raises a score 0.3ms
✓
a clamped verdict says why; the ledger carries every verdict, clamped or not 0.5ms
the question · 2 tests
✓
is a choice with a criteria MAP over exactly the six shapes (an array is a 422) 0.5ms
✓
the state carries observations, not a verdict 0.3ms
wiring in src/index.ts · 4 tests
✓
conversation turns only, reported on failure, run beside the judge 0.5ms
✓
BOTH judge paths clamp, prefix the reasoning and name the failure — one rule, two branches 1.0ms
✓
the website field is shown to the judge, from both producers of it 0.5ms
✓
the context is rolled out 0.6ms
the delivery call is metered to the turn it judged · 3 tests
✓
with a meter: exactly one quality row, op reply_delivered, the choice and confidence, no score 2.3ms
✓
no meter → no row; Jev failing → no row, and null 1.4ms
✓
the op is a literal on one line, and index.ts passes the meter and the staged-card approval 4.4ms
src/chat/withheld-card-fixes.vitest.ts
the panel card shows the prompts it saves (V5-loop-F05) · 2 tests
✓
every prompt is on the card, and the confirm saves exactly those prompts 201.2ms
✓
a prompt the model chose that names a vendor is never saved unseen: the card is withheld, names the prompt, and offers the reword 80.6ms
a withheld card names the part it cannot show and offers a fix that can clear it (V5-loop-F02) · 9 tests
✓
a panel NAME that carries a vendor: the sentence says its name (not its prompts), a rename chip, and the renamed panel confirms 51.9ms
✓
a campaign name that says something is free: the sentence names the campaign's name, and typing it yourself shows the card whole — its chip resumes 49.1ms
✓
a campaign name the rail alters for something typing cannot clear: the sentence says plainly a campaign cannot be renamed, and offers no chip that cannot work 17.3ms
✓
a recipient address the rail still alters: the sentence says the ADDRESS, names the draft, and points to Drafts; once that draft is gone the rest confirms 50.3ms
✓
each part is judged the way the exit judged the card: a price the person typed is theirs, so only the other subject is blamed 21.9ms
✓
a subject that says something is free: the sentence names the subject of that draft, and "Edit the drafts" stays the fix 15.0ms
✓
the DNS card withheld for a record already on the zone that looks like a key: the sentence says so, and the manual route is the chip 26.9ms
✓
each withheld card is counted, by the part that tripped and the fix offered 15.7ms
✓
the two cards with no free text (weekly share of voice, the rank-scan resume) ship whole, so no withheld sentence can fire on them 40.0ms
withheldCardNotice: one sentence per cause, and every sentence passes the guardrail · 12 tests
✓
send — two subjects 0.8ms
✓
send — a recipient whose name trips too 0.5ms
✓
send — a subject and another recipient 0.5ms
✓
rank track — one of three 0.5ms
✓
panel — keyword panel built from a search term 0.4ms
✓
panel — name and a prompt 0.4ms
✓
resume — a price in the name 0.3ms
✓
standing instruction 0.3ms
✓
DNS — a record on the zone 0.5ms
✓
weekly share of voice (no free text) 0.3ms
✓
rank-scan resume (no free text) 0.4ms
✓
every card gate has its own sentence — a ninth gate cannot fall through to a generic one unnoticed 3.9ms
no tool text the model reads calls a named panel measured on a schedule (V5-loop-F03) · 3 tests
✓
sov_trend (the WEEKLY tool) says named panels are measured only on request and never by the weekly run 0.6ms
✓
panel_segments routes no "tracking" phrase as if a panel were tracked; "stop measuring" is answered with the truth 0.5ms
✓
aeo_visibility's segment parameter promises no week-to-week cadence 0.3ms
test/replay/conversation-replay.vitest.ts
conversation replay (whole conversations through the real default.fetch) · 26 tests
✓
the corpus is whole: at least 25 conversations, each pinned, no stale pin 2.7ms
✓
chips-confirm-chip-free-name-dropped 437.3ms
✓
chips-every-option-dropped-generic-three 223.5ms
✓
chips-option-naming-supplier-dropped 191.7ms
✓
chips-option-price-or-free-dropped 193.8ms
✓
keywords-reword-newest-chip-tracks 412.7ms
✓
keywords-vendor-then-reword 412.4ms
✓
panel-add-confirm-list 346.8ms
✓
panel-limit-and-remove 349.3ms
✓
panel-vendor-label 347.2ms
✓
panel-vendor-prompt 443.2ms
✓
resume-card-clean-name-control 385.3ms
✓
resume-card-free-noun-name 434.4ms
✓
send-card-control-instruction-not-altered 466.3ms
✓
send-card-only-inside-withheld-instruction 457.0ms
✓
send-card-withheld-bare-yes 463.0ms
✓
send-card-withheld-what-did-you-show 480.2ms
✓
send-free-claim-what-did-you-show 488.0ms
✓
send-free-noun-audit 515.0ms
✓
send-secret-block 603.0ms
✓
send-vendor-recipient 700.9ms
✓
sov-weekly-card-with-panels 648.9ms
✓
standing-internal-then-reword 795.1ms
✓
standing-reword-newest-chip-saves 774.7ms
src/seo/aipolicy-horizon.vitest.ts
Q27: the calendar clause is a precondition, not a suggestion · 5 tests
✓
states it as a gate on the tool being allowed at all 2.4ms
✓
carries it as a rule in the procedure, always 0.8ms
✓
answers YES with a condition rather than refusing the question 0.3ms
✓
requires a named human to accept responsibility, not merely to edit 0.5ms
✓
will not confirm a page-level claim on the content check ALONE 0.5ms
Q27: it never claims to detect AI · 2 tests
✓
frames the finding as whether a person added anything 0.8ms
✓
says the useful question is not which tool wrote it 0.4ms
Q27: the tagging gap is the structural finding · 5 tests
✓
confirms it when drafts cannot be traced to live pages 0.4ms
✓
says the comparison cannot be reconstructed later 0.6ms
✓
kills it when everything is traceable 0.4ms
✓
leaves the regulated-subject question to the user, always 0.4ms
✓
delivers the procedure even with nothing measured 0.8ms
Q17: a range, never a date · 4 tests
✓
says so outright and explains the cost of a date 14.7ms
✓
returns three bands, each a month RANGE rather than a point 1.5ms
✓
tells the reader not to plan against the stretch band 0.3ms
✓
shortens the range when the site is already established 0.4ms
Q17: stopping is modelled, not waved away · 5 tests
✓
counts weakly-held separately from strongly-held 0.3ms
✓
produces a number for six and twelve months 0.4ms
✓
prices the exposure once revenue is measurable 0.6ms
✓
states that the decay fractions are a judgement (GS-003) 0.3ms
✓
excludes branded terms from the starting position 0.2ms
Q17: cost is asked for, never invented · 4 tests
✓
keeps cost untested and says why 0.3ms
✓
quotes no figure and asks for the one input 0.3ms
✓
keeps capacity and rival velocity untested 0.2ms
✓
delivers the ranges even with nothing on file 0.4ms
Q27 and Q17: no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps field and table names out of the prose 0.6ms
src/seo/tracking-feasibility.vitest.ts
the empty account gets the whole answer, not a refusal · 5 tests
✓
still answers YES and names the missing piece 1.9ms
✓
does not open with STOP — that is a diagnosis word and this is a policy 0.4ms
✓
tells them not to buy a tracker first 0.2ms
✓
its situation line says the absence is the subject, not a limit 0.2ms
✓
the ask is the panel, with a weekly owner 0.2ms
the grounding kill · 4 tests
✓
an ungrounded run KILLS the retrieval hypothesis rather than footnoting it 0.4ms
✓
says why it is easy to miss — every cell still fills 0.4ms
✓
the decision refuses to let a memory score be reported as visibility 0.2ms
✓
a grounded run lets it survive 0.7ms
mention and citation are different events · 2 tests
✓
a run with mentions and zero sources is killed, not called partial 0.4ms
✓
counts both, so the reader can see the gap between them 0.3ms
the frozen-list hypothesis needs a REPEAT, not a run · 4 tests
✓
one run on the panel is not a frozen list 0.3ms
✓
two runs on the SAME panel make it frozen 0.3ms
✓
two runs on DIFFERENT panels do not — that is two questions, not two readings 0.2ms
✓
an untagged run counts for nothing — it cannot be matched to a panel 0.6ms
a panel under the floor is a spot check, not a measurement unit · 2 tests
✓
is killed, and names the floor and why it exists 0.2ms
✓
primaryPanel picks the largest, so one thin panel cannot hide a real one 0.3ms
the referral leg is corroboration and says so · 3 tests
✓
when referrals exist it still refuses to be the measurement 0.3ms
✓
no analytics is untested, not killed — nothing was looked at 0.2ms
✓
analytics connected with no AI referrals is expected, and said so 0.2ms
the brief holds the shared contract · 3 tests
✓
carries every one-pager field and its own headline 0.4ms
✓
the two-source rule holds — no verdict rests on one reading 0.3ms
✓
never claims to measure citation PERFORMANCE — that is Q02/Q19/Q26 0.3ms
Q04 is wired on every surface · 3 tests
✓
is built, chained, in BOTH payload lists and rendered 0.4ms
✓
renders ahead of the incident fallback, or it never reaches the page 0.5ms
✓
is routed and labelled in the turn 0.4ms
src/tools/intelligence/preflight.vitest.ts
dispatch · 4 tests
✓
says nothing for a tool with no assessor — so a gate can call it unconditionally 2.0ms
✓
does not even count a tool it has no assessor for 0.7ms
✓
NEVER throws when an assessor throws — an advisory check cannot break the action it advises on 1.0ms
✓
NEVER throws when telemetry fails — the finding still reaches the user 1.2ms
measurement — the gap §9 names · 1 test
✓
counts a silent run as well as a firing one, so a RATE is computable 0.6ms
output invariants — an assessor cannot break the card it rides on · 4 tests
✓
drops a finding with no note: a chip with no stated reason is a mystery button 0.2ms
✓
bounds the note and the chips rather than trusting an assessor to 1.1ms
✓
drops empty chips instead of rendering a blank button 0.2ms
✓
survives an assessor returning junk 0.5ms
registry · 7 tests
✓
carries both adopted tools, and the barrel is what loads them 0.7ms
✓
a retired tool name cannot dodge the check 0.7ms
✓
every external-effect tool has an assessor or a written exemption 0.3ms
✓
every exemption states a reason, because "no check needed" is only useful when argued 0.7ms
✓
every SPEND-VARYING tool has a decision too — the axis the first version missed 0.2ms
✓
"not yet" and "never" stay in different maps 0.4ms
✓
a wanted tool that grows an assessor leaves the debt list 0.2ms
attachAdvisory · 4 tests
✓
carries the finding as a field, leaving the card copy untouched 0.3ms
✓
returns the card unchanged when there is nothing to say 0.2ms
✓
does not mutate the card it was handed 0.2ms
✓
never invents a confidence or a verdict 0.2ms
historyWithAdvisory · 2 tests
✓
keeps the note in the record even though the card no longer prints it 0.2ms
✓
leaves the message alone when there is no finding 0.1ms
note clamping · 4 tests
✓
never cuts mid-word 0.4ms
✓
prefers stopping on a complete sentence 0.2ms
✓
does not keep a sentence break that throws away most of the finding 0.3ms
✓
leaves a note under the cap completely alone 0.1ms
src/chat/capabilities-answer.vitest.ts
it renders as HTML, and safely · 8 tests
✓
is a styled HTML body, not markdown 2.3ms
✓
uses NO italics anywhere — owner ruling, italics read as low confidence 0.5ms
✓
escapes the stored domain — settings are user-supplied input 0.4ms
✓
prices nothing in dollars and names no vendor (CLAUDE.md §4) 0.5ms
✓
survives the outbound guardrail intact 8.7ms
✓
gives every row all three cells — a ragged table is worse than a list 0.6ms
✓
has no coloured left rule on the cards — owner ruling, it reads as an alert 0.4ms
✓
lays sections out horizontally, and still collapses on a narrow panel 0.4ms
clubbing must never lose a capability · 5 tests
✓
puts every item in exactly one themed row 0.9ms
✓
catches an item that matches NO theme instead of dropping it 1.1ms
✓
sinks the catch-all to the bottom — it is the least specific row 0.4ms
✓
shows the real commands in the row, not just a category noun 0.5ms
✓
states the total and prices each themed row in tokens 0.3ms
it ends by ASKING, not by listing (CLAUDE.md §3a) · 2 tests
✓
closes with exactly one question 0.4ms
✓
offers the right first move for what they actually hold 0.5ms
it adapts to what we already hold · 3 tests
✓
says it already knows the domain 0.4ms
✓
asks for the domain once when we have none, instead of pretending 0.2ms
✓
names the user when we have a name, and does not invent one when we do not 0.3ms
the intelligence layer is part of the answer, not a footnote · 3 tests
✓
covers the BEFORE-the-spend half, not only the research half 0.4ms
✓
states all four differentiators as observable behaviour 0.4ms
✓
promises the unverified marker the code actually renders 0.3ms
the chips give somewhere to go · 2 tests
✓
offers four concrete starters, site-specific when we know the site 0.9ms
✓
still offers four when we know nothing about them 0.3ms
routing — the shortcut must not eat real questions · 2 tests
✓
catches the phrasings users actually open with 50.1ms
✓
does NOT eat a real question that starts the same way 17.8ms
src/dashboard/vitals.vitest.ts
the spine is fixed · 4 tests
✓
opens with what is waiting and closes with the constraint 15.7ms
✓
says "Nothing" rather than 0 when nothing is waiting 1.3ms
✓
flags waiting work and offers the way to it 0.4ms
✓
renders a missing balance as null, never as zero 0.3ms
a number it cannot stand behind is not shown · 3 tests
✓
suppresses the visibility score when the sample is too thin 0.4ms
✓
says "too thin" rather than an em dash, which would imply unmeasured 0.4ms
✓
carries the trend only when there is one 0.3ms
the gap between tracked and ranked is its own row · 3 tests
✓
shows how many of the tracked keywords have ever been ranked 0.4ms
✓
warns when NONE of them have been checked 0.5ms
✓
drops the row entirely once every tracked keyword has a rank 0.9ms
problems appear, non-problems do not take up space · 4 tests
✓
shows unindexed pages with the way to investigate 0.3ms
✓
omits the row at zero rather than printing a permanent "0" 0.2ms
✓
shows site health moving, which is what the tenant could not see 0.2ms
✓
omits the delta when the score has not moved 0.1ms
dormant modules stay VISIBLE, muted — never omitted · 2 tests
✓
shows every module as a dormant row with a way in 0.4ms
✓
never leaves a dormant row without a command 0.2ms
outbound keeps only the rows that pass the overnight test · 4 tests
✓
drops the odometers 0.5ms
✓
keeps bounces and whether anything is running 0.4ms
✓
hides bounces at zero but still says nothing is running 0.2ms
✓
goes dormant when outbound has never been used, even with contacts on file 0.2ms
the panel stays a panel · 4 tests
✓
does not outgrow the sidebar on the busiest tenant 2.5ms
✓
never drops a warning, a dormant row, or the spine — only healthy detail 0.6ms
✓
returns the rows untouched when they already fit 0.4ms
✓
never returns fewer than the spine 0.1ms
fmtTokens · 1 test
✓
matches the panel formatting so nothing jumps 0.2ms
src/email/held-sends.vitest.ts
1. an open confirms a held send — billed and counted once, and counted as an open when a person made it · 6 tests
✓
a person's open of a send the email service never answered: sent and OPENED at the open's time, billed once 37.7ms
✓
repeated and later events never bill it again; the first open stays the open 7.1ms
✓
a person's click on a held send: sent and CLICKED at the click's time, billed once 3.8ms
✓
a mail system's fetch confirms it too — a scanner only fetches what was delivered — and is never an open 2.2ms
✓
a held send that WENT OUT (its outcome write was lost) is confirmed and NOT billed again 315.1ms
✓
CONTROL — a row that is not held, and another tenant's, are left alone 2.9ms
2. a click confirms a held send; the redirect never waits on it · 1 test
✓
a scanner following the link: 302 to the link, the row sent and billed once, no click counted 2.3ms
3. a bounce and a reply confirm a held send, and are recorded on it as on any send · 2 tests
✓
a bounce webhook for a held send: sent at the bounce's time, billed once, then bounced 2.5ms
✓
a reply to a held send: sent, billed once, then replied — and a second reply bills nothing 8.5ms
4. exactly once, whichever arrives first · 3 tests
✓
an open while the email service is still answering, which then never answers: delivered, billed once by the send 3.1ms
✓
CONTROL — an open while the email service is answering, which then accepts: the late outcome write keeps it, one fee 2.5ms
✓
the held note landing between a confirmation's read and its write: the write misses, re-reads, bills once 0.9ms
4b. a held row leaves `sending` only through its confirmation · 3 tests
✓
a bounce recorded between a confirmation's read and its write is kept: that confirmation confirms nothing 1.8ms
✓
an open of a held row that carries a stale send time goes through the confirmation, never straight to opened 2.1ms
✓
…and so does a click on one 1.7ms
5. the drip: a held step stays delivered, whatever comes back for it · 3 tests
✓
a held step that then bounces is not mailed again by the next tick 3.8ms
✓
an open while the step's send gets no answer: the step is delivered — billed and advanced on this tick 2.0ms
✓
a step's own late outcome write does not throw away a bounce that came back first 2.1ms
6. Resend anyway: the Sent panel's button (POST /api/emails/:id/release) · 3 tests
✓
puts a held send back in Drafts, unsent — and then it is a draft like any other, sent through the claim 5.1ms
✓
a held send that evidence confirmed first stays in Sent: 409, not released 6.9ms
✓
only the caller's own interactive held sends: a drip step and another tenant's are refused untouched 2.0ms
7. Resend anyway in chat: a staged card, and only a click on its confirm moves anything · 4 tests
✓
the card covers exactly the held sends, says they may arrive twice, and is judged shown from the reply 11.5ms
✓
typed words never release; the click on the shown card does, exactly its rows; a second click runs nothing 4.7ms
✓
a card shown before an open confirmed one of its rows: that row stays in Sent and the reply says so 4.2ms
✓
nothing held: no card is staged 0.5ms
src/leads/note-priority.vitest.ts
the CA repro: paid-boundary stop must not be misattributed to missing product brief · 3 tests
✓
does NOT return the product-brief catch-all when a real paid shortfall explains the 0 results 1.8ms
✓
the catch-all only fires when there truly is no other explanation (paidShortfall === 0) 0.4ms
✓
a real sourceNote always wins over the catch-all, brief missing or not 0.3ms
person_locality: a location filter must explain itself, never go silent (widened to cities 2026-08-29) · 3 tests
✓
discloses the limitation even when the corpus/paid tiers would otherwise explain 0 results 0.3ms
✓
fires even on a NONZERO result — those results matched on something other than state 0.2ms
✓
does not fire when person_locality was never requested 0.2ms
sharedNote must reach the user, not be silently dropped · 2 tests
✓
surfaces diag.sharedNote when the corpus tier had an honest WHY and nothing else outranks it 0.2ms
✓
sourceNote still outranks sharedNote when both are present 0.2ms
existing priority order is preserved · 6 tests
✓
credit error always wins 0.5ms
✓
apollo error suppresses the note entirely (handled by `error` field elsewhere) 0.2ms
✓
free-tier cap message renders with the real requested/cap numbers — when the cap actually cut the delivery 0.3ms
✓
poor-fit verdict rides even on a delivered, non-empty batch 0.2ms
✓
all-owned-tier note fires only when something was actually found 0.2ms
✓
a fully satisfied, well-fitting, product-brief-having search gets no note at all 0.1ms
unappliedOwnedTierFilters — say what did not run, and nothing else · 5 tests
✓
reports ONLY revenue — the one with no column and no source data 1.0ms
✓
does NOT claim industry or company size were dropped — they are applied now 0.3ms
✓
says nothing at all when the paid provider ran — it applies revenue too 0.6ms
✓
reports only what was actually requested 0.5ms
✓
leaves the single-string note picker free to say something else 0.2ms
a degraded corpus is the headline · 3 tests
✓
beats the cap note, the coverage note and the paid boundary on a zero result 0.2ms
✓
beats "all from your own contacts" on a partial result, but not the fit verdict 0.2ms
✓
a provider credit error still comes first — the search did not run at all 0.1ms
the cap note is only for a cap that actually cut something · 3 tests
✓
stays silent on a zero result 0.1ms
✓
stays silent when fewer than the cap came back 0.1ms
✓
never says "you asked for N" about a number the user did not type 0.2ms
src/leads/paid-escalation.vitest.ts
when the free sources come up short · 4 tests
✓
escalates on a full miss 2.6ms
✓
escalates on a partial fill 0.4ms
✓
BUYS THE SHORTFALL, NOT THE ORIGINAL ASK 0.2ms
✓
carries every other filter through unchanged 0.8ms
when escalating would be wrong · 6 tests
✓
does not escalate a search the user already paid for 0.2ms
✓
does not escalate when the ask was filled 0.2ms
✓
does not escalate a FAILED search 0.2ms
✓
does not escalate while a provider run is already in flight 0.3ms
✓
is null-safe on both sides 0.5ms
✓
ignores a nonsense shortfall rather than quoting one 0.3ms
what the user reads · 4 tests
✓
leads with what was already tried, not with the price 0.5ms
✓
says how many were found when some were 0.1ms
✓
quotes no dollars — this product bills in tokens 0.2ms
the chip text, for the user who still types it · 4 tests
✓
is one string built in one place 0.2ms
✓
round-trips: what we emit, we recognise 0.3ms
✓
tolerates a user editing it before sending 0.1ms
✓
does not fire on an unrelated sentence 0.1ms
the card replaces the prose, it does not sit under it · 5 tests
✓
drops the offer made in words, because the card makes it with a button 0.6ms
✓
KEEPS the result — this strips the offer, never the answer 0.2ms
✓
leaves a delivering reply completely untouched 0.1ms
✓
leaves no censored-looking gap behind 0.2ms
no paid quote on a degraded run · 1 test
✓
stands down when the corpus could not finish 0.2ms
no paid quote over a refused delivery · 1 test
✓
stands down when the relevance gate refused candidates 0.1ms
src/routes/pillar-page-parity.vitest.ts
both pillar pages carry the whole template · 22 tests
✓
has a hero image WITH intrinsic dimensions 27.5ms
✓
shares that image socially, or every share is a bare link 1.4ms
✓
carries the outcome panel — the block an engine lifts to answer "what is this page for" 1.2ms
✓
carries the diagnosis block 1.6ms
✓
carries the interactive simulator 1.2ms
✓
wraps its body in <article> and uses <section> for each h2 1.3ms
✓
serves Last-Modified, so a crawler can skip an unchanged page 0.7ms
✓
carries all three JSON-LD blocks 1.0ms
✓
its WebPage schema names a language, an image and a publisher 2.0ms
✓
states a question count that matches the questions it lists 1.6ms
✓
has no stray unstyled robots directive in the body 1.2ms
✓
has a hero image WITH intrinsic dimensions 1.3ms
✓
shares that image socially, or every share is a bare link 1.1ms
✓
carries the outcome panel — the block an engine lifts to answer "what is this page for" 0.8ms
✓
carries the diagnosis block 0.8ms
✓
carries the interactive simulator 0.8ms
✓
wraps its body in <article> and uses <section> for each h2 1.0ms
✓
serves Last-Modified, so a crawler can skip an unchanged page 0.5ms
✓
carries all three JSON-LD blocks 1.1ms
✓
its WebPage schema names a language, an image and a publisher 1.0ms
✓
states a question count that matches the questions it lists 0.9ms
✓
has no stray unstyled robots directive in the body 0.9ms
/ai-visibility-answered meets the SERP budgets it was rewritten for · 3 tests
✓
title fits the ~60-character cut, differentiator included 1.0ms
✓
description fits the ~160-character cut 1.1ms
✓
title and description agree with the question count rather than hardcoding it 1.4ms
src/tools/own-site-read.vitest.ts
isOwnSite · 7 tests
✓
https://rhetoricaudit.com → true 2.5ms
✓
http://www.rhetoricaudit.com/pricing?x=1 → true 0.4ms
✓
rhetoricaudit.com/about → true 0.5ms
✓
https://blog.rhetoricaudit.com → false 0.4ms
✓
https://rival.com → false 0.3ms
✓
no saved site matches nothing 0.3ms
decideOwnSiteRoute — Jev decides, code guarantees · 10 tests
✓
no stored evidence (every new tenant) → live, and Jev is not even asked 1.7ms
✓
context not rolled out → live 0.7ms
✓
performance ≥ 0.7 with stored evidence → stored, labelled as Jev's judgment 24.6ms
✓
performance below the bar → live (a literal read is never turned into something else on a guess) 1.1ms
✓
page_content → live (jev_page_content) 0.6ms
✓
both → live (jev_both) 0.6ms
✓
unclear → live (jev_unclear) 0.5ms
✓
nonsense → live (jev_unclear) 0.5ms
✓
Jev failing → live, and reported 0.8ms
✓
the question is a keyed choice over the request, with a criteria MAP (an array is a 422) 0.4ms
the real read_url dispatch · 6 tests
✓
THE BUG: reading your own site returns the page, never "not read directly" 9.7ms
✓
a new tenant (nothing stored) is read live with no Jev call, and the route says why 0.4ms
✓
with stored evidence and a content question, Jev says page_content → the page is read 0.6ms
✓
another site is read as always, with no route and no Jev 0.4ms
✓
a performance question with stored evidence: the DISPATCHER runs diagnose, no page fetch 19.5ms
✓
a stored answer that comes back empty falls back to reading the page 5.7ms
a stored-path answer renders as diagnose, not as an empty page · 2 tests
✓
the presenter draws the measurements table 0.7ms
✓
the formatter does not print "Untitled page — 0 words" 4.7ms
src/seo/vendor-leak.vitest.ts
the guardrail rail sees a vendor name inside an identifier · 11 tests
✓
redacts DATAFORSEO_CREDENTIALS_MISSING 3.7ms
✓
redacts APIFY_RUN_FAILED 0.4ms
✓
redacts OPENROUTER_KEY missing 0.2ms
✓
redacts NHOST_ADMIN_SECRET not set 0.3ms
✓
redacts HASURA_GRAPHQL_ADMIN_SECRET 0.3ms
✓
redacts MILLIONVERIFIER_TIMEOUT 0.2ms
✓
redacts PROXYCURL_402 0.3ms
✓
still catches the prose form it always caught 0.3ms
✓
does NOT redact a vendor name buried inside a real word 0.5ms
✓
leaves the deliberate user-facing allowlist alone 0.4ms
✓
covers every name on the list, so a supplier added later is protected too 1.3ms
friendlySeoError never hands a vendor or a machine code to the user · 14 tests
✓
maps DATAFORSEO_CREDENTIALS_MISSING to a human sentence 0.9ms
✓
maps DFS_NO_TASK to a human sentence 0.8ms
✓
maps VALUESERP_KEY not configured to a human sentence 0.2ms
✓
maps APIFY_NO_KEY (apify/actor-id) to a human sentence 0.2ms
✓
maps APIFY_ERROR_500 (apify/actor-id): body to a human sentence 0.2ms
✓
maps APIFY_NO_CREDITS (apify/actor-id) to a human sentence 0.1ms
✓
maps No SERP provider configured (SERP_PROVIDER_KEY_MISSING) to a human sentence 0.1ms
✓
maps SERP_ERROR_402 (quota) to a human sentence 0.3ms
✓
says WHICH KIND of failure it was, rather than falling through to the generic 0.4ms
✓
PASSES THROUGH a sentence already written for a user 0.6ms
✓
a site-crawl timeout is no longer blamed on the provider 0.2ms
✓
keeps the branch order that names the right subsystem 0.2ms
✓
is idempotent — a friendly message survives a second pass 0.1ms
✓
and the belt still holds if a future branch forgets: scanOutbound catches the raw form 0.7ms
src/leads/shared/tier-search.vitest.ts
revealCorpusCandidates · 7 tests
✓
reveals only up to the shortfall the ladder still needs 33.4ms
✓
never treats a phone identifier as an email address 15.7ms
✓
never spends a REVEAL round trip on a candidate with no identifier, and batches the P2 ask 17.1ms
✓
offers a constructed address ONLY for the shortfall, after every held address is used 20.0ms
✓
lets one refused reveal cost one lead, not the rung 17.6ms
✓
marks every corpus lead unverified, with the corpus as the source 18.0ms
✓
dedupes one address that appears on two candidate entities 22.3ms
corpusLeadTier · 6 tests
✓
arms only the tenants named in the flag 0.5ms
✓
still arms everyone on the literal 1 0.5ms
✓
is absent without a tenant, even with the flag on 0.2ms
✓
is absent when the tier flag is off 0.3ms
✓
exists only when both hold 0.2ms
✓
caps the corpus ask at 25 — the ask drives the wall clock 0.3ms
the stage deadline fits inside the rung deadline · 1 test
✓
gives a stage enough room to actually finish 0.5ms
the relevance gate sits BEFORE reveal (2026-09-15, [3.1.3]) · 2 tests
✓
a no-fit sample reveals nothing, bills nothing, and says so 18.6ms
✓
an unreadable verdict fails OPEN — reveal runs exactly as before 16.9ms
the reveal phase accounts for every candidate it was given · 2 tests
✓
counts failures by reason and keeps the sample, while delivering what it can 20.8ms
✓
a reveal that never returns is a timeout, not a hang 34.7ms
the rung sizes every phase inside the budget it was given · 5 tests
✓
derives the stage deadline from the budget minus the post-search reserve 0.7ms
✓
a search every stage of which stalled says the database was slow — and spends nothing more 18.3ms
✓
a superseded lexical stage is not a stalled one 0.5ms
✓
matched people it could not release: says so, in our words, as our fault 24.9ms
✓
the wording never names a vendor or an internal stage name 0.8ms
"show the closest matches anyway" skips the relevance gate · 2 tests
✓
a no-fit verdict carries the marker the reply reads 16.3ms
✓
with acceptClosest the gate is not even asked, and the candidates are delivered 21.5ms
client/format.vitest.ts
fmtApprovalTokens — the §4 surface · 3 tests
✓
says "No extra cost" for zero, never "0" and never "Free" 2.1ms
✓
never emits a currency symbol at any magnitude 0.8ms
✓
rounds by magnitude the way the card reads 0.3ms
esc and escVitals — two escapers that disagree, on purpose · 4 tests
✓
both escape the four HTML-significant characters 0.5ms
✓
DISAGREE on null, and both behaviours are live 0.3ms
✓
escVitals also blanks 0, which esc renders 0.2ms
✓
escapes an ampersand FIRST, so an escape is never double-escaped 0.3ms
relTime · 4 tests
✓
reads "now" under a minute 0.2ms
✓
counts minutes, then hours, then days 0.6ms
✓
rounds rather than truncates at each boundary 0.2ms
✓
does not crash on a future timestamp 0.8ms
truncateRecentTitle · 6 tests
✓
passes a short title through, trimmed 0.2ms
✓
falls back to "Chat" only for a FALSY title 0.2ms
✓
returns EMPTY for a whitespace-only title — the fallback does not catch it 0.1ms
✓
keeps a 44-character title whole and clips a 45-character one 0.2ms
✓
uses three ASCII dots, not a single ellipsis character 0.2ms
✓
does not leave a dangling space before the dots 0.1ms
stripChipMd · 3 tests
✓
strips ** and __ emphasis the model emits 0.2ms
✓
is not a markdown parser and leaves everything else alone 0.1ms
✓
renders null and undefined as empty, not as "null" 0.2ms
detectDelimiter · 4 tests
✓
recognises a tab-separated header 0.2ms
✓
recognises a semicolon-separated header (decimal-comma locales) 0.1ms
✓
is not fooled by a comma inside a quoted header when tabs separate 0.2ms
src/billing/carried-ceiling.vitest.ts
V12-money-F01 — the JS-rendered crawl the hourly sweep finishes · 6 tests
✓
the world reproduces V12 O2: 150 rendered pages cost 1,125,000 tokens 2.7ms
✓
[fail-first] debits at most the confirmed 170,000 and absorbs the rest (was: 1,125,000) 118.1ms
✓
[fail-first] the report the user reads says the maximum held, in tokens, with no vendor and no dollar 46.3ms
✓
[fail-first] the job's own earlier rows are its spent-so-far: 100,000 already charged leaves 70,000 24.5ms
✓
[fail-first] a second sweep of the same crawl (the marker survived a crash) charges nothing more 38.2ms
✓
a crawl no card confirmed is billed exactly as before (cron-owned / auto-approved work is unchanged) 15.0ms
V12-money-F01 — a queued job: the share travels, and a redelivery resumes from the ledger · 5 tests
✓
[fail-first] a redelivered job does not reset spent-so-far: 80K charged, then 50K more → 20K billed, 30K absorbed 6.4ms
✓
[fail-first] a message #691 enqueued (spendCeilingTokens only) also resumes from its own rows 5.6ms
✓
a job with no card carries nothing and is billed in full 2.0ms
✓
[fail-first] a ledger that cannot be read holds the line: nothing more is charged against the card 1.0ms
✓
a malformed carried record carries nothing 0.7ms
V12-money-F01 — the depth chip "Standard — up to 150 pages (75K)" on a JS-rendered site · 2 tests
✓
[fail-first] the chip prints the figure the run is capped at 2.3ms
✓
[fail-first] the real on-page dispatch, under the chip's ceiling, debits at most 75,000 (was: 375,000) 200.7ms
V12-money-F01 — an on-page crawl a LATER chat turn collects settles against the card that bought it · 1 test
✓
[fail-first] "check crawl results" on a crawl confirmed earlier: the crawl row is capped by the carried card, not by nothing 6.1ms
V12-money-F01 — the hand-off arithmetic · 2 tests
✓
a share leaves the request; what stays plus what left is the card 0.8ms
✓
a unit-bound ceiling carries its identity, so a marker written inside a job names the job 0.8ms
V12-money-F01 — the wiring (index.ts is not importable under node), pinned in source · 8 tests
✓
[fail-first] the jobs consumer re-opens the carried ceiling with the job's own rows (runAsyncJobInline and the store-check poll) 0.8ms
✓
[fail-first] the serpdex consumer re-opens the share before the crawl runs 0.3ms
✓
[fail-first] the enqueue hands the share off with the job, once its row exists 0.5ms
✓
[fail-first] the serpdex enqueue carries the spider's share in the message 0.2ms
✓
[fail-first] the on-page marker carries the ceiling; the deadline hands the rest off; both collectors settle against it 0.4ms
✓
[fail-first] the onpage_depth chip opens its printed price as the ceiling before the run, on both the queued and inline paths 0.5ms
✓
[fail-first] a priced SEO route chip with no card is capped at the top of its printed range 0.4ms
✓
the sweep opens the marker's ceiling inside the tenant's window, before the first metered call 0.3ms
src/campaigns/send-retry-duplicate.vitest.ts
chat send_emails: a 1-of-2 partial send, writes intact (control) · 1 test
✓
the retry mails only the one that failed 60.4ms
#47 — the reply to a 1-of-2 send counts what went out and offers a retry of only the unsent · 1 test
✓
names the one that failed and why, and promises the one that went out will not go again 9.8ms
chat send_emails: a delivered email whose outcome write fails · 11 tests
✓
one 502 on the write: retried and recorded — the batch finishes, nothing is mailed twice 71.6ms
✓
a write that never lands: held as Delivery unconfirmed, billed and counted, never offered again 324.3ms
✓
a refusal whose outcome cannot be written is held, named, and kept out of the retry offer 317.2ms
✓
the token expires part-way through the batch: nothing in the send loop uses it 5.9ms
✓
no answer from the email service: unconfirmed, held, not billed, counted, never resent 6.2ms
✓
a row another run claims between the read and the claim is not sent by this one 6.7ms
✓
a claim whose answer is lost after it landed: the row is held, and this run never sends on a guess 4.2ms
✓
a claim that failed without landing is tried once more, and the row is sent once 10.8ms
✓
an outcome write that landed but lost its answer is read back, not reported as unrecorded 63.9ms
✓
a bounce that lands before the outcome write is kept: the write resolves only the row it claimed 7.1ms
✓
the claim and the outcome are written on the admin secret, scoped to the caller 3.1ms
REST POST /api/emails/send: the whole batch, after the token expires · 3 tests
✓
a 3-message batch whose token lapses after the first: all reported sent, all recorded, none mailed twice 5.0ms
✓
a 502 on one delivered write: reported sent, recorded, not resent 63.1ms
✓
a refusal is humanised — never the provider's own words or a database error 3.2ms
POST /api/emails/:id/send — the Drafts panel's single send · 5 tests
✓
a 502 on the delivered write: 200, recorded, and Send again finds nothing to send 65.4ms
✓
the person's token is not on the send path at all 3.5ms
✓
a refusal is a 422 with the humanised reason; no answer is a 202 the panel can show 5.2ms
✓
a suppressed address is refused before any send and its draft cancelled — on the admin secret 1.7ms
✓
an internal failure is a sentence that names no vendor 0.9ms
the drip: its own claim covers it, and no answer stays a hold · 1 test
✓
a step whose provider call gets no answer is held, never marked failed, and the next tick does not resend it 3.8ms
a draft written with the person's JWT does not carry the claim (migration 196) · 1 test
✓
the user-token insert leaves status to the column default; the admin path still names it 2.6ms
the provider's own dedupe key, as a belt beside the claim · 1 test
✓
a first attempt carries the row as its key; a retry of a refused row carries none 4.2ms
src/chat/card-provenance.vitest.ts
scanOutbound's tenantOwned: the vendor check skips the range, and only the vendor check · 6 tests
✓
a vendor name inside the range ships as written; the same name a byte outside it is redacted 5.4ms
✓
with no ranges the scan is exactly what it was 3.3ms
✓
every other check still reads the range: a price, a "free" claim, an instruction line, a key 0.7ms
✓
a text that already carries a placeholder character gets no exemption 0.4ms
✓
ranges are clamped, merged and ordered; nonsense ranges exempt nothing 0.5ms
✓
a vendor name the range only partly covers is not exempt: that range is dropped and the name redacted 0.4ms
the provenance table covers every card gate, and only what the card draws from the tenant is theirs · 2 tests
✓
every card gate declares whose words its parts are — the same nine withheld-card.ts has a sentence for 5.9ms
✓
the tenant owns exactly: recipient addresses, campaign names, a keyword panel's search terms, the zone's records and names 0.3ms
the Resend anyway card (DECISIONS #54): its addresses are the tenant's, anchored to its own rows · 3 tests
✓
the address cell of each row is exempt, never the subject — even one quoting the address 6.0ms
✓
read with those spans exempt, a vendor in an address shows as it is; one in a model-written subject is still altered 0.6ms
✓
a withheld card says where the same release is one click: Sent 0.3ms
tenantOwnedSpans: anchored to where the card draws the value · 8 tests
✓
send: the address cell of each row, never the subject — even a subject that quotes the address 0.8ms
✓
send: a row the card does not draw yields no span 0.3ms
✓
resume: the name inside its quotes, never the same words elsewhere on the card 0.2ms
✓
keyword panel: only the search term inside each prompt — not our template words, not the panel name 2.2ms
✓
keyword panel: a prompt with no seed, or not built by our template, is nobody's but ours 0.2ms
✓
an audience panel: the prompts and the name are the model's — no span at all 0.2ms
✓
DNS: the records already on the zone (whole or clipped as the summary quotes them) and its record names — never a record we would write 0.9ms
✓
rank tracking, a standing instruction, weekly share of voice and the scan resume own no tenant text 0.4ms
tenantOwnedInPart: the ranges of one part the withheld sentence may not blame for a vendor · 3 tests
✓
whole for an address, a campaign name and a zone record; none for a subject, a panel name, keywords or an instruction 0.5ms
✓
a prompt: the search term inside it on a keyword panel, nothing on any other panel 0.3ms
✓
the withheld sentence, scanned the way the exit scans: a vendor in the address is not blamed, the subject's free claim is 0.8ms
the template inverse and the quoted record forms live beside what they invert · 2 tests
✓
keywordPromptTerm finds the term in both prompt shapes deriveKeywordSegment builds, and nothing else 0.4ms
✓
quotedRecordForms carries each clip the DNS summaries print 0.2ms
src/chat/visibility-response.vitest.ts
the reply is scannable, not a wall of bullets · 4 tests
✓
renders markdown pipe tables the chat renderer can draw 20.3ms
✓
leads with the verdict and the movement, not a label 0.5ms
✓
shows no composite line when the blend equals the citation rate 0.4ms
✓
draws a bar beside every rate, never instead of one 0.5ms
nothing the old prose carried was lost in the reformat · 5 tests
✓
keeps the run cost 0.3ms
✓
keeps every engine, including the weak ones 0.4ms
✓
keeps the share-of-voice denominator caveat, which is the whole reason that number differs 0.3ms
✓
keeps the auto-detected competitor-set disclosure 0.2ms
✓
keeps both gap types distinct — a missing page and an ignored page need different work 0.6ms
Google's two surfaces are reported separately · 2 tests
✓
names AI Overviews and AI Mode with their own rates 2.1ms
✓
omits the table entirely rather than showing a surface that did not run 0.4ms
an unreachable engine is called out before any table · 1 test
✓
says it was excluded, not scored zero 0.6ms
a percentage over one answer states what it rests on · 4 tests
✓
THE REGRESSION: the headline names the basis, not just the shape asked for 0.4ms
✓
warns, in the same reply, that the number cannot be acted on 0.2ms
✓
still carries the stored mention-event caution beside the share 0.2ms
✓
an adequate run keeps the old sentence and gains no warning 0.2ms
sov_trend states the sample behind each point · 3 tests
✓
qualifies the current figure and the delta beside it 4.5ms
✓
puts the basis on every HISTORY row, so the column cannot read as volatility 0.4ms
✓
carries both cautions — they count different things 0.4ms
pctBar · 1 test
✓
is proportional and clamped 0.3ms
a composite run quotes the CITATION rate, not the blend · 4 tests
✓
the headline is 42%, the citation rate — never the 26% blend 0.3ms
✓
the headline is never below every engine in the table beneath it 0.5ms
✓
still reports the blend — labelled as a score across surfaces, naming its legs 0.3ms
✓
refuses a delta across a change of engine set, and says why 0.2ms
src/db/migration-194.vitest.ts
the two files, against the snapshot and each other · 6 tests
✓
_clear.json is, per table, one drop and one create of the BEFORE: for the ledgers every column, own rows, aggregations 4.1ms
✓
...and for every other table exactly its last recorded grant (010 for the two reports, 183 for connections) 26.9ms
✓
the AFTER file is the same two operations per table, and each AFTER is its BEFORE minus exactly the revoked columns 3.6ms
✓
the named five are among the revoked (the owner ruling), and what the user is charged stays readable 2.1ms
✓
the committed snapshot holds the AFTER shape (hand-edited; the orchestrator re-reads it with --refresh once 194 is applied) 0.6ms
✓
no migration file before 194 records a user-role SELECT on either ledger, so the recovery file is the only record of the BEFORE 2.8ms
194_apply.sh against the stand-in · 18 tests
✓
narrows every SELECT, keeps the filter and every other column, verifies itself, and a re-run writes nothing 415.0ms
✓
a live `columns: "*"` on a ledger is the BEFORE shape when the role sees exactly the file's columns 203.1ms
✓
...but `*` on a table whose BEFORE is recorded (010) is a STOP, even when it grants the same columns 103.7ms
✓
...and a STOP, before any write, once `*` grants a column the file does not name (a column added since) 114.5ms
✓
--dry-run reports every change and writes nothing 113.0ms
✓
--clear restores the BEFORE (recovery only), and a forward run then narrows again 613.5ms
✓
a half-applied run resumes: a table already AFTER is left alone, the others are narrowed 204.1ms
✓
a drifted SELECT on ANY table is a STOP before anything is written on any table 782.2ms
✓
no SELECT at all is a STOP too: this migration narrows a read, it never creates one 105.8ms
✓
a refused drop changes nothing on that table, says so, and a re-run finishes 396.0ms
✓
a drop whose reply is lost (a 502 after it applied) is recognised, and the create still runs 201.1ms
✓
a failed create restores exactly the SELECT read before the drop, and fails the run 189.5ms
✓
...and "exactly" includes a live `*`: the restore is `*`, not the file's list 184.5ms
✓
a create whose reply is lost (a 502 after it applied) is recognised, proved and reported as applied 204.3ms
✓
proof (a) is a re-read: a permission that changed under the run fails it, naming the table 198.0ms
✓
proof (b) is an independent read: a user-role schema still showing a revoked column fails the run, aggregate fields included 235.9ms
✓
proof (c): inconsistent metadata fails the run 320.3ms
✓
refuses to run from edited migration files: an AFTER that keeps a revoked column, or drops a kept one, is a STOP before any read 289.5ms
src/email/suppression-after-replace.vitest.ts
control: the harness sends, and a replaced contact with no history is mailed · 1 test
✓
a clean address is mailed before and after the contact is replaced 35.5ms
the unsubscribe link, pressed AFTER the tenant replaced the contact (V2-suppression-F01 S1, S2) · 7 tests
✓
S1 send, tenant deletes the contact, recipient unsubscribes: the opt-out is recorded and the re-inserted address is refused 4.3ms
✓
S2 send, tenant renames the contact to a parked address, recipient unsubscribes: the MAILED address is recorded, not the parked one 3.4ms
✓
a link in mail sent before this change names the CONTACT: it records the address that contact's sends went to, not its current one 4.3ms
✓
the confirmation does not claim success when the link resolves to no address: a sentence, not {success:true}, and nothing written 3.1ms
✓
control: the header link and the footer link are the same link 1.5ms
✓
a send row pointed at ANOTHER tenant's contact (the user role writes contact_id freely): the link stamps nothing of theirs 1.8ms
✓
control: per tenant — tenant B's recipient of the same address is unaffected by tenant A's opt-out 6.9ms
a reply, a bounce notice and a provider complaint AFTER the tenant replaced the contact (S3, S4, stop reply) · 5 tests
✓
S3 send, rename, provider webhook spam complaint naming the mailed address: recorded, and the re-inserted address is refused 12.9ms
✓
send, DELETE, provider webhook hard bounce: the send still matches by the address it went to 25.5ms
✓
S4 send, delete, a bounce notice attributed by tracking id: the ledger gets the mailed address 4.1ms
✓
send, delete, a reply asking to stop: the ledger gets the mailed address 5.8ms
✓
send, rename, a reply asking to stop: the MAILED address is recorded, not the parked one 2.5ms
the send row records the address it went to, and the record cannot be moved · 5 tests
✓
the send carries the recipient address and its suppression key 0.9ms
✓
re-addressing a DELIVERED send is refused: flip it back to draft, rename, send again — the parked address is not mailed and the link still names the recipient 2.1ms
✓
a send whose address cannot be recorded is not sent (fail closed) 0.9ms
✓
a tracking id that is not this tenant's send is not sent: the link would name someone else's row 0.6ms
✓
control: a transport failure frees the address — a corrected contact is mailed on retry, and its link records the corrected address 2.1ms
a link already in an inbox names the CONTACT, and the tenant has since deleted it (V3-optout-F01) · 4 tests
✓
X3 the legacy link records the address that contact's sends went to, and the re-inserted address is refused 1.5ms
✓
a send made now records the contact it was addressed under, and the contact-id link still resolves after a delete 1.3ms
✓
a refused transport releases the address but keeps the contact the row was addressed under 1.2ms
✓
each opt-out lands on the tenant whose mail carried the link, and on no other 1.4ms
a provider complaint is matched to the send it is about whatever status the tenant has written on it (V3-optout-F02) · 2 tests
✓
W1 send, the tenant puts the delivered row back to draft, a complaint names the mailed address: recorded, and the address is refused 3.6ms
✓
control: a draft that was never sent is not what a complaint lands on (no recorded recipient, still a draft) 1.2ms
src/llm/model-cooldown-attribution.vitest.ts
a cooldown entry is a claim about the model, not about our request · 18 tests
✓
404 is model health — cool it down 1.7ms
✓
408 is model health — cool it down 0.2ms
✓
409 is model health — cool it down 0.2ms
✓
429 is model health — cool it down 0.2ms
✓
500 is model health — cool it down 0.1ms
✓
502 is model health — cool it down 0.1ms
✓
503 is model health — cool it down 0.2ms
✓
504 is model health — cool it down 0.2ms
✓
400 is OUR payload — do not cool it down 0.5ms
✓
401 is OUR payload — do not cool it down 0.2ms
✓
402 is OUR payload — do not cool it down 0.2ms
✓
403 is OUR payload — do not cool it down 0.1ms
✓
413 is OUR payload — do not cool it down 0.1ms
✓
422 is OUR payload — do not cool it down 0.1ms
✓
404 is health, not a payload error — that is the whole reason this is a list 0.1ms
✓
both !res.ok branches gate markModelBad on the classifier 1.1ms
✓
a truncation at our own ceiling does not mark the model bad 0.2ms
✓
no write site is gated on isLast any more — the safety net lives on the READ 0.2ms
the tool-call timeout floor clears observed successful latency · 6 tests
✓
is above the slowest chat model call that actually returned 0.2ms
✓
leaves real headroom, because the sample is right-censored 0.1ms
✓
still leaves the ceiling meaningfully above the floor 0.1ms
✓
a short prompt gets exactly the floor, and scaling still adds per 1K tokens 0.5ms
✓
never exceeds the ceiling however large the prompt 19.5ms
✓
the reasoning floor is not weakened by the raise 0.2ms
src/runtime/clarify-gate.vitest.ts
the incident prompt is stopped before it spends · 2 tests
✓
asks instead of spending on "founders working on programmatic SEO for directories" 9.6ms
✓
explains what IS usable, so it reads as help rather than refusal 1.6ms
a well-specified prompt is never interrogated · 8 tests
✓
proceeds when the request declares a industry 0.4ms
✓
proceeds when the request declares a specific title 0.2ms
✓
proceeds when the request declares a exec title with an industry 0.3ms
✓
proceeds when the request declares a geography 0.2ms
✓
proceeds when the request declares a domain 0.4ms
✓
proceeds when the request declares a a local search, which carries its own targeting 0.3ms
✓
proceeds when the request declares a all three 0.7ms
✓
no longer treats business_function as a handle — the field does not exist any more 0.4ms
scope · 4 tests
✓
never gates a tool that spends no provider money 0.3ms
✓
leaves a paid tool with no probe alone rather than inventing a question 0.3ms
✓
gates a paid-plan user too 1.1ms
✓
only ever probes tools that actually cost money 0.6ms
per-tool probes · 8 tests
✓
asks which competitor, since a gap analysis has nothing to compare without one 0.5ms
✓
asks for keywords on the per-keyword billed tools 0.5ms
✓
does not gate seo_enrich_keywords on its own default mode 0.2ms
✓
accepts a saved site instead of asking for a domain 0.4ms
✓
off-page takes the same saved-site escape as backlinks — it is the one that broke live 0.3ms
✓
an ARGS key can no longer open the gate — only the caller-supplied fact can 0.3ms
✓
every tool the caller looks the site up for is a tool that probes for one 2.5ms
✓
never probes verify_contacts — the tool's own picker names the lists, this layer cannot 0.4ms
rendering · 2 tests
✓
leads with the question and carries chips, not prose instructions 4.6ms
src/runtime/cron-checkin-coverage.vitest.ts
the six formerly unmonitored cron jobs check in · 20 tests
✓
probeInfraHealth is called inside withSentryCronCheckIn(env, 'infra-health-probe', …) in its arm 4.2ms
✓
'infra-health-probe' is registered at '*/3 * * * *' in MONITOR_CONFIGS 0.2ms
✓
probeInfraHealth has its own dispatcher catch that files 'scheduled:probeInfraHealth' 0.3ms
✓
corpusKeepWarm is called inside withSentryCronCheckIn(env, 'corpus-keep-warm', …) in its arm 2.8ms
✓
'corpus-keep-warm' is registered at '*/3 * * * *' in MONITOR_CONFIGS 0.2ms
✓
corpusKeepWarm has its own dispatcher catch that files 'scheduled:corpusKeepWarm' 0.2ms
✓
processDripCron is called inside withSentryCronCheckIn(env, 'drip-hourly', …) in its arm 3.9ms
✓
'drip-hourly' is registered at '0 * * * *' in MONITOR_CONFIGS 0.4ms
✓
processDripCron has its own dispatcher catch that files 'scheduled:processDripCron' 0.3ms
✓
processLifecycleCron is called inside withSentryCronCheckIn(env, 'lifecycle-hourly', …) in its arm 3.9ms
✓
'lifecycle-hourly' is registered at '0 * * * *' in MONITOR_CONFIGS 0.1ms
✓
processLifecycleCron has its own dispatcher catch that files 'scheduled:processLifecycleCron' 0.2ms
✓
runCommerceReconciliationCron is called inside withSentryCronCheckIn(env, 'commerce-reconciliation', …) in its arm 3.7ms
✓
'commerce-reconciliation' is registered at '0 * * * *' in MONITOR_CONFIGS 0.1ms
✓
runCommerceReconciliationCron has its own dispatcher catch that files 'scheduled:runCommerceReconciliationCron' 0.2ms
✓
recordNhostSnapshot is called inside withSentryCronCheckIn(env, 'nhost-snapshot', …) in its arm 3.8ms
✓
'nhost-snapshot' is registered at '0 * * * *' in MONITOR_CONFIGS 0.1ms
✓
recordNhostSnapshot has its own dispatcher catch that files 'scheduled:recordNhostSnapshot' 0.2ms
✓
the */3 monitors fit inside their own interval (margin < 3 and runtime < 3 minutes) 0.7ms
check-cron-monitors fails on a job the dispatcher runs without a check-in · 4 tests
✓
passes on the current tree, counting every dispatched job as covered 289.0ms
✓
MUTANT: recordNhostSnapshot called bare in the hourly else (slug removed so only the new rule can fire) 567.9ms
✓
MUTANT: corpusKeepWarm called bare in the */3 arm 574.5ms
✓
MUTANT: a hourly slug registered at the */3 schedule still fails (the 2026-10-14 rule, re-proven) 571.4ms
src/seo/aeo-cross.vitest.ts
deriveAeoFindings — the joins · 10 tests
✓
J1: a page that is READY and never retrieved 3.3ms
✓
J2: a page AI already cites is the weakest answer on the site 0.7ms
✓
J2 matches through www and trailing-slash drift 0.8ms
✓
J3: entity collision AND zero citations is a diagnosis, not two facts 0.3ms
✓
J3 does NOT fire when the brand is cited despite a collision 0.3ms
✓
J4: the winning shape is one nobody can publish their way into 0.7ms
✓
J4 stays silent when the winning shape IS something we can publish 0.3ms
✓
findings come back in directive order (GS-011) 0.4ms
✓
nothing on file produces nothing — never a padded finding 0.5ms
✓
every absence copy states a CONSEQUENCE, not an instruction 0.7ms
aeo_full_audit artifact (R-G acceptance) · 14 tests
✓
no longer staples three whole sub-reports together 0.3ms
✓
leads with the join, and renders all four directive groups with their absences 0.3ms
✓
shows both sides of the evidence for each finding 0.2ms
✓
names every source, its age, and whether it was on file at all 0.2ms
✓
the score is greyed and labelled provisional while the picture is partial 0.2ms
✓
a cross-check source that is absent does not grey the score 0.4ms
✓
a complete, fresh picture scores in colour with no provisional label 0.3ms
✓
a tenant with nothing on file gets guidance, never an error card 0.3ms
✓
renders both sides, both timestamps and the countable difference 0.4ms
✓
leads on the contradiction rather than on the score 0.2ms
✓
states the presence reading the "effectively absent" narrative contradicted 0.1ms
✓
claims the sources agree ONLY when the checks actually ran 0.4ms
✓
timestamps same-day sources to the minute, not "measured today" 0.8ms
✓
an artifact stored BEFORE R-G still renders its nested sub-reports (trap 14) 5.5ms
src/seo/aeo-disagreements.vitest.ts
deriveAeoDisagreements — the live contradiction · 8 tests
✓
does NOT report two runs 27 minutes apart as a contradiction 1.7ms
✓
still catches the pair that WAS one run — 0% and 40%, 36 seconds apart 1.8ms
✓
names the countable difference — the surfaces — not a guessed mechanism (AEO-008) 0.6ms
✓
goes quiet once the run publishes one share to both records — the v2.491.0 unification 0.3ms
✓
catches the stale competitor set that could only ever score zero 0.3ms
✓
catches the 33/100 headline sitting beside a real citation 0.3ms
✓
does NOT call the same day's 100-to-0 swing a disagreement 0.3ms
✓
reports every one of them — this is the tool's stated purpose, not a footnote 0.7ms
deriveAeoDisagreements — silence when the sources agree · 9 tests
✓
returns an empty list rather than padding it 0.7ms
✓
does not invent a share-of-voice conflict from noise 0.4ms
✓
says nothing about a second run that is not on file 0.4ms
✓
does not call a thin run a competitor-set mismatch 0.3ms
✓
fires only when the two runs are actually comparable 0.4ms
✓
will not let two single answers contradict each other 0.2ms
✓
will not call a changed question a changed answer 0.2ms
✓
does not compare two runs a month apart as a same-picture swing 0.4ms
✓
every disagreement carries two sides, a countable difference and a reading 0.6ms
deriveAeoDisagreements — the converse of the live defect · 1 test
✓
flags a strong score over a run that cited nothing 0.5ms
aeo_full_audit dispatch — the payload actually carries them · 6 tests
✓
is a real slice of the dispatch, not an empty string that passes everything 0.2ms
✓
loads the share-of-voice series — the second number nothing could see 0.2ms
✓
computes and RETURNS both, or the modules are dead code 0.3ms
✓
puts them ahead of the evidence tail, so the model budget cannot drop them 0.3ms
✓
stamps every source with the timestamp the ledger renders 0.2ms
✓
reports the disagreement count in telemetry 0.2ms
src/seo/citation-sources.vitest.ts
classifyPageShape · 7 tests
✓
puts a roundup before an article even though roundups live at blog paths 4.9ms
✓
recovers a roundup from the TITLE when the slug hides it 0.6ms
✓
a numbered list of products is a roundup; a numbered list of steps is not 0.5ms
✓
host rules beat slug rules 0.3ms
✓
separates a homepage from a product page 0.3ms
✓
never throws on junk, and junk is not silently a homepage 0.2ms
✓
every shape maps to exactly one fix owner (AEO-009) 0.5ms
captureSources · 5 tests
✓
rank is the engine ORDER, 1-based — not a search ranking 1.1ms
✓
a repeated URL keeps its BEST rank instead of becoming two rows 1.8ms
✓
drops non-http junk without consuming a rank 0.7ms
✓
truncation is REPORTED, never silent 0.7ms
✓
attaches a title when the provider supplied one, and omits the key when not 0.4ms
rivalSources — durability, not volume (AEO-006) · 3 tests
✓
breadth across engines outranks raw citation count 2.2ms
✓
excludes our own host — this table answers "who instead of us" 0.6ms
✓
an errored cell contributes nothing, and a pre-R-A cell is not read as empty 0.3ms
shapeMix — what KIND of page wins here (AEO-007) · 2 tests
✓
counts rival citations only, with top-3 share per shape 0.6ms
✓
an uncaptured run yields a zero total, which callers must render as "never looked" 0.2ms
fixesByOwner — who has to do the work (AEO-009) · 3 tests
✓
groups by owner and orders by where the citations actually are 0.8ms
✓
targets carry the URL, not just the host — a domain is not actionable 0.4ms
✓
excludes our own pages and returns nothing on an uncaptured run 0.3ms
rankDistribution — AEO-004, a count equal to the execution count is a constant · 4 tests
✓
marks the leading run whose count equals the answer count 0.6ms
✓
only a LEADING run is structural — a deep coincidence is not 0.2ms
✓
a genuinely uneven distribution carries no note it did not earn 0.2ms
✓
returns empty rather than inventing buckets on an uncaptured run 0.2ms
src/seo/landscape-policy.vitest.ts
Q12 — the rule is the deliverable, not the list · 6 tests
✓
returns written rules, each tied to what was measured 3.7ms
✓
writes NO rule for a problem this site does not have 1.1ms
✓
carries the "align to Google" clause, which is the counter-intuitive half 0.5ms
✓
orphans are the facet signature, and need BOTH systems 0.8ms
✓
variants are NEVER killed — a crawler cannot tell a meaningful difference from a cosmetic one 0.5ms
✓
"Google ignored the hint" is always untested — we hold only what the page declares 0.5ms
Q04 — classifying who holds the result · 1 test
✓
matches on host or subdomain, never substring 0.8ms
Q04 — the scorecard follows the park rule · 4 tests
✓
AVOID beats everything — a term held by a marketplace is parked at any position 0.9ms
✓
WIN is striking distance, using the IMPORTED definition 13.8ms
✓
a term we do not rank for is WATCH, and says why rather than guessing 0.4ms
✓
leads with the parking when nothing is winnable — that IS the saving 0.4ms
Q04 — the half of the rule we cannot compute is said out loud · 4 tests
✓
never claims rival authority 0.3ms
✓
the links hypothesis is permanently untested, and says why rank is not a substitute 0.4ms
✓
whitespace is untested — a domain does not tell you a page format 0.3ms
✓
does not re-derive striking distance 0.3ms
both — shared rules and reachability · 5 tests
✓
no confident verdict on fewer than two sources 0.5ms
✓
no internal vocabulary reaches the reader — GS-005 0.5ms
✓
route from the sentence, traceable apart, one renderer 9.1ms
✓
do not steal the tools they sit beside 0.9ms
✓
Q12 reuses the SAME technical evidence — a third read could disagree with the other two 1.6ms
Q12 delivers its policy when nothing survives · 2 tests
✓
says what it can rather than returning a bare STOP, and keeps the coverage sentence 0.9ms
✓
DOES point at the rules when it has some 0.1ms
Q04 — striking distance: the reading is having positions, not finding one · 2 tests
✓
KILLS page_two when positions were read and none sit in the range 0.2ms
✓
still reports untested when no term has a position at all 0.3ms
scripts/lib/ledger-population-check.vitest.mjs
check-ledger-population on the real tree · 3 tests
✓
passes: 31 readers declared and applied, every census file registered or allow-listed 285.2ms
✓
registers the 31 reader ids of the R3 census, LR14/LR15 (single-user) excluded 1.3ms
✓
every allow-listed kind is one of the five 2.7ms
planted mutants are caught by name · 6 tests
✓
a reader that loses its declaration (LR04 in telemetry.ts) 129.9ms
✓
a reader that declares P_real but strips every application (users.ts) 122.5ms
✓
a pooled declaration without a reason (LR10) 124.1ms
✓
a file that drops the population import (sessions.ts) 121.7ms
✓
a NEW cross-user reader that nobody registered 122.4ms
✓
the pre-fix tree shape: no population module anywhere → every reader fails, floor exit 163.5ms
declarationsIn · 1 test
✓
reads the id, the population(s) and whether a pooled declaration states why 1.7ms
each declared reader is bound to its own query (V12-data-F03) · 5 tests
✓
premise: the mutant really removes LR08's query application and nothing else 1.0ms
✓
LR08 declared, its funnel filter removed → fails naming LR08 (and only LR08) 125.5ms
✓
an inheriting reader (LR06) fails when the handle it inherits from is no longer applied 124.4ms
✓
an inheritance claim is required: dropping LR09's inherits() fails LR09 122.3ms
✓
a declaration not assigned to a handle cannot be bound to a query 121.3ms
a filter that is only TEXT is not applied (V12b-cron-data-F01) · 8 tests
✓
M2: LR08's funnel filters stripped, a COMMENT still names POP_FUNNEL.where( → fails naming LR08 121.0ms
✓
M2b: … or a BLOCK comment does 125.6ms
✓
M3: … or a dead STRING does (single, double, template text) → fails naming LR08 374.2ms
✓
M6: LR17's only application COMMENTED OUT at its use site (sessions.ts) → fails naming LR17 122.2ms
✓
a declaration that exists only in a comment is not a declaration 120.0ms
✓
an import that exists only in a comment is not an import 121.6ms
✓
THE URL TRAP: a real application on a line after a URL string still counts (no false failure) 123.9ms
✓
a regex literal holding // before an application on the same line does not hide it 120.2ms
src/billing/set-bounds-and-quotes.vitest.ts
§5 — every set-operating tool can be told how many · 12 tests
✓
generate_emails accepts a count 2.4ms
✓
generate_emails tells the model to use it 0.3ms
✓
enrich_contacts accepts a count 0.2ms
✓
enrich_contacts tells the model to use it 0.2ms
✓
verify_contacts accepts a count 0.2ms
✓
verify_contacts tells the model to use it 0.2ms
✓
assign_to_campaign accepts a count 0.3ms
✓
assign_to_campaign tells the model to use it 0.1ms
✓
enroll_in_sequence accepts a count 0.6ms
✓
enroll_in_sequence tells the model to use it 0.2ms
✓
the two tools that BILL PER CONTACT are among them 0.3ms
✓
the tool that ARMS REAL SENDS is among them 0.2ms
§2 — a quote that reads its own arguments · 11 tests
✓
backlink_outreach_search has a dynamic estimator 0.3ms
✓
backlink_outreach_search falls back to the table when the count is unknown 0.3ms
✓
seo_serp_spider has a dynamic estimator 0.2ms
✓
seo_serp_spider falls back to the table when the count is unknown 0.2ms
✓
tap_volume has a dynamic estimator 0.1ms
✓
tap_volume falls back to the table when the count is unknown 0.2ms
✓
google_god_mode_report has a dynamic estimator 0.2ms
✓
google_god_mode_report falls back to the table when the count is unknown 0.2ms
✓
a small ask is quoted below a large one — the whole point 0.2ms
✓
a known count reserves its own bound, not the catalogue ceiling 0.2ms
✓
LLM-length spread is left static rather than dressed as per-unit 0.3ms
src/chat/tool-message.vitest.ts
toolMessageContent — the JSON is always valid · 3 tests
✓
returns a small result byte-identical to JSON.stringify 2.0ms
✓
never emits a cut token, however the payload is shaped 43.8ms
✓
survives a circular result instead of killing the turn 0.3ms
toolMessageContent — what was dropped is named · 6 tests
✓
drops the largest key and says which one 3.6ms
✓
keeps the small answer keys and sheds only the evidence tail 3.4ms
✓
preserves the original key order of whatever survived 0.4ms
✓
marks a truncated bare string inside the value 0.4ms
✓
marks a shortened array with how many items went 12.2ms
✓
reports total loss honestly rather than emitting a stump 1.2ms
the search_leads shape — the omission must not read as a failure · 3 tests
✓
sheds the bulk keys and keeps every semantic key the model reasons from 0.6ms
✓
sheds `contact_ids` too, with no per-key list to maintain 0.4ms
✓
tells the model the field is intact, not missing — and not to apologise 0.5ms
toolMessageBudget — a schema rejection is a different payload · 1 test
✓
gives a rejection the larger ceiling and everything else the default 0.2ms
the industry rejection reaches the model whole · 4 tests
✓
would have been cut in half by the old 4000-character slice 0.5ms
✓
delivers all 318 labels, as valid JSON, under the rejection budget 0.6ms
✓
includes the values that sit past the old cut — the ones the retry needs 1.1ms
✓
still bounds a rejection that carries several vocabularies 0.6ms
withSoftFailureDisclosure · 6 tests
✓
leaves a healthy result completely untouched 0.2ms
✓
names the actual shortfall, not a generic warning 0.2ms
✓
keeps the original payload — the disclosure is additive, never a replacement 0.1ms
✓
makes reporting MANDATORY, not advisory 0.1ms
✓
closes the gap-filling routes by name 0.2ms
✓
tells the model that saying so IS the complete answer 0.1ms
src/leads/verify-recheck.vitest.ts
Jev decides; code keeps `unchecked` as the guarantee · 11 tests
✓
p 0.02 → unchecked, declined 28.3ms
✓
p 0.99 → the model's 'any' stands 1.1ms
✓
p 0.9 exactly → honoured (the bar is >=) 0.8ms
✓
Jev throwing → unchecked, and reported 0.8ms
✓
a malformed answer (non-finite p) → unchecked, and reported 0.8ms
✓
rollout off → unchecked, and Jev is never called 1.3ms
✓
a click (Next action: {"action":"verify_contacts","params":{"list_name":"List A","filter":{"verified":"any"}}}) is the consent: kept, and Jev is never called 4.9ms
✓
a click (Cost confirm:0f0e0d0c-0000-4000-8000-000000000001) is the consent: kept, and Jev is never called 0.7ms
✓
the default (unchecked) is not a request: nothing to decide, Jev never called 0.4ms
✓
the default (undefined) is not a request: nothing to decide, Jev never called 0.4ms
what Jev sees · 3 tests
✓
the exact question, context and timeout 0.9ms
✓
addresses are masked, and neither the model's argument nor any count is in the state 1.0ms
✓
offered is true only when the previous reply carried the re-check marker 0.3ms
the loop decides BEFORE anything prices the call · 3 tests
✓
decideVerifyRecheck runs before the quote reads the count and before the card is staged 0.6ms
✓
a decision that differs narrows the call IN PLACE — to what it named, via declinedRecheckArgs — so the card and the run read it 0.7ms
✓
the decision rides the run signal, source included 0.3ms
declinedRecheckArgs · 6 tests
✓
'invalid' declined → the ids it named, with unchecked: nothing to buy 0.3ms
✓
'valid' declined → the same shape 0.2ms
✓
(neg) never rewrites a declined 'invalid' to unchecked on the list — that set shares no address with it 0.2ms
✓
named nothing, or unread → left as asked (the dispatch backstop answers without spending) 0.2ms
✓
capped at contact_ids' own schema ceiling 0.3ms
✓
the source the dispatch records 0.3ms
src/runtime/guard-sandbox-copy.vitest.ts
sandboxCopyFilter — what no guard reads stays out · 12 tests
✓
skips blog/public/images/hero.webp 2.2ms
✓
skips client/font.woff2 0.3ms
✓
skips admin-app/node_modules 0.2ms
✓
skips blog/.wrangler 0.2ms
✓
keeps blog/wrangler.toml 0.3ms
✓
keeps src/index.ts 0.2ms
✓
keeps scripts/check-deploy-path.mjs 0.7ms
✓
keeps docs/README.md 0.3ms
✓
keeps blog/src/icon.svg 0.3ms
✓
keeps migrations/184_x.sql 0.1ms
a real sandbox · 2 tests
✓
still carries what check-deploy-path discovers (every wrangler config) 0.4ms
✓
holds no image, font or archive (the 60 MB of blog images that filled /tmp) 25.4ms
copyIntoSandbox — a transient I/O error is retried, a real one is not · 3 tests
✓
EIO once, then success: the sandbox is built 100.7ms
✓
EIO three times: gives up and throws the real error 301.9ms
✓
a non-transient error (ENOENT) is not retried 0.5ms
createGuardSandbox({ only }) — a suite copies what its guard reads, and nothing it names can vanish · 6 tests
✓
copies the named entries and none of the others 0.4ms
✓
the guards it hosts still run: check-graphql-schema is green in the narrowed copy 811.1ms
✓
an entry that is not in COPY throws instead of silently copying nothing 0.4ms
✓
a sub-path of a COPY entry copies exactly that path 2.1ms
✓
a sub-path that does not exist throws — a typo must not copy nothing 0.4ms
✓
a sub-path cannot climb out of its entry 0.2ms
src/tools/openapi.vitest.ts
search_leads schema — the incident this exists to prevent · 8 tests
✓
rejects a sentence in the industry enum 3.8ms
✓
gives free intent a home that is not an enum 0.5ms
✓
constrains every field that the provider constrains 0.9ms
✓
exposes the filters the provider still offers 0.4ms
✓
exposes the fields the rebuild introduced 0.9ms
✓
leaves person_titles free text — the provider matches titles loosely 0.2ms
✓
takes no free-text query field — that field IS the defect 0.3ms
✓
refuses unknown arguments rather than passing them through 0.2ms
search_leads schema — both live branches are covered · 3 tests
✓
carries the local-business fields, not only people search 0.7ms
✓
states the postal-code/country pairing rule 0.4ms
✓
constrains country_code to the maps actor's own ISO-2 list 0.6ms
enum ↔ resolver agreement (the drift that would 400 live) · 2 tests
✓
every geography enum value resolves through the country ladder 11.1ms
✓
company sizes use the UNSPACED ranges the provider currently requires 0.6ms
copy rules on a document a model reads and a browser can fetch · 3 tests
✓
names no backend vendor 1.2ms
✓
quotes no dollar amount for what nqzai charges 0.2ms
✓
never calls anything free 0.9ms
buildToolsOpenApi · 5 tests
✓
emits OpenAPI 3.1 with one operation per schematised tool 0.4ms
✓
derives the request schema from TOOL_SCHEMAS — no second copy 0.1ms
✓
reports enforcement state truthfully 0.1ms
✓
documents the rejection response so a caller can retry correctly 0.2ms
✓
uses the origin it was given 0.1ms
getToolSchema · 2 tests
✓
returns null for an unschematised tool rather than a partial object 0.3ms
✓
is not fooled by inherited object keys 0.1ms
src/seo/merge-compare.vitest.ts
merged_totals reads the source comparison, never a second summation · 5 tests
✓
reports the decline the source measured 2.7ms
✓
never disagrees with compare.gsc.totals — they are now the same object 0.3ms
✓
is null when a source ran no comparison — not a zero prior 0.3ms
✓
takes sessions and revenue from GA4 deltas 0.5ms
✓
survives a GA4 block whose deltas are null (empty window) 0.2ms
an empty analytics window is not a window of zeros · 5 tests
✓
suppresses the deltas and names the reason when the current period has no rows 0.3ms
✓
does not report -100% for a period Analytics never measured 0.4ms
✓
does NOT claim a comparison when both periods are empty — nothing was measured 0.3ms
✓
still compares when the current period has rows 0.8ms
✓
reports both row counts so a reader can check the basis 0.3ms
the model timeout scales with what the model was asked to read · 5 tests
✓
leaves a small turn on the old fixed budget 0.3ms
✓
gives the 105K-token turn enough budget to have finished 2.0ms
✓
caps a pathological prompt rather than holding the turn open 107.4ms
✓
keeps the 60s floor for reasoning calls 0.3ms
✓
handles null/empty message lists 0.2ms
a paid call that degrades must not degrade invisibly · 1 test
✓
nameThemes reports its failure instead of swallowing it 1.4ms
one source being silent must not read as no data at all · 6 tests
✓
states the Search Console comparison plainly, with direction 13.8ms
✓
says Analytics is UNMEASURED and forbids generalising it to the whole period 0.3ms
✓
never claims there is no prior data when one source has it 0.3ms
✓
says so plainly when no comparison was requested 0.2ms
✓
reports an up-move with a sign 0.2ms
✓
handles Search Console having nothing to compare 0.1ms
the model sees the summary, not two page rows · 1 test
✓
orders the merge result so compare precedes rows 0.5ms
src/seo/overview-attribution.vitest.ts
movements joins on keywords present in BOTH windows · 3 tests
✓
a keyword in only one window is not a movement 2.2ms
✓
excludes keywords under the impressions floor on EITHER side 1.2ms
✓
matches case-insensitively, so one casing change is not a lost query 0.3ms
the arithmetic test — the template's "fake CTR crash" · 6 tests
✓
impressions up, clicks held, position held → arithmetic 0.4ms
✓
clicks actually down is NOT arithmetic — that is a real loss 0.2ms
✓
a position that slid is a ranking story, not an answer box 0.2ms
✓
impressions barely moving is not inflation 0.2ms
✓
a CTR that did not fall is never arithmetic 0.3ms
✓
a missing position on either side refuses rather than assuming it held 0.5ms
real click loss · 2 tests
✓
is measured against the earlier reading, not an absolute 0.3ms
✓
a query with no clicks to begin with cannot have lost any 0.3ms
attributionStats suppresses shares below the floor · 3 tests
✓
reports readable=false rather than a number computed from four queries 0.3ms
✓
and readable once the floor is met 0.3ms
✓
the arithmetic share is null when nothing fell — never 0%, which reads as a finding 0.2ms
Q03 legs inside the Q11 brief · 6 tests
✓
kills the premise when clicks did not fall — there is no loss to attribute 14.5ms
✓
confirms the arithmetic fall and says it would fund the wrong work 0.5ms
✓
does NOT call it arithmetic when the clicks really went 0.3ms
✓
NEVER attributes the fall to an answer box — permanently untested 0.4ms
✓
names the confounders by name rather than hedging 0.3ms
✓
the causal hypothesis never claims two sources — that would be one system twice 0.4ms
no history is a state, not a silence · 3 tests
✓
one window says so, and says it answers itself 0.3ms
✓
a span mismatch is reported as its own cause, not as missing data 0.4ms
✓
an account with no history at all still gets the other hypotheses 0.3ms
src/seo/primary-source.vitest.ts
allCitedHosts · 2 tests
✓
counts every citation, ours included — the denominator is ALL of them 3.2ms
✓
an errored engine contributes nothing either way 1.1ms
INTERMEDIARY_KINDS excludes the sources that ARE primary · 1 test
✓
a standards body or regulator is never a middleman 1.0ms
the middleman test · 3 tests
✓
survives when intermediaries outweigh our own pages 0.6ms
✓
is killed when our own pages carry the answer 0.6ms
✓
names the entity-card gap only when NOTHING of ours is cited 0.5ms
too few citations is not a position in a source graph · 3 tests
✓
every citation-based hypothesis is untested below the floor 0.6ms
✓
names how many there actually were 0.2ms
✓
a single source is not two — the confident branch stays out of reach 0.7ms
what it deliberately does NOT answer · 3 tests
✓
the page side is deferred to the E-E-A-T review, and says so 0.4ms
✓
it still reports the author count it saw, as corroboration only 0.3ms
✓
WHY a page was quoted is not recorded, so that stays untested 0.2ms
the brief holds the contract · 4 tests
✓
states the shares in its situation line 0.4ms
✓
says plainly when there is no run 0.2ms
✓
an ungrounded run is labelled recall 0.3ms
✓
carries the one-pager fields and a headline of its own 0.8ms
Q07, Q05 and Q20 are wired · 3 tests
✓
Q07 is built, chained, in both payload lists and rendered 0.9ms
✓
Q05 and Q20 are registered playbooks reachable from the dispatcher 0.6ms
✓
all three are routed and labelled in the turn 1.4ms
a tie is not a finding, and an unclassified majority is not a source graph · 4 tests
✓
a dead heat between the two shares is untested, not a reassuring "killed" 0.7ms
✓
refuses when most citations are domains nothing recognises 1.2ms
✓
the situation line states the unrecognised share rather than hiding it 0.5ms
✓
still answers when the gap is wide and the classification is good 0.4ms
src/seo/serp-spider.vitest.ts
robots.txt disallow parsing · 3 tests
✓
parses typical disallow rules for global agent * 48.8ms
✓
correctly matches URLs against disallow rules 1.5ms
✓
always probes orphans + exact_absent gaps in full; caps only bulk healthy/ambiguous 2.0ms
serpdex durable queue · 13 tests
✓
enqueues onto SERPDEX_QUEUE when the binding is present (no waitUntil) 2.5ms
✓
falls back to ctx.waitUntil when the queue is unbound 20.2ms
✓
report counts only exact_absent as gaps — a verified-indexed sitemap URL is never a gap 41.9ms
✓
report renders round-3 fixes: orphan reconciliation, dynamic actions, canonical, redirect, score note 2.0ms
✓
report surfaces the paid-tier upsell when free verification was capped 0.8ms
✓
crawl-only (no verify) report is PROVISIONAL — unconfirmed, not "0 gaps healthy" 1.8ms
✓
provisional CAPPED run tells the user to top up, not to re-run (re-run checks the same set) 1.4ms
✓
SCORING BUG (owner, 2026-08-02): a capped run that DID exact-verify some URLs must not score as if it verified all of them 2.3ms
✓
unconfirmed sitemap URLs are never submittable even alongside a confirmed gap 0.8ms
✓
paid tier hides the token top-up upsell (already unlocked) 0.6ms
✓
runSerpdexJob marks the task failed AND rethrows so the queue retries 15.5ms
✓
threads serp_features_keywords into the queued job payload 0.8ms
✓
omits serpFeaturesKeywords from the job entirely when no keywords were requested 0.4ms
seo_serp_spider report — SERP-intelligence section (three states) · 4 tests
✓
never requested, FREE tier → shows a labeled dummy-data preview with a LOCKED button 0.8ms
✓
never requested, PAID tier → same dummy preview, but the button is live (unlocked) 0.6ms
✓
requested on the free tier → locked state with a top-up CTA, no fabricated results 0.5ms
✓
populated (paid tier) → aggregate counts + per-keyword PAA/related drill-down 0.8ms
fetchSerpIntelligence — SERP-features add-on · 3 tests
✓
extracts and dedupes peopleAlsoAsk + relatedSearches per keyword (the response shape the SERP provider returns) 1.8ms
✓
caps at 5 keywords, silently dropping the rest — matches the schema's maxItems 1.5ms
✓
one keyword failing (provider hiccup) does not drop the others — empty findings, not a thrown batch 2.3ms
src/ai-crawler-tracking.vitest.ts
'blog' Worker: DataFast AI-crawler tracking · 11 tests
✓
uses the same websiteId as the outbound Worker 2.5ms
✓
reports a crawler page hit with the public URL and the final status code 31.8ms
✓
carries a 404 through, so crawlers hitting dead URLs are visible 0.9ms
✓
never awaits DataFast: the page returns while the POST is still in flight 1.1ms
✓
sends nothing for a human visitor 0.8ms
✓
skips framework internals under the basePath, which the library defaults miss 1.1ms
✓
still reports crawler-facing files under the basePath (sitemap.xml) 1.0ms
✓
a DataFast outage never reaches the page 1.4ms
✓
a synchronous throw inside tracking never reaches the page 1.4ms
✓
does not swallow an error from the page itself 1.2ms
✓
keeps every other handler on the wrapped Worker 0.4ms
'docs-site' Worker: DataFast AI-crawler tracking · 11 tests
✓
uses the same websiteId as the outbound Worker 0.2ms
✓
reports a crawler page hit with the public URL and the final status code 1.0ms
✓
carries a 404 through, so crawlers hitting dead URLs are visible 0.5ms
✓
never awaits DataFast: the page returns while the POST is still in flight 0.5ms
✓
sends nothing for a human visitor 0.4ms
✓
skips framework internals under the basePath, which the library defaults miss 0.6ms
✓
still reports crawler-facing files under the basePath (sitemap.xml) 0.5ms
✓
a DataFast outage never reaches the page 0.6ms
✓
a synchronous throw inside tracking never reaches the page 0.6ms
✓
does not swallow an error from the page itself 0.3ms
✓
keeps every other handler on the wrapped Worker 0.2ms
src/admin/gsc-coverage-sampler.vitest.ts
runRollingCoverageSample — quota + failure disclosure (the contract that moved) · 6 tests
✓
reserves the shared daily quota ONCE per run, for the slice it is about to inspect 31.1ms
✓
inspects only what was granted and flags quota_exhausted when the budget ran out 1.1ms
✓
counts partial failures and returns the reason 1.2ms
✓
treats a 429 as rate-limited and stops rather than burning the rest of the slice 1.0ms
✓
never opens more than the bounded number of concurrent inspections 10.4ms
✓
reports the real universe size so the card shows a denominator, not a bare count 7.1ms
runRollingCoverageSample — what the rolling design adds · 5 tests
✓
never STARTS an inspection past its deadline, and keeps what it finished 2.1ms
✓
walks the universe: each run starts where the last stopped, and results accumulate 4.5ms
✓
keeps Google's chosen canonical, so a duplicate says which page won 1.8ms
✓
a quota GUARD failure is reported as such — never as "quota exhausted" 1.0ms
✓
rebuilds the URL universe at most daily (the blog sitemap is the slow part) 1.6ms
isCoverageStale — the gate that froze the page · 4 tests
✓
treats a missing cache as stale (first run must always sample) 0.3ms
✓
holds a fresh snapshot inside the window — this is correct, and is why an explicit force is REQUIRED 0.2ms
✓
opens once past the window 0.2ms
✓
treats an unparseable timestamp as stale rather than trusting it 0.2ms
admin GSC performance requests — the shape every number depends on · 3 tests
✓
asks for fresh (preliminary) data, not only finalised days 8.0ms
✓
fetches property totals with NO dimensions, aggregated byProperty 0.8ms
✓
surfaces Google's own first_incomplete_date instead of guessing a fixed lag 0.7ms
runRollingCoverageSample — the live timing budget (2026-09-23) · 4 tests
✓
the per-call timeout leaves room for a normal ~7-8 s inspection 0.3ms
✓
the worst background run (last start + one full timeout) fits inside ctx.waitUntil 0.2ms
✓
the worst awaited run fits inside the 100 s proxy limit 0.2ms
✓
the configured timeout is what each call actually gets (real timers, scaled down) 85.9ms
src/auth/account-export-schema.vitest.ts
the account export reads only columns production has · 22 tests
✓
the snapshot is a real capture, so this test cannot pass by reading nothing 1.7ms
✓
contacts: every selected column, the user_id scope and the sort column exist 0.9ms
✓
contact_lists: every selected column, the user_id scope and the sort column exist 0.2ms
✓
campaigns: every selected column, the user_id scope and the sort column exist 0.2ms
✓
emails_sent: every selected column, the user_id scope and the sort column exist 0.3ms
✓
templates: every selected column, the user_id scope and the sort column exist 0.2ms
✓
drip_sequences: every selected column, the user_id scope and the sort column exist 0.2ms
✓
drip_enrollments: every selected column, the user_id scope and the sort column exist 0.2ms
✓
tracked_keywords: every selected column, the user_id scope and the sort column exist 0.5ms
✓
keyword_site_performance: every selected column, the user_id scope and the sort column exist 0.3ms
✓
connections: every selected column, the user_id scope and the sort column exist 0.2ms
✓
token_usage: every selected column, the user_id scope and the sort column exist 0.1ms
✓
ai_prompts: every selected column, the user_id scope and the sort column exist 0.1ms
✓
activity_events: every selected column, the user_id scope and the sort column exist 0.1ms
✓
chat_response_feedback: every selected column, the user_id scope and the sort column exist 0.1ms
✓
seo_snapshots: every selected column, the user_id scope and the sort column exist 0.1ms
✓
aeo_snapshots: every selected column, the user_id scope and the sort column exist 0.1ms
✓
entity_snapshots: every selected column, the user_id scope and the sort column exist 0.1ms
✓
marketing_plans: every selected column, the user_id scope and the sort column exist 0.1ms
✓
marketing_initiatives: every selected column, the user_id scope and the sort column exist 0.1ms
✓
content_pieces: every selected column, the user_id scope and the sort column exist 0.1ms
✓
the document the handler sends is built from exactly those names 0.2ms
src/chat/site-ask.vitest.ts
who is eligible — code decides whether Jev is even asked · 7 tests
✓
a first prompt, no site, no brief, no URL → eligible 2.6ms
✓
a site on file → not eligible 0.5ms
✓
a brief on file / a skip (onboardingTurn false) → not eligible 0.5ms
✓
a URL in the message → not eligible 0.4ms
✓
a site offer → not eligible 0.3ms
✓
a machine message → not eligible 0.3ms
✓
not the first prompt → not eligible 0.3ms
decideSiteAsk — Jev decides, code guarantees · 7 tests
✓
below the bar → no ask (answered as today) 1.1ms
✓
context not rolled out → no ask, and Jev is not called 1.2ms
✓
Jev failing → no ask, and reported 0.8ms
✓
an answer with no probability is a failure, never a silent 0 0.5ms
✓
the call is bounded — a first turn does not wait on Jev past the timeout 0.7ms
✓
the question is a noul over the request, and the state asserts no verdict 0.6ms
what the reply carries · 3 tests
✓
an ask carries the question, the original message to re-send, and is labelled as Jev's 0.4ms
✓
the model is told the field exists and not to ask again — and is not told to stop working 0.5ms
✓
a shortcut ask carries no resend unless given one 0.3ms
wiring in src/index.ts · 5 tests
✓
runChatV2 decides only for an eligible turn, reports a failed judgment, and tells the model 0.7ms
✓
with the field shown the composer-prefill chip is dropped and the skip chip stays 0.3ms
✓
the ask reaches the final event and the history 0.7ms
✓
the two deterministic "what is your website?" replies carry the field too (sweep) 0.4ms
✓
the context is rolled out 0.6ms
src/llm/router.vitest.ts
resolveToolModelChain — Phase 0 eval override seam · 5 tests
✓
is unaffected by default (no override set) 2.8ms
✓
leads with the mapped candidate model when a valid override is set 0.4ms
✓
falls through to the normal TOOL_MODELS chain after the candidate (never narrows reliability) 0.7ms
✓
rejects an unknown key — reqCtx stays null, no injection 0.7ms
✓
never includes the disqualified judge-family model as a candidate 0.3ms
resolveRouterRollout — env flag parsing · 3 tests
✓
returns null for unset/off/empty (no live change) 0.3ms
✓
maps a known candidate key to its model id 0.2ms
✓
returns null for an unknown key rather than injecting it as a model id 0.1ms
resolveToolModelChain — live rollout flag · 4 tests
✓
default 'off' leaves the chain exactly as it ships today 0.5ms
✓
leads with the rollout model and keeps the tier chain behind it as failover 0.3ms
✓
an unknown flag value falls back to the normal chain (fail-safe, not fail-open) 0.2ms
✓
the admin eval override outranks an active live rollout 0.2ms
timeout errors name the model and the budget · 3 tests
✓
callOpenRouterTools reports a timeout, not "The operation was aborted" 3.1ms
✓
callOpenRouterFull reports a timeout the same way 1.2ms
✓
a non-abort failure keeps its own message 0.6ms
callOpenRouterFull — attempts and the http span · 7 tests
✓
a 429 then a 200: both attempts recorded, exactly one http span (ok:false, http_429) 26.7ms
✓
the same model inside its cooldown: a cooldown_skip attempt and NO extra span 1.4ms
✓
a chain that fails entirely throws an error that carries every attempt 2.2ms
✓
empty content and a timeout-free network error are named, not folded into ok 1.9ms
✓
servedModel is the id in the response body, not the one asked; `model` stays the chain entry 0.9ms
✓
servedModel falls back to the asked id when the body names none 1.2ms
✓
a 200 on the first try: one ok attempt, no http span 1.0ms
src/reports/contracts.vitest.ts
report contract registry — predicate hygiene · 2 tests
✓
every registered contract has at least one executable predicate (no empty stubs) 2.1ms
✓
an unregistered non-prose type is itself reported as a violation 0.5ms
report contract predicates — fixture execution · 9 tests
✓
entity_audit: sound fixture passes, count-mismatch + out-of-range fails 0.7ms
✓
score bounds are validated for every scored report (god_mode health + backlinks DR) 0.6ms
✓
entity_audit: the glenindia.com mislabel (partial verdict on a different-entity match) is caught 0.9ms
✓
share_of_model leg: the isOurs-phantom shape (coverage>0, no ours cited) is caught 0.6ms
✓
share_of_model leg: citing cannot exceed answered 0.2ms
✓
campaign_stats: opened emails cannot exceed sent emails 0.3ms
✓
campaign_stats: a stage bucket cannot exceed the audience it is drawn from 0.5ms
✓
campaign_stats: replies with nobody parked at "opened" is VALID, not a violation 0.2ms
✓
campaign_stats: a contact at "opened" from an earlier campaign with 0 sent is VALID 0.2ms
aeo_visibility transparency contract · 3 tests
✓
a positive score with no prompt matrix is a violation 1.0ms
✓
a positive score backed by prompts is sound 0.4ms
✓
a zero/absent score is not asserted (nothing measured yet) 0.3ms
aeo_full_audit — a cited site can never be graded absent · 6 tests
✓
a sound synthesis result passes 0.2ms
✓
catches the live defect: presence graded absent while the run cited us 0.2ms
✓
catches a citation count that exceeds the answers received (AEO-001) 0.2ms
✓
catches a synthesis run that never checked for disagreements at all 0.2ms
✓
catches a one-sided "disagreement" 0.2ms
✓
legacy artifacts (no synthesis flag, no presence) still pass 0.1ms
campaign_stats and campaign_dashboard are ONE contract, not two copies · 2 tests
✓
the two entries are the same object 0.1ms
✓
and the alias still enforces the funnel invariants 0.2ms
src/tools/disambiguation-rules.vitest.ts
the four rules that belong to no tool · 5 tests
✓
ADVISORY vs IMPERATIVE — the planner's entire reachability 2.0ms
✓
and never by dumping a SAVED plan, which happened once 0.6ms
✓
AN EXPLICIT COUNT IS THE ANSWER — applies to every list-returning tool 0.3ms
✓
ANSWER, DO NOT RE-ASK — a specified request is not a question 0.3ms
✓
the legacy alias names, which are the MODEL'S vocabulary and not any tool's 0.4ms
the seventeen that moved are on their tools · 12 tests
✓
item (1) is on search_leads 0.3ms
✓
item (2) is on list_contacts 0.2ms
✓
item (5) is on seo_onpage_audit 0.2ms
✓
item (6) is on seo_backlink_deep_scan 0.5ms
✓
item (7) is on seo_serp_spider 0.2ms
✓
item (10) is on aeo_full_audit 0.2ms
✓
item (11) is on search_leads 0.2ms
✓
item (13) is on seo_geo_research 0.1ms
✓
item (14) is on generate_emails 0.1ms
✓
item (15) is on seo_google_merge 0.2ms
✓
item (16) is on seo_backlink_value 0.2ms
✓
item (17) is on find_competitors 0.1ms
the two defects found while reading it · 2 tests
✓
no route to full_seo_audit survives, in EITHER arrow spelling 0.3ms
✓
the stray "(17b)" that numbered two rules 17 is gone 0.2ms
the duplication is gone · 3 tests
✓
the eighteen-item routing table is not in V2_SYSTEM 0.2ms
✓
the residue is a quarter of what it replaced 0.2ms
✓
V2_SYSTEM stays under its ratchet 0.1ms
src/seo/backlink-value.vitest.ts
source matching · 2 tests
✓
reads the host half of GA4 source/medium 1.9ms
✓
matches subdomains in both directions 0.4ms
computeBacklinkValue — measured, never appraised · 12 tests
✓
uses GA4 revenue when there is revenue 14.7ms
✓
prices traffic at the tenant's OWN value per session, not a benchmark 0.5ms
✓
refuses to price traffic at all when the property records no revenue 0.6ms
✓
values a domain ONCE however many links it has 0.4ms
✓
sums a host split across mediums instead of counting it twice 0.5ms
✓
distinguishes "sent nothing" from "we could not look" 0.4ms
✓
flags value landing on dead pages as recoverable 0.8ms
✓
does not call a domain wasted when only SOME of its targets are dead 0.4ms
✓
applies NO nofollow or hosting discount — those are rules about crawlers, not visitors 1.2ms
✓
ignores (direct) and (not set), which are not referring domains 0.2ms
✓
leads with concentration when a few domains carry everything 0.3ms
✓
says so plainly when there is nothing on file 0.2ms
why the property guard has to exist upstream · 1 test
✓
matches purely on source host, with no property awareness 1.0ms
the connected property parses to a host in both GSC forms · 3 tests
✓
reduces a domain property to its host 0.2ms
✓
reduces a URL-prefix property to the same host 0.2ms
✓
agrees with normDomain on a bare host, so the guard is stable across all three 1.7ms
a report must not contradict its own columns · 4 tests
✓
calls sessions-without-revenue unpriced, never "no traffic" 0.3ms
✓
says visits ARRIVED when they did, even with nothing to price them by 0.3ms
✓
still says nothing arrived when nothing did 0.2ms
✓
carries DR, follow-state and anchors through for the profile section 0.3ms
src/seo/engine-divergence.vitest.ts
the overlap measure itself · 3 tests
✓
is Jaccard — shared over union, not shared over either side 1.8ms
✓
two engines that retrieved NOTHING share nothing — never 100% 0.3ms
✓
hostOf strips www and drops anything unparseable rather than guessing 0.4ms
the real run: engines are not reading the same web · 6 tests
✓
corpus_disjoint survives, and quotes the CLOSEST pair not the average 0.5ms
✓
names two engine FAMILIES as its sources — the engines are the independent systems 1.0ms
✓
counts the prompts no engine cited at all, without folding them into a cause 0.3ms
✓
bot_access is RULED OUT on a site whose checks all pass — not left untested 0.8ms
✓
third_party_cited reads owned citations against third-party ones 0.2ms
✓
a www-prefixed owned URL still counts as ours 0.5ms
bot access is the one cause with a genuinely separate second reading · 2 tests
✓
a blocked crawler makes it survive, and it is named 0.7ms
✓
with no crawl on file it is untested, not silently ruled out 0.6ms
what it refuses to say · 5 tests
✓
the ranking hypothesis is permanently untested, with the reason 0.6ms
✓
an UNGROUNDED run says the engines answered from memory, not that nothing ran 0.7ms
✓
no run at all is a different sentence again 0.4ms
✓
the ask names the ranking blind spot when the join is absent 0.5ms
✓
claims no traffic or revenue consequence it has not observed 0.6ms
the Google-grounded / chat split · 2 tests
✓
survives only on a real gap, and names both sides with their rates 0.6ms
✓
is ruled out when the two families are close — no separate programmes on this evidence 0.5ms
the decision when several findings hold at once · 4 tests
✓
does not tell the reader to run what it just read 0.5ms
✓
says they are separate plays, and names them 0.9ms
✓
access still takes precedence INSIDE the multi-survivor case 1.0ms
✓
a SINGLE survivor still gets its own actFirst line, not the plan wording 0.8ms
src/seo/keyword-map.vitest.ts
Q03: the revenue gate is named, never quietly dropped · 5 tests
✓
keeps the revenue hypothesis permanently untested 16.2ms
✓
says volume alone is not a reason to target 0.7ms
✓
calls the ordering a map of what is reachable, not what is worth reaching 0.3ms
✓
asks for the one figure that would close the gate 0.3ms
✓
still asks for sign-off when every term landed in one bucket 1.9ms
Q03: the kill list is produced and counted · 3 tests
✓
kills terms with neither volume nor a single impression 0.7ms
✓
names the kill list in the ask, because the template asks for it to be signed off 0.3ms
✓
says plainly why a killed term is on the list at all 0.3ms
Q03: the map separates the four kinds of work · 4 tests
✓
parks terms already at the top as no-compete 0.7ms
✓
sends striking-distance terms to consolidate, not to a new page 0.3ms
✓
targets measured demand with no page behind it 0.3ms
✓
ranks improvement above production in the decision 0.3ms
Q03: the unevidenced share is surfaced, not hidden · 2 tests
✓
warns when most of the list carries no demand figure 0.4ms
✓
does not warn when the list is well evidenced 0.3ms
Q03: brand detection is conservative on purpose · 5 tests
✓
matches the domain label 0.2ms
✓
does not match an unrelated commercial term 0.2ms
✓
matches the brand when punctuation surrounds it 0.3ms
✓
still does not match a different word that merely contains the brand 0.1ms
✓
refuses to guess from a very short domain label 0.1ms
Q03: never looked is not nothing found (GS-004) · 2 tests
✓
separates "nothing tracked" from "tracked but never measured" 0.4ms
✓
leaves the page-type hypothesis untested — positions are stored, page types are not 0.2ms
Q03: no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps table and field names out of the prose 0.5ms
src/seo/recovery-generative-eligibility.vitest.ts
Q06: recovery is subtraction · 7 tests
✓
leads with do not publish more of the same 2.9ms
✓
identifies the template that moved rather than the whole domain 0.7ms
✓
will not report a percentage fall from a template that had nothing to fall from 0.4ms
✓
needs a real early baseline before calling a fall 0.2ms
✓
refuses to compare a window too short to split 0.7ms
✓
rules out the measurement BEFORE any programme when analytics is silent 0.6ms
✓
keeps the manual action unknown and says it decides the answer 0.4ms
Q11: not all of search, and never a share from a tiny sample · 8 tests
✓
classifies seen-and-not-clicked as overview-prone 13.4ms
✓
classifies a healthy first-page query as classic 0.5ms
✓
refuses to classify below the sample floor 0.3ms
✓
says leave the stable ones alone, in as many words 1.1ms
✓
never states a share of voice from a tiny sample 0.4ms
✓
excludes branded queries from the classification 0.3ms
✓
never claims to have seen the results page 0.4ms
✓
uses the SAME thresholds as the measurement contract 0.2ms
Q21: titles before markup · 6 tests
✓
leads with the cheaper fix 0.7ms
✓
finds pages ranking well and barely clicked 1.0ms
✓
never calls found markup VALID or eligible 0.4ms
✓
never claims to know which features are winnable 0.3ms
✓
warns about retired features and the 28-day window 0.3ms
✓
treats absent markup as an eligibility gap, not a ranking cause 0.3ms
all three keep internal vocabulary out (GS-005) · 1 test
✓
no field or table names in the prose 1.0ms
src/admin/feedback-rca.vitest.ts
feedback-rca — retry predicate · 5 tests
✓
retries on a request timeout (AbortError) 1.6ms
✓
retries on a length-truncated empty/short reasoning reply 0.5ms
✓
does NOT retry (propagates) a genuine error 0.4ms
✓
retries on an OpenRouter 400/404 (unknown or delisted model id) — 2026-07-21 model swap safety net 0.3ms
✓
does NOT retry 401/403 even though they are 4xx — same key would fail identically on the fallback 0.2ms
feedback-rca — repo file targeting · 4 tests
✓
ranks the file that actually threw above one that merely shares a word with the operation 0.8ms
✓
a directory or basename match beats an incidental substring anywhere in the path 0.3ms
✓
drops generic verb prefixes from a culprit so every handler does not match everything 0.6ms
✓
still works with no culprits at all (telemetry-only run) 0.5ms
feedback-rca — F6 dynamic file budget · 3 tests
✓
floors at the original static budget for a narrow window 0.3ms
✓
scales up for a window implicating many operations 0.2ms
✓
caps at double the static budget so the prompt stays bounded 0.1ms
feedback-rca — F4 tenant identity · 4 tests
✓
tags rows whose user_id is a known internal/eval account 0.2ms
✓
does not tag a real customer row 0.1ms
✓
treats a missing user_id as NOT internal rather than throwing 0.1ms
✓
preserves every other field on the row untouched 0.1ms
verifyRcaPaths — a cited path that does not exist must say so · 5 tests
✓
flags the exact fabricated path from the 2026-08-17 report 0.5ms
✓
stays silent when every cited path resolves 0.1ms
✓
is silent on a report that cites no source paths at all 0.1ms
✓
strips trailing punctuation before deciding a path is unknown 0.1ms
✓
lists each unknown path once, however often it is cited 0.1ms
src/chat/next-action-seal.vitest.ts
a typed next action is refused and never runs · 6 tests
✓
a typed action that IS a chip target is refused too — typing it is not clicking it 0.3ms
✓
a made-up signature is refused as forged, including one dated in the past 2.7ms
✓
an unparseable payload is refused with the malformed copy 0.3ms
a server-emitted, signed action executes · 5 tests
✓
the chip round-trips through the client and is admitted with its own arguments 2.5ms
✓
a spread argument set (define_icp → search_leads) survives the round trip whole 1.1ms
✓
argument key order does not matter — the signature is over the canonical form 1.0ms
✓
history keeps the action as the user saw it, without the signature 0.6ms
✓
a panel chip carries no signature — it opens a panel and never posts back 0.5ms
a signed action is bound to its user, session, arguments and lifetime · 7 tests
✓
user A's signed action replayed by user B is refused 0.6ms
✓
the same user in another session is refused 0.6ms
✓
an expired action is refused, with its own copy 0.8ms
✓
changed arguments are refused (the signature covers them) 0.5ms
✓
a genuine signature moved onto another action is refused 0.5ms
✓
even a valid signature over a tool no chip can offer is refused 0.5ms
✓
the signer will not sign a tool no rule offers 0.2ms
with no signing secret, nothing dispatchable is offered and nothing runs · 2 tests
✓
dispatching chips are dropped rather than sent unsigned; panel chips survive 0.3ms
✓
a click is refused as no_key 0.2ms
refusal copy · 1 test
✓
every refusal says nothing ran, and none prices anything in currency 0.6ms
src/drip/migration-187-plan.vitest.ts
the plan: 187 owns its three columns and nothing else · 15 tests
✓
008 is live (187 runs before 188): adds the three columns and carries filter and check through exactly 3.3ms
✓
008 is live (187 runs before 188): --clear after apply puts back exactly what was live before 0.5ms
✓
008 is live (187 runs before 188): a second apply, and a clear with nothing to clear, are no-ops 0.5ms
✓
188 is live (187 runs after 188): adds the three columns and carries filter and check through exactly 0.6ms
✓
188 is live (187 runs after 188): --clear after apply puts back exactly what was live before 0.4ms
✓
188 is live (187 runs after 188): a second apply, and a clear with nothing to clear, are no-ops 0.4ms
✓
188 landing between 187 and its --clear is kept: the clear never reverts 188 0.4ms
✓
carries Hasura's default backend_only: false through 0.3ms
✓
refuses on drift: no permission at all 0.6ms
✓
refuses on drift: a check nobody wrote down 0.3ms
✓
refuses on drift: a different filter 0.3ms
✓
refuses on drift: a column preset 0.2ms
✓
refuses on drift: backend_only: true 0.2ms
✓
refuses on drift: a column list neither shape 0.2ms
✓
refuses on drift: only some of 187's columns 0.2ms
187's copy of 188's CHECK is 188's CHECK · 1 test
✓
matches the pg_create_update_permission for drip_enrollments in 188_user_role_write_references_and_suppression.json 0.8ms
187_apply.sh end to end, offline, in both orders · 5 tests
✓
187 first (008 is live): applies, proves, and --clear restores the exact pre-state 591.9ms
✓
188 first (188 is live): applies, proves, and --clear restores the exact pre-state 562.2ms
✓
a failed create restores EXACTLY what was read, 188 CHECK included 187.9ms
✓
drift: STOPs before any write — no SQL, no drop, no create 96.4ms
✓
the stand-in is the only server the script can reach from here 0.4ms
src/outbound-run/state.vitest.ts
bounced_hard vs bounced_soft — the defect this module must not reintroduce · 5 tests
✓
bounced_hard is terminal 2.6ms
✓
bounced_soft is NOT terminal on its own — a full mailbox is not a dead address 0.4ms
✓
bounced_soft blocks the next send only once it hits SOFT_BOUNCE_TOLERANCE 0.4ms
✓
a terminal state blocks regardless of soft-bounce count 0.3ms
✓
bounced_soft can transition back to send_queued (retryable); bounced_hard cannot transition anywhere 0.3ms
approval expiry is derived from day close, never independent — §14 q2 · 3 tests
✓
derives expiry as exactly the day close time 0.3ms
✓
an active approval past its expiry is expired 0.6ms
✓
a revoked approval is expired regardless of the clock 0.3ms
digest margin is checkable, not a hope — §3 · 3 tests
✓
rejects a digest fired after close (the failure mode the doc names) 0.8ms
✓
rejects a digest inside the minimum margin 0.3ms
✓
accepts a digest at or before the minimum margin 0.3ms
dedupe key is run-scoped, not day-scoped — the fix for invariant 1 · 2 tests
✓
the same contact on two different days of the same run gets the SAME key 0.2ms
✓
the same contact in a different run gets a different key 0.9ms
idempotency key: revision-independent for paid non-send stages — §9.4 · 3 tests
✓
enrich/verify keys are identical across a revision bump 0.4ms
✓
draft keys DO vary by revision — a new revision is a genuinely new artifact 0.3ms
✓
draft without a revision throws rather than silently omitting it 1.0ms
state-transition tables — a sample of the doc's §4 diagrams, not exhaustive · 5 tests
✓
run: draft cannot jump straight to running 0.2ms
✓
run: completed and stopped are terminal 0.2ms
✓
day: awaiting_approval can close (expired unapproved) or proceed to sending 0.2ms
✓
lead: validated_risky can be excluded (not explicitly allowed) or drafted (allowed) 0.2ms
✓
lead: invalid is terminal 0.2ms
src/reports/diagnose-brief-render.vitest.ts
no brief renders the literal "undefined" to a user · 10 tests
✓
competitive_landscape has no undefined in its HTML 15.5ms
✓
competitor_counter_plan has no undefined in its HTML 0.5ms
✓
eeat_proof has no undefined in its HTML 0.4ms
✓
backlink_policy has no undefined in its HTML 0.3ms
✓
keyword_map has no undefined in its HTML 0.3ms
✓
directive_policy has no undefined in its HTML 0.3ms
✓
measurement_contract has no undefined in its HTML 0.4ms
✓
ai_content_policy has no undefined in its HTML 0.3ms
✓
investment_horizon has no undefined in its HTML 0.7ms
✓
migration_runbook has no undefined in its HTML 0.4ms
the Measured block belongs to the index-health brief alone · 2 tests
✓
does not appear on briefs whose counts have different keys 4.9ms
✓
DOES appear for index health, so the guard did not simply delete the block 0.7ms
each brief is published under its OWN headline · 2 tests
✓
the counter-plan names the rival, not a content-pruning list 0.4ms
✓
every brief supplies a non-empty headline naming the site 0.4ms
playbooks render through their own block, with the anchor visible · 5 tests
✓
renders rules with their trigger, signal and owner 0.6ms
✓
renders the ANCHOR — a playbook without it reads as tailored when it is not 0.3ms
✓
renders the REASON when there is no anchor, rather than nothing 0.4ms
✓
renders decisions WITH their options — an option list is the point 0.3ms
✓
does NOT print an empty "Causes tested" heading 0.3ms
a specific brief outranks the generic incident brief · 2 tests
✓
renders the migration runbook, not the incident brief beside it 0.3ms
✓
still renders the incident brief when it is the only one 0.2ms
src/scoring/user-scores.vitest.ts
recencyDecay · 3 tests
✓
is 1.0 for today and ~0.5 at the 7-day half-life 2.0ms
✓
decays smoothly, unlike 1/(d+1) which cliff-drops day 0→1 0.3ms
✓
handles junk input 0.2ms
smoothedRate · 4 tests
✓
does not give a 1-for-1 user a perfect score (the whitepaper bug) 0.3ms
✓
converges to the true rate with volume 0.2ms
✓
is the 0.5 prior when there were no attempts 0.1ms
✓
clamps successes above attempts (defensive) 0.2ms
consistencyScore · 3 tests
✓
needs at least 3 active days 0.2ms
✓
is 1 for perfectly regular usage 0.5ms
✓
is lower for erratic usage than regular usage 0.2ms
percentileRank · 3 tests
✓
is outlier-robust where min-max is not 0.3ms
✓
ranks within 0..100 with mean-rank ties 0.2ms
✓
handles empty reference and NaN values 0.2ms
shrinkToPrior · 3 tests
✓
regresses to the prior with no evidence 0.2ms
✓
weights evidence at 50% at n0 0.1ms
✓
approaches the observed value with lots of evidence 0.1ms
assignTier · 1 test
✓
maps the 2x2 engagement×proficiency grid 0.2ms
computeBadges + badgePoints · 4 tests
✓
gives a fresh user no badges 0.6ms
✓
awards milestone badges at thresholds 1.4ms
✓
finisher needs 5+ attempts, not a lucky 1-for-1 0.3ms
✓
every badge key computeBadges can emit exists in the BADGES catalog 0.4ms
src/runtime/enqueueable-tools.vitest.ts
isEnqueueableTool · 21 tests
✓
allows the declared background tool aeo_full_audit 1.7ms
✓
allows the declared background tool aeo_visibility 0.2ms
✓
allows the declared background tool entity_audit 0.1ms
✓
allows the declared background tool aeo_page_check 0.2ms
✓
allows the declared background tool backlink_outreach_search 0.1ms
✓
allows the declared background tool seo_backlink_verify 0.1ms
✓
allows the declared background tool seo_write_content 0.2ms
✓
allows the declared background tool seo_google_merge 0.1ms
✓
allows the declared background tool google_god_mode_report 0.5ms
✓
allows the declared background tool seo_onpage_audit 0.2ms
✓
allows the Tier-B safety-net tool seo_offpage_audit 0.2ms
✓
allows the Tier-B safety-net tool seo_competitor_gap 0.1ms
✓
allows search_leads, which runs its own durable delivery path 0.1ms
✓
refuses the action tool send_emails 0.1ms
✓
refuses the action tool enroll_in_sequence 0.1ms
✓
refuses the action tool set_campaign_sequence 0.1ms
✓
refuses the action tool resume_campaign 0.1ms
✓
refuses the action tool launch_campaign 0.1ms
✓
refuses the action tool cloudflare_fix_email_dns 0.1ms
✓
refuses the action tool connect_connector 0.1ms
✓
refuses an unknown or forged tool name 0.1ms
src/tools/audits-wave4.vitest.ts
the audit cluster · 12 tests
✓
seo_onpage_audit accepts the empty call — "my site" is the common case 2.0ms
✓
seo_offpage_audit accepts the empty call — "my site" is the common case 0.2ms
✓
seo_backlinks accepts the empty call — "my site" is the common case 0.1ms
✓
seo_serp_spider accepts the empty call — "my site" is the common case 0.2ms
✓
seo_onpage_audit accepts a named site 0.6ms
✓
seo_offpage_audit accepts a named site 0.1ms
✓
seo_backlinks accepts a named site 0.3ms
✓
seo_serp_spider accepts a named site 0.2ms
✓
seo_onpage_audit rejects the retired domain alias 0.6ms
✓
seo_offpage_audit rejects the retired domain alias 0.2ms
✓
seo_backlinks rejects the retired domain alias 0.2ms
✓
seo_serp_spider rejects the retired domain alias 0.1ms
per-tool arguments · 2 tests
✓
seo_onpage_audit bounds the crawl depth 0.2ms
✓
seo_serp_spider keeps verify_index opt-in and typed 0.2ms
fallbacks go only where validation replaced them · 6 tests
✓
seo_onpage_audit no longer reads tool.domain 0.4ms
✓
seo_offpage_audit no longer reads tool.domain 0.1ms
✓
seo_backlinks no longer reads tool.domain 0.1ms
✓
seo_serp_spider no longer reads tool.domain 0.2ms
✓
still-legacy full_seo_audit KEEPS its fallback 0.1ms
✓
still-legacy share_of_model KEEPS its fallback 0.1ms
the contract-seams parser does not depend on formatting · 1 test
✓
no longer slices the properties block by indentation 0.2ms
src/seo/ai-crawler-access.vitest.ts
robots.txt, per role · 5 tests
✓
REGRESSION: `User-agent: *` + `Disallow: /` blocks every search crawler — the old checks called this "default Allow" 3.1ms
✓
checks OAI-SearchBot specifically — the crawler ChatGPT search answers from 0.5ms
✓
is scoped to the page: a Disallow on another path does not fail this one 0.5ms
✓
blocking a TRAINING crawler is reported as a choice, never a failure 1.4ms
✓
no robots.txt means everything is allowed, and says so 0.3ms
robots.txt that could not be read · 3 tests
✓
a 404 is "no file, nothing disallowed" 0.4ms
✓
REGRESSION: a refusal (StackOverflow answered 418, live 2026-10-17) is "could not tell", never "nothing is disallowed" 0.6ms
✓
a 5xx says what it would mean if crawlers see it too 0.3ms
private paths · 4 tests
✓
finds the named groups that reopen what `*` disallows 1.5ms
✓
is quiet when every group repeats the private paths 0.4ms
✓
link-preview fetchers reopening an app path are deliberate, not a leak (nqz.ai flagged itself live before this) 1.8ms
✓
ignores `Disallow: /` under `*` (that is a block, not a private path) and a file with no `*` 0.2ms
firewall / CDN · 9 tests
✓
a refusal status where a normal request succeeded is a block 0.6ms
✓
a bot challenge page with a 200 is a block too 0.1ms
✓
when the normal request was refused as well, it cannot be told apart — unknown, never blocked 0.1ms
✓
the same response is allowed 0.1ms
✓
a refusal of OAI-SearchBot fails the finding, says what it costs, and gives the Cloudflare path on Cloudflare 0.3ms
✓
a pass says plainly what it cannot see 0.2ms
✓
not run → not applicable, not a failure 0.2ms
✓
sends one request per probe crawler, each naming that crawler AND us 1.6ms
✓
never imitates Googlebot or Bingbot — many firewalls reject an unverified one, which would be a false alarm 0.4ms
src/seo/backlink-tier-value.vitest.ts
computeLinkValues — the backlink report headline · 17 tests
✓
prices a dofollow link off the DR band it falls in 2.4ms
✓
bands on the FLOOR, so a DR just under a threshold does not take the tier above 0.5ms
✓
prices nofollow off its own much lower ladder, not as a discount on dofollow 0.4ms
✓
prices an unknown follow state off the dofollow ladder — the link still exists 0.3ms
✓
returns a value for EVERY link, not one per domain 1.5ms
✓
decays repeat links from ONE domain — the trust is the domain's, not the URL's 0.4ms
✓
does not decay across DIFFERENT domains — each starts at full value 0.3ms
✓
ranks the dofollow link first, so the decay lands on its nofollow sibling 0.3ms
✓
prices a dead target at zero — it buys nothing until redirected 14.1ms
✓
prices search engines and aggregators at zero rather than at their enormous DR 0.3ms
✓
counts an unrated link rather than silently pricing it at the bottom band 0.4ms
✓
never lets the gross carry a hosting haircut — the discounts sit beside it 0.3ms
✓
halves independent and CDN-fronted links in the realistic figures 0.2ms
✓
counts an unresolved host as zero in BOTH realistic figures, never as independent 0.2ms
✓
states the range and the haircut in the note that travels with the number 0.3ms
✓
sorts links by what they are worth, so the report leads with the ones that matter 0.2ms
✓
takes NO traffic input at all 0.4ms
registrableRoot / isSubdomain · 3 tests
✓
identifies a subdomain whose DR would be its parent's 0.4ms
✓
treats a bare root as its own root 0.2ms
✓
keeps multi-part suffixes intact 0.2ms
a subdomain carries its parent's rating, and the hosting haircut is what answers it · 1 test
✓
prices a shared-hosting subdomain at a twentieth once its cluster is known 0.2ms
src/seo/competitor-counter-plan.vitest.ts
Q25: "consistently" means more than once · 5 tests
✓
one term ahead is a coincidence, not a dominant rival 1.7ms
✓
two terms ahead is a pattern 0.5ms
✓
a rival BEHIND us on a term is not counted as holding it 0.2ms
✓
a term we do not rank for at all counts as theirs 0.3ms
✓
picks the rival ahead on the most terms 0.3ms
Q25: the plan is capacity-bound and the cut is visible · 4 tests
✓
COUNTS what it left out rather than dropping it silently (GS-004) 0.8ms
✓
hands the capacity call to the user instead of inventing a team size 0.4ms
✓
ranks by what the term already earns 1.2ms
Q25: work we cannot win is never funded · 3 tests
✓
excludes terms topped by a platform result from the plays 0.8ms
✓
warns against funding them in the decision when other work exists 0.4ms
✓
reports a real STOP rather than manufacturing a play 0.3ms
Q25: what we cannot see stays unseen · 3 tests
✓
never concludes anything about the rival's authority 0.4ms
✓
never kills the cannibalisation hypothesis, because no URL is recorded 0.3ms
✓
distinguishes "no rank readings" from "nobody is ahead" 0.5ms
Q25: speculative work is labelled and goes last · 2 tests
✓
groups zero-demand terms into one play at the end 0.5ms
✓
does not invent a speculative play from a single term 0.2ms
Q25: no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps table and field names out of the prose 0.4ms
Q25: a cause the evidence contradicts is RULED OUT, not "not tested" · 3 tests
✓
kills the absence hypothesis when we rank for everything they hold 0.2ms
✓
does not report a fully-read site as entirely untested 0.4ms
✓
when nothing was scanned, every thin reason says so — never "we rank somewhere" 0.6ms
src/seo/domain-extract.vitest.ts
extractExplicitDomain · 8 tests
✓
recovers the domain from the prompts that misrouted 2.7ms
✓
returns '' when the user named no domain — the saved-site fallback must still win 0.5ms
✓
ignores domains inside email addresses — a recipient is never an audit target 0.2ms
✓
still finds a real target alongside an email address 0.2ms
✓
normalises case and strips www 0.2ms
✓
takes the first domain when several are named 0.2ms
✓
does not match ordinary prose that merely contains a dot 0.3ms
✓
handles subdomains and hyphenated hosts 0.2ms
pickContextMessage · 10 tests
✓
walks back past a depth chip to the turn that named the domain 0.8ms
✓
walks back past the other chip/confirm tokens 0.4ms
✓
skips consecutive control tokens to the newest real message 0.3ms
✓
leaves an ordinary message untouched 0.1ms
✓
falls back to the control token when no real prior turn exists 0.2ms
✓
takes the NEWEST real message, not the oldest 0.2ms
✓
walks back past the raw route chip the UI posts 0.2ms
✓
walks back past the "SEO route: <choice>" confirm form 0.1ms
✓
does NOT treat a typed request as a chip — the em-dash is the tell 0.3ms
✓
route chip then depth chip still recovers the request two turns back 0.1ms
god-mode style asks resolve a real domain or nothing at all · 3 tests
✓
recovers the domain when one is actually named 0.2ms
✓
returns nothing for a phrase that names no domain 0.2ms
✓
never reads a recipient address as an audit target 0.1ms
src/seo/keyword-themes.vitest.ts
buildThemes — groups and sizes, never judges · 7 tests
✓
groups the registry and sums volume per theme 2.0ms
✓
sorts by VOLUME, so the biggest market leads even with few members 0.5ms
✓
keeps a one-keyword theme when it is the biggest market present 0.3ms
✓
carries NO verdict field — relevance is the one call nqzai must not make 1.0ms
✓
counts members with no volume rather than treating them as zero 0.3ms
✓
falls back to the strongest keyword as the name, never an invented one 1.4ms
✓
returns an empty summary rather than throwing on no keywords 0.8ms
nameThemes — a label on measured data, or nothing · 2 tests
✓
keeps the deterministic names when the model call fails 101.0ms
✓
never changes the volumes, whatever the naming does 32.2ms
themeNote — describes, hands the judgement back · 4 tests
✓
states the largest theme, its share, and whose call relevance is 25.8ms
✓
never calls a theme off-brand, noise, or a distraction 0.8ms
✓
says the sizes are a floor when volume is missing somewhere 0.4ms
✓
says nothing when there are no themes 0.2ms
themeNamingBudget — NQZAI-8H regression · 5 tests
✓
never returns the 208 that failed four times, at the theme count that produced it 0.4ms
✓
leaves the maximum theme count below its own ceiling 0.2ms
✓
scales with the fan-in rather than returning a constant 0.3ms
✓
keeps real headroom per line, not a fitted estimate 0.2ms
✓
still bounds an absurd fan-in — derived, not unbounded 0.2ms
theme names are SELECTED from the cluster, not generated (2026-09-20) · 3 tests
✓
candidates are the shared phrases first, then the keywords themselves, capped and title-cased 4.3ms
✓
one choice per theme over its own candidates, with a none option, judging the name only 1.0ms
✓
the select path runs before the generative one and is gated on its flag word 2.8ms
src/seo/publish-detect.vitest.ts
slugTokens · 3 tests
✓
keeps the identifying words and drops the scaffolding 2.3ms
✓
keeps digits — they are often the only thing separating two articles 1.1ms
✓
strips the host and the file extension from a URL 0.7ms
detectPublished — what it claims · 2 tests
✓
matches a real generated title to a real blog URL 1.2ms
✓
a URL carrying extra path segments still matches — containment is one-directional 0.4ms
detectPublished — what it refuses · 7 tests
✓
two drafts on one topic claim NOTHING 0.3ms
✓
one draft matching two pages claims NOTHING 0.4ms
✓
a page that has not changed since before we wrote is not ours 0.3ms
✓
a page edited AFTER we wrote stays a candidate 0.6ms
✓
a thin title cannot claim a page — it would claim the whole niche 0.4ms
✓
a partial overlap is not a match 0.2ms
✓
an unrelated page on the same site is left alone 0.2ms
collectSitemapUrls · 4 tests
✓
follows a subdomain listed in the apex sitemap — the whole reason this is not one fetch 24.2ms
✓
never leaves the tenant's registrable domain 0.6ms
✓
a fetch failure yields no URLs rather than throwing 0.3ms
✓
returns nothing for a blank site rather than fetching a bare https:// 0.2ms
an inference may never overwrite an observation · 2 tests
✓
a detected write only ever fills an empty slot 0.1ms
✓
a connector write is NOT restricted the same way — re-publishing is legitimate 0.1ms
the weekly pass · 3 tests
✓
no sitemap means no inference, not a confident zero 0.1ms
✓
one tenant's unreachable sitemap does not end the pass for everyone 0.2ms
✓
runs on the existing zero-spend Monday cron, with its own monitor 0.3ms
src/billing/appsumo.vitest.ts
planIdForStackCount — pure · 3 tests
✓
maps 1/2/3 directly 2.3ms
✓
caps at appsumo3 — plans.ts defines no level beyond it, even though AppSumo allows stacking up to 10 0.4ms
✓
floors at appsumo1 for a non-positive count, defensively 0.3ms
getAppsumoPlanForUser / getAppsumoStackCount · 3 tests
✓
returns null — no entitlement — for a user with zero redemptions 0.7ms
✓
maps a real count to the right plan id 0.4ms
✓
fails to null/0 rather than throwing on a ledger read error — same posture as hasPaidTopUp 1.4ms
redeemAppsumoCode — the compare-and-swap · 8 tests
✓
happy path: claims the code, grants the flat base amount, reports the new stack level 5.6ms
✓
a SECOND code for the same user stacks — this is how stacking actually works, not a separate code SKU 0.6ms
✓
rejects an empty/whitespace code without ever calling the ledger 0.7ms
✓
the cap is checked BEFORE the CAS — a sold-out deal never touches a specific code row 0.4ms
✓
is NOT fooled by an unused margin below the cap — reaching it exactly still blocks 0.2ms
✓
reports already_redeemed when the CAS loses to a concurrent (or earlier) redemption of the SAME code 0.3ms
✓
reports invalid_code when the code has never existed at all 0.2ms
✓
reads a still-unissued code after a failed claim as cap_reached, not invalid_code 0.3ms
redeemAppsumoCode — side effects on the happy path · 4 tests
✓
drops the cached balance so the buyer sees their tokens immediately 1.0ms
✓
fires the redemption event with the resolved level, not a hardcoded one 0.7ms
✓
marks the person as appsumo but NOT as paying — they paid AppSumo, not us 1.0ms
✓
still succeeds when telemetry throws 0.4ms
constants match the locked doc (docs/APPSUMO_LTD_PRICING.md §4b) · 2 tests
✓
base grant is the ~70%-off-at-$49 figure, not the earlier 25M cost-safety guess 0.1ms
✓
code cap and max stack level match the locked ladder 0.2ms
src/billing/estimate-tolerance.vitest.ts
three dials, three questions · 3 tests
✓
the entry buffer is 25K — lowered so small balances stay usable (owner 2026-09-01) 1.6ms
✓
the overrun alarm is NOT dragged down with the buffer 0.5ms
✓
is NOT aliased to the cost-card threshold 1.0ms
ENTRY — the gate DEMANDS a buffer above the reservation · 5 tests
✓
a run that would land ABOVE zero after an optimistic estimate is admitted 0.3ms
✓
a run that could land BELOW zero is refused — this is the whole point 0.2ms
✓
SMALL BALANCES STAY USABLE — the reason 100K was lowered to 25K 0.4ms
✓
the gate demands the buffer rather than permitting an overdraft 0.6ms
✓
the downsize suggestion respects the buffer too 0.2ms
EXIT — an estimate missing a leg reports itself · 7 tests
✓
the seo_serp_spider case fires 0.4ms
✓
an ordinary approximation error does NOT fire 0.2ms
✓
a run that comes in UNDER its reservation is silent 0.2ms
✓
is wired at teardown and attributes to the tool that ran 0.5ms
✓
measures THIS run, not the whole turn 0.7ms
✓
clears the pair only for the run that OWNS the window 0.6ms
✓
the alarm itself only fires for the owning run 0.5ms
the buffer bounds approximation, never bugs — stated so it is not mistaken for a cap · 3 tests
✓
the spider overrun dwarfs the buffer, so the buffer alone could never have stopped it 0.1ms
✓
the code says so where someone would otherwise assume protection 0.4ms
✓
the two dials are on different axes and documented as such 0.4ms
a failed ledger read is UNKNOWN, never BROKE · 2 tests
✓
strict mode rethrows instead of reporting an empty account 0.3ms
✓
the swallow-everything catch is gone 0.2ms
src/chat/first-turn-shape.vitest.ts
a bare domain is an offer — the turn onboarding was built for · 8 tests
✓
drashti@homhub.ai: https://nuxt.homhub.ai 2.7ms
✓
rajputsudheer8127: https://creditcarddotcom.netlify.app/ 0.5ms
✓
iamahacker.unofficial: https://www.vidtwo.com/ 0.2ms
✓
mganwerbaig: Chipperstreeservice.net 0.2ms
✓
janavijadhav504: https://www.ycis.ac.in/ 0.2ms
✓
balajistoneexports: "https://udaipurcabservice.com/" that is my 0.2ms
✓
framing words around a domain are still an offer 0.8ms
✓
naming onboarding itself is an offer, whatever verb carries it 0.2ms
a URL the sentence asks us to WORK on is a task · 8 tests
✓
chandramedia2221: Read https://vercel.com/blog and list the headings 0.5ms
✓
hards2000: Run an SEO audit for https://prakashinfotech.com/ 0.2ms
✓
vibinchitradevi: https://www.easc-cs-cybersecurity.com/ do site au 0.2ms
✓
khanmeha938: keywords for seo websire is https://www.dminternatio 0.1ms
✓
samridhibhatia014: How can I improve this website what score you will g 0.1ms
✓
talkeriq: run a SEO,AEO & GEO review on https://talkeriq.com/ 0.1ms
✓
promisesociety5: Analyze how AI answer engines discover, describe and 0.1ms
✓
phrasings nobody has written yet still classify as tasks 0.2ms
the failure directions are not symmetric, so the default is task · 4 tests
✓
a long remainder is a task even when every word looks harmless 0.1ms
✓
no URL at all is a task — there is nothing to onboard 0.2ms
✓
is not stateful — URL_RE is /g, and .test() on a global regex advances lastIndex 0.3ms
✓
an offer misread as a task loses nothing; the reverse loses the account 0.2ms
src/chat/misroute-standdown.vitest.ts
whyNoMisroute names every stand-down · 3 tests
✓
agrees with resolveMisroute on when the guard fires 13.2ms
✓
distinguishes the four remaining reasons 4.4ms
✓
is recorded on the turn, both branches 4.2ms
keyword economics survive the guardrail · 3 tests
✓
allows currency for every tool that emits CPC 0.5ms
✓
still redacts currency for a tool with no tenant money in it 0.2ms
✓
grants the exemption from ANY tool in the turn, not just the last 3.8ms
augment: the evidence step happens even when nothing costs money · 7 tests
✓
fires in augment mode for a free tool, dropping nothing 1.6ms
✓
still REPLACES a gated tool — augment did not weaken the original guard 0.4ms
✓
replaces only the gated tool and keeps the free one 0.6ms
✓
stays silent when the model already chose diagnose 0.3ms
✓
stays silent for a non-diagnostic question 0.2ms
✓
stays silent when the user also asked for an action 0.2ms
✓
stays silent once diagnose has already run this turn 0.1ms
every declared answer-call predicate reaches the diagnose dispatch condition · 7 tests
✓
has the dispatch block to test against (not a stale anchor) 0.3ms
✓
every `const isQ*/isAi*` alias declared for dispatch is used in the OR-condition 1.2ms
✓
isAi01 specifically dispatches 0.4ms
✓
isAi13 specifically dispatches 0.3ms
✓
isAi22 specifically dispatches 0.3ms
✓
isAi24 specifically dispatches 0.4ms
✓
isAi04 specifically dispatches 0.3ms
src/chat/records-as-tables.vitest.ts
mdTable · 3 tests
✓
emits a header, a separator and one row per record 2.4ms
✓
returns nothing for no rows, so callers do not print an empty header 0.3ms
✓
escapes pipes and newlines that would otherwise split the row 1.5ms
records render as tables, everywhere they are listed · 7 tests
✓
leads found by a search — as a BLOCK, and every lead, not the first five 1.0ms
✓
email drafts — as a block, every recipient, not three of them 0.6ms
✓
backlink outreach prospects — as a block 0.7ms
✓
no stacked blank lines where a table was removed 0.4ms
SEO report bodies list records as tables · 5 tests
✓
on-page audit — issues carry a count and a share, weak pages carry a fault list 0.5ms
✓
on-page audit — a broken page outranks a numerous one in the next moves 0.2ms
✓
off-page audit — anchors and ranking keywords are records, not bullets 13.0ms
✓
full audit — leads with the constraint and tables the join, never "N/2 sections" 0.4ms
✓
full audit — a blocked half states the consequence, never the raw error 0.2ms
prose stays prose · 1 test
✓
a one-column list is still a list — a table would be worse 0.2ms
the model is told the same rule the formatters follow · 1 test
✓
V2_SYSTEM tells the model the records are already tabulated, and never to draw one 0.3ms
full_seo_audit — every named gap has a way through · 3 tests
✓
offers the connector for the missing source that unlocks the most 1.4ms
✓
falls back to the ordinary next steps when nothing is missing 0.2ms
✓
picks the gaps that are actually absent, not a fixed list 0.2ms
src/chat/sov-insight.vitest.ts
sovTrendInsight — a card may only claim a movement it can support · 4 tests
✓
states the movement first, then the standing 2.2ms
✓
marks which metric is the tenant, and gives the rival NO delta 2.1ms
✓
picks the LEADING rival, not the first in the list 0.2ms
✓
appends the displacement sentence when the tool produced one 0.4ms
sovTrendInsight — one movement, one number · 4 tests
✓
takes the tool delta rather than computing a second opinion 0.3ms
✓
claims no movement at all when the tool supplies none 0.3ms
✓
explains the absent comparison instead of qualifying a narrowed window 0.4ms
✓
carries the break through to the series so the chart can break the line 0.4ms
sovTrendInsight — an overtake between two parties with no share is not an event · 2 tests
✓
drops the displacement sentence when nobody is being cited 0.5ms
✓
keeps it when someone actually holds share 0.2ms
sovTrendInsight — refuses rather than half-claims · 5 tests
✓
returns null on a single measurement — a trend through one point is a snapshot 0.2ms
✓
returns null with no series at all 0.2ms
✓
drops malformed points instead of charting NaN 0.3ms
✓
says "unchanged" rather than "up 0 points" 0.1ms
✓
survives a result with no entities, falling back to the domain 0.2ms
sovTrendInsight — the sample behind the movement · 5 tests
✓
THE REGRESSION: does not assert a 100-point move off two single answers 0.3ms
✓
qualifies on the THINNER end of the delta, not just the latest run 0.2ms
✓
carries the set-change caveat AND the thin-sample one when both apply 0.2ms
✓
states the basis but no caveat when the sample carries its own weight 0.2ms
✓
says nothing about the sample when the payload predates the field 0.2ms
src/db/user-role-token-reads.vitest.ts
baseline · 1 test
✓
the clean tree passes and says how many user-token column reads it compared 824.1ms
1. the real readers: the in-class columns 194 left for the owner each fail on their reader · 3 tests
✓
serp_spider_tasks.provider_used off the user role's SELECT: exits 1 and names handleSerpSpiderTasks' file, line and column 837.7ms
✓
credits_used and error_message too, when they go: each is named 0.8ms
✓
tracked_keywords.source has two readers on the user token: GET /api/keywords and seo_list_keywords 0.3ms
2. every way a document reads a column is compared · 12 tests
✓
the committed snapshot is already 194's AFTER shape for the columns these shapes read 1.5ms
✓
a plain selection: exits 1 and names it 0.6ms
✓
an aliased root and an aliased field: exits 1 and names it 0.3ms
✓
a _by_pk root: exits 1 and names it 0.4ms
✓
an aggregate sum: exits 1 and names it 0.6ms
✓
an aggregate's nodes: exits 1 and names it 0.3ms
✓
a where filter: exits 1 and names it 0.3ms
✓
a where filter inside _and: exits 1 and names it 0.2ms
✓
an order_by: exits 1 and names it 0.2ms
✓
a distinct_on: exits 1 and names it 0.3ms
✓
a mutation's returning reads columns too 0.2ms
✓
...and so does a _by_pk mutation's selection 0.2ms
3. controls: what must still pass · 4 tests
✓
the same read on the ADMIN secret passes: it is not the user role's 832.1ms
✓
a user-token read of the columns that remain passes 0.3ms
✓
a relationship's nested selection is not mistaken for the parent table's columns 0.2ms
✓
a fragment spread is counted as not checked, never passed as checked 0.4ms
src/email/consent-gate.vitest.ts
consent gate — the unsubscribe complaint · 8 tests
✓
blocks a marketing kind for a suppressed user 5.2ms
✓
inactive_3_day_reminder is marketing and honours the opt-out 0.6ms
✓
unfinished_setup_nudge is marketing and honours the opt-out 0.5ms
✓
weekly_product_progress_digest is marketing and honours the opt-out 0.5ms
✓
sov_weekly_digest is marketing and honours the opt-out 0.6ms
✓
seo_rank_digest is marketing and honours the opt-out 0.3ms
✓
commerce_weekly_digest is marketing and honours the opt-out 0.3ms
✓
still delivers operational mail to a suppressed user 1.1ms
consent gate — the account-deletion complaint · 3 tests
✓
blocks marketing to a deleted account 0.8ms
✓
blocks OPERATIONAL mail to a deleted account too 0.5ms
✓
allows the deletion confirmation itself through the deleted block 0.6ms
consent gate — failure and bypass behaviour · 7 tests
✓
fails CLOSED when the consent lookup errors 0.5ms
✓
records a feature event when it blocks, with the reason 0.4ms
✓
leaves no delivery row behind when it blocks 0.3ms
✓
refuses marketing with no userId 0.3ms
✓
allows the declared operator test send 0.3ms
✓
treats an unregistered kind as marketing (fail-closed default) 0.3ms
✓
keeps the operator report kinds operational so an owner opt-out cannot mute them 0.2ms
footer — the promise must match the enforcement · 2 tests
✓
puts the unsubscribe link on marketing mail 0.3ms
✓
omits it from operational mail and says why instead 0.4ms
src/routes/public-endpoints.vitest.ts
robots.txt · 4 tests
✓
serves 200 as text/plain 26.0ms
✓
never blanket-disallows the site 1.9ms
✓
points at the sitemap with an absolute URL 0.7ms
✓
keeps the AI-agent paths crawlable 0.7ms
robots.txt — what each crawler is actually told · 8 tests
✓
every AI crawler is kept out of the private paths and let into every public page 46.4ms
✓
OpenAI's search crawler is allowed — blocking it removes the site from ChatGPT search answers 1.5ms
✓
crawl-delayed SEO crawlers are kept out of the private paths too 1.8ms
✓
search engines (the * group) may fetch /dashboard and /app to read their noindex, and nothing else private 6.5ms
✓
the dead /report/ block is gone (no route serves it; the block hid its 404 from Google) 0.5ms
✓
advertises only XML sitemaps (Search Console rejects the JSON /.ai/sitemap.json) 0.8ms
✓
link-preview fetchers still reach /app so shared links unfurl 0.7ms
✓
every group that names a crawler, other than link previews, carries every private path 2.0ms
sitemaps · 4 tests
✓
the index is well-formed XML with absolute child locs 0.7ms
✓
the pages sitemap lists absolute, deduplicated URLs on this origin 1.2ms
✓
escapes ampersands so the XML stays parseable 0.4ms
✓
serves XML content types 0.7ms
ai-sitemap.json · 2 tests
✓
is valid JSON with an absolute site and sitemap list 0.9ms
✓
carries a parseable generated_at 0.3ms
llms.txt · 2 tests
✓
serves plain text with the required H1 and summary blockquote 0.9ms
✓
links are absolute so an agent can follow them without a base URL 1.0ms
src/tools/aeo-family-rules.vitest.ts
the seven rules that were NOT already on their tool · 8 tests
✓
MOVE 1 — readiness is not visibility, stated in the direction that FAILS 2.0ms
✓
MOVE 2 — aeo_visibility names the surfaces users ask for by name 0.4ms
✓
MOVE 3 — sov_trend: only `delta` is a movement 0.3ms
✓
MOVE 4 — sov_trend: relay comparability_note when delta is null 0.3ms
✓
MOVE 5 — sov_trend: latest_basis names the surfaces 0.2ms
✓
and the incident those three exist for is recorded where the rule lives 0.3ms
✓
MOVE 6 — aeo_full_audit makes no measurements of its own 0.3ms
✓
MOVE 7 — tap_volume states its cost and refuses speculative calls 0.4ms
the llms.txt discriminator survived, via the tool it gets confused with · 2 tests
✓
aeo_page_check says it scores rather than generates, and names the generator 0.6ms
✓
and states that generator is free, so cost is not inferred from the family 0.3ms
aeo_full_audit no longer contradicts itself about its own price · 3 tests
✓
the stale "three paid legs" claim is gone 0.4ms
✓
but the routing half of that rule survives 0.2ms
✓
and it says what to do when nothing has been measured 0.2ms
the family stays discoverable, because every tool in it is deferred · 5 tests
✓
no AEO tool is in CORE, so the pointer is the only always-on signal 0.4ms
✓
the pointer separates this family from SEO in one line 0.3ms
✓
it names each distinct question, in the user's words 0.4ms
✓
it warns that readiness and visibility sound alike 0.2ms
✓
and that one tool is very expensive 0.2ms
the duplication is gone · 2 tests
✓
the per-bullet routing table is not in V2_SYSTEM 0.2ms
✓
V2_SYSTEM stays under its ratchet 0.2ms
src/seo/competitor-annotation.vitest.ts
annotateStoredCompetitors — the live divergence · 4 tests
✓
returns every stored entry, so nothing is dropped on the round trip 2.1ms
✓
marks exactly the three the engine screens out 1.0ms
✓
names the reason in the user's language, not the filter's 0.6ms
✓
a counted entry carries no reason — an explanation implies a problem 0.2ms
the annotation is DERIVED from the engine, never a second copy of the rule · 7 tests
✓
case 0: counted set === orderStoredCompetitors output 0.5ms
✓
case 1: counted set === orderStoredCompetitors output 0.3ms
✓
case 2: counted set === orderStoredCompetitors output 0.4ms
✓
case 3: counted set === orderStoredCompetitors output 0.2ms
✓
case 4: counted set === orderStoredCompetitors output 0.4ms
✓
case 5: counted set === orderStoredCompetitors output 0.2ms
✓
case 6: counted set === orderStoredCompetitors output 0.3ms
annotateStoredCompetitors — the other ways an entry falls out · 5 tests
✓
never screens an entry the user typed 0.3ms
✓
explains a duplicate as a duplicate, not as a screened host 0.2ms
✓
explains the cap as the cap 0.5ms
✓
screens a platform and a directory with their own reasons 0.3ms
✓
does not throw on a malformed or absent row 0.2ms
GET /api/product/brief serves the annotated set · 4 tests
✓
is a real slice of the route 0.3ms
✓
uses the shared helper 0.1ms
✓
no longer parses the competitor set by hand 0.1ms
✓
the write path still stores the COMPLETE set, screened or not 0.7ms
src/seo/content-assessment.vitest.ts
countSourcing — testing the rule, not prompting it · 5 tests
✓
counts a percentage claim and notices it has no source 2.0ms
✓
a claim with a link in the same sentence is sourced 0.8ms
✓
a heading is a title, not a statistic 0.2ms
✓
a small bare number is not a claim 0.2ms
✓
recognises all three claim shapes 0.3ms
assessContent — corrective findings rest on two measured facts · 5 tests
✓
flags writing a second page for a term we already rank for 0.5ms
✓
does NOT flag a term we rank badly for — there is no signal to split 0.3ms
✓
flags a prior draft for the same keyword, and says whether it went live 4.7ms
✓
flags unattributed claims only when they dominate 0.6ms
✓
says nothing about sourcing on a draft with too few claims to judge 0.2ms
assessContent — suggestive and advisory · 4 tests
✓
says when nothing will measure the term we just wrote for 0.3ms
✓
reports the publish rate only once it is a pattern 0.4ms
✓
stays quiet when most drafts did go live 0.2ms
✓
a clean draft produces no findings at all 0.2ms
assessmentLead · 3 tests
✓
leads with the count of blockers and names the first 0.3ms
✓
says nothing is blocking when only softer findings exist 0.2ms
✓
returns null on a clean draft rather than inventing a concern 0.1ms
the rendered report leads with the judgement · 3 tests
✓
replaces the prose-about-our-own-output lead 0.2ms
✓
groups by directive and only shows groups that have something 0.2ms
✓
an artifact stored before the assessment existed still renders its old lead 0.7ms
src/seo/content-inventory.vitest.ts
KILL is the only irreversible label, so it carries the strictest test · 4 tests
✓
needs BOTH readings to agree — no earnings and no links 3.4ms
✓
is WITHHELD ENTIRELY when the link index has never been read 1.8ms
✓
a page with links is never killed, however little it earns 0.5ms
✓
says so in the situation line when nothing can be killed 14.0ms
the four buckets follow the template rule, in its order · 3 tests
✓
earning beats everything — a page with clicks is KEEP even if the crawl calls it thin 0.4ms
✓
impressions without clicks is IMPROVE — the intent exists and the page is losing it 0.5ms
✓
thin AND drawing impressions is COMBINE — there is demand, wrong page answering it 0.5ms
the redirect map · 4 tests
✓
sends everything that moves to the page that actually EARNS 0.8ms
✓
never redirects a page to itself 2.8ms
✓
leaves redirect_to null when there is no page worth redirecting into 0.7ms
✓
the leak hypothesis is killed when everything moving has a destination 0.3ms
the judgement we refuse to make · 1 test
✓
toxic links is ALWAYS untested — we count links, we do not judge them 0.4ms
honesty about the population · 4 tests
✓
never implies the labelled set is the whole site 0.2ms
✓
degrades honestly with nothing on file 0.3ms
✓
the two-source rule holds across every shape 0.6ms
✓
labels each page exactly once, even when it appears in both inputs 0.2ms
no internal vocabulary reaches the reader — GS-005 · 1 test
✓
never names a tool, a field or an issue code 0.6ms
Q16 is recognised and reachable · 3 tests
✓
recognises the question and refuses a production request 1.9ms
✓
routes from the sentence and is traceable 2.4ms
✓
the dispatch attaches it, computed before the empty-evidence gate 0.5ms
src/seo/content-pieces.vitest.ts
saveContentPiece · 5 tests
✓
records the piece and returns its id 4.0ms
✓
never throws — the article is already in the user's hands 0.8ms
✓
returns null rather than a fabricated id when the insert returns nothing 0.5ms
✓
refuses a row that could never be read back or would read as a real piece 0.7ms
✓
a rewrite carries source_url and no keyword 0.5ms
listContentPieces · 3 tests
✓
is scoped to the tenant AND the site, newest first 0.5ms
✓
does NOT select body — a listing must not drag every draft across the wire 0.4ms
✓
clamps the limit and degrades to empty rather than throwing 0.7ms
priorPiecesForKeyword · 2 tests
✓
matches case-insensitively — the same term typed twice is the same term 0.6ms
✓
an empty result and a failed read are indistinguishable, so it may only ever SOFTEN 0.7ms
markContentPiecePublished · 5 tests
✓
records the URL and how we know it 0.6ms
✓
scopes the write to the tenant, not just the row id 0.3ms
✓
refuses a URL without provenance, matching the CHECK constraint 0.5ms
✓
reports false when no row matched, rather than implying success 0.3ms
✓
never throws — the article is already live on their site 0.3ms
saveContentPiece persists the brief · 2 tests
✓
writes the brief verbatim alongside the article 0.2ms
✓
records ABSENCE as null, so it never reads as a recorded-but-blank brief 0.3ms
the publish pass reads tell a failure from an empty answer · 3 tests
✓
tenantsWithUnpublishedPieces rejects when the read fails 1.3ms
✓
tenantsWithUnpublishedPieces still answers [] for a read that found nothing 0.3ms
✓
unpublishedPieces rejects when the read fails, and answers [] for a blank site without reading 0.6ms
src/seo/diagnose-intents.vitest.ts
isRevenueOutcomeQuestion · 8 tests
✓
recognises: Why did my sales drop last quarter? 2.0ms
✓
recognises: revenue is down 30% this month, what happened 0.4ms
✓
recognises: orders fell off a cliff after the redesign 0.2ms
✓
recognises: why are conversions lower than in May 0.2ms
✓
leaves alone: why is my AI visibility down 0.2ms
✓
leaves alone: why am I not getting replies 0.1ms
✓
leaves alone: show my sales pipeline 0.2ms
✓
leaves alone: what is holding my site back 0.2ms
isSetupCheckQuestion · 7 tests
✓
recognises: Something feels off with my setup — can you check what I have configured and what is missing? 1.0ms
✓
recognises: what do I have set up 0.4ms
✓
recognises: am I ready to send campaigns? 0.2ms
✓
recognises: what connections are configured 0.1ms
✓
leaves alone: why is my traffic down 0.2ms
✓
leaves alone: which keywords are missing from my site 0.1ms
✓
leaves alone: check my backlinks 0.1ms
revenueInsufficiencyResult · 1 test
✓
refuses to attribute, names what is on file and what is needed, and tells the model so 0.6ms
setupCheckResult · 3 tests
✓
names what THIS tenant has and lacks, and one concrete next step 0.5ms
✓
with nothing configured, the first missing item is the site and the headline counts the gaps 0.2ms
✓
with everything configured, says so and moves to growth 0.2ms
the revenue branch keys on a CONNECTED STORE with orders (source pin, 2026-09-15) · 1 test
✓
reads commerce_shops beside commerce_orders and requires both 2.1ms
src/seo/extractable-passages.vitest.ts
a clean site is RULED OUT, not untestable · 6 tests
✓
not_in_html is killed on a clean site, with both readings named 3.6ms
✓
no_boundaries is killed on a clean site, with both readings named 0.8ms
✓
no_machine_claim is killed on a clean site, with both readings named 0.5ms
✓
buried is killed on a clean site, with both readings named 0.5ms
✓
nothing_to_lift is killed on a clean site, with both readings named 0.6ms
✓
the decision counts the ruled-out causes and the untestable one SEPARATELY 1.1ms
each cause survives on its own evidence and nothing else · 5 tests
✓
not_in_html survives, and it is the ONLY survivor 0.5ms
✓
no_boundaries survives, and it is the ONLY survivor 0.4ms
✓
no_machine_claim survives, and it is the ONLY survivor 0.7ms
✓
buried survives, and it is the ONLY survivor 0.4ms
✓
nothing_to_lift survives, and it is the ONLY survivor 0.3ms
`na` is not a pass · 2 tests
✓
an na SSR check leaves the cause killed rather than surviving 0.3ms
✓
an empty status is not read as a failure either 0.2ms
one reading is never enough — the two-source rule holds · 3 tests
✓
crawl only: every cause is untested, and the ask names the review 0.8ms
✓
review only: every cause is untested, and the ask names the crawl 0.6ms
✓
neither: the ask says BOTH are needed and why 0.5ms
passage shape is untested no matter what the page scores say · 2 tests
✓
stays untested on a perfectly clean site 0.4ms
✓
the ask surfaces it, so the reader is told what nobody looked at 0.5ms
the brief never claims a citation outcome it has not observed · 2 tests
✓
says nothing about rankings, traffic or citation counts 0.3ms
src/seo/migration-runbook.vitest.ts
Q07: the two systems are joined, not concatenated · 5 tests
✓
merges a URL that is both linked and indexed into ONE entry 3.4ms
✓
keeps genuinely different URLs apart 0.4ms
✓
sums referring domains across several links to one target 0.4ms
✓
ranks linked URLs above indexed-only ones 0.4ms
✓
counts the three kinds separately 7.9ms
Q07: the gate is a precondition, and single-hop survives · 5 tests
✓
says do not go live, not "check afterwards" 0.3ms
✓
keeps the single-hop clause and says why a chain is the trap 0.6ms
✓
warns against redirecting everything to the homepage 0.4ms
✓
carries the ninety-day and two-week windows 0.7ms
✓
states the gate even with no list yet 0.6ms
Q07: the list never claims to be complete · 4 tests
✓
says it is a floor while per-URL click data is missing 0.4ms
✓
names exactly what it would miss 0.2ms
✓
drops the caveat if click data ever becomes available 0.3ms
✓
caps the named list but keeps the true count 0.5ms
Q07: what it cannot see stays unseen · 5 tests
✓
keeps the staging leak untested 0.3ms
✓
keeps the false-cliff hypothesis untested and asks for the one action 0.2ms
✓
flags already-dead targets as the failure in miniature 0.2ms
✓
separates "nothing read" from "nothing to lose" 0.3ms
✓
says a lost link cannot be re-earned, which is why linked URLs lead 0.2ms
Q07: no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps field and table names out of the prose 0.4ms
src/seo/page-conversion.vitest.ts
the three states are kept apart · 4 tests
✓
names silence as unmeasured, never as zero 2.6ms
✓
names "nothing configured to count" separately from silence 0.6ms
✓
says plainly when no reading exists at all 0.4ms
✓
a silent window produces NO conversion verdict on any page 2.1ms
the triage routes the work, and twice it routes it away from search · 5 tests
✓
low engagement is a job for whoever owns the page, not a search rewrite 0.6ms
✓
engaged but not converting means a different KIND of page, not more copy 0.6ms
✓
cannot triage when nothing is counting, and says measurement comes first 0.5ms
✓
triageFor refuses to triage an unmeasured or uncounted site 0.3ms
✓
ignores pages without enough clicks to judge 0.9ms
what it will not conclude · 3 tests
✓
never decides a query mismatch from the words 0.6ms
✓
keeps the speed hypothesis untested — no field data is stored for anyone 0.7ms
✓
reports silence as the finding rather than a failure to answer 0.6ms
no internal vocabulary reaches the user (GS-005) · 2 tests
✓
keeps field and table names out of the prose 0.7ms
✓
says "engagement" rather than "bounce", because engagement is what is on file 0.3ms
foldOutcomeRows: the derivation that had no cover · 6 tests
✓
decides the state from the ROW COUNT, never from summed zeros 0.5ms
✓
treats a missing row count as silence rather than as measurement 0.2ms
✓
sums a URL across its per-date rows 1.5ms
✓
weights engagement by sessions, not by dates 0.4ms
✓
weights position by impressions — the only average of a position that means anything 0.2ms
✓
reports whether anything is counted or earned 0.4ms
client/vitals-render.vitest.ts
the jsdom environment is actually present · 1 test
✓
has a document with a body 8.5ms
a value we do not have · 3 tests
✓
renders an em dash, not a zero 21.6ms
✓
renders an em dash for undefined too — `== null` must catch both 3.1ms
✓
still renders a REAL zero as "0" — the rule is about absence, not about the digit 2.5ms
deltas · 4 tests
✓
shows a down arrow and the magnitude for a negative delta 3.8ms
✓
shows an up arrow for a positive delta 4.8ms
✓
renders NO arrow for a zero delta — "▲ 0" would claim a movement that did not happen 1.5ms
✓
renders no arrow when there is no delta at all 1.7ms
tone and dormancy · 2 tests
✓
marks a warning row without marking it dormant 2.6ms
✓
renders a dormant module as one muted row rather than omitting it 4.2ms
an actionable row is a way in, not a dead end · 5 tests
✓
dispatches its command on click 3.7ms
✓
dispatches on Enter and on Space, so it is reachable from the keyboard 2.5ms
✓
sends the row's OWN command when several rows are actionable 2.8ms
✓
is not actionable, and does not throw, when no dispatcher is supplied 1.2ms
✓
survives a dispatcher that throws — a dead send must not blank the panel 2.8ms
rendering is idempotent and text is not interpreted · 3 tests
✓
replaces the previous rows rather than appending to them 2.6ms
✓
treats a label as text, never as markup 1.5ms
✓
paints nothing and does not throw on a null host or null rows 0.9ms
the failure line · 1 test
✓
is ONE honest line, not a grid of em dashes pretending to be measurements 1.9ms
scripts/lib/lead-normalize.vitest.mjs
normalizePersonName — the organization key · 5 tests
✓
lowercases and strips punctuation the way the stored rows were written 2.1ms
✓
KEEPS the legal suffix 0.8ms
✓
folds accents rather than dropping the name 0.2ms
✓
drops digits — so two differently-numbered companies collide, by design 0.3ms
✓
refuses a name with no letters, and one that is absurdly long 0.5ms
normalizeUsDomain — the other half of the key · 3 tests
✓
strips scheme, www and trailing dot 0.4ms
✓
keeps a subdomain that is not www 0.3ms
✓
returns null rather than a guess for junk 0.3ms
normalizeEmail · 2 tests
✓
lowercases and validates the domain half 0.6ms
✓
rejects anything that is not an address 0.3ms
parseEmployeeBand — migration 136 stores bounds, not labels · 3 tests
✓
reads the source vocabulary 0.6ms
✓
treats an open top as open, not as a number 0.2ms
✓
contributes nothing rather than a zero when it cannot parse 0.4ms
validity gates — refuse what we cannot recognise · 6 tests
✓
accepts the band vocabulary the source actually uses 0.3ms
✓
REJECTS the real junk that landed in Company Size 0.3ms
✓
accepts real industry labels including punctuated ones 0.5ms
✓
REJECTS prose and the lost-quoting signature 0.2ms
✓
is SHAPE-based, not an allow-list, so a new legitimate industry still passes 0.1ms
✓
accepts place names and rejects sentences in the place columns 0.3ms
src/admin/alerts.vitest.ts
computeAlerts · 12 tests
✓
is silent on an empty/unknown input — absence is not a breach 2.4ms
✓
does not treat a null metric as healthy OR as breached 0.4ms
✓
escalates the request quota from warning to critical 0.4ms
✓
fires the Durable Object storage tripwire on any non-zero byte 1.1ms
✓
ignores a judge failure rate below the attempt floor — 1 of 2 is 50% and means nothing 0.5ms
✓
ignores a downvote rate below the response floor 0.4ms
✓
treats truncation as INFO — incomplete numbers, not a broken system 0.3ms
✓
says when capabilities were never judged — an unjudged tool looks exactly like a healthy one 0.4ms
✓
flags names judged that are not registered capabilities as a wiring smell 0.5ms
✓
does not put a balance figure in the title — the panel is the place to read it 0.4ms
✓
sorts critical before warning before info 0.4ms
✓
gives every alert an action, not just a colour 7.2ms
judge-coverage alerts name the items · 4 tests
✓
lists the unrecognised names in the detail 0.2ms
✓
lists unjudged capabilities too 0.2ms
✓
says "1 run", not "1 runs" 0.3ms
✓
bounds a long list and says how many are hidden, rather than truncating silently 0.2ms
unjudged alert distinguishes a defect from an empty week · 3 tests
✓
is a WARNING when the tools actually ran, and names the run counts 0.2ms
✓
raises no unjudged alert when nothing was invoked-but-ungraded 0.2ms
✓
drops to INFO and stops claiming invocation when run counts are unavailable 0.2ms
src/billing/cost-exposure.vitest.ts
one dial · 2 tests
✓
the threshold IS the acceptable deficit — changing it is a single edit 1.6ms
✓
never sits below the cost of asking 0.4ms
every wide-ceiling tool prices the CALL, not the average · 4 tests
✓
finds the tools whose ceiling outruns their typical 0.2ms
✓
verify_contacts (37,500 typical / 750,000 ceiling) has a per-call estimator 0.8ms
✓
seo_onpage_audit (25,000 typical / 150,000 ceiling) has a per-call estimator 0.2ms
✓
seo_keywords (68,550 typical / 100,750 ceiling) has a per-call estimator 0.2ms
a tool that reserves far more than it spends is tracked, not forgotten · 3 tests
✓
no NEW tool starts reserving a ceiling it will not spend 0.7ms
✓
a tool that gains a per-call estimator is REMOVED from the list 0.2ms
✓
aeo_visibility now prices the call the user actually chose 1.1ms
costOfCall answers for every tool, priced or not · 4 tests
✓
prices an unpriced tool at zero rather than refusing to answer 0.2ms
✓
prefers the per-call estimate over the table when arguments decide the cost 0.3ms
✓
never reads approvalMode off a per-call estimate 0.2ms
✓
quotes the ceiling when the arguments cannot say how big the call is 0.3ms
count-in-args tools price the call, not the ceiling · 6 tests
✓
seo_request_indexing: 20 URLs no longer reserves the 200-URL ceiling 0.2ms
✓
keyword volume is dominated by the PER-TASK charge, not the keyword count 0.2ms
✓
crosses a real step only when a new TASK is needed 0.1ms
✓
falls back to the flat ceiling when the caller named no items 0.2ms
✓
seo_geo_visibility needs BOTH dimensions before it prices a real call 0.4ms
✓
every cleared tool is out of the frozen list and into the estimators 0.3ms
src/billing/money-idempotency.vitest.ts
the 1,000,000-token signup bonus is granted once per user · 4 tests
✓
a failed read of the bonus row grants nothing: the read fails closed 26.9ms
✓
the app-boot path does not re-grant on a failed read either (it retries on the next boot) 2.9ms
✓
two boots racing for a new user write ONE bonus, and the loser is a quiet no-op 4.0ms
✓
with migration 186 applied, a read that missed a pre-existing bonus still writes nothing, and says so without an error 2.1ms
a Stripe redelivery never writes money a second time · 8 tests
✓
top-up: a redelivery whose dedupe read fails answers 500 and credits nothing; the retry is a no-op 9.3ms
✓
top-up: two concurrent deliveries of one session credit it once, both answer 200, nothing is reported 6.5ms
✓
top-up: a credit that committed but whose answer was lost finishes in the same delivery (200, receipt, fresh balance) 4.2ms
✓
refund: a redelivery whose running-total read fails answers 500 and reverses nothing more 3.8ms
✓
refund: two concurrent deliveries of one refund reverse it once 5.4ms
✓
refund: a partial refund and the full refund arriving together reverse the credit exactly once in total 4.0ms
✓
dispute won: a redelivery whose idempotency read fails answers 500 and restores nothing more 1.9ms
✓
dispute won: two concurrent deliveries restore the tokens exactly once 5.5ms
a dispute moves its money or answers 5xx — never 200 with nothing moved · 4 tests
✓
the charge is read at Stripe's real address, and an opened dispute reverses the credit 3.5ms
✓
dispute opened: a failed charge read answers 500 and moves nothing; the retry reverses it once 4.4ms
✓
dispute won: a failed charge read answers 500; the retry restores it once 4.5ms
✓
a refund whose credit-row read fails answers 500 instead of filing "no credit row" and answering 200 1.5ms
an AppSumo code grants its tokens exactly once, even when an answer is lost · 3 tests
✓
a claim that committed but whose answer was lost is finished by the retry, not refused 3.4ms
✓
a grant that failed after the claim is written by the retry, once 3.4ms
✓
re-entering a code this user already redeemed grants nothing and says it is theirs 2.5ms
src/billing/provider-failure.vitest.ts
classification — the class, never the provider text · 12 tests
✓
{"httpStatus":429} → rate_limited 2.5ms
✓
{"httpStatus":402} → quota 0.5ms
✓
{"httpStatus":401} → auth 0.4ms
✓
{"httpStatus":403} → refused 0.3ms
✓
{"httpStatus":503} → server_error 0.3ms
✓
{"httpStatus":400} → client_error 0.3ms
✓
{"error":{"name":"TimeoutError"}} → timeout 0.2ms
✓
{"error":{}} → quota 0.4ms
✓
{"error":{}} → quota 0.7ms
✓
reads the status a client folded into its message 0.5ms
✓
reads the status a client ATTACHED to its error, so the message can carry none (DECISIONS #131) 0.7ms
✓
turns an endpoint into an operation 0.4ms
the shared clients record a failed call · 7 tests
✓
dfsPost: an HTTP 500 is a dfs <op>:failed row, cost 0, and the error is re-thrown unchanged 27.0ms
✓
dfsPost: a task-level quota refusal (HTTP 200, status 40201) is recorded as quota 1.7ms
✓
dfsPost: a success leaves NO failure row 0.7ms
✓
googleFetch: a 429 from Search Console is a google gsc:failed row 1.2ms
✓
the leads provider: a timeout is recorded even though the caller swallows it 0.8ms
✓
the SERP client: a 402 is a serp:failed quota row under its provider 2.6ms
✓
a missing credential is not a call and records nothing 0.5ms
src/campaigns/enrich-grounding.vitest.ts
hasGroundedResearch — saved homepage or news research, nothing else · 3 tests
✓
a one-liner, a homepage summary read from a homepage, or a news title counts; a signal summary alone does not 1.9ms
✓
the stored-enrichment form reads news as an object, as the enrich merge saves it 0.4ms
✓
groundingSource names what the note rests on 0.4ms
the enrich formatter states the grounded count · 6 tests
✓
0 of 9 grounded (the 70dfb970 shape) says so, and says where the notes came from 5.6ms
✓
9 of 9 grounded has no "other" clause 0.4ms
✓
a partial run previews only grounded contacts 0.3ms
✓
the remainder is enriched minus the bullets shown: 9 enriched, 1 grounded says "the other 8" 0.4ms
✓
2 grounded of 9 shows 2 and says 7; 5 grounded of 9 shows 3 and says 6; 3 of 4 shows 3 and says one 0.7ms
✓
an older result without `grounded` is counted from its rows, never assumed 0.5ms
wiring: the dispatch counts with the same predicate · 2 tests
✓
the enrich result carries grounded and the ledger counts, allowlisted 0.3ms
✓
the generate_emails hint counts grounded research, not any saved signal 0.4ms
a legacy homepage_summary is not grounded research · 3 tests
✓
stored: a summary with no flag, no one-liner and no news does not count 0.2ms
✓
flat result row: the same rule, and the Source column agrees 0.2ms
✓
9 contacts whose only "research" is a legacy summary read 0 of 9, with no preview bullet 0.2ms
mergeHomepageSummary — the flag always describes the summary saved beside it · 3 tests
✓
a run that read a homepage writes its summary and the flag 0.7ms
✓
a run that read nothing keeps the stored pair as it was: a legacy summary stays unflagged 0.3ms
✓
a fetched run with no summary does not flag an older, unflagged one 0.3ms
wiring: every writer of homepage_summary writes the pair through the one merge · 2 tests
✓
no merge writes a bare `homepage_summary: r.homepageSummary || …` any more 13.5ms
✓
the enrich result row carries the flag, and the personalised prompt cites only a grounded summary 1.0ms
src/chat/confirm-card-binding.vitest.ts
send_emails: the chip sends the card the person was shown · 4 tests
✓
a re-stage hidden behind a second card is not sent by "Yes, send them" — the current card is shown instead 285.3ms
✓
positive control: a card the agent loop rendered is sent by its chip, exactly the recipients it named 31.7ms
✓
the shortcut path marks its card shown too: "Send all 2 drafts" then the chip sends the 2 21.4ms
✓
a send staged with the SAME recipients behind a second card is still not the card that was shown 48.5ms
a card the guardrail kept off the screen was not shown · 1 test
✓
a send card replaced by the outbound guardrail cannot be sent by its chip 27.9ms
seo_rank_track: the chip tracks the keywords that were on the card · 1 test
✓
"Yes, track these keywords" does not track 40 keywords that were re-staged behind a panel card 48.9ms
every CONFIRM_GATES row confirms only a card that was on screen · 6 tests
✓
resume_campaign: staged behind another card, "Yes, resume it" changes nothing and shows its card; the next click completes it 48.0ms
✓
cloudflare_fix_email_dns: staged behind another card, "Yes, apply the DNS fixes" changes nothing and shows its card; the next click completes it 39.7ms
✓
sov_trend: staged behind another card, "Yes, track my share of voice weekly" changes nothing and shows its card; the next click completes it 46.8ms
✓
resume_scheduled_scan: staged behind another card, "Yes, resume the weekly rank scan" changes nothing and shows its card; the next click completes it 35.0ms
✓
panel_segments: staged behind another card, "Yes, add this panel" changes nothing and shows its card; the next click completes it 38.4ms
✓
seo_rank_track: staged behind another card, "Yes, track these keywords" changes nothing and shows its card; the next click completes it 37.0ms
set_standing_instruction: "Yes, save it" saves the text on the card · 1 test
✓
a different instruction staged behind a panel card is not saved by the chip 39.6ms
what runs must be what the shown card was minted for · 1 test
✓
a DNS card shown, then its args record replaced underneath it: the chip changes nothing and shows what would run 21.7ms
the card primitives · 5 tests
✓
shownCardVerdict: only the shown, still-staged card with an unchanged digest runs 0.5ms
✓
cardsRenderedBy: a card counts only when its whole rendering is in the text that ships (V3-loop-F01) 0.6ms
✓
collectStagedCards: each of two parallel calls is credited only with the card it staged 0.5ms
✓
every staging mints a new card; a card shown in one conversation is not shown in another 1.5ms
✓
a bare cost confirm answers only a card THIS conversation rendered; the card's own id still works anywhere 0.8ms
src/chat/jev-shadow.vitest.ts
jevShadowFor — asked only for our own accounts, only for listed contexts · 4 tests
✓
true for an internal account and a listed context 1.8ms
✓
(neg) never for a real tenant, whatever the config says 0.3ms
✓
(neg) no "1" = everything form, no unlisted context, no key, no list 0.3ms
✓
the audience is the canonical internal predicate: the test tenant by id, our people by email 0.5ms
A7 in shadow asks, and never acts · 2 tests
✓
decideSurface ignores a shadow answer: the email surface needs the live flag 0.3ms
✓
the loop asks with emailFlag || emailShadow, but decides with emailFlag alone 0.9ms
A5 in shadow: asked after the cost gate, beside the tools, labelled by what ran · 3 tests
✓
only in the OFF arm, with a valid saved set, a contact tool in the round, and the shadow gate 0.8ms
✓
starts AFTER the cost gate (a halted round never pays for a question it cannot label) and BEFORE the tools run 1.5ms
✓
the audience travels as an argument from the request, never from reqCtx 1.4ms
shadowSameSetLabel — what the round acted on, against the saved set · 2 tests
✓
same, subset, different, unknown 0.4ms
✓
several runs: any contact outside the set is different; all equal is same 0.3ms
the manifest carries labels and rounded numbers only · 3 tests
✓
shadow, ct_shadow_p and ct_shadow_label 1.5ms
✓
empty strings on a turn with no shadow, and -1.00 for an unanswered ask 0.3ms
✓
the waste reader whitelists the new keys and drops prose in them 0.8ms
a7_shadow scores what `on` would have done, and keeps its cost out of the live A7 net · 2 tests
✓
hits, false surfaces and misses at the live threshold 0.3ms
✓
shadow cost is its own line; the live A7 question count excludes it 0.2ms
a5_shadow: the calibration table the rollout rule needs · 1 test
✓
confusion at the live threshold; subset and unknown kept apart; unanswered counted, not scored 0.3ms
config: the shadow list, and the thresholds the report scores against · 2 tests
✓
JEV_SHADOW is exactly A7 and A5, and each is still dark where it would act 1.4ms
✓
the report scores at the same lines the live decisions use 0.2ms
src/chat/unfulfilled-promise.vitest.ts
the four shapes, taken from the transcripts verbatim · 5 tests
✓
a tool call the model TYPED — promisesociety5, the one that cost a whole session 2.6ms
✓
catches the PRE-redaction spelling too 0.2ms
✓
an announcement — adityakushwaha 0.6ms
✓
an announcement — v8081395298 0.5ms
✓
a bare acknowledgement — anchalsharma and 26muthumari 0.2ms
WORDING ALONE IS NEVER THE DEFECT — delivery is half the test · 4 tests
✓
the same announcement is FINE when the result arrived 0.3ms
✓
an artifact counts as delivery 0.2ms
✓
CHIPS count — a picker is a real turn 0.3ms
✓
an approval card counts — a decision was delivered 0.5ms
what it must NOT flag · 5 tests
✓
a real answer that merely mentions running something 0.2ms
✓
a long answer whose LAST line happens to be an announcement 0.2ms
✓
an honest report of a failure is not a promise 0.1ms
✓
HTML in a report body is not a typed tool call 0.2ms
✓
empty or junk input 0.2ms
what the user is told instead · 2 tests
✓
says nothing ran, never guesses WHY, and offers one action 1.0ms
✓
the bare-ack wording admits the specific lie it told 0.2ms
it runs on the live path, with delivery derived from the response itself · 3 tests
✓
the agent route checks every turn 4.8ms
✓
delivery comes from deriveRenderManifest, NOT reqCtx.renderedManifest 6.0ms
✓
the rewrite is COUNTED, not just silenced 4.3ms
src/leads/product-scan.vitest.ts
parseProductProfile · 5 tests
✓
parses valid JSON with surrounding prose and coerces field types 2.7ms
✓
returns null on malformed JSON and on empty identity 0.5ms
✓
parses fenced JSON (```json blocks) 0.2ms
✓
salvages a truncated (finish=length) payload 0.9ms
compileBriefFromProfile · 3 tests
✓
keeps the legacy line shape extractCompanyName/extractProductName parse 0.7ms
✓
appends the richer fields after the legacy block 0.3ms
✓
omits empty fields entirely 0.3ms
mergeScanCompetitors · 4 tests
✓
appends new scan finds as auto without touching user entries 1.6ms
✓
filters own domain (incl. subdomains), reference hosts, invalid domains, and dupes 0.5ms
✓
returns null when nothing new survives, so callers skip the write 0.3ms
✓
caps the stored set at 12 0.4ms
compactProductContext · 3 tests
✓
builds priority-first lines from the profile within the budget 0.9ms
✓
a small budget still keeps the identity lines (never a mid-line cut) 0.3ms
✓
falls back to a brief slice without a profile 0.1ms
repairTruncatedJson · 2 tests
✓
closes open arrays/objects and drops a cut-off partial string 0.3ms
✓
drops a dangling key with no value 0.2ms
discoverAuxPages · 2 tests
✓
returns same-origin high-signal pages, deduped, capped at 2 0.6ms
✓
excludes the scanned page itself and tolerates bad base URLs 0.2ms
src/reports/artifact-card.vitest.ts
buildArtifactCard · 5 tests
✓
carries the markdown as copy_text so a paste keeps its structure 1.9ms
✓
falls back to stripped HTML for a preview when the tool has no markdown 0.7ms
✓
drops <style> bodies rather than previewing raw CSS 0.3ms
✓
caps the preview — the card is collapsed, the full text rides in copy_text 0.5ms
✓
omits preview and copy_text entirely when there is nothing to show 0.3ms
buildArtifactCard publish routing · 5 tests
✓
offers publish when a connector is live 0.7ms
✓
reports a disconnected connector rather than hiding it — the card shows a connect CTA 0.3ms
✓
lists every resolved destination, not just the first 0.4ms
✓
omits a destination the tool never resolved, while keeping one it did 0.5ms
✓
offers NOTHING when the tool resolved no connector state at all 0.3ms
messageRepeatsDocument · 6 tests
✓
catches the model repeating the whole article as its message 0.4ms
✓
still catches it with a lead-in and light edits 0.2ms
✓
does NOT flag a genuine summary that quotes the opening 0.2ms
✓
does NOT flag a diagnosis that happens to accompany a report 0.2ms
✓
does not fire on short documents, where summary and duplicate are indistinguishable 0.2ms
✓
handles empty and missing input without throwing 1.2ms
documentHandoffMessage · 3 tests
✓
names the document and its size, and points at the card 13.5ms
✓
omits the size rather than claiming 0 words 0.1ms
✓
does not try to summarise the document 0.2ms
src/runtime/agent-kv.vitest.ts
listReportArtifacts · 3 tests
✓
returns the newest report even when its key sorts LAST lexicographically 3.0ms
✓
scopes to the user prefix and sorts by createdAt desc 1.0ms
✓
returns [] when CHAT_HISTORY is absent 0.3ms
pending standing-instruction gate · 4 tests
✓
write → consume is one-shot (returns pinned text, then null) 7.2ms
✓
cancel drops the pending record so a later confirm finds nothing 1.1ms
✓
fails closed when KV is unbound (no durable confirmation channel) 0.3ms
✓
is tenant-scoped — one user cannot confirm another user's pending text 0.4ms
lastDraftBatch · 4 tests
✓
round-trips the ids the next turn needs 0.4ms
✓
is tenant-scoped — one tenant can never resolve another tenant's drafts 0.5ms
✓
returns null rather than an empty set when nothing was drafted 0.2ms
✓
survives an unbound KV without throwing — it is a convenience, never a dependency 0.8ms
pending send: the id record and its context · 8 tests
✓
writes the sorted id list, byte-identical to before, for 600 s 0.7ms
✓
writes the context on its own key for 600 s, and reads it back 0.5ms
✓
a malformed context reads as null (the free-text path then fails closed) 1.2ms
✓
is tenant-scoped: another tenant sees neither record 1.2ms
✓
consume is one-shot, accepts a subset of what was previewed, and deletes BOTH keys 0.4ms
✓
consume refuses ids outside the previewed set, and still spends the record 0.3ms
✓
cancel deletes both keys 0.4ms
✓
unbound KV: nothing loads, so neither the typed approval nor the chip is armed — nothing can send 0.3ms
src/runtime/guardrail-instruction-span.vitest.ts
the internal-instruction rule stops at the element it starts in · 9 tests
✓
a saved article keeps every section after a recital (real seo_write_content HTML) 38.2ms
✓
a recital with no period of its own still ends at its paragraph (real article HTML) 1.4ms
✓
the marketing plan keeps every initiative after a recital in one of them (real plan HTML, one line) 2.0ms
✓
an attribute value, a JSON-ish string and a markdown cell end where they end 0.5ms
✓
a prose recital is still removed through its own sentence end, and the next sentence stays 0.3ms
✓
a quoted word inside a prose recital does not end it early 0.2ms
✓
a URL inside the recital is not a sentence end (bklink 2026-09-18) 0.3ms
✓
a recital closed by a sentence end inside a tag still takes its period 0.2ms
✓
a reply that is only the recital still gets the non-empty fallback 1.3ms
no guardrail rule reaches past its token on single-line report HTML · 10 tests
✓
internal_instruction 0.9ms
✓
schema_speak inside an attribute leaves the attribute closed 1.6ms
src/tools/ops-wave6.vitest.ts
seo_request_indexing — the external one · 5 tests
✓
is classified as leaving nqzai 1.8ms
✓
takes an array of urls 1.0ms
✓
accepts the empty call 0.2ms
✓
rejects the retired singular url 0.3ms
✓
clamps an over-long batch instead of refusing it 1.1ms
seo_rank_track — the alias was in the schema · 3 tests
✓
rejects the singular that used to be DECLARED alongside it 0.4ms
✓
requires at least one keyword 0.3ms
seo_content_quality · 4 tests
✓
rejects the retired page alias 0.2ms
✓
rejects the retired site alias 0.2ms
✓
requires a page — this tool cannot run on nothing 0.1ms
seo_monitor · 2 tests
✓
accepts the empty call and a named site 0.2ms
✓
rejects the retired domain alias 0.1ms
seo_google_merge — held back from wave 4 for a reason · 3 tests
✓
declares the window arguments the helpers actually consume 0.3ms
✓
declares the row limits with bounds instead of hiding them 0.2ms
✓
rejects an invented argument 0.1ms
the SEO section is done · 2 tests
✓
every remaining tool.domain fallback belongs to a shortcut capability 1.5ms
✓
the registry still holds every tool 0.7ms
src/tools/seo-keywords-schema.vitest.ts
seo_keywords is schematised · 4 tests
✓
is registered as a schema-first tool 2.5ms
✓
declares topic as the only required field 0.9ms
✓
exposes include_volumes to the model, which the deleted shortcut could not 0.4ms
✓
bounds the topic so a sentence cannot pass as a seed term 0.4ms
the model-facing definition comes from the schema · 2 tests
✓
generates a tool definition rather than a hand-written registry entry 0.5ms
✓
names no vendor and no USD price 0.5ms
argument validation — the incident prompts and their paraphrases · 13 tests
✓
accepts the seed term "ai seo tools" 0.9ms
✓
accepts the seed term "media bias detection" 0.2ms
✓
accepts the seed term "fact checking" 0.5ms
✓
accepts the seed term "programmatic seo" 0.3ms
✓
accepts the seed term "b2b lead generation" 0.2ms
✓
accepts a full economics ask once the model has structured it 0.3ms
✓
rejects the whole user sentence — what extractKeywordTopic used to produce 0.3ms
✓
rejects an empty or one-character topic rather than researching nothing 0.3ms
✓
rejects a missing topic, so the model asks instead of guessing 0.2ms
✓
rejects an off-schema field instead of silently ignoring it 0.3ms
✓
`query` is MIGRATED to topic, not ignored — the value survives 0.3ms
✓
rejects a limit below the minimum but clamps one above the maximum 0.3ms
✓
rejects a wrong-typed include_volumes rather than coercing it 0.2ms
src/seo/brand.vitest.ts
buildBrandIdentity · 7 tests
✓
prefers the product-brief company name over the domain prefix 2.6ms
✓
explicit brand wins over everything 0.6ms
✓
falls back to the domain prefix with no brief 0.8ms
✓
domainTokens compact multi-word names down to URL-matchable tokens 0.4ms
✓
drops sub-3-char tokens (alias noise guard) 0.2ms
✓
the structured profile company/product win over the brief-regex derivation 0.5ms
✓
explicit brand still outranks the profile company 0.3ms
extractDeclaredBrand · 5 tests
✓
prefers Organization JSON-LD name over everything 1.8ms
✓
handles @graph arrays and picks the Organization node 1.3ms
✓
falls back to og:site_name when no Organization schema 0.4ms
✓
falls back to the shortest <title> segment (the brand, not the tagline) 0.5ms
✓
malformed JSON-LD does not throw; returns null when nothing authoritative 0.4ms
brandTextRegexes — response-text matching · 3 tests
✓
matches the company name in engine prose (the exact reported miss) 0.2ms
✓
matches the product name too 0.2ms
✓
word boundaries prevent substring false positives 0.3ms
isOurs — alias-aware citation-domain matching · 4 tests
✓
matches the exact domain and subdomains (unchanged) 0.2ms
✓
matches brand-name domains that differ from the primary domain 0.3ms
✓
legacy single-token callers still work 0.2ms
✓
rival domains stay rivals 0.2ms
src/seo/domain-rating-batch.vitest.ts
one request, not one per domain · 5 tests
✓
rates eight domains with a single call 29.9ms
✓
POSTs a targets array — never the GET form that returns one rating for the whole set 1.2ms
✓
strips the trailing slash the endpoint returns 0.8ms
✓
chunks at the measured ceiling of 1000 5.0ms
✓
sends each distinct domain once 0.7ms
why a rating is missing stays as precise as the single-fetch path · 7 tests
✓
a domain the response omits is unrated, not an error 0.7ms
✓
a 403 marks every domain in the chunk `auth` 0.6ms
✓
a 429 is rate_limited, and anything else is error 1.2ms
✓
a failed chunk does not take a healthy one down with it 2.4ms
✓
rejects junk before spending a request on it 3.8ms
✓
treats a 0 as unrated, not as a rating of zero 0.8ms
✓
makes no request at all when nothing is rateable 0.5ms
readRating · 7 tests
✓
keeps a real rating 0.3ms
✓
rounds, because the endpoint answers in floats 0.2ms
✓
treats 0 as unknown, not as the bottom band 0.2ms
✓
keeps a sub-1 rating, because 0.1 is a measurement and 0 is not 0.3ms
✓
never returns a positive rating that would store as 0 0.4ms
✓
is exclusive at zero, not inclusive 0.2ms
✓
rejects a non-number rather than coercing it 0.6ms
src/seo/keyword-performance-history.vitest.ts
the history row is written alongside the current-state row · 5 tests
✓
writes both tables from one pull 3.9ms
✓
carries the same identity columns as the current-state row 1.5ms
✓
normalises a URL-prefix property to the same host as its domain property 0.5ms
✓
writes nothing at all when the pull resolved no property 1.0ms
✓
writes no history when every row was filtered out 0.4ms
a row states the window it describes — the basis, not the pull date · 7 tests
✓
stores the window the caller actually asked for 0.6ms
✓
does not assume 28 days — a 90-day pull is stored as 90 0.5ms
✓
derives the length from the dates rather than trusting a caller count 0.3ms
✓
a single-day window is 1, not 0 0.5ms
✓
records when we LOOKED separately from what the reading covers 0.7ms
✓
every row in one pull shares one window and one pull date 0.4ms
✓
refuses to write history for a pull that cannot state its basis, and reports it 0.4ms
the population is IDENTICAL to the current-state write · 1 test
✓
holds exactly the same keywords, in the same order 0.6ms
the upsert conflict target — the Hasura constraint trap · 4 tests
✓
names a constraint the migration actually declares 0.4ms
✓
the declared constraint is the grain: one row per user, site, keyword, WINDOW 0.2ms
✓
the earlier day-keyed grain is gone, not merely unused 0.2ms
✓
re-reading the same window UPDATES the metrics and never the conflict keys 1.0ms
a failed history write is reported, never swallowed · 2 tests
✓
reports the failure and still writes the registry 0.6ms
✓
a failed CURRENT-state write still leaves the observation recorded 0.4ms
src/seo/panel-segments-surface.vitest.ts
the panel surface exists and is dispatched · 2 tests
✓
handles list, add and remove 1.8ms
✓
reads and writes the panel setting rather than a private store 0.5ms
the on-demand run cost is quoted from the SHARED function · 4 tests
✓
prices with aeoVisibilityFanoutCostUsd, the same one the approval card uses 0.3ms
✓
does not multiply a per-cell price itself 0.3ms
✓
quotes ONE on-demand run, never a weekly or yearly commitment that does not exist 0.3ms
✓
quotes the engines the run will actually use, never the plan maximum 0.2ms
a keyword panel is DERIVED, never typed · 4 tests
✓
builds it from live search data 0.2ms
✓
refuses rather than inventing a panel when there is nothing to seed from 0.2ms
✓
requires prompts for every OTHER kind 0.5ms
✓
enforces the panel ceiling 0.2ms
a run can be attributed to the panel it measured · 3 tests
✓
aeo_visibility resolves the named panel BEFORE the library fallback 0.4ms
✓
the geo leg passes the resolved panel down to the runner 0.2ms
✓
the snapshot is tagged ONLY when a panel was named 0.1ms
the model is told what a panel costs · 3 tests
✓
the schema says nothing measures a panel on a schedule, and never asks for a weekly or yearly cost 0.3ms
✓
names no USD price — this product bills in tokens 0.2ms
✓
aeo_visibility declares the segment parameter it now accepts 0.1ms
the panel tool is findable for the DELETE intent · 3 tests
✓
names the delete intent in the words a user says 0.2ms
✓
says what these panels are NOT, because the word is overloaded 0.2ms
✓
the summary itself advertises deletion, not just creation 0.2ms
src/seo/small-helpers.vitest.ts
safeCacheKeyMeta — must never log a user-derived key · 4 tests
✓
takes the namespace before the first colon 1.9ms
✓
degrades to "unknown" rather than leaking a key with no separator 0.4ms
✓
degrades on a leading colon rather than emitting an empty scope 0.2ms
✓
never returns the raw key in either field 0.3ms
hashKey · 2 tests
✓
is stable and distinguishes near-identical keys 0.8ms
✓
is non-reversible and fixed-shape, including for empty input 0.8ms
cleanDomain · 5 tests
✓
strips scheme, path, query and case 0.5ms
✓
prefers the URL out of a markdown link 0.4ms
✓
falls back to the label when the markdown link has no URL 0.6ms
✓
strips stray wrapping punctuation 0.4ms
✓
returns empty for empty input instead of throwing 0.3ms
extractCanonicalFromHtml · 5 tests
✓
reads a canonical link regardless of attribute order or quoting 0.5ms
✓
reads og:url with content on EITHER side of property 0.2ms
✓
returns nulls when absent rather than empty strings 0.3ms
✓
does not match a rel that merely CONTAINS canonical 0.1ms
✓
ignores tags past the head budget instead of scanning a whole huge page 0.3ms
topUpMessage · 3 tests
✓
names the estimate, the balance and the action 13.0ms
✓
never shows a NEGATIVE balance to the user 0.2ms
✓
quotes tokens, never currency 0.2ms
scripts/lib/gc-safety.vitest.mjs
the safe case · 1 test
✓
allows a prune when every worktree is idle 2.4ms
uncommitted work blocks — this is the whole point · 2 tests
✓
blocks on a single staged file 0.5ms
✓
names the offending worktree, not just "unsafe" 0.3ms
recent activity blocks · 5 tests
✓
blocks when an index was written inside the quiet period 0.4ms
✓
blocks on an index written THIS INSTANT — the real 2026-08-29 case 0.2ms
✓
allows once the index is older than the quiet period 0.3ms
✓
honours a caller-supplied quiet period, and defaults to 10 minutes 0.3ms
✓
does not block on a FUTURE index mtime (clock skew must not read as activity) 0.2ms
locks and in-flight operations block · 6 tests
✓
blocks when a lock file is present 0.5ms
✓
blocks during a rebase 0.3ms
✓
blocks during a merge 0.2ms
✓
blocks during a cherry-pick 0.1ms
✓
blocks during a bisect 0.1ms
✓
reports every independent reason rather than stopping at the first 0.8ms
FAILS CLOSED — an unreadable state is never an all-clear · 4 tests
✓
blocks when the dirty count could not be read 0.2ms
✓
blocks when the index mtime could not be read 0.2ms
✓
blocks when the gatherer returned NOTHING — a broken instrument is not an idle repo 0.3ms
✓
reports the unreadable worktree ONCE, without inventing derived reasons 0.2ms
src/admin/readiness-scope.vitest.ts
the scope is declared where the rules live · 1 test
✓
G1 and G2 (the production-proof gates) count only P_real, per build band, in a bounded window 2.2ms
D1: a figure off its gate's scope never passes · 12 tests
✓
control: P_real, one build band, 30 days → PASS 1.6ms
✓
on P_harness → FAIL-unmeasurable off_scope, naming why 0.6ms
✓
on P_probe → FAIL-unmeasurable off_scope, naming why 0.4ms
✓
on P_code → FAIL-unmeasurable off_scope, naming why 0.4ms
✓
on probe_harness_pooled → FAIL-unmeasurable off_scope, naming why 0.2ms
✓
on P_candidate → FAIL-unmeasurable off_scope, naming why 0.3ms
✓
on pooled → FAIL-unmeasurable off_scope, naming why 0.4ms
✓
no build band → off_scope 0.6ms
✓
a window beyond the gate's bound, or all history → off_scope 0.4ms
✓
the worst case must be in scope too: a P_real point over a P_harness worst case does not pass 0.3ms
✓
a FAIL is untouched: an off-scope figure that fails still reads NOT READY, as before 0.5ms
✓
offScope is null for a sub with no declared scope (the P_code census gates are not affected) 0.2ms
D1 end to end: production proof cannot read READY on our own traffic · 2 tests
✓
with G1 and G2 on P_harness, both read off_scope and production proof is NOT READY 2.2ms
✓
control: the same fixture on P_real passes G1 and G2 — the ONLY change is the population 2.3ms
D3: a fixture supplies figures, never rules · 3 tests
✓
a catalogue-shaped fixture has no problems and scores every catalogue sub 0.8ms
✓
a threshold that differs from the catalogue is a problem, not a rule (G1 at 5/30 under 0.1) 0.3ms
✓
an unknown sub is a problem; an absent sub has no figure, so its gate cannot pass 1.0ms
src/billing/confirmed-ceiling.vitest.ts
P4-06-F04 (b) — settlement: the charge is min(actual, confirmed maximum) · 8 tests
✓
[fail-first] the live run, replayed under its 115,000 card: charged 115,000, not 196,800 40.4ms
✓
[fail-first] a row that straddles the maximum is split: the part that fits is billed, the rest absorbed 5.5ms
✓
[fail-first] an LLM row that does not fit is absorbed whole; one that fits is billed 5.3ms
✓
no ceiling open → every row is charged in full, exactly as before 5.7ms
✓
a ceiling is the opening tenant's: a row for another user is neither capped nor counted 3.3ms
✓
a zero or missing maximum opens nothing (a card with no number is not a promise of zero) 5.2ms
✓
[fail-first] closeSpendCeiling hands back the settlement: charged + absorbed = what the run cost 14.4ms
✓
[fail-first] the balance query itself leaves absorbed rows out (both tables) 0.7ms
P4-06-F06 (a) — a provider call that returned no answer is recorded, never charged · 1 test
✓
[fail-first] trackAbsorbedApiCall writes the cost and leaves the balance untouched 3.3ms
P4-06-F04 (a) — the quote: a card prices every call, one line per tool · 5 tests
✓
[fail-first] three keyword-research calls are one line, "× 3", at three calls' price 2.5ms
✓
[fail-first] a caller override is the figure for EVERY call of that name, never multiplied again 0.8ms
✓
[fail-first] three calls that each sit under the gate threshold, together over it, are gated 1.7ms
✓
a single call is priced and labelled exactly as before 2.7ms
✓
the live card is reproducible from its own parts: one call priced, three run 2.6ms
P4-06-F04 — the wiring in src/index.ts (not importable under node), pinned in source · 4 tests
✓
[fail-first] the cost-confirm handler opens the ceiling from the CONFIRMED card before anything runs 0.8ms
✓
[fail-first] a confirmed run sent to the queue carries its share, and the job opens it 5.8ms
✓
[fail-first] the agent loop SUMS per-call estimates by tool instead of keeping the last one 1.2ms
✓
[fail-first] the shared card path passes the call counts to both card builders 0.4ms
src/billing/onpage-uncollected-ceiling.vitest.ts
V12b-money-F01 — the world reproduces the verifier's card · 2 tests
✓
the card is 509,500; the rendered crawl costs 375,000; off-page costs exactly its 339,500 line 3.4ms
✓
control T: the crawl collected inline — the card holds at 509,500 on both trees 98.5ms
V12b-money-F01 — the pages fetch fails once (HTTP 503), then "Check crawl results" in a later turn · 2 tests
✓
[fail-first] the card is never debited above its confirmed 509,500 (was: 714,500) 35.0ms
✓
[fail-first] what lies past the card is recorded as absorbed platform cost, against THIS card, and the user is told 24.6ms
V12b-money-F01 — the pages fetch fails once (HTTP 503), then asking again and taking the 25K depth chip · 2 tests
✓
[fail-first] the card is never debited above its confirmed 509,500 (was: 714,500) 14.8ms
✓
[fail-first] what lies past the card is recorded as absorbed platform cost, against THIS card, and the user is told 17.0ms
V12b-money-F01 — the first status poll rejects (the 8 s timeout), then "Check crawl results" in a later turn · 2 tests
✓
[fail-first] the card is never debited above its confirmed 509,500 (was: 714,500) 14.4ms
✓
[fail-first] what lies past the card is recorded as absorbed platform cost, against THIS card, and the user is told 15.4ms
V12b-money-F01 — the first status poll rejects (the 8 s timeout), then asking again and taking the 25K depth chip · 2 tests
✓
[fail-first] the card is never debited above its confirmed 509,500 (was: 714,500) 15.9ms
✓
[fail-first] what lies past the card is recorded as absorbed platform cost, against THIS card, and the user is told 20.7ms
V12b-money-F01 — the marker the confirm turn leaves · 1 test
✓
[fail-first] on an error exit the marker carries the crawl's own share of the card, never the crawl-start snapshot 10.2ms
V12b-money-F01 — the deadline exit hands off the share, not all the room (the under-charge) · 1 test
✓
[fail-first] off-page is billed at its line, not absorbed, and the card is debited exactly its maximum (was: 375,000) 14.0ms
V12b-money-F01 — controls (both trees) · 4 tests
✓
control R: on-page LAST on the card, pages fetch fails, collected later — held at 509,500 14.8ms
✓
control L: the crawl row LANDED in the confirm turn and the report build then threw — no hand-off, so nothing is under-charged or recorded twice 19.5ms
✓
control: a crawl no card confirmed carries nothing and is billed in full when collected 6.3ms
✓
control: a single-tool chip ceiling (no shares) still hands the crawl all of its room, and holds at the chip's price 6.8ms
V12b-money-F01 — the wiring, pinned in source · 2 tests
✓
[fail-first] one hand-off, taking the on-page share, runs on every exit that leaves the crawl uncollected 0.5ms
✓
carryCeiling is called only inside the on-page audit (no other polled tool writes a snapshot) 6.0ms
src/chat/contextual-reply.vitest.ts
typed confirmations reach the approval the button would have · 6 tests
✓
accepts the words users actually type 3.0ms
✓
maps to the exact protocol message the SPA posts 0.4ms
✓
recognises a refusal so it cancels instead of falling through 0.4ms
✓
REGRESSION: internal punctuation must not defeat the match 0.7ms
✓
REGRESSION: a punctuated refusal cancels — the more dangerous half 0.3ms
✓
keeps the apostrophe form matching after normalisation 0.3ms
it must not approve spend on anything but a bare yes · 3 tests
✓
ignores a reply that carries new instructions 0.4ms
✓
does nothing when no approval is pending — a stray "yes" cannot arm spend 0.3ms
✓
does not read an unrelated short message as consent 0.6ms
a typed source choice routes like the picker chip · 3 tests
✓
accepts the picker options as bare words 0.5ms
✓
stays silent when no lead search is pending 0.3ms
✓
prefers the named source over a generic confirmation 0.2ms
a reply to the send card is marked for judgment, never approved here · 6 tests
✓
I1: with a cost card pending, a "yes" is the cost card's — no send kind, ever 0.8ms
✓
no live send card → a stray "yes" or "confirm and send" is nothing 0.3ms
✓
a live card: the reply is marked for Jev, and it has no canonical message of its own 0.2ms
✓
a question is never judged as an approval 0.1ms
✓
past twelve words it is an instruction, not an answer 0.9ms
✓
the picker still wins its own words when a send card is also live 0.2ms
src/chat/human-gates-loop.vitest.ts
a model confirm:true completes none of the six — the card comes back instead · 6 tests
✓
resume_campaign: the model's own confirm, on a live staged record, changes nothing 192.5ms
✓
cloudflare_fix_email_dns: the model's own confirm, on a live staged record, changes nothing 39.6ms
✓
sov_trend: the model's own confirm, on a live staged record, changes nothing 39.3ms
✓
resume_scheduled_scan: the model's own confirm, on a live staged record, changes nothing 17.9ms
✓
panel_segments: the model's own confirm, on a live staged record, changes nothing 20.5ms
✓
seo_rank_track: the model's own confirm, on a live staged record, changes nothing 23.2ms
the person's chip completes each of the six · 6 tests
✓
resume_campaign: "Yes, resume it" applies exactly the staged change 18.3ms
✓
cloudflare_fix_email_dns: "Yes, apply the DNS fixes" applies exactly the staged change 12.1ms
✓
sov_trend: "Yes, track my share of voice weekly" applies exactly the staged change 18.0ms
✓
resume_scheduled_scan: "Yes, resume the weekly rank scan" applies exactly the staged change 14.4ms
✓
panel_segments: "Yes, add this panel" applies exactly the staged change 14.5ms
✓
seo_rank_track: "Yes, track these keywords" applies exactly the staged change 10.7ms
the two writes that had no gate now stop at a card when the model calls them · 6 tests
✓
panel_segments add, called by the model with no confirm, saves nothing and says what saving it means 17.7ms
✓
seo_rank_track, called by the model with no confirm, tracks nothing new and quotes the scan 16.9ms
✓
a keyword that is already tracked adds no commitment, so it registers with no card 24.4ms
✓
listing and removing panels stay ungated 20.0ms
✓
the panel list is drawn by the system, and a confirm card draws no table 0.6ms
✓
the cancel chip drops a staged panel and saves nothing 4.4ms
src/chat/judge-acknowledgement.vitest.ts
acknowledgement by asking for the prerequisite · 5 tests
✓
counts the real 0.2 cases as acknowledged 2.9ms
✓
still catches the concealment shape this guard exists for 0.4ms
✓
is not satisfied by a reply that merely ends in a question 0.2ms
✓
requires the reply to ask for the SAME thing the tool said was missing 0.2ms
✓
leaves a genuine no-failure turn alone 0.3ms
the failure and the reply may use different words for the same thing · 6 tests
✓
domain <-> website URL is the same prerequisite 0.2ms
✓
site url <-> domain, both directions 0.2ms
✓
lead <-> contact <-> list is the same prerequisite 0.2ms
✓
recognises the two ask shapes that were being read as concealment 0.5ms
✓
and neither shape can be satisfied by narrative prose 0.2ms
✓
but a different prerequisite still does not acknowledge 0.3ms
STATING the zero is owning up — the empty result the reply printed · 5 tests
✓
accepts a printed count 0.6ms
✓
accepts the same fact stated without a digit 0.4ms
✓
and the whole reply now reads as acknowledged, which is the point 0.3ms
✓
does NOT excuse a broken run, only an empty one 0.2ms
✓
does NOT accept a reply that conceals the emptiness 0.2ms
the clamp that produced the 0.2 constant · 2 tests
✓
still pins a genuinely concealed failure, so this fix narrowed the trigger not the guard 0.2ms
✓
does not clamp when the failure was acknowledged 0.1ms
src/chat/judge-honesty.vitest.ts
failureWasAcknowledged · 5 tests
✓
is false when the reply never mentions that anything went wrong 2.3ms
✓
is TRUE for the live fabrication — which is why this detector alone was not enough 0.4ms
✓
is true when the reply plainly says it did not work 0.4ms
✓
is true when there was no failure at all, so callers can ignore it 0.2ms
✓
only reads the opening of a long reply — a buried admission is not an admission 0.7ms
the note handed to the judge states the fact, not a suspicion · 4 tests
✓
names the tool, the failure, and that nothing was saved 0.4ms
✓
classifies it as hallucination and caps hard 0.3ms
✓
says fluency is aggravating, not mitigating 0.3ms
✓
leaves the honest exit open 0.4ms
caps bind deterministically, because prose caps do not bind LLMs · 5 tests
✓
a concealed failure is clamped whatever the model said 0.3ms
✓
dead_end is capped at 0.6 — the rubric said so and nothing enforced it 0.2ms
✓
hallucination is capped even without the platform signal 0.1ms
✓
leaves a clean verdict alone 0.2ms
✓
still clamps disproportionate 0.1ms
an acknowledged failure keeps the softer, existing treatment · 1 test
✓
gets the ordinary outcome note, not the contradiction note 0.4ms
the invariant that actually catches the live case · 3 tests
✓
EVERY failed run tells the judge nothing was persisted 0.3ms
✓
tells the judge to cross-check against stored context, which it already receives 0.1ms
✓
forecloses the specific excuse the live reply used 0.1ms
src/chat/reply-frame.vitest.ts
resultForBrowser: the four things the app reads off a result, and nothing else · 5 tests
✓
a send log, a send result and a scan carry nothing the app reads: no result at all 2.0ms
✓
a confirmation gate: only that it is one 0.8ms
✓
the campaign dashboard: which panel, for which campaign 0.3ms
✓
create_campaign: the new campaign's id; search_leads: the list it fills; neither from another tool 0.5ms
✓
not an object: nothing 0.3ms
usageForBrowser: the footer's token counts, never a currency · 2 tests
✓
keeps every token count and drops the dollar figure and anything else 0.4ms
✓
a number that is not finite is not a count 0.3ms
replyFrameForBrowser: the same frame, narrowed, and the server's copy untouched · 3 tests
✓
cuts result, the usage and the search note; leaves every rendered field as it was 1.3ms
✓
never touches the payload the server kept 0.5ms
✓
a frame with nothing to narrow is the same frame, field for field 0.3ms
the app reads nothing off a reply that the frame does not keep · 4 tests
✓
every read of data.result in client/main.ts is a field the frame keeps 5.7ms
✓
the app never reads the result some other way: no alias, no index, no other client module 4.6ms
✓
the usage footer reads only token counts the frame keeps, and renders from cumulative or usage 2.6ms
✓
the search note is read for its token count, and the server builds it without a dollar figure 9.4ms
the wiring: every final frame leaves through sendEvent, and sendEvent narrows it · 4 tests
✓
the SSE writer narrows every final frame for a browser, and only the operator harnesses keep the whole result 0.4ms
✓
no frame is written any other way, and every final frame goes through sendEvent 0.8ms
✓
only the admin harnesses pass evalOverrides: the browser route never can 5.3ms
✓
the non-streaming failure says a scanned sentence, like its streaming twin 0.2ms
src/chat/send-jev.vitest.ts
decideSendApproval — Jev approves, code guarantees · 8 tests
✓
"confirm and send" at 0.96 → approved, labelled as Jev's 3.3ms
✓
Jev disabled (rollout or key missing) → no approval and no call 1.3ms
✓
a throw or a timeout → no approval, reported 1.5ms
✓
an answer with no probability is a failure, never a silent approval 0.5ms
✓
the threshold is exact: 0.89 fails, 0.90 passes 0.5ms
✓
I3: subset and conditional replies Jev scores low do not send 0.7ms
✓
I3: "send the first 3" against a card of 9 is refused by arithmetic, with NO Jev call 0.5ms
✓
the count rail lets the card's own count through, and no number at all 0.3ms
the approval state — built from counts, never from history · 4 tests
✓
carries the card in numbers, as the calibration measured it 0.5ms
✓
has no address, no subject and no name anywhere 0.6ms
✓
the reply is clipped, so a pasted essay is not the state 0.3ms
✓
the question is a noul naming ALL, exclusions, conditions, delays and open questions 0.4ms
decideSendStart — the paraphrase band only stages, and only on Jev's yes · 4 tests
✓
below the bar → the model takes the turn 0.3ms
✓
off or failing → not a start, no throw 0.5ms
✓
the question names what is NOT a start 0.4ms
rollout · 2 tests
✓
JEV_ROLLOUT in wrangler.toml names send_start and send_approve (calibration passed 2026-09-24) 0.7ms
✓
the constants carry their live calibration 0.3ms
src/commerce/shopify-oauth.vitest.ts
normalizeShopDomain · 2 tests
✓
accepts canonical myshopify domains, case/protocol/path-insensitive 2.5ms
✓
rejects lookalikes and junk 0.6ms
verifyCallbackHmac · 6 tests
✓
accepts a correctly signed callback query (hmac + signature excluded, keys sorted) 5.4ms
✓
rejects a tampered param and a wrong secret 1.3ms
✓
rejects missing/garbage hmac 0.3ms
✓
accepts a signature over the RAW percent-encoded query string 1.3ms
✓
accepts a signature over the re-encoded canonicalization 1.1ms
✓
still rejects tampering under all canonicalizations 0.8ms
verifyWebhookHmac · 1 test
✓
accepts the raw body signed with the app secret and rejects tampering 1.5ms
verifySessionToken · 3 tests
✓
accepts a valid token and returns the normalized shop 1.7ms
✓
rejects expired, wrong-aud, wrong-signature, malformed 1.5ms
✓
rejects a dest that is not a myshopify domain 0.5ms
shopifyConnectAllowed (App Store review gate) · 3 tests
✓
unset allowlist → gated for everyone (safe default during review) 0.3ms
✓
allowlisted email connects; others gated; case/space-insensitive 0.3ms
✓
'*' opens the gate for everyone, including no email (Shopify reviewer) 0.2ms
shop claim tokens (Shopify-initiated install account-link) · 3 tests
✓
round-trips shop + claim and survives URL encoding 1.9ms
✓
rejects tampered and garbage tokens 0.9ms
✓
rejects claims older than the pending TTL 0.6ms
src/email/esp-webhooks.vitest.ts
webhook URL token · 6 tests
✓
round-trips the tenant it was minted for 7.5ms
✓
rejects a token minted for a DIFFERENT provider 0.8ms
✓
rejects a token whose user id has been swapped 0.6ms
✓
rejects a token minted under a different worker secret 0.6ms
✓
rejects malformed tokens rather than throwing 0.8ms
✓
gives different tenants different tokens 1.1ms
provider allow-list · 1 test
✓
accepts only the four providers that can actually send 0.3ms
Svix signature (Resend) · 3 tests
✓
rejects a payload with no signature headers 21.0ms
✓
rejects a signature outside the replay window 0.8ms
✓
accepts a correctly signed payload and rejects a tampered body 8.1ms
payload parsing · 8 tests
✓
Mailjet: reads its own hard_bounce verdict rather than the free-text error 4.2ms
✓
Resend: Permanent / Transient / Undetermined map to hard / soft / unknown 0.5ms
✓
SendGrid: classifies through the SAME function the DSN parser uses 1.0ms
✓
Mailtrap: a named bounce with no readable code stays HARD 0.4ms
✓
ignores every event that does not mean "stop sending here" 0.7ms
✓
marks spam complaints distinctly, and always as terminal 0.7ms
✓
drops events with no recipient instead of inventing one 0.4ms
✓
survives payloads that are not the shape the provider documents 0.5ms
src/leads/local-business.vitest.ts
extractPostal · 8 tests
✓
maps 5-digit anchored zips to US 2.1ms
✓
maps 6-digit codes to India 0.4ms
✓
never matches bare counts or short codes 0.5ms
✓
country cue beats digit inference — 75001 France is Paris, not Texas 0.3ms
✓
country cue unlocks 4-digit postals 0.3ms
✓
alphanumeric postals require a matching country cue 0.6ms
✓
postal AFTER the city is caught — live retainly miss 2.1ms
✓
cue alias forms work — UK, USA 0.3ms
detectLocalBusiness · 8 tests
✓
detects category + zip 2.8ms
✓
detects category + pincode (India) 1.1ms
✓
zip alone is enough — no recognised category needed 0.6ms
✓
detects category + free-text city 0.2ms
✓
falls back to persona geography when the query has no location tail 0.1ms
✓
rejects B2B persona queries even with a location 0.1ms
✓
rejects local category with no resolvable place 0.2ms
✓
detects medical categories with a place 0.4ms
the maps actor is gone, and stays gone · 2 tests
✓
exports no actor id and no input builder 0.3ms
✓
still parses historical run payloads 0.2ms
src/leads/onboarding-first-turn.vitest.ts
a Worker must not fetch its own zone · 4 tests
✓
recognises our own host, with or without www or a path 2.0ms
✓
leaves every real customer domain alone 0.4ms
✓
follows APP_BASE_URL rather than a hardcoded literal 0.3ms
✓
does not throw on junk input 0.3ms
reasoning must not quote our own instruction machinery · 3 tests
✓
redacts the identifiers that mark a leak as a leak 2.9ms
✓
redacts rather than blocks — the surrounding sentence is usually harmless 0.5ms
✓
leaves ordinary language alone 0.3ms
scanProductSite refuses our own zone before it fetches · 2 tests
✓
returns a typed SELF_ZONE error and never makes a request 0.8ms
✓
says what actually happened and asks for something usable 0.7ms
a failed scan carries its own routing, not just an error · 1 test
✓
the dispatch returns brief_saved:false plus the three ways forward 1.2ms
domainFromMessage (shared by every shortcut that names a subject) · 4 tests
✓
pulls the domain a user named in a natural request 0.5ms
✓
returns null when no domain is named — the saved site must still resolve 0.2ms
✓
ignores pasted file paths, which are not subjects 0.2ms
✓
takes the FIRST domain when several appear — the subject, not an aside 0.1ms
scanProductSite — the scan is enrichment, the URL is a fact · 4 tests
✓
SELF_ZONE still saves nothing — there the URL is not worth keeping 0.2ms
✓
a refused crawl still saves the site — the business is real, our crawler was blocked 28.4ms
✓
does NOT save when the domain never resolved — that is a typo, not a block 0.9ms
✓
never claims a save it did not make — no userId, no flag 0.7ms
src/leads/product-context.vitest.ts
repairTruncatedJson · 10 tests
✓
leaves already-valid JSON parseable and unchanged in meaning 2.3ms
✓
closes an object cut off mid-structure 0.4ms
✓
DROPS a value truncated mid-string rather than keeping a half-word 0.4ms
✓
drops a dangling key that has no value yet 0.4ms
✓
drops a trailing separator rather than emitting {"a":1,} 0.2ms
✓
closes nested structures in the right order 0.3ms
✓
is not fooled by braces or quotes INSIDE a string 0.3ms
✓
preserves escaped characters through the repair 0.2ms
✓
keeps bare literals that completed 0.5ms
✓
always returns something JSON.parse accepts, even for junk 1.3ms
autoLinkBrand · 8 tests
✓
links the first occurrence of the company name 0.4ms
✓
links only ONCE, not every mention 0.7ms
✓
does nothing when the body already contains a link 0.1ms
✓
does nothing without a URL 0.1ms
✓
adds https:// to a bare domain rather than emitting a relative href 0.2ms
✓
treats a brand name with regex metacharacters literally 0.2ms
✓
falls back to the product name when the company name is absent from the body 0.1ms
✓
leaves the body untouched when neither name appears 0.1ms
src/planner/plan-builder.vitest.ts
the hard blocker names the work it actually blocks · 5 tests
✓
fires only when the plan contains site-dependent work 1.8ms
✓
outbound and commerce are NOT site-dependent 0.4ms
✓
seo, aeo and content ARE 0.3ms
✓
no longer claims the whole plan is unmeasurable 0.4ms
✓
the string has ONE definition — it had two 0.5ms
CreatePlan mutation is not a "//"-poisoned GraphQL document · 1 test
✓
the CreatePlan mutation literal contains no JS-style "//" line 0.4ms
blockedFamilyLine (no raw tool/readiness keys to the user) · 3 tests
✓
renders known families and prerequisites in plain English 0.3ms
✓
never contains a snake_case identifier for any known family 0.5ms
✓
falls back to a humanized (not raw) label for an unmapped family/prerequisite 0.6ms
neverUsedFamiliesLine (no raw tool keys to the user) · 2 tests
✓
renders known families in plain English 0.3ms
✓
never contains a snake_case identifier 0.3ms
countSharedMeasurements / decorateInitiative (Track B #3 — honest shared-signal copy) · 3 tests
✓
counts items sharing the same adapter+key, ignores unmeasurable items 0.3ms
✓
adds a "shared" note only when the same signal backs more than one item 0.5ms
✓
never adds a shared note to a non-learning (unmeasurable) item 0.2ms
isTopicGrounded (no ungrounded topic reaches a paid tool call) · 4 tests
✓
passes a topic that shares a real word with the tenant context 0.2ms
✓
rejects a topic with zero word overlap — the live incident case 0.1ms
✓
is case-insensitive 0.1ms
✓
passes through when the value has no substantive (length > 3) words to check 0.1ms
src/planner/plan-source-ledger.vitest.ts
buildPlanSourceLedger — every audit type is accounted for · 3 tests
✓
covers EVERY SNAPSHOT_TYPE, present or not 2.4ms
✓
an absent stored source explains what its absence cost, in readable English 0.9ms
✓
no row is labelled with its raw internal key (GS-005) 1.5ms
buildPlanSourceLedger — "not on file" is never "could not be read" (GS-004) · 4 tests
✓
an errored audit read says so, and is flagged 0.4ms
✓
a legitimately absent audit says never run — reporting OUR outage as THEIR missing data is the defect 0.3ms
✓
a failed keyword read is distinguished from a tenant with no keywords 0.3ms
✓
a PARTIAL keyword failure keeps the half we do hold 0.5ms
buildPlanSourceLedger — provenance classes are real distinctions (GS-003) · 4 tests
✓
stored context is RECORDED, audits are MEASURED 0.6ms
✓
age is null when the source carries no timestamp — never 0 0.5ms
✓
a dated snapshot reports its real age 0.3ms
✓
today reads as "measured today", not "0 days old" 0.3ms
buildPlanSourceLedger — keyword coverage states what is MEASURED, not just held · 1 test
✓
separates registry membership from measured performance 0.2ms
planSourceSummary — counts, not adjectives · 2 tests
✓
counts present sources and names failures 0.3ms
✓
says nothing about failures when there were none 0.1ms
the plan report renders the ledger · 4 tests
✓
shows each source with its provenance class 13.2ms
✓
says the ledger was captured at BUILD time, not now 0.3ms
✓
a plan that PREDATES the ledger renders no ledger block at all 0.4ms
✓
names failed reads in the section header, so a degraded plan cannot look complete 0.3ms
src/reports/aeo-phase2.vitest.ts
aeo_page_check — crawlability is a gate, not a component (P-001/P-002) · 4 tests
✓
a blocked page is never called "partially AI-ready" 2.1ms
✓
the score is greyed and stage-labelled, without changing the arithmetic 0.4ms
✓
never asserts reachability it did not check 1.0ms
✓
a crawlable page is unaffected 0.3ms
aeo_page_check — one list, ordered by impact (P-003/P-004) · 6 tests
✓
the blocker outranks every measured deduction 0.3ms
✓
measured deductions outrank structural checks, largest first 0.2ms
✓
the heavier GEO pillar comes before the lighter one 0.3ms
✓
states the ordering rule, and does not claim a precision it lacks 0.2ms
✓
names the stack on fixes when we know it (P-004) 0.5ms
✓
does not list the crawl block twice 0.3ms
seo_geo_research — not ranking is not zero (G-001) · 2 tests
✓
renders no gauge at all rather than a confident zero 0.3ms
✓
a ranking page still gets its gauge 0.4ms
seo_geo_research — the competitor delta IS the report (G-002/G-003) · 6 tests
✓
compares our signals against the cited pages on the same axes 0.2ms
✓
uses the MEDIAN, so one outlier cannot set the target 0.2ms
✓
ranks the axes we are BEHIND on first 0.1ms
✓
a failed gap analysis is never rendered as its own content (G-003, trap 1) 0.1ms
✓
when nothing could be measured it says so, rather than showing an empty section 0.3ms
✓
a real gap analysis still renders normally 0.4ms
src/runtime/caller-stamp-writers.vitest.ts
the schema-REJECTED tool_run writer carries the caller · 4 tests
✓
correct code (each sibling in its own child scope): stamped with the caller, status untouched 33.3ms
✓
THE P0-07b-01 SHAPE, the merge re-introduced: a sibling mints between this call's entry and its write → scope_mismatch 3.2ms
✓
a NESTED sub-tool's rejection under its parent's run is not a mismatch 3.2ms
✓
written under ANOTHER user's context → scope_mismatch, whatever the run 0.6ms
the balance-REFUSED tool_run writer carries the caller, and is gated on the ENTRY run · 3 tests
✓
correct code: a top-level refusal is written, stamped, status untouched 2.7ms
✓
the merge shape: a top-level refusal whose context a sibling minted into is WRITTEN (it used to be read as nested and dropped) and flagged 3.9ms
✓
a nested sub-tool's refusal still writes no row: it belongs to its parent's run, which writes its own 2.0ms
SPEND rows a run writes carry the run's caller (P0-07b-03 remainder) · 6 tests
✓
a provider row inside a run: caller_user and caller_turn from the run scope, no flag 3.5ms
✓
a row written under ANOTHER user's identity while the run is open disagrees with itself: scope_mismatch 4.1ms
✓
no run open → no caller stamp (nothing to compare); closing the run clears it 5.6ms
✓
a child run scope starts with no caller and never leaks one to its siblings 1.1ms
✓
a QUEUED job's run, minted by startTokenTracking, stamps its spend rows with the job's user (V-lows-F06) 2.8ms
✓
stampRunCaller: a row whose user is absent (the platform floor) is not flagged 0.4ms
wiring — src/index.ts writes exactly what this file drives · 5 tests
✓
the entry run is read with the entry turn, and stampAtEntry compares against it 0.6ms
✓
the rejected writer goes through stampAtEntry 0.4ms
✓
the refused writer is gated on the entry run and goes through stampAtEntry 0.5ms
✓
the minting branch records the run's caller from the closure 0.4ms
✓
every tool_run writer in src is stamped (4 of 4) 2.2ms
src/runtime/unbounded-awaits-residue.vitest.ts
withTimeout: the bound for calls that take no signal · 3 tests
✓
a value in time is returned and the timer is cleared 4.3ms
✓
a call that never answers rejects with a TimeoutError at the limit, naming the call 1.6ms
✓
a value that arrives AFTER the limit reaches onLate instead of vanishing; a late rejection is swallowed 1.4ms
the email binding: a wait that ends, an outcome that is unknown · 3 tests
✓
env.EMAIL.send never answers: the attempt ends at CLOUDFLARE_EMAIL_SEND_TIMEOUT_MS as ok:false "unconfirmed", called once, reported as unconfirmed 1.7ms
✓
a message id that arrives after the limit is logged, not lost 2.5ms
✓
a BYOK provider whose call ends at its ceiling is answered as unconfirmed (reported), not thrown through the chain 302.3ms
the coverage refresh: one limit per statement, never per job · 7 tests
✓
a stalled statement is reported with its label and skipped; the refresh continues and writes the rest 185.2ms
✓
one client per statement: 1 countries + 2 global + 4 per-country + 1 write = 8 clients for 8 statements 0.9ms
✓
a stalled WRITE rejects: nothing was stored, and the monitor must see it 182.2ms
✓
every count stalling rejects rather than storing nothing silently 1087.4ms
✓
only a stall is skipped: isStatementTimeout reads the driver's wrapped TimeoutError and nothing else 0.8ms
✓
the limit is a statement-scale number: ten times the measured 16.8 s scan, under the monitor's 30-minute job ceiling 0.4ms
✓
SOURCE: every neon client in the refresh is built with a timeout signal, and no client is shared across statements 0.4ms
the app shell: a platform asset read that never answers still ends · 1 test
✓
ASSETS.fetch hangs → appShellResponse rejects with a TimeoutError inside the limit 54.9ms
SOURCE PINS for the sites that cannot be driven here · 4 tests
✓
the visibility tracker's self-call carries a timeout signal, sized above the longest engine probe 0.9ms
✓
the crawl-run Durable Object call is wrapped, and its expiry is reported and read as "state unavailable" 1.0ms
✓
the push-channel upgrade is wrapped (never a signal on the fetch: a 101 must outlive any timer) and a miss is a 504 6.9ms
✓
the unmatched-path asset passthrough shares the app shell's limit 5.6ms
src/support/bug-report.vitest.ts
sanitizeBugReport · 9 tests
✓
requires a title and a description of real length 3.2ms
✓
falls back to normal severity rather than rejecting an unknown one 0.6ms
✓
keeps a valid severity 0.3ms
✓
STRIPS THE QUERY STRING from the page URL 0.4ms
✓
keeps the fragment, because the SPA deep-links with it 0.3ms
✓
keeps an unparseable URL rather than dropping it — a malformed URL is still a clue 0.4ms
✓
strips the query string from every network-trail path too 0.5ms
✓
truncates the network trail from the FRONT, keeping the most recent calls 1.2ms
✓
drops junk entries rather than storing empty rows 0.9ms
screenshotKey · 1 test
✓
partitions by UTC year and month so a lifecycle rule can act on a prefix 0.4ms
submitBugReport · 8 tests
✓
writes the screenshot to R2 BEFORE the row, and stores the key it actually wrote 3.2ms
✓
NEVER takes the reporter from the payload — user_id is the one passed in 0.4ms
✓
files the report anyway when the R2 binding is unbound, and says the screenshot did not save 0.6ms
✓
deletes the orphaned screenshot when the row insert fails 0.5ms
✓
refuses a user who is over the hourly limit, and names the number 0.4ms
✓
FAILS OPEN when the rate-limit query itself throws 0.3ms
✓
records no screenshot key when none was supplied 0.6ms
✓
still files the report when the email lookup fails 0.3ms
src/tools/content-wave3.vitest.ts
seo_write_content: the two modes are declared · 10 tests
✓
accepts keyword mode 2.3ms
✓
accepts rewrite mode 0.3ms
✓
lets a ready-made brief be passed, which was impossible before 0.4ms
✓
rejects the retired topic alias 0.4ms
✓
rejects the retired title alias 0.2ms
✓
rejects the retired url alias 0.3ms
✓
rejects the retired rewrite_url alias 0.2ms
✓
rejects the retired content_brief alias 0.2ms
✓
bounds length through the schema: floor errors, ceiling clamps 0.8ms
✓
tells the model both modes exist 0.4ms
seo_content_brief · 3 tests
✓
accepts the declared shape 0.2ms
✓
rejects the retired topic alias 0.2ms
✓
requires the keyword 0.1ms
seo_content_ideas · 2 tests
✓
accepts the empty call and a named site 0.2ms
✓
rejects an invented argument 0.1ms
the coalescing chains are gone · 3 tests
✓
seo_write_content reads one name per concept 0.4ms
✓
seo_content_brief no longer coalesces topic 0.2ms
✓
leaves still-legacy tools their fallbacks 0.1ms
src/seo/aeo-prompt-library-roundtrip.vitest.ts
the fake is faithful to the live templates schema · 3 tests
✓
rejects the pre-fix library write for the reason production did 7.2ms
✓
rejects a constraint Hasura does not expose 0.7ms
✓
upsertSettings has no global path: without a userId it throws before sending anything 0.6ms
write column == read column · 2 tests
✓
the settings reader asks for the library key at all 0.6ms
✓
the library is stored in exactly the column the reader selects — derived from the operations sent 2.5ms
round trip through generateAeoPromptLibrary · 5 tests
✓
a second picker load is served from the library, with no LLM call 6.8ms
✓
a failed save is reported and says so — not swallowed 1.4ms
✓
a degraded build is not stored (and says so), so the next load retries at full strength 0.9ms
✓
regenerate replaces the stored library and never serves the old one 2.8ms
✓
a changed brief invalidates the stored library 2.3ms
a prompt the guardrail would alter is withheld from every reader, never from the store · 2 tests
✓
the generated library is stored whole and returned without them, with origins aligned 39.3ms
✓
served from the store it is withheld again, and the library is NOT rebuilt for being thinner 3.9ms
the library edit path acts on a real row · 3 tests
✓
removing prompts keeps origins aligned with the prompts that remain 0.4ms
✓
a library the user trimmed below the degraded-build floor is still served, not rebuilt 1.3ms
✓
deleteSettings clears the per-isolate cache, so a cached read cannot serve the deleted row 0.6ms
templates: `instruction` is the only value column anything writes · 3 tests
✓
scans a real population 61.9ms
✓
no insert_templates writes or updates any column but instruction 56.1ms
✓
nothing outside the store helpers touches the library row with raw GraphQL 43.6ms
src/seo/audience-split.vitest.ts
audienceView · 3 tests
✓
measures the comparison-prompt shape of a panel 1.9ms
✓
a use-case panel reads as far less comparison-shaped 0.3ms
✓
builds the source diet from OTHER people's hosts, not ours 0.3ms
dietDivergence compares SHARES, never raw counts · 2 tests
✓
two panels of different sizes are still comparable 0.3ms
✓
sorts by the widest gap first 0.4ms
with fewer than two audience panels it REFUSES, and names what to build · 4 tests
✓
no panels: both comparison hypotheses untested 0.4ms
✓
ONE panel is still a refusal — one panel has no difference in it 0.5ms
✓
a CONFIGURED but unmeasured panel changes the instruction, not the verdict 0.3ms
✓
ignores panels of another kind — a language panel is not a second audience 0.6ms
with two audience panels it answers · 4 tests
✓
compares the prompt shapes with both panels as sources 0.8ms
✓
names the source kind that diverges most 0.3ms
✓
kills the diet hypothesis when the two panels draw on the same kinds 0.3ms
✓
the decision funds two backlogs rather than asking which to pick 0.2ms
the two hypotheses nothing here can test · 3 tests
✓
what the answer TEXT said is not recorded, so the integration claim stays untested 0.2ms
✓
self-reported influence needs a CRM field that does not exist 0.2ms
✓
they stay untested even with both panels measured — more panels cannot supply them 0.1ms
the brief holds the contract · 2 tests
✓
the headline changes with what could actually be done 0.5ms
✓
carries the one-pager fields 0.4ms
src/seo/backlink-gap.vitest.ts
computeBacklinkGap — the subtraction · 6 tests
✓
returns their referring domains that are absent from ours 2.4ms
✓
compares on the referring DOMAIN, not the page URL 1.1ms
✓
collapses many links from one site into ONE prospect 0.5ms
✓
ranks by domain rating, highest first 0.4ms
✓
marks a domain nofollow_only only when EVERY observed link was nofollow 0.4ms
✓
drops rows with no usable referring URL rather than inventing a prospect 0.2ms
computeBacklinkGap — basis is the honesty gate · 3 tests
✓
is `no_baseline` when we hold none of our own links 0.4ms
✓
is `measured` once we hold any of our own referring domains 0.3ms
✓
reports their distinct domain count, not their link count 0.4ms
backlinkGapNote — the disclosure that travels with it · 6 tests
✓
refuses the word "gap" with no baseline, and names the fix 0.4ms
✓
says how partial the sample is when we know our true total 13.2ms
✓
stays quiet about partiality when the sample IS the whole profile 0.2ms
✓
claims completeness ONLY when the provider confirmed the set was exhausted 0.3ms
✓
does not infer completeness from the counts happening to match 0.2ms
✓
never claims completeness while also admitting the sample is partial 0.3ms
the rendered reply cannot contradict its own disclosure · 3 tests
✓
with NO baseline it never tells the user to pitch anyone 6.0ms
✓
with a baseline the pitch IS the next move 0.2ms
✓
never calls it a gap in the heading without a baseline 0.3ms
src/seo/backlink-policy.vitest.ts
Q09: disavow is reachable ONLY through a concentrated network · 5 tests
✓
a very low-authority domain is IGNORED, never disavowed 3.2ms
✓
spammy-looking anchors and zero DR still do not trigger disavow 0.5ms
✓
fires only once enough domains share one network 0.8ms
✓
tells the reader NOT to build a disavow file when no network is found 0.5ms
✓
always says the manual-action half of the rule is not visible from here 0.7ms
Q09: the other three clauses survive · 3 tests
✓
says do not buy links, naming paid guest posts 0.6ms
✓
measures in-niche referring domains, not a rating 0.6ms
✓
produces an earn plan rather than a rating target 0.6ms
Q09: reclaim is found and ranked first · 2 tests
✓
classifies links pointing at dead pages as reclaim 0.8ms
✓
puts the redirect at the top of the plan — nothing to ask anyone for 0.4ms
Q09: what we cannot see stays unseen · 3 tests
✓
never concludes how rivals earned their links 0.4ms
✓
never concludes anything about unlinked mentions 0.2ms
✓
distinguishes "no link data" from "no links" 0.9ms
Q09: findNetworks prefers the narrower signal · 3 tests
✓
groups on prefix rather than ASN when both exist 0.3ms
✓
falls back to ASN when no prefix is known 0.3ms
✓
ignores domains with neither signal 1.7ms
Q09: no internal vocabulary reaches the user (GS-005) · 2 tests
✓
keeps table and field names out of the prose 0.5ms
✓
states the low-authority threshold as a judgement, not a field 0.3ms
src/seo/competitor-gap.vitest.ts
computeKeywordGap — the subtraction · 6 tests
✓
removes keywords the tenant demonstrably ranks for 2.7ms
✓
removes keywords the tenant merely tracks, too — tracking one means it is not news 0.4ms
✓
matches on the normalized key, so casing and punctuation cannot split one keyword in two 1.1ms
✓
de-duplicates the competitor list — a provider can return one keyword per match type 0.4ms
✓
preserves provider order and the full row, so volume/difficulty survive to the table 0.8ms
✓
drops empty/unusable competitor keywords rather than counting them as gaps 0.3ms
computeKeywordGap — basis is the honesty gate · 7 tests
✓
is `measured` only when GSC ranking data exists 0.5ms
✓
is `registry_only` when we hold tracked keywords but no ranking evidence 0.5ms
✓
is `unknown` when we hold nothing — an empty registry is not evidence of a gap 0.7ms
✓
counts the union, so a keyword in both sets is not compared against twice 0.2ms
✓
is `read_failed`, not `registry_only`, when the GSC read errored and a registry exists 0.3ms
✓
is `read_failed`, not `unknown`, when the GSC read errored and nothing else is held 0.2ms
✓
a failed read still subtracts the registry — an interest list is valid either way 0.2ms
gapBasisNote — the disclosure that must travel with the gap · 5 tests
✓
states the measured baseline size 13.8ms
✓
says plainly that a registry-only gap is NOT a ranking claim 0.4ms
✓
refuses to call an unknown baseline a gap 0.2ms
✓
says "could not be read" for read_failed, never "isn't connected" 0.4ms
✓
is grammatical at n=1 — singular/plural is user-visible copy 0.2ms
src/seo/content-keyword-join.vitest.ts
the stance is decided by POSITION, and by nothing else · 6 tests
✓
calls a striking-distance term improve, not new 2.1ms
✓
calls a top-3 term defend — a new page competes with the winning one 0.3ms
✓
calls position 44 new — far enough that writing beats re-pointing 0.2ms
✓
does NOT call a tracked-but-unranked term improve — tracking is an intention 0.4ms
✓
matches on the normalized key, so casing and punctuation cannot split one term in two 0.2ms
✓
keeps the measured row when two entries normalize to the same key 0.2ms
nothing is ever dropped · 4 tests
✓
returns every idea it was given, whatever the stance 0.9ms
✓
re-ordering preserves every idea and is stable within a stance 0.4ms
✓
inverts for the long game, and leaves an unset horizon untouched 0.6ms
✓
puts defend last under BOTH horizons — real information, nobody's next action 0.3ms
the basis is stated, because a count off no data is wrong rather than small · 5 tests
✓
is measured when any row carries a position 0.2ms
✓
is registry_only when rows exist but none is ranked 0.1ms
✓
is unknown with nothing to compare against 0.1ms
✓
refuses to claim anything when the basis is unknown 0.5ms
✓
names the weaker basis rather than presenting it as a measurement 12.9ms
the note says the thing the tool got wrong before · 3 tests
✓
names the already-ranking term and its position, and says re-point 0.4ms
✓
warns about competing with your own top-3 page 0.2ms
✓
says nothing when there are no ideas 0.2ms
src/seo/cron-balance-guard.vitest.ts
cron balance guard · 7 tests
✓
both scheduled spend paths call the guard 1.7ms
✓
the keyword guard runs BEFORE the paid SERP call 0.4ms
✓
the SOV guard runs BEFORE the composite tool call 0.3ms
✓
a balance-lookup failure blocks the run rather than authorising it 0.3ms
✓
a balance-lookup failure is reported, not swallowed silently 0.3ms
✓
a blocked run tells the user — activity + email, deduped per week 0.2ms
✓
the email template exists and names which tracking paused 0.4ms
scheduled-run completion emails · 5 tests
✓
the rank digest is gated on measurement, not on movement 0.3ms
✓
the rank digest still says something true when nothing moved 0.5ms
✓
a completed AI-visibility run emails the user unconditionally 0.3ms
✓
the prior score is read BEFORE the run overwrites it 0.2ms
✓
a first run is reported as a first run, not as an unchanged score 0.2ms
the balance guard runs before the scan, per tenant · 3 tests
✓
there is no shared guard or scan budget left to re-merge 0.3ms
✓
within a tenant: claim, then the balance guard, then the SERP scan 0.3ms
✓
a guard failure for one tenant is reported, not left to abort anything else 0.1ms
cronBalanceGuard runtime behavior · 3 tests
✓
sufficient balance: proceeds, tells nobody anything 1.1ms
✓
insufficient balance: blocks AND notifies — the exact path that had a 0% send rate 2.7ms
✓
a throwing balance lookup: blocks AND reports — never silent, never authorises spend 0.8ms
src/seo/dfs-location.vitest.ts
resolveDfsLocation — country level · 2 tests
✓
maps a supported ISO to its location_code 2.5ms
✓
is case- and whitespace-insensitive 0.3ms
resolveDfsLocation — the silent-US defect · 3 tests
✓
flags assumedUs for an unsupported country 0.3ms
✓
flags assumedUs when nothing at all is supplied 0.4ms
✓
does NOT flag assumedUs when the US was actually requested 0.2ms
resolveDfsLocation — city level · 5 tests
✓
emits DFS-format location_name for city + country 0.3ms
✓
includes the region when given, in DFS city,region,country order 0.3ms
✓
never emits location_name for a country it cannot NAME 0.3ms
✓
ignores a city with no country rather than guessing one 0.5ms
✓
treats a whitespace-only city as absent 0.2ms
dfsLocationCode — back-compat · 2 tests
✓
is unchanged for every supported ISO 0.5ms
✓
still returns 2840 for unknown, empty and absent input 0.2ms
the two market tables agree · 2 tests
✓
covers exactly the same ISO set 0.2ms
✓
supports city level for every market it supports at country level 0.4ms
ai_visibility_check carries the location disclosure · 4 tests
✓
emits label, assumed and city_level 26.7ms
✓
keeps location_assumed === false instead of collapsing it to null 0.7ms
✓
records a true assumption as true 0.8ms
✓
is null — not false — when the caller said nothing, so old runs are not counted as resolved 0.7ms
src/seo/link-verify.vitest.ts
relToVerdict · 1 test
✓
reads the strongest credit-withholding token 2.0ms
hostMatches · 2 tests
✓
matches across www and subdomains 0.5ms
✓
does not match a different domain that merely ends similarly 0.3ms
classifyLinkPage · 6 tests
✓
finds the anchor and reads its rel 1.4ms
✓
reports no_link when the page does not link to us at all 0.3ms
✓
reports the STRONGEST link when a page links to us more than once 0.3ms
✓
handles single quotes, unquoted attributes and protocol-relative hrefs 0.4ms
✓
ignores relative hrefs — they cannot point at another domain 0.2ms
✓
strips markup out of the anchor text 0.5ms
mergeVerdict — the two-pass rule · 3 tests
✓
calls a page that blocks us but answers a browser BLOCKED, not dead and not dofollow 0.2ms
✓
calls a page that answers nobody dead 0.2ms
✓
uses the parse result when the page was readable 0.2ms
summarizeVerification · 6 tests
✓
excludes blocked pages from the dofollow denominator 0.5ms
✓
counts removed links and dead pages together as lost 0.2ms
✓
never claims a percentage when nothing was confirmed present 0.1ms
✓
says nothing is verified when no page could be read 0.1ms
✓
states the result is first-hand, unlike every provider-reported figure 0.1ms
✓
handles an empty run without dividing by zero 0.7ms
src/seo/visibility-movement.vitest.ts
the basis decides whether a delta exists at all · 11 tests
✓
THE LIVE CASE: 29% over four engines vs 42% over three is NOT +13 2.4ms
✓
same engine set — the delta is real and signed 0.5ms
✓
engine ORDER is not a basis change 0.3ms
✓
an engine ADDED is a basis change, not just an engine removed 0.2ms
✓
the same engines on DIFFERENT questions is not comparable 0.4ms
✓
question ORDER is not a change, but question MEMBERSHIP is 0.4ms
✓
case and surrounding whitespace do not make a new panel 0.3ms
✓
when BOTH halves change, the note says so rather than naming one 0.3ms
✓
an empty prompt set is never comparable, even to another empty one 0.4ms
✓
no previous run reads as a baseline, never as "no change" 0.3ms
✓
a genuinely unchanged rate says so rather than printing +0 0.3ms
what it will not do · 3 tests
✓
never returns a delta when the current engine list is empty 0.2ms
✓
ignores a previous reading with no usable percentage 0.2ms
✓
the phrase never carries a number the movement says is absent 0.3ms
the previous rate is read BEFORE the legs that overwrite it · 4 tests
✓
previousCitationRate is called before the GEO leg dispatches 0.4ms
✓
there is exactly one call site — a second could sit on the wrong side 0.2ms
✓
a run compared with itself would report "no change", which is the symptom to recognise 0.2ms
✓
the REAL comparison for that run refuses a delta — 3 engines then, 4 now 0.3ms
src/leads/shared/coverage.vitest.ts
classifyCoverage · 5 tests
✓
calls an empty axis ABSENT — applying it can only return zero 2.1ms
✓
calls a minority axis PARTIAL — the filter works, the pool is thin 0.3ms
✓
calls a well-populated axis BROAD and says nothing 0.3ms
✓
treats exactly the threshold as broad 0.3ms
✓
ONE row is partial, not absent 0.2ms
a stale measurement is not evidence · 3 tests
✓
ages out to PARTIAL rather than to its last value 0.3ms
✓
does not guess BROAD when nothing has been measured 0.2ms
✓
treats an unparseable timestamp as stale rather than as now 0.2ms
what the user is told · 5 tests
✓
says we hold none of it when an axis is absent 0.6ms
✓
does NOT claim a partial filter was dropped 0.4ms
✓
quotes the WORST axis as an UPPER BOUND when several are partial 0.3ms
✓
uses the user’s words, not the column names 0.2ms
✓
says nothing at all when there is nothing to disclose 0.1ms
the state note now reads the measurement · 5 tests
✓
says we found nobody THERE, not that location targeting is unavailable 0.4ms
✓
STOPS claiming we have none once even a little exists 0.2ms
✓
still says a paid source would not add it — that part did not expire 0.2ms
✓
invents no percentage when coverage was never measured 0.2ms
✓
keeps outranking the empty-result explanations 0.1ms
client/chat-anatomy.vitest.ts
environment · 1 test
✓
has a DOM — otherwise every test below is vacuously absent 5.1ms
decorateTraceBlock — the header says what it can prove · 7 tests
✓
counts steps and states the elapsed the caller measured 26.7ms
✓
says "Worked" with no time rather than inventing one 3.8ms
✓
names failures in the collapsed state, where they are easiest to hide 4.0ms
✓
names unfinished steps too, and does not call them failures 2.9ms
✓
refuses to decorate a tree with no steps 2.9ms
✓
is idempotent — history replay must not stack two headers 3.9ms
✓
collapsing hides the tree and reports the state 4.6ms
renderInsightCard — a card may not outlive its content · 9 tests
✓
renders label, body and the metric with its own sign 28.3ms
✓
marks which metric is the tenant 2.3ms
✓
gives a rival NO delta element rather than a zero 3.8ms
✓
renders NOTHING when there is no text 1.0ms
✓
renders nothing for a null insight or a missing host 1.6ms
✓
is idempotent — history replay re-renders the same turn 2.0ms
✓
a caution is visually distinct from a rationale 2.3ms
✓
draws a sparkline only when there are at least two points 7.8ms
✓
carries the caveat when the card has one 4.2ms
client/xss-sinks.vitest.ts
onclick title — a model-authored report title never becomes script (P1-13a-F01) · 2 tests
✓
server chip (src/reports/html.ts reportChipMarkup): click opens the report with the exact title, nothing runs 45.7ms
✓
client job_completed chip: same title, same result — the two authors are one 12.9ms
hover breakout — a double quote in an artifact title adds no attribute (P1-13a-F02/E5) · 1 test
✓
artifacts panel row: no handler fires on hover or click; click opens with the exact title and tool 18.5ms
backslash — a value ending in \ cannot re-arm the quote (P1-13a-F02/E2) · 1 test
✓
lead panel phone copy button: nothing runs; the handler receives the phone verbatim 19.7ms
javascript: URLs are refused wherever data chooses the URL (P1-13a-F03) · 3 tests
✓
chart drill-down panel (P0-02c-F01): crawl label and URL can neither inject markup nor carry a script scheme 30.8ms
✓
turn-evidence row (client/chat-anatomy.ts): a crawled URL with a script scheme is not linked 15.7ms
✓
server report (seo_geo_research competitor URL): javascript: never reaches href 59.7ms
markdown link URL cannot close href="…" (P0-02c-F02) · 2 tests
✓
renderMarkdown: the named-link URL stays inside the attribute; nothing runs on hover 19.7ms
✓
renderMarkdown still links ordinary URLs and escapes text 13.8ms
stored and legacy server HTML goes through one choke point (mountServerHtml) · 3 tests
✓
a legacy chip carrying the F01 payload: no script, and the chip still opens its report 17.5ms
✓
legacy literal-command buttons keep working without their inline JS 11.0ms
✓
any other inline handler, and any script-scheme URL, is removed rather than kept 14.2ms
every inline-handler shape the server stored before 2026-09-26 still works after migration · 5 tests
✓
top-up, export, topical send, initiative and GEO-cell buttons map to their actions 27.3ms
✓
the Save-report menu toggle and the collapsible detail rows still toggle 13.4ms
✓
all four copy-button variants copy their data 12.1ms
✓
the submit-for-indexing block: select-all, per-row count and submit 21.1ms
✓
image fallbacks still fall back 12.0ms
src/admin/infra-health.vitest.ts
it takes TWO failures to cry wolf · 2 tests
✓
one bad probe is silent — a blip is not an outage 3.5ms
✓
the second consecutive failure alerts, and only once 1.1ms
a throw is a detection, not an error to swallow · 2 tests
✓
DNS/TLS failure counts as down 0.6ms
✓
a timeout counts as down and says so 0.6ms
recovery · 1 test
✓
reports how long we were down, as a LOG not a fault 1.1ms
UNKNOWN must never read as DOWN · 4 tests
✓
no stored record reads healthy 0.2ms
✓
an UNPARSEABLE record reads healthy, not broken 0.3ms
✓
VALID json of the WRONG SHAPE reads healthy too 0.3ms
✓
an unconfigured NHOST_URL does not invent an outage 0.5ms
its monitor says what the run did (src/runtime/cron-run.ts) · 5 tests
✓
rejects when it could not RECORD its state — a probe nobody can read did no work 1.6ms
✓
rejects when it could not READ its state, but still probes and still alerts 0.6ms
✓
ONE lost write after a fresh record is a one-tick lag: it resolves, and says so in Logs 1.5ms
✓
a lost write when the PREVIOUS tick did not record either (record 6 min old) still rejects 0.5ms
✓
resolves with its record when the probe ran and the record was written — up OR down 0.5ms
it shares nothing with what it watches · 3 tests
✓
never reaches the database 0.2ms
✓
state lives in Cloudflare KV, and the alert goes to Sentry 0.2ms
✓
cannot take down the tick it rides on, and its monitor sees every run 4.7ms
src/billing/debit-ledger-keys.vitest.ts
logTokenUsage — one model response, one charge · 7 tests
✓
[fail-first] the same generation written twice is one row and one charge 38.6ms
✓
[fail-first] a 502 before the write commits is retried: the charge is recorded, not dropped 4.7ms
✓
[fail-first] an answer lost after the write committed: the retry finds the row, and nothing is charged twice 4.4ms
✓
two calls the provider did not name are two charges (no false collision) 1.7ms
✓
two different generations with identical usage are two charges 2.8ms
✓
both attempts failing is still reported, never silent 2.4ms
✓
with migration 198, a generation already recorded under an older random id is refused too 1.2ms
logApiUsage / trackApiCall — one provider call, one charge · 4 tests
✓
[fail-first] a 502 before the write commits is retried: the provider charge is recorded 2.4ms
✓
[fail-first] an answer lost after the write committed is one row, not two, and not an error 1.9ms
✓
[fail-first] trackApiCall inside a tenant window: a lost answer is still one charge 3.1ms
✓
two calls are two charges 1.3ms
the admin grant — one grant_id, one credit · 6 tests
✓
[fail-first] the same grant sent twice credits once and sends one receipt 3.6ms
✓
[fail-first] a lost answer on the grant does not credit twice on the operator's retry 2.9ms
✓
two grants with different grant_ids are two credits, even when identical otherwise 2.6ms
✓
the grant id is the same name for two users only by coincidence: it is keyed per user 2.7ms
✓
grantIdFrom reads body grant_id, else the Idempotency-Key header; empty or over 200 characters is none 3.0ms
✓
the route refuses a grant with no grant_id, in a sentence, before anything is written 7.8ms
src/billing/event-keys-redelivery.vitest.ts
a queue redelivery of the same message is the same event (DECISIONS #80) · 5 tests
✓
[fail-first] the same message delivered twice writes each unnamed provider row once 39.0ms
✓
[fail-first] a message whose window names no job (a fan-out branch) is still named by its body 7.9ms
✓
two different jobs are two rows, and two polls of one self-re-enqueuing job are two rows 7.1ms
✓
queueMessageUnit prefers the body's own id to the delivery's, and never invents one 1.3ms
✓
a chat turn (no named job) keeps #666's per-turn behaviour: the same call in two turns is two rows 4.9ms
a cron re-run of the same tick is the same event (DECISIONS #80) · 3 tests
✓
[fail-first] the same tick run twice writes each event once; the next day's tick writes its own 11.1ms
✓
cronEventKey is null outside a scheduled scope — a manual run is not mistaken for the tick 1.0ms
✓
the calendar keys: ISO week belongs to its Thursday's year; day is UTC 1.0ms
re-judging a response is a NEW event (DECISIONS #81) · 5 tests
✓
two judge calls on one response in one invocation are two rows 4.2ms
✓
[fail-first] re-judging a response inside a REDELIVERED job is a new row, though the job's other rows collapse 4.5ms
✓
[fail-first] a judge row is named by response + op + attempt, recomputable, and labelled as a caller key 2.0ms
✓
[fail-first] one judge call's row written twice is one row 1.6ms
✓
no response id, or no scope, is no judge key — never a shared one 1.0ms
caller groups keyed by their own ids · 4 tests
✓
[fail-first] a provider task seen twice — by two different turns — is one row (DFS backlinks) 5.8ms
✓
[fail-first] the render manifest is named by its turn: a second write for the turn is refused by the ledger 2.4ms
✓
providerEventKey: sorted, and null when any id is missing 0.7ms
✓
[fail-first] every caller group passes its own id to the writer 80.2ms
src/billing/stripe-signature.vitest.ts
verifyStripeSignature — accepts only genuine, fresh signatures · 8 tests
✓
accepts a correctly signed, current payload 9.6ms
✓
rejects a signature made with the WRONG secret 0.8ms
✓
rejects when the BODY was altered after signing 0.6ms
✓
rejects a stale signature outside the tolerance window (replay) 0.5ms
✓
rejects a FUTURE timestamp too — tolerance is absolute, not one-sided 0.4ms
✓
rejects a missing, empty or malformed header rather than throwing 0.5ms
✓
rejects a non-numeric timestamp instead of treating NaN age as in-window 0.2ms
✓
rejects a truncated signature that is a PREFIX of the real one 0.8ms
isTopUpPack · 1 test
✓
rejects values that are not declared packs, including prototype keys 0.6ms
top-up packs · 3 tests
✓
offers exactly $10 / $50 / $100, priced at the flat retail rate 1.8ms
✓
serves the list and the sentence from that one table 0.5ms
✓
accepts only the three live ids 0.3ms
isOurCheckoutSession · 5 tests
✓
claims a session that points back at our own success_url 0.3ms
✓
does NOT claim a sibling product on the same account — the exact 2026-09-13 session 0.2ms
✓
still claims OUR session when the metadata is gone — the case the alarm exists for 0.2ms
✓
claims our host however it is cased — a false negative here silences the alarm 0.1ms
✓
refuses every host that merely CONTAINS ours 0.5ms
src/billing/usage.vitest.ts
search_leads TOOL_COST_ESTIMATE · 2 tests
✓
tokens = ORCHESTRATION_FLOOR + provider cost, with the LLM term declared separately 1.8ms
✓
maxTokens (local-business ceiling) uses the same floor on the $0.40 worst case 0.2ms
FREE_TIER_LEAD_SEARCH_CAP · 1 test
searchLeadsEstimate · 6 tests
✓
quotes a people search as a RANGE from the corpus rate to the provider rate 0.5ms
✓
scales BOTH ends of the range with the requested count 0.3ms
✓
keeps the full local-business worst-case ceiling for a local search 0.2ms
✓
keeps the ceiling for a local search declared without a postcode 0.2ms
✓
never returns a lower ceiling than the base tokens figure 0.4ms
✓
the people-search ceiling is its OWN derived one, never the local-business table figure 0.6ms
buildCostGateMessage / buildCostApprovalData — search_leads override · 4 tests
✓
message quotes THIS search's own range, never the local-business ~2.0M 0.7ms
✓
message still carries the ~2.0M ceiling for a local-business search 0.3ms
✓
card totals reflect the override, not the flat TOOL_COST_ESTIMATE ceiling 0.4ms
✓
with no override, falls back to costOfCall — the SAME figure resolveCostApproval decides on, not a different (flat table) one 0.4ms
searchLeadsEstimate — derived ceilings must reach the balance gate · 4 tests
✓
marks per-argument estimates as ceilings so the static table cannot override them 0.2ms
✓
exposes a per-lead scale so a refusal can offer the size that fits 0.3ms
✓
prices the corpus rung per lead too, and far below the provider rung 0.2ms
✓
local business keeps the static table and claims no ceiling 0.2ms
src/billing/verify-contacts-reservation.vitest.ts
verify_contacts reservation · 6 tests
✓
reserves the resolved count, not the 500-address ceiling 1.8ms
✓
does not reserve the catalogue ceiling for a small list — the incident, exactly 0.4ms
✓
asserts isCeiling only when the count is known 0.3ms
✓
scales the reservation with the count 0.3ms
✓
keeps the CARD a single honest figure — targetSizedEstimate still drops maxTokens 0.3ms
✓
prices a named list with no members at zero, not at the ceiling 0.6ms
targetSizedReservation — what the central balance preflight reserves · 6 tests
✓
a resolved count of 0 reserves 0 0.3ms
✓
25 addresses reserve 37,500 and say it is the ceiling 0.3ms
✓
(neg) only for a target-sized tool 0.5ms
✓
the picker (nothing named) demands 0, not 750,000 0.3ms
✓
a zero reservation is never refused, whatever the balance; a real one still is 37.5ms
✓
the CENTRAL BALANCE PREFLIGHT resolves the count, reserves it, and records it on the call 4.8ms
a zero is only free when the caller asserts it · 5 tests
✓
generate_emails is still refused below the 25K buffer 0.7ms
✓
scan_product is still refused below the 25K buffer 0.5ms
✓
define_icp is still refused below the 25K buffer 0.4ms
✓
generate_emails is refused by a stated turn budget with its headroom committed 0.7ms
✓
(neg) an asserted zero passes at the same balance, and reserves nothing 0.2ms
src/campaigns/search-leads-payload.vitest.ts
the keys that change what the turn MEANS survive the cut · 5 tests
✓
keeps error, note and the in-flight markers readable at 24 leads 2.6ms
✓
keeps error, note and the in-flight markers readable at 100 leads 1.3ms
✓
puts error FIRST — it changes what every other key means 0.5ms
✓
keeps a paid run in flight visible, so the turn cannot be summarised as finished 2.0ms
✓
keeps the paid-shortfall block readable — it is what the escalation gate is built from 0.4ms
the fixture matches production · 1 test
✓
a lead is about a kilobyte, as measured — not the 293 chars this test first assumed 0.2ms
the bulk goes last, where losing it costs least · 3 tests
✓
all is the biggest key and is emitted after everything semantic 1.3ms
✓
the arrays are what overflow, not the semantics 0.4ms
✓
preview is a strict prefix of all, so dropping all loses no distinct row 1.0ms
THERE IS NO SMALL-RESULT CASE · 3 tests
✓
overflows the model window at THREE leads 0.3ms
✓
still shows every semantic key at three leads 0.4ms
✓
shows everything only when there are no leads at all 0.2ms
the ordering function itself · 5 tests
✓
is total — every key survives, exactly once, with its value untouched 0.3ms
✓
puts an UNKNOWN key in the middle, where the model can see it 0.2ms
✓
leaves a key it has never heard of alone when there is no bulk at all 0.3ms
✓
ignores classified keys that are absent 0.2ms
✓
classifies the keys this fix was written for 0.6ms
src/campaigns/send-staging.vitest.ts
the card names every recipient · 2 tests
✓
9 drafts → a 9-row card with no "more" 19.3ms
✓
201 drafts → 200 rows (the per-send ceiling) and 1 left for the next batch 8.4ms
staging writes the id record and its context, both for 10 minutes · 2 tests
✓
sorted ids under send:pending:<user>, and the context under its own key 3.5ms
✓
a readiness note on the card is recorded as a flag, never as its text 2.2ms
only the authorised confirm sends, and only once · 7 tests
✓
with the flag: confirm:true sends the 9; a second confirm sends nothing (one-shot) 6.9ms
✓
I2: an expired record never sends — confirm:true re-previews 3.3ms
✓
I3/I4: the model's confirm:true (no flag) never sends — it re-stages the set it names 4.8ms
✓
I3: with the flag, ids outside the previewed set send nothing 2.4ms
✓
the hourly cap refuses with an error and sends nothing 2.6ms
✓
every id already sent → the no-drafts answer, never "Ready to send 0" 0.7ms
✓
unbound KV: the model's confirm:true still cannot send (the old gate was inactive there) 1.2ms
the send authorisation is scoped to the one call it was granted for · 3 tests
✓
a model confirm in another request, while an approved send is in its loop, only stages 5.1ms
✓
another request starting or finishing cannot revoke an approved send before it is checked 3.8ms
✓
the authorisation is bound to its tenant: a dispatch for another user inside it only stages 2.8ms
a re-stage in another tab cannot be approved from the tab that showed the old card · 3 tests
✓
parked at preflight 7.5ms
✓
parked at put:send:pending:tenant-a 3.8ms
✓
parked at put:send:pending:ctx:tenant-a 10.3ms
src/chat/loop-halts.vitest.ts
a blocked outcome ends the turn without going back to the model · 2 tests
✓
halts on isBlockedOutcome after the verbatim halt, rendering the tool's own sentence 2.6ms
✓
blockedCall is the shared classifier, not a copy of it 0.4ms
a single rendered tool ends the turn without a narration call · 4 tests
✓
exists, after the per-tool loop and before the halt is applied 0.3ms
✓
fires only for one real, non-errored tool with a renderer of its own 0.6ms
✓
the after-lookup path asks Jev, the first path does not, and only a 'render' decision halts 0.4ms
✓
evidence tools keep their narration turn — their output is input to the answer 2.3ms
the shortcut defers to the request, not just the tool · 3 tests
✓
a write request over a lookup keeps the loop alive 0.6ms
✓
the stand-down is instrumented, because its absence is what hid the defect 0.5ms
✓
keepGoing gates the after_lookup path: a two-instruction message never renders or asks Jev 6.2ms
a timed-out verify settles, or halts on its progress · 4 tests
✓
the settle branch sits in the tool catch, after the timeout test and before the safety net 1.0ms
✓
the deadline and the signal reach the tool 0.8ms
✓
the timeout halt comes after the blocked halt and ends the turn 0.3ms
✓
(neg) only tools that report progress and stop on their signal are listed 75.6ms
formatTimeoutHalt · 4 tests
✓
states what was saved and charged, from the counters — and why the charge stands 59.1ms
✓
a verdict whose save is still landing is charged, and said to be still saving 0.4ms
✓
mixed: one still with the provider, one saving, one untouched 0.3ms
✓
no progress, or nothing asked → none were checked and none were charged 0.7ms
src/chat/saved-records-exits.vitest.ts
a finished skill's chips quote the tenant's saved records as they are · 5 tests
✓
cold launch: the campaign its first step created keeps its chip although its name holds a supplier's name 162.4ms
✓
cold launch, CONTROL: a campaign the first step did not save is anyone's words, and its chip goes 28.1ms
✓
quick list build: the list its search saved leads to keeps its chip 13.4ms
✓
quick list build, CONTROL: a list nothing was saved to is not the tenant's, and its chip goes 7.6ms
✓
the result the chips were built from never reaches the browser 15.6ms
a lead search that saved its leads made them the tenant's contacts · 3 tests
✓
the search table shows the saved leads as they are, and a lead it could not save stays checked 90.3ms
✓
the same contact reads the same in the contact list 77.3ms
✓
CONTROL: a search that saved nothing (the store failed) leaves every lead a corpus lead, checked in full 82.7ms
the saved-row marker: which rows a store wrote, and the guard reading it per row · 4 tests
✓
markSavedRows marks the first lead of each stored address, and never one with no usable address 0.7ms
✓
backlink prospects: a saved prospect is the tenant's contact in its block, an unsaved one is checked 1.0ms
✓
CONTROL: for a part not declared row by row, a column that mixes a declared value with anything else still pins nothing 0.4ms
✓
a column mixing a saved row with an undeclared value pins only its saved rows, and only for a part declared row by row 0.4ms
the producers mark what they saved · 2 tests
✓
backlink_outreach_search: the prospects the store wrote carry the contact they became; one it could not store does not 3.6ms
✓
cold_launch keeps what its campaign step returned, so the finished run can prove the campaign is the tenant's 1.1ms
DECISIONS #56: whose values these are, exactly · 3 tests
✓
scan_product's url is the tenant's only when it is their saved site 0.7ms
✓
list_sent_emails' campaign filter is the person's only when they typed it, in the reply and in the table's scope 3.2ms
✓
a saved lead shows as the store saved it, in the search table and the contact list alike 37.7ms
src/chat/site-ownership-claim.vitest.ts
the claim we were deaf to · 7 tests
✓
hears the live message 2.3ms
✓
does NOT change what firstTurnShape decides — that call is load-bearing 1.5ms
✓
accepts the ordinary ways people say it 0.7ms
✓
refuses a bare domain — "audit stripe.com" is a COMPETITOR audit 0.3ms
✓
refuses a THIRD PARTY possessive, however it is phrased 0.3ms
✓
refuses when BOTH readings are present — an ambiguous claim is not a claim 0.2ms
✓
is safe on junk input 0.3ms
the write is guarded at the call site · 10 tests
✓
only writes on an explicit claim 0.3ms
✓
only writes from the message typed THIS turn, never from history or a chip 0.5ms
✓
never overwrites a site the tenant already has 0.3ms
✓
applies the platform-profile guard — "my site" about facebook.com is not a website 0.2ms
✓
is best-effort — a failed write must not cost the audit the user asked for 0.2ms
✓
also builds the product brief, not just the site row 0.1ms
✓
does not re-scan a tenant that already has a brief 0.1ms
✓
writes the site BEFORE scanning, so a failed scan still leaves the domain saved 0.2ms
✓
the scan cannot cost the user the audit they asked for 0.2ms
✓
SAYS it read their site — a silent profile of someone's business is not acceptable 0.1ms
src/chat/tenant-data-replies.vitest.ts
1 · the tenant's own records show as they are in a reply the product renders · 3 tests
✓
a paused campaign named after a vendor is named as it is, and the next turn and the restored transcript say the same (agent loop) 241.7ms
✓
a campaign the model named and saved is announced under that name, in the lead and the body (#45: exempt once saved) 32.7ms
✓
a send result names the recipient it could not reach as they are, while the provider's own words stay hidden (shortcut send_confirm) 47.4ms
1b · the tenant's own site is named as it is; anyone else's domain is not theirs · 2 tests
✓
the Cloudflare connect instruction for the tenant's own zone names it as it is, in the text and in the panel picture (agent loop, render_verbatim) 26.0ms
✓
CONTROL: the same instruction for a domain that is not the tenant's own site stays checked 21.5ms
1c · a report built from the tenant's own data names it as it is (publishReportChip, GET /api/reports/:id) · 2 tests
✓
the campaign report the agent loop published names the campaign as it is 51.5ms
✓
a Search Console + Analytics report: the property, its pages, its queries and its own traffic sources show; a sentence of ours naming a vendor does not 13.1ms
controls: a model's words, product copy, and every other check inside tenant data, stay guarded · 2 tests
✓
a model sentence quoting the tenant's campaign verbatim beside a vendor is still the model's: both redacted 19.1ms
✓
a price inside the tenant's campaign name is still redacted; a key inside it still blocks the reply 37.5ms
2 · a part whose whole text the person typed is theirs · 4 tests
✓
a standing instruction the person typed word for word: the card ships whole, saves on its chip, and the saved reply names it as typed 24.2ms
✓
CONTROL: a model that rewords what the person typed gets no exemption — withheld, nothing saved 25.1ms
✓
CONTROL: the same words in the product brief (a model wrote it from their site) are not typed — withheld 14.0ms
✓
CONTROL: the same words only in a model's or a tool's text are not typed — withheld 27.7ms
3 · a draft subject the person edited in Drafts is theirs · 3 tests
✓
edited in the Drafts panel: the row is stamped on the admin secret, and the send card ships whole with the subject and sends on its chip 32.2ms
✓
CONTROL: a save that changes nothing (the panel re-saves before every send) stamps nothing — the model's subject stays guarded 15.1ms
✓
CONTROL: a subject rewritten after the person's edit is no longer theirs — the stale stamp exempts nothing 26.8ms
the wiring · 1 test
✓
finalizeChatResponse reads the message and its lead with the tenant spans, and never the reasoning; cards stay finishChatReply's 3.9ms
src/chat/verify-contacts-format.vitest.ts
verify_contacts selection step · 2 tests
✓
asks which list instead of picking one 6.8ms
✓
offers each list as a one-click chip 1.8ms
verify_contacts results · 4 tests
✓
reports verified and deliverable counts 0.3ms
✓
says unchecked addresses were NOT marked bad when the provider gave no verdict 0.4ms
✓
surfaces the free-tier cap note and a top-up chip 0.4ms
✓
relays an error without pretending anything was verified 0.3ms
a run that stopped at its deadline · 5 tests
✓
reports what WAS checked instead of reporting a failure 0.4ms
✓
names the remainder and says continuing is not paid for twice 0.4ms
✓
CLAIMS NO CAUSE IT CANNOT KNOW 0.6ms
✓
says nothing about a remainder when there is none 0.3ms
✓
accounts for skipped addresses as money not spent 0.3ms
verify_contacts answers from the verdicts on file · 6 tests
✓
nothing_to_check: the counts on file, the marker, and that nothing was charged — never "Verified 0 of 0" 0.4ms
✓
the 25th-member run leads with the list, 9 of 25 deliverable — not "0 look deliverable" 0.4ms
✓
an address with no verdict: its status is unchanged and nothing was charged for it 0.2ms
✓
every address with no email: said as such, still no charge, no marker (nothing to re-check) 0.3ms
✓
(neg) without on_file the run's own counts render as before — and "None" when nothing got a verdict 0.2ms
✓
no currency, no vendor, no "didn't complete" in any of them 1.0ms
src/email/draft-authorship.vitest.ts
an edit, not a save · 6 tests
✓
a changed subject is stamped with the fingerprint of what the person saved 5.1ms
✓
a save that changes nothing stamps nothing — the model's words do not become the person's 0.7ms
✓
the editor re-serialising the body is not an edit; a changed visible text is 0.6ms
✓
a field already the person's stays theirs across a save that leaves it alone, re-stamped to the bytes saved 0.7ms
✓
a stale stamp (the text was rewritten since) is dropped, not carried 0.5ms
✓
draftBodyText: tags and whitespace do not make two bodies different 0.3ms
a fingerprint, not a flag · 1 test
✓
isPersons holds only while the text is exactly what was stamped 0.8ms
nothing a model reaches can set it · 4 tests
✓
the only document that WRITES a stamp column is stampDraftEdit's, and it runs on the admin secret 57.4ms
✓
the stamp is written only to the caller's own editable row, and only while it still holds the text just saved 0.8ms
✓
stampDraftEdit has ONE caller, the Drafts panel's PATCH handler — no tool, no model path 52.8ms
✓
the snapshot gives the user role no write on either stamp column 1.3ms
check-graphql-schema fails when a stamp column becomes writable by the user role (header item 5) · 6 tests
✓
clean snapshot: passes 825.5ms
✓
emails_sent_set_input.person_subject_sha granted to the user role: exits 1, names it and says why 42.1ms
✓
emails_sent_set_input.person_body_sha granted to the user role: exits 1, names it and says why 42.9ms
✓
emails_sent_insert_input.person_subject_sha granted to the user role: exits 1, names it and says why 40.9ms
✓
emails_sent_insert_input.person_body_sha granted to the user role: exits 1, names it and says why 40.9ms
✓
a user-token document writing the stamp fails the user-role check (handleUpdateDraft's own save, widened) 829.4ms
src/email/send-duplicate-class.vitest.ts
V6-send-F01: an email service 5xx after accepting is held, never retried into a second delivery · 8 tests
✓
chat send_emails: the 504 row is Delivery unconfirmed, not billed, not offered; "send" again mails nobody twice 56.5ms
✓
REST POST /api/emails/send: reported unconfirmed, and the same batch posted again sends nothing 13.9ms
✓
the Drafts panel single send: a 202 the panel shows as held; Send again finds no draft 3.4ms
✓
every HTTP provider branch reads a 5xx the same way, and a 4xx stays a refusal 6.9ms
✓
the connected-Gmail branch too 2.8ms
✓
the classification itself: 2xx accepted, 5xx / 408 / 409 unconfirmed, any other 4xx refused 1.2ms
✓
a 2xx whose body cannot be read is still an acceptance (it went out) 1.6ms
✓
the drip: a 504 step is held, not narrated as a failure, and the next tick advances without resending it 4.4ms
V6-send-F03: an unreadable drip attempts history holds the step; it is never read as "never attempted" · 3 tests
✓
tick 1 sends but its advance fails; tick 2 cannot read the attempts: nothing is sent; tick 3 advances 5.5ms
✓
an answer without its rows is unreadable too 0.8ms
✓
CONTROL: a readable, empty history sends the step once 2.6ms
V6-send-F02: Resend anyway only on a hold that has settled — never on a send still in flight · 4 tests
✓
a release fired from inside the provider call is refused; the acceptance is kept; nothing goes twice 14.3ms
✓
settled: an unanswered note releases at once; an unnoted claim only once it is older than the window 4.3ms
✓
the claim stamps its own time (no trigger is assumed) 2.5ms
✓
the Sent list says releasable on its own clock and carries neither the note nor the stamp 2.5ms
V6-loop-F01: the Resend anyway card honours the Drafts edit stamp, and names the part it cannot show · 2 tests
✓
a subject the person wrote shows whole, as it does on the send card 9.9ms
✓
a stamp for a different subject does not count; the withheld sentence names the subject and the way out 6.1ms
src/leads/icp-ledger.vitest.ts
what counts as a criterion · 2 tests
✓
counts only the axes the user actually named 3.0ms
✓
keeps an axis the user named even when we can do nothing with it 0.6ms
absent coverage is not a thin filter · 5 tests
✓
offers the paid source for an axis a provider CAN answer 0.5ms
✓
does not offer to buy something nobody sells 0.2ms
✓
keeps the verdict and changes only the offer once the user has said yes to paid 0.4ms
✓
treats PARTIAL coverage as a filter that ran — because it did 0.2ms
✓
treats UNKNOWN coverage as a filter that ran, not as an absent one 0.2ms
translation is not relaxation (owner correction) · 4 tests
✓
calls a vocabulary translation EXACT and still says what was searched 0.3ms
✓
says nothing when the user’s word IS the stored value 0.7ms
✓
declares a term the vocabulary has never heard of, and does not offer to buy it 0.4ms
✓
does NOT declare the whole axis unmatched when only one of two terms missed 0.2ms
the headline is the fraction · 5 tests
✓
names the count, the fraction, and what was missed 0.5ms
✓
says nothing at all when everything the user asked for was honoured 0.3ms
✓
refuses differently when NOTHING could be matched 0.2ms
✓
drops the count when the caller has none to give 0.2ms
✓
uses the singular for one contact 0.2ms
the per-axis view · 1 test
✓
renders as bullets and marks each axis 0.3ms
src/leads/icp-suggestions.vitest.ts
chips are built from the ICP, one title group each · 6 tests
✓
yields at most three chips, each carrying the brief's evidence and executable arguments 4.2ms
✓
the label names every filter that will run and no number 0.5ms
✓
a dropped axis leaves BOTH the arguments and the label 0.3ms
✓
a thin brief or a brief with no buyer yields nothing — the fallback producer runs instead 0.3ms
✓
title groups: one each up to the cap, then two per chip in the extractor's order 0.3ms
✓
title case keeps acronyms and small words readable 0.3ms
a click is matched to the stored label, however the client sends it back · 4 tests
✓
normalises quotes, case, trailing punctuation and spacing 0.5ms
✓
round-trips through the session store and matches the clicked label 0.8ms
✓
pending arguments survive the picker turn and are cleared once read 0.7ms
✓
no session store → no match, no throw 0.9ms
coverage decides what a chip may ask for · 1 test
✓
drops an axis the corpus cannot serve, or serves for too little of it — never the title 33.2ms
the scan entry point · 3 tests
✓
uses the extractor when it reads a buyer, stores the chips, and returns the labels 34.3ms
✓
falls back to the persona-query producer when the brief has no buyer in it 26.7ms
✓
never throws — an extractor outage is the fallback, not a failed scan 26.3ms
the chat router honours a clicked chip before any intent handler · 3 tests
✓
matches the chip right after the intent match, gates the disambiguation on it, and routes it into the lead path 0.7ms
✓
the selection path runs the chip's stored arguments instead of re-structuring the sentence 1.0ms
✓
every scan site produces its chips through the extractor, with the old producer as fallback 1.7ms
src/leads/inventory.vitest.ts
shouldSkipInventory · 2 tests
✓
skips when the user explicitly asks for new/fresh/more contacts 1.5ms
✓
does not skip plain discovery queries 0.2ms
buildInventorySignals · 1 test
✓
lowercases + dedupes titles, drops query stopwords from keywords 0.3ms
buildInventoryWhere · 4 tests
✓
always scopes to the user and excludes verifier-rejected emails 0.2ms
✓
uses title synonyms and named domains as primary signals 0.2ms
✓
falls back to keyword terms only when no title/domain signal exists 0.2ms
✓
returns null on zero signal — never an unfiltered dump of recent contacts 0.2ms
rankOwnedContacts · 3 tests
✓
ranks title+verified matches above topic-only matches, tags _tier owned 0.5ms
✓
respects the limit 0.5ms
✓
topic hits are capped so they cannot outrank a title match 0.2ms
rankOwnedContacts subject-relevance gate · 2 tests
✓
title-only hit is excluded when the query has subject keywords it does not overlap 0.3ms
✓
title-only hit still qualifies when the query has NO subject keywords 0.3ms
rankOwnedContacts industry gate · 5 tests
✓
REGRESSION: an industry-filtered search does not return contacts from another industry 0.3ms
✓
matches by STEM, so "Dentists" evidences itself against "Dentistry" 0.1ms
✓
drops short words so "Oil and Gas" cannot let "and" vouch for the whole table 0.1ms
✓
an explicitly named domain still wins over the taxonomy 0.2ms
✓
no industry filter → behaviour is exactly as before 0.1ms
src/leads/provenance.vitest.ts
a timestamp is evidence, so it rides only with a verdict · 2 tests
✓
writes verified_at for an API verdict 2.2ms
✓
writes NO verified_at for a provider claim — the whole defect 0.5ms
isApiVerified answers the question that decides money · 4 tests
✓
is true only for a valid verdict we produced 0.3ms
✓
is FALSE for a provider claim, however confident it looks 0.2ms
✓
is FALSE for legacy rows, because they are indistinguishable from claims 0.2ms
✓
is FALSE for a verdict that came back bad 0.2ms
the user-facing phrasing never overstates what we know · 4 tests
✓
never calls a provider claim "verified" 0.6ms
✓
says "verified" only for a confirmed address 0.2ms
✓
is honest about legacy rows rather than silently promoting them 0.5ms
the vocabulary is closed · 1 test
✓
has exactly the six values the columns may hold 0.4ms
summariseVerification · 6 tests
✓
counts a provider claim as unproven, never as checked 0.4ms
✓
forbids the deliverability claim outright when nothing was checked 0.3ms
✓
bounds the claim to the checked subset on a mixed set 0.2ms
✓
lets a fully checked set say so 0.2ms
✓
separates a bad verdict from an absent one 0.2ms
✓
handles an empty set without inventing a rate 0.6ms
src/leads/reply-signals.vitest.ts
detectCompetitorMentions — the signal · 4 tests
✓
finds a competitor named as a domain 2.5ms
✓
finds a competitor named as a proper noun 1.0ms
✓
derives the brand token from the domain when no name is stored 0.4ms
✓
reports each competitor once, however many times it appears 1.1ms
detectCompetitorMentions — the false positives it must not produce · 5 tests
✓
does NOT fire on a lowercase common-word use of a brand name 0.3ms
✓
does NOT fire on a short or generic stored name 0.5ms
✓
does NOT match a brand token inside a longer word 0.3ms
✓
returns nothing for an empty or unreadable body rather than guessing 0.3ms
✓
returns nothing when the tenant tracks no competitors 0.6ms
replyBodyText — reading only what the human typed · 8 tests
✓
drops headers, so our own infrastructure cannot register as a mention 1.2ms
✓
cuts quoted history, so OUR message coming back cannot trigger a mention 1.0ms
✓
cuts an Outlook-style original-message divider 0.2ms
✓
drops residual quote lines 0.2ms
✓
decodes quoted-printable, which would otherwise silently match nothing 0.3ms
✓
decodes base64 single-part bodies 0.2ms
✓
strips HTML tags rather than matching inside markup 0.5ms
✓
returns empty string for undecodable input — callers must read that as "could not read" 0.3ms
src/middleware/next_actions.vitest.ts
next_actions · 10 tests
✓
substitutes result params 1.6ms
✓
skips rules with missing result fields 0.2ms
✓
keeps static params 0.2ms
✓
suggests draft follow-ups 0.3ms
✓
never suggests reviewing contacts after drafting (they were already resolved) 0.2ms
✓
suggests post-send follow-ups 0.1ms
✓
suggests google-merge follow-ups 0.2ms
✓
lists next-action rules 0.3ms
✓
has no deprecated names in rules 0.5ms
✓
shows the WordPress-connect nudge only in the exact unconnected-WP state 0.3ms
optional next-action parameters · 1 test
✓
drops an absent optional key and keeps the chip; a missing required key still drops the chip 1.9ms
verify_contacts chips · 6 tests
✓
labelFrom is used: the result names the count and the price 0.8ms
✓
the spread carries the tool's own arguments: the same list, verified: any 0.2ms
✓
(neg) no offer → no chip; a result without a label keeps the static one 0.4ms
✓
price honesty: the label price is verifyContactsEstimate(n), formatted as the card formats it 0.4ms
✓
(neg) nothing skipped → no offer at all 0.1ms
✓
price honesty on a capped plan: the label names the capped count and its price, and says why 0.4ms
src/reports/godmode-phase2.vitest.ts
google_god_mode_report — no internal vocabulary reaches the user (GS-005) · 3 tests
✓
status pills name the operation, not the internal key or the vendor 29.8ms
✓
the lead no longer recites the vendor stack 0.7ms
✓
an error banner names the section in English, not by key 0.6ms
google_god_mode_report — "unavailable" is not "error" (GS-004) · 3 tests
✓
a section with no data renders neutral, not as a fault 0.5ms
✓
OUR unbuilt capability says so, and explicitly implies nothing about their site 0.6ms
✓
unavailable sections are still SAID — dropping them is the other half of the defect 0.5ms
google_god_mode_report — one population per number · 2 tests
✓
the session tiles state their scope 0.6ms
✓
the all-channel tile is omitted when we do not have the number, never zeroed 0.4ms
google_god_mode_report — leads with a judgement (GS-001) · 3 tests
✓
names the top problem, not the user's own counts 0.9ms
✓
a clean read says so rather than padding a finding (GS-009) 4.9ms
✓
the counts survive as context, with their scope attached 0.5ms
sov_trend — a share is a claim about a field, not about one comparison · 3 tests
✓
100% against ONE competitor is PROVISIONAL 5.8ms
✓
drops the caveat once the comparator set can support the claim 0.7ms
✓
names zero competitors honestly rather than saying "0 tracked competitors" 0.6ms
sov_trend — the problem count counts THEIR site, not our settings · 3 tests
✓
weekly tracking being off is not a signal needing attention 0.6ms
✓
the tracking prompt is still shown — demoted, not deleted 0.6ms
✓
a REAL problem still raises the count 0.6ms
src/reports/report-fix-prompts.vitest.ts
entity_audit report — density + fix prompts · 4 tests
✓
renders every fetched KG field, not just the verdict 2.0ms
✓
surfaces errored queries instead of dropping them 0.3ms
✓
has a per-finding copy button for every non-recognized entity and none for recognized 0.4ms
✓
§17: signal-overview bento (per verdict), plain headers, feedback mount 0.6ms
stack-aware prompts (fingerprint attached by dispatch) · 3 tests
✓
entity_audit prompts carry Next.js placement when fingerprinted 0.6ms
✓
aeo_page_check header names the stack and placement (WordPress+Yoast) 0.5ms
✓
no fingerprint → generic phrasing, no stack claims 0.6ms
seo_write_content — publish routing by connector + stack · 6 tests
✓
connector live → still no baked buttons; connector state must not reach stored HTML 13.6ms
✓
WordPress site, no connector → slot + stack passed through for hydration 0.8ms
✓
non-WordPress stack → stack-aware coding-agent fallback, no publish markup 0.5ms
✓
legacy result without wp_connected flag → NO optimistic one-click publish 0.4ms
✓
is a publish-first deliverable: no findings bento, no KPI tiles / Q&A grid, article + publish + feedback 0.6ms
✓
renders GFM: bold, links, ordered lists, fenced code, and tables (no raw markdown) 1.0ms
aeo_page_check report — per-finding + top-level fix prompts · 4 tests
✓
shows the all-fixes button at the top and per-cluster buttons 0.3ms
✓
gives every failed finding its own copy button, pass rows none 0.2ms
✓
prompts are self-contained (carry the page URL and the finding) 0.3ms
✓
§17: signal-overview bento (3 dimensions), plain headers, feedback mount 0.6ms
src/runtime/blocked-outcome.vitest.ts
isBlockedOutcome — deliberate stops · 14 tests
✓
cost gate (the screenshot) is blocked, not failed 1.7ms
✓
clarify question is blocked, not failed 0.2ms
✓
picker is blocked, not failed 0.2ms
✓
balance gate is blocked, not failed 0.2ms
✓
plan/test cap is blocked, not failed 0.2ms
✓
zero-yield breaker is blocked, not failed 0.2ms
✓
plan-cap uplift is blocked, not failed 0.2ms
✓
plan cap with NO upsell to offer is blocked, not failed 0.1ms
✓
connector gate is blocked, not failed 0.5ms
✓
a genuine provider failure is NOT blocked 2.9ms
✓
a thrown-shaped error is NOT blocked 2.0ms
✓
a plain result is NOT blocked 0.1ms
✓
null is NOT blocked 0.1ms
✓
recognises a marker-less expected refusal by its prose 0.1ms
a gate turn offers ONE action · 3 tests
✓
renders no failure chips under an approval card 2.0ms
✓
lets a clarify question keep its own suggestion chips — they ARE the answer path 0.2ms
✓
leaves genuine failures their recovery chips 0.2ms
src/seo/comparison-prompts.vitest.ts
the source taxonomy keeps "unclassified" visible · 4 tests
✓
never calls an unrecognised domain a vendor 4.1ms
✓
a rival is only ever one the tenant NAMED 0.3ms
✓
classifies the categories it does recognise, including subdomains 0.5ms
✓
counts CITATIONS, not distinct domains 0.3ms
comparison intent · 2 tests
✓
catches how buyers really write it, both directions 0.3ms
✓
does not swallow ordinary questions 0.2ms
the real shape: everything ruled out is the ANSWER · 5 tests
✓
reads only the comparison prompts, not the whole panel 0.3ms
✓
the comparison rate is reported AGAINST the panel-wide rate 0.4ms
✓
the listicle premise is RULED OUT, with the number 0.5ms
✓
does not start a listicle programme, and says why 0.8ms
✓
the honest coverage statement travels WITH the recommendation 0.2ms
when the findings do hold · 3 tests
✓
absence from comparisons survives and leads the decision 0.6ms
✓
a review-platform category flips the listicle premise 2.2ms
✓
rivals out-citing us survives only when the tenant NAMED them 0.7ms
what it refuses to say · 3 tests
✓
a panel with NO comparison prompt says so, and names the fix 0.4ms
✓
the constraint-table and treadmill hypotheses stay untested 0.4ms
✓
a high unclassified share is disclosed in the ask 0.4ms
src/seo/competitor-set.vitest.ts
the reference-host screen covers the class that leaked, not just the instances · 7 tests
✓
screens out sk.sagepub.com 2.3ms
✓
screens out emerald.com 0.4ms
✓
screens out ideas.repec.org 0.2ms
✓
screens out www.tandfonline.com 0.3ms
✓
screens out onlinelibrary.wiley.com 0.3ms
✓
does NOT screen out the real rivals 0.6ms
✓
cannot catch forensicsciencesimplified.org, and is not expected to 0.3ms
filterDerivablePool — one definition of "surviving candidate" · 2 tests
✓
drops us, our subdomains, and screened hosts; ranks by citation count 0.9ms
✓
normalizes before comparing, so one rival cited two ways is one candidate 0.6ms
a stored AUTO set is not permanent · 4 tests
✓
is replaced when the run cites a field it shares nothing with 2.6ms
✓
is KEPT when even one stored rival is still cited — a partly-right set is not churned 0.7ms
✓
is KEPT when the run surfaced too thin a pool to overturn it 0.4ms
✓
is KEPT when there is no pool at all (a run where nobody was cited) 0.4ms
a USER-confirmed set is never second-guessed · 3 tests
✓
survives zero overlap with a broad pool 0.5ms
✓
protects an auto entry sitting alongside a user one 0.6ms
✓
an explicit argument still wins over everything and becomes the durable set 0.6ms
the screen and the re-derive agree · 1 test
✓
never installs a domain that would have counted as overlap 1.3ms
src/seo/cross-audit.vitest.ts
cross-audit — the join between on-page and off-page · 9 tests
✓
finds an inbound link landing on a dead page — a fault neither half can see alone 3.0ms
✓
finds authority landing on a page Search Console reports as not indexed 0.6ms
✓
ranks on-page issues by what the page actually earns — the stake the on-page audit lacks 0.5ms
✓
promotes a ranking page to corrective only when the fault is blocking 0.3ms
✓
every finding is legal on the provenance axis (FR-031) 0.7ms
✓
emits NOTHING when either half failed — a one-sided join is a fabrication 0.7ms
✓
matches URLs across providers that disagree about protocol, www and trailing slash 0.4ms
✓
flags an anchor/ranking divergence as advisory, never as something to go fix 0.3ms
✓
does not flag a divergence when the anchors and the rankings share terms 0.6ms
cross-audit — locating the constraint · 4 tests
✓
names authority when the pages are clean and the site has none 0.3ms
✓
names the pages when there is authority going unconverted 0.3ms
✓
orders the work when both are weak — pages before links 0.2ms
✓
refuses to name a constraint it cannot measure 0.3ms
cross-audit — gaps are consequences, never plumbing (GS-004/GS-005) · 4 tests
✓
reports a failed half as what the report cannot answer 0.4ms
✓
never names a sub-audit, a cache, a step or a vendor 0.4ms
✓
says an unconnected Search Console is why unindexed pages cannot be found 0.1ms
✓
reports missing link destinations rather than silently finding nothing 0.1ms
src/seo/eeat-proof.vitest.ts
Q24: the takedown clause · 5 tests
✓
says TAKEDOWN, not refresh, when pages are unattributed 2.2ms
✓
states the clause CONDITIONALLY — it never asserts the tenant is YMYL 0.5ms
✓
never decides whether the tenant is YMYL 0.4ms
✓
asks the one question that changes the work 0.3ms
✓
does not raise takedown when nothing is unattributed 0.3ms
Q24: the two-source rule is structural · 4 tests
✓
will not confirm the authorship gap on the content check alone 0.4ms
✓
confirms it once both readings are present 0.4ms
✓
leaves the off-site gap untested when the brand was never read 0.4ms
✓
surfaces a weak brand as a gap no page edit can close 0.6ms
Q24: never looked is not the same as nothing wrong (GS-004) · 4 tests
✓
says so plainly when no content check exists 0.8ms
✓
reports a clean result differently from an unmeasured one 0.3ms
✓
keeps the editorial-process hypothesis permanently untested 0.3ms
✓
never kills the about-page mismatch, because nothing compares those pages 0.3ms
Q24: gaps name work, not categories (GS-005) · 2 tests
✓
uses no internal field names in user-facing text 0.5ms
✓
every gap carries an owner and a named fix 0.3ms
Q24: a cause the evidence contradicts is RULED OUT, not "not tested" · 2 tests
✓
kills the authorship hypothesis when both readings exist and the pages are clean 0.2ms
✓
thin reasons name WHICH reading is missing rather than asserting a clean result 0.5ms
src/seo/onboarding-candidates.vitest.ts
onboarding competitor candidates · 7 tests
✓
captures the category owners ranking for the tenant's own niche term 3.2ms
✓
never offers the tenant their own site as a competitor 0.4ms
✓
screens out the directories a category SERP is full of 0.4ms
✓
does not re-offer a domain already on the confirmed list 0.4ms
✓
caps the list — this is a confirmation prompt, not an inventory 1.2ms
✓
keeps TRUE SERP position, so "who owns this category" is not reordered 0.3ms
✓
yields nothing from an empty SERP rather than inventing a candidate 0.2ms
the candidate key is readable · 2 tests
✓
__competitor_candidates__ is registered in SETTING_KEYS 0.5ms
✓
candidates are a SEPARATE key from the confirmed set 0.8ms
the reference class the screen missed · 3 tests
✓
screens a college library guide hosted on a .com 0.3ms
✓
still admits the three that were actually right 0.4ms
✓
drops it from a candidate list without disturbing the rest 0.3ms
the confirmation gate is wired end to end · 5 tests
✓
reads a real file, not an empty string that passes everything 0.2ms
✓
GET /api/product/brief returns the candidates 1.5ms
✓
PUT /api/product/brief writes back what is still pending 0.4ms
✓
the panel renders them with an accept and a dismiss 1.1ms
✓
accepting one promotes it as user-sourced, so auto-derive cannot screen it away 0.3ms
src/seo/trend-series.vitest.ts
buildTrendSeries · 6 tests
✓
one measurement is a point, not a direction (the competitor defect) 1.9ms
✓
drops unusable rows rather than defaulting them to zero 0.8ms
✓
sorts oldest-first however the caller supplied them 0.4ms
✓
identifies gaps that are long RELATIVE to this series cadence 0.4ms
✓
an outlier cannot raise the threshold it is judged against 0.3ms
✓
two runs a day apart are not a "long gap" whatever the multiple says 0.2ms
renderTrendSvg · 7 tests
✓
positions X by real elapsed time, not by run index 1.1ms
✓
draws the unknown stretch dashed, and says so in the tooltip 0.5ms
✓
Y starts at zero so a small change cannot be cropped into a collapse 0.5ms
✓
does not distort its own marks 0.2ms
✓
is self-contained — an exported artifact has no access to the panel stylesheet 0.3ms
✓
the axis states how many days carry data (AEO-013) 0.2ms
✓
a steady series gets no dashed-gap sentence it did not earn 0.2ms
sov_trend artifact (R-E acceptance) · 4 tests
✓
is no longer an evenly-spaced bar chart of user-initiated runs 0.2ms
✓
states its coverage and marks the unknown stretch 0.1ms
✓
keeps the set-changed warning, as a ringed point rather than an asterisk 0.1ms
✓
a single-run history renders the honest empty state, not a line from zero 0.3ms
src/leads/shared/us-locality-extract.vitest.ts
the copied normalisers stay byte-identical to the ingest · 4 tests
✓
canonicalLinkedIn has the same body in both files 1.9ms
✓
text has the same body in both files 0.4ms
✓
produces the canonical form the corpus stores in contact_identifier.normalized_value 0.5ms
✓
rejects anything that is not an /in/ profile 0.3ms
columns are resolved by name, never by position · 2 tests
✓
matches case-insensitively and ignores surrounding space 0.2ms
✓
returns -1 for a column the file does not have 0.2ms
the misaligned-row anchor · 7 tests
✓
reads a well-formed row 0.8ms
✓
accepts a row damaged AFTER the anchor — the prefix is provably intact 0.2ms
✓
REJECTS a row shifted before the anchor, rather than writing a region into locality 1.0ms
✓
REJECTS a shift that lands a company URL on the anchor 0.3ms
✓
drops a row too short to reach either column 0.3ms
✓
drops a row with a profile but no locality 0.2ms
✓
lowercases and collapses whitespace, because locality is a FILTER KEY 0.2ms
the extractor is importable without running · 2 tests
✓
guards main() on being the entry point 0.3ms
✓
renames the output only on success, so a killed run cannot look complete 0.2ms
the ingest no longer claims the US export lacks Locality · 2 tests
✓
does not repeat the false ABSENT-in-the-US comment 0.2ms
✓
still reads the column 0.2ms
scripts/lib/version-conflict.vitest.mjs
the defect itself · 2 tests
✓
setVersion alone leaves a conflicted file conflicted, and says nothing 1.9ms
✓
assertResolved is what turns that into a failure, with the same message npm gave 1.1ms
resolving a version-only conflict · 5 tests
✓
produces valid JSON carrying the allocated number 1.3ms
✓
keeps the content that was never in dispute 0.2ms
✓
does the same for src/version.ts 0.5ms
✓
handles one block per commit, as a multi-commit rebase produces 0.2ms
✓
leaves a clean file exactly as it found it 0.3ms
what it refuses to resolve · 3 tests
✓
refuses when the branch also changed a dependency 1.0ms
✓
refuses a diff3 block rather than guessing at three sides 0.6ms
✓
refuses a marker with no terminator instead of eating the rest of the file 0.4ms
assertResolved · 4 tests
✓
catches a marker-free file that is still not JSON 0.2ms
✓
passes a clean file through unchanged 0.2ms
✓
does not try to JSON.parse a TypeScript file 0.3ms
hasConflictMarkers · 2 tests
✓
finds each marker kind at line start 0.2ms
✓
is not fooled by content that merely looks like a marker 0.2ms
src/admin/bug-reports.vitest.ts
list · 5 tests
✓
REJECTS an unknown status by name instead of returning an empty list 28.7ms
✓
reports the TRUE total from the aggregate, not the length of the page 1.7ms
✓
still renders the list when the badge counts fail, and admits the counts are unknown 1.0ms
✓
names BOTH causes when the table cannot be read 1.0ms
✓
403s without the admin secret 0.7ms
update · 7 tests
✓
stamps triaged_at and resolved_at when a report is closed 5.3ms
✓
CLEARS both timestamps when a report is reopened 0.9ms
✓
clears resolved_at when moving back to a non-terminal state 0.6ms
✓
rejects an unknown status rather than writing it and failing the CHECK constraint 1.2ms
✓
an empty note CLEARS the field rather than being ignored as falsy 1.4ms
✓
refuses an update that changes nothing 0.7ms
✓
404s on an id that does not exist 0.4ms
screenshot · 4 tests
✓
404s when the report has no screenshot 0.4ms
✓
410s — not 404 — when the object has aged out of its retention window 0.4ms
✓
serves the bytes privately, never with a public cache directive 0.4ms
✓
503s with a named cause when storage is not configured 0.3ms
src/admin/build-stamp-alert.vitest.ts
build_id must be a commit sha · 12 tests
✓
a real 40-char sha raises nothing 1.9ms
✓
THE INCIDENT: a semver raises a critical alert naming the value 0.5ms
✓
a NULL stamp fires — that is how the incident actually presented 0.3ms
✓
but a caller that never asked about builds gets NO alert 0.2ms
✓
rejects dfb12e320dd7bde52c490ac360a2f08380e491b 0.2ms
✓
rejects dfb12e320dd7bde52c490ac360a2f08380e491b8a 0.3ms
✓
rejects DFB12E320DD7BDE52C490AC360A2F08380E491B8 0.2ms
✓
rejects dfb12e320dd7bde52c490ac360a2f08380e491b8 0.2ms
✓
is CRITICAL, because it invalidates every other signal on the page 0.4ms
✓
reads the worker's OWN stamp rather than fetching /api/version 0.5ms
the deploy boundary refuses an unstamped ship · 4 tests
✓
npm run deploy runs the precondition FIRST 0.3ms
✓
the stamp flag is no longer OPTIONAL 0.3ms
✓
the precondition exits non-zero and demands a lowercase 40-hex sha 0.2ms
✓
it points at the resolver instead of just refusing 0.2ms
src/admin/telemetry-revenue-unbilled.vitest.ts
the unbilled-row predicate is the balance's own · 1 test
✓
every platform-overhead provider and every :redelivery operation is unbilled; a billed provider is not 2.2ms
telemetry revenue and margin count only what a user was debited (DECISIONS #90) · 8 tests
✓
[fail-first] LLM by model (legacy): revenue from the billed row only, cost from all three 1.0ms
✓
[fail-first] the whole console's revenue equals what the biller debits (legacy) 2.3ms
✓
[fail-first] LLM by model (cost): revenue from the billed row only, cost from all three 0.3ms
✓
[fail-first] the whole console's revenue equals what the biller debits (cost) 0.8ms
✓
[fail-first] API by provider (sample): a repeat call and the overhead buckets carry cost, never revenue 0.5ms
✓
[fail-first] API by provider (exact grouped totals): the same rule on the overlay, including a group the sample missed 0.9ms
✓
[fail-first] judge spend (platform overhead) is cost in the LLM table, never revenue — under either billing model 0.4ms
✓
a ledger with only billed rows reads exactly as before (no regression on the common case) 0.6ms
DECISIONS #93: a row under the platform user is cost, never revenue, whatever its provider · 7 tests
✓
isUnbilledApiRow: the platform user is unbilled on any provider; a tenant on a billed provider is not; no user id changes nothing 0.3ms
✓
[fail-first] LLM by model (legacy): an admin Jev call under the platform user is cost with zero revenue; the tenant's call on the same model is revenue 0.5ms
✓
[fail-first] LLM by model (cost): an admin Jev call under the platform user is cost with zero revenue; the tenant's call on the same model is revenue 0.2ms
✓
[fail-first] API by provider (sample): a platform-user probe on a paid SERP provider carries cost, never revenue; the tenant's row on that provider does 0.3ms
✓
[fail-first] API by provider (exact grouped totals): the group's platform-user share is subtracted from revenue; a group that is all platform has none 0.6ms
✓
[fail-first] the Operations table (sample rows): platform-user rows reach the cost of their cluster and none of its revenue 0.3ms
✓
a ledger with no platform-user rows reads exactly as before 0.2ms
src/auth/email-identity.vitest.ts
canonicalAuthEmail — the credential · 3 tests
✓
trims and lowercases 2.4ms
✓
PRESERVES gmail dots and +tags — they are part of the credential 0.4ms
✓
never throws on junk input 0.3ms
normalizeEmail — dedupe/referral only · 4 tests
✓
collapses gmail dots, +tags, and googlemail 0.4ms
✓
strips +tags but KEEPS dots on non-gmail domains 0.2ms
✓
handles an address with no @ without mangling it 0.2ms
✓
uses the LAST @ so a local part containing @ cannot shift the domain 0.2ms
the two normalizers are NOT interchangeable · 2 tests
✓
diverge on exactly the inputs that cause lockouts 0.9ms
✓
agree on a plain address, which is why the swap is easy to miss 0.6ms
fraud checks · 2 tests
✓
flags disposable domains case- and whitespace-insensitively 0.3ms
✓
does not flag an address with no domain 0.2ms
presentableName · 5 tests
✓
prefers a real stored name 0.2ms
✓
REJECTS the Nhost default, which is the email itself 0.3ms
✓
prettifies the local part when there is no usable name 0.2ms
✓
drops a +tag rather than rendering it as part of the name 0.1ms
✓
returns empty rather than a stray character when there is nothing to work with 0.2ms
src/billing/cost-based-billing.vitest.ts
the ×10 margin invariant · 3 tests
✓
P / V is exactly 10 1.6ms
✓
any cost billed through the rule yields exactly ×10 revenue 0.5ms
✓
LLM and provider spend use the SAME conversion (no separate margin) 0.2ms
cost-based vs legacy billing, per model · 2 tests
✓
legacy over-charges cheap models and under-charges expensive ones 0.4ms
✓
cost-based lands every model on 10x 0.2ms
free-model cost floor · 4 tests
✓
imputes the owner-set floor for a $0/$0 model instead of charging nothing 0.2ms
✓
uses the exact owner-specified rates ($0.019 in / $0.30 out per 1M) 0.7ms
✓
a free-model turn still bills a non-zero token amount at 10x 0.3ms
✓
does NOT apply the floor to a merely-cheap model (only $0 on BOTH sides) 0.5ms
billingModel gate · 2 tests
✓
defaults to legacy (no live change without an explicit flip) 0.3ms
✓
accepts the documented on value 0.2ms
credit preservation under cost-based billing · 3 tests
✓
a granted balance with no spend is fully available 0.2ms
✓
spend is deducted from the grant at cost×10, not at raw token count 0.1ms
✓
credits never silently vanish when cost_usd is 0 on the grant rows 0.4ms
admin console tracks the live billing model · 2 tests
✓
legacy revenue is token-count driven 5.1ms
✓
cost mode reports revenue as cost × 10, restoring a true margin 0.3ms
src/billing/credit-invalidates-balance.vitest.ts
A — the admin grant · 3 tests
✓
invalidates the cached balance 2.3ms
✓
reads the post-grant balance, not a cached one 0.4ms
✓
invalidates BEFORE it reads — order is the whole property 0.3ms
B — the Stripe top-up · 3 tests
✓
goes through the shared helper, not a copy of the key 0.3ms
✓
no longer hand-rolls the cache key 0.4ms
✓
and usage.ts is still the only place that spells the key 1.5ms
C — the agent may not quote a balance it did not read · 6 tests
✓
injects the current balance as ground truth every turn 0.5ms
✓
forbids quoting a balance from earlier in the conversation 0.4ms
✓
forbids claiming a check that did not happen 0.7ms
✓
sends spend-history questions to the ledger, not to this figure 0.4ms
✓
says nothing at all when the read fails 0.5ms
✓
is fetched in the same round as the other per-turn ground truth 0.5ms
D — the AppSumo redemption grant · 4 tests
✓
invalidates the cached balance after crediting 0.2ms
✓
invalidates AFTER the credit row is written — order is the whole property 0.2ms
✓
uses the shared helper, never its own key 0.2ms
✓
does not mark an AppSumo buyer as paying — they paid AppSumo, not us 0.2ms
src/billing/g3e-reservation.vitest.ts
seo_geo_research: a free run reserves the one-engine run it is, asserted (R4-G3e-F02) · 6 tests
✓
is plan-shaped, so the gate hands it the caller's plan at all 2.0ms
✓
the free estimate asserts its ceiling, so the table row cannot floor it 0.8ms
✓
the GATE reserves the computed figure on the free tier, not 479,000 0.9ms
✓
the balance a free user needs is inside 3x of the measured p90 20.1ms
✓
a plan that runs every engine, or an unreadable plan, reserves the table row exactly as before 0.5ms
✓
the card quotes the same computed figure the gate holds, in tokens 0.6ms
seo_serp_spider: a call that omits max_pages is a 15-page call (R4-G3e sweep) · 5 tests
✓
the dispatch and the estimator read one default 1.9ms
✓
free: 15 pages + 15 verify credits (ruling #106), not 30 pages + 50 verify + 5 feature lookups 0.5ms
✓
paid: 15 pages + the 150-credit verify cap, not the catalogue's 2,275,000 0.5ms
✓
named feature keywords on a page-less call are still priced 0.4ms
✓
the catalogue question (no args at all) keeps the flat shape: plan pages + verify + 5 lookups 0.3ms
seo_serp_spider: owner ruling #106 — a free run verifies at most as many sitemap URLs as it crawled pages · 5 tests
✓
the RUN: a free 10-page crawl with 50 extra sitemap URLs exact-verifies 10 of them 28.3ms
✓
paid tiers keep the plan cap 0.2ms
✓
the run uses that cap, and the report and chat carry the line 5.2ms
✓
the GATE: 10 free pages reserve the capped ceiling, asserted — not 750,000 0.3ms
✓
the estimator and the run price one rule, at every free page count 0.3ms
src/billing/spend-blocked.vitest.ts
the gate records that spend is blocked · 2 tests
✓
sets the flag on refusal, and only on refusal 3.8ms
✓
is reset per request, so one broke turn cannot mute the next 0.6ms
the loop stands down instead of retrying · 5 tests
✓
strips only the PRICED tools 8.0ms
✓
leaves the free tools, which are what a broke turn should fall back on 8.6ms
✓
does NOT exit the loop — that would ship the silent-turn fallback 7.9ms
✓
fires at most once per run 15.2ms
✓
tells the model to name the cheapest thing that WOULD fit 6.8ms
the APPROVAL gate stands down the same way — one behaviour, two entry points · 4 tests
✓
calls the SAME function rather than re-implementing the strip 6.5ms
✓
keeps the refusal text as the FALLBACK, not as the answer 8.4ms
✓
continues the turn when something free survived 6.8ms
✓
and the stand-down tells the model to do the free part first 6.6ms
the turn has a ceiling of its own, and it is the 100K the owner set · 5 tests
✓
is the same 100K, not a second opinion 0.3ms
✓
is checked BEFORE a round, not after 8.4ms
✓
stands the turn down rather than breaking out of it 6.6ms
✓
fires once, and never on the first round 6.4ms
✓
tells the model to answer and to name what it skipped 8.2ms
src/chat/answer-options.vitest.ts
the extraction is the app's rule, moved unchanged · 12 tests
✓
same options as the app picked: "There are a few ways to go from here:\n- " 2.3ms
✓
same options as the app picked: "Pick one:\n1. Find leads\n2) Show my campa" 0.3ms
✓
same options as the app picked: "• Draft emails\n• Verify contacts\nSome pr" 0.3ms
✓
same options as the app picked: "Only one:\n- Find leads\n\nand prose." 0.2ms
✓
same options as the app picked: "A list that resets:\n- one\ntext\n- two\n- t" 0.3ms
✓
same options as the app picked: "Indented:\n * Find leads\n * Show my c" 0.2ms
✓
same options as the app picked: "- This item is far too long to be a chip" 0.2ms
✓
same options as the app picked: "No list at all, just a sentence." 0.2ms
✓
same options as the app picked: "" 0.5ms
✓
keeps the line each option sits on, so a rewrite can be matched to it 0.4ms
✓
never an empty option, which the app could render as a blank button 0.9ms
✓
a list item longer than the limit is never an option 0.2ms
a line the guardrail rewrote is never an option · 4 tests
✓
the probe: the rewritten bullet is withheld, the untouched ones are offered 3.1ms
✓
a price and a "free" claim rewritten in place are withheld the same way 0.7ms
✓
what the guardrail did not touch is untouched: nothing withheld, nothing recorded 0.3ms
✓
a record from an EARLIER pass still counts — the original is not needed at the exit 0.3ms
src/chat/honesty.vitest.ts
the defects that passed `requireTool: true` · 4 tests
✓
catches a success claim with no number — the sentence that hid a 10-of-50 run 6.3ms
✓
passes the same claim once it carries the count 0.7ms
✓
passes the grounded-count sentence the enrich formatter writes now (2026-09-24, audit A10) 137.6ms
✓
catches a bare acknowledgement after a tool ran 0.3ms
copy invariants are checked on EVERY row, not opted into · 4 tests
✓
catches a vendor name 0.4ms
✓
catches nqzai priced in dollars 0.4ms
✓
does NOT flag the user's own business figures in currency 0.2ms
a blocked turn must offer a way through · 3 tests
✓
flags an accurate refusal that offers nothing 0.5ms
✓
passes once the turn carries an action 0.3ms
✓
says nothing about turns that are not blocked 0.2ms
per-row expectations · 2 tests
✓
requires the sentence a scenario is about 0.4ms
✓
forbids the sentence a scenario must not produce 0.3ms
countAgrees — the strongest assertion, where the artifact is available · 3 tests
✓
passes when the prose matches the artifact 0.2ms
✓
fails when the prose inflates the count 0.2ms
✓
fails when the reply states no count at all 0.1ms
src/chat/render-jev.vitest.ts
decideRenderAfterLookup — Jev decides, code guarantees · 8 tests
✓
0.2 / 0.7 renders, labelled as Jev's, on its own context and the send timeout 3.9ms
✓
work_left 0.86 ("track my keyword rankings" after seo_enrich_keywords) narrates 0.8ms
✓
reply_answers 0.3 narrates, even with no work left 0.3ms
✓
the thresholds are exact: work_left 0.4 and reply_answers 0.5 both render; one step past either narrates 0.8ms
✓
a throw or a timeout returns jev_unavailable and reports it 1.7ms
✓
an answer with no finite probability is a failure, never a silent render 0.5ms
✓
flag off never calls fetch: rollout word missing, key missing, or mode off 1.5ms
✓
shadow asks Jev and reports its reason, but never renders 0.4ms
renderAfterLookupMode — who is asked · 2 tests
✓
shadow needs a user list: empty means nobody, never everybody 0.6ms
✓
on applies to the list when set, to everyone when not; anything else is off 0.4ms
the state Jev reads · 4 tests
✓
has no array anywhere and no @-address anywhere 0.9ms
✓
clips the request to 400 and the reply to 800, and keeps the reply's line breaks 1.4ms
✓
redactEmails replaces addresses with <email> 0.1ms
✓
the questions reference only fields the state has 1.0ms
wrangler.toml ships the render decision ON for every tenant · 2 tests
✓
mode is on and the user list is empty 0.3ms
✓
so any tenant gets "on", and the Jev context is rolled out 0.5ms
src/commerce/forecasting.vitest.ts
poissonTailAtLeast · 3 tests
✓
matches known Poisson values 0.4ms
✓
monotone: more stock → lower stockout probability 0.4ms
computeVariantRisk · 8 tests
✓
gates insufficient history honestly, stating exactly what is missing 0.6ms
✓
computes demand rate, cover, and Poisson stockout probability 0.4ms
✓
deep stock → healthy or overstocked, never fabricated risk 0.3ms
✓
untracked inventory is labelled, not guessed 0.3ms
✓
horizon constant sanity 0.2ms
✓
reorder suggestion targets 30 days of cover at the observed rate 0.5ms
✓
reorder is zero when cover already exceeds the target, and zero for untracked stock 0.3ms
✓
without a selection, the row is labelled as the rate baseline 0.3ms
selectDemandModel (champion/challenger ladder) · 5 tests
✓
short history → baseline, challengers never compete 0.4ms
✓
strong weekly pattern → seasonal challenger promoted via backtest 0.6ms
✓
structureless demand → champion retained with an honest reason 0.2ms
✓
crostonRate: intermittent demand estimated, single-demand series refused 0.2ms
✓
selection drives the risk math when supplied 0.8ms
src/email/lifecycle-consent-userid.vitest.ts
every marketing lifecycle send identifies its recipient · 11 tests
✓
inactive_3_day_reminder passes a userId 2.0ms
✓
unfinished_setup_nudge passes a userId 0.4ms
✓
weekly_product_progress_digest passes a userId 0.2ms
✓
seo_rank_digest passes a userId 0.2ms
✓
sov_weekly_digest passes a userId 0.3ms
✓
inactive_3_day_reminder is still marketing-class, so the userId is load-bearing 0.3ms
✓
unfinished_setup_nudge is still marketing-class, so the userId is load-bearing 0.2ms
✓
weekly_product_progress_digest is still marketing-class, so the userId is load-bearing 0.1ms
✓
seo_rank_digest is still marketing-class, so the userId is load-bearing 0.5ms
✓
sov_weekly_digest is still marketing-class, so the userId is load-bearing 0.2ms
✓
the ids come from the same value the dedupeKey already used 0.5ms
the kinds that legitimately have no user id are operational · 2 tests
✓
signup_validation_reminder is operational — it fires BEFORE an account exists 0.3ms
✓
the admin adoption sample refuses to send without one, rather than silently blocking 0.3ms
the guard that would have caught it · 3 tests
✓
check-email-consent asserts the CALLER, not only the gate 0.2ms
✓
it refuses to pass on an empty parse, in both directions 0.2ms
✓
it brace-matches the argument literal instead of slicing a window 0.1ms
src/email/send-readiness.vitest.ts
counting — mirrors the send loop, or the preview lies in the other direction · 3 tests
✓
counts an invalid verdict and an unsubscribe as blocked, exactly as the send loop skips them 2.1ms
✓
a blocked recipient is NOT also counted unverified — one recipient, one fact 0.4ms
✓
treats a PROVIDER's claim of 'valid' as unverified, because it is 0.4ms
restraint — when it must say nothing · 4 tests
✓
silent on an all-verified batch 0.2ms
✓
silent on an empty batch rather than reporting a 0-of-0 problem 0.2ms
✓
silent on a SMALL unverified batch — mailing two people you know about is normal 0.2ms
✓
silent when unverified addresses are a minority, even in a large batch 0.3ms
the finding — what it says when it does speak · 6 tests
✓
states the number that will ACTUALLY send, not just the number skipped 0.4ms
✓
says plainly when nothing would go out at all 0.5ms
✓
folds the unverified risk INTO the blocked sentence when it dominates — one finding, one chip 0.4ms
✓
reproduces the live tenant shape: 186 recipients, 3 blocked, 183 unverified 0.4ms
✓
does NOT add the deliverability clause when the sendable remainder is mostly verified 0.5ms
✓
warns on a majority-unverified batch and offers verification as the fix 0.3ms
the rules every adoption inherits · 3 tests
✓
never offers a "send anyway" chip — the preview's own confirm IS that 0.2ms
✓
never names a vendor and never prices in dollars (CLAUDE.md §4) 0.4ms
✓
phrases the finding as an observation before a decision, never a refusal 0.2ms
src/leads/corpus-criteria.vitest.ts
the denominator is what the user named · 3 tests
✓
counts every axis they filled and nothing else 3.3ms
✓
has no criteria at all for a local business search 0.5ms
✓
does not treat a state as one of the criteria 0.4ms
the finding · 7 tests
✓
names the fraction and both missing axes on the real 2026-08-22 request 3.1ms
✓
is in the FUTURE tense, because nothing has run yet 1.2ms
✓
offers the free repair first and the paid one second 0.9ms
✓
does not offer paid sources to someone who already said yes 2.8ms
✓
SAYS NOTHING when every criterion can be matched 0.7ms
✓
says nothing when the user named no criteria at all 0.6ms
✓
says nothing when coverage has never been measured 0.7ms
coverage that is thin but real is a different sentence, not the same one · 5 tests
✓
treats 13% industry coverage as a filter that RUNS 0.6ms
✓
still says the pool is thin, because 13% presented as the whole corpus is the same lie 0.9ms
✓
offers no narrowing chip for a thin pool — every filter named will run 0.8ms
✓
will not quote a percentage from a measurement that has expired 0.5ms
✓
keeps the combined note inside the card’s 400-character ceiling 0.6ms
R4 — the one case we refuse · 1 test
✓
changes the sentence entirely when nothing at all can be matched 0.6ms
src/leads/scan-identity-claim.vitest.ts
the scan decides whose site it is before it writes · 6 tests
✓
reads the ESTABLISHED site rather than trusting the host it was handed 2.7ms
✓
treats a subdomain of the established site as the same site, in BOTH directions 0.5ms
✓
gates EVERY identity write, not just the visible one 0.5ms
✓
the FAILURE path is gated too 0.5ms
✓
still returns the research answer it was asked for 0.6ms
✓
discloses in DATA, never in a directive the model would recite 0.4ms
only a real ownership assertion may replace an established site · 5 tests
✓
the "that site is my company" chip claims — it IS the consent 1.7ms
✓
a first-turn SITE OFFER claims 0.6ms
✓
the settings form and the admin rescan claim 0.8ms
✓
the AEO scan OFFER does NOT claim — its domain came from the question 0.6ms
✓
the model cannot make the claim: it is not a tool argument at all 1.9ms
numotocare scanning talkeriq.com — the reported defect · 5 tests
✓
does not repoint __site_url__, and writes no identity at all 45.6ms
✓
still answers the question it was asked 2.0ms
✓
WITH the ownership claim, it writes — the user said it is theirs 1.0ms
✓
a tenant with NO site established is unchanged — onboarding still works 0.7ms
✓
refreshing their OWN site still writes, subdomain included 0.7ms
src/runtime/attention.vitest.ts
the side-effect axis · 6 tests
✓
is separate from the cost axis — a free tool can still be consequential 53.8ms
✓
is separate from the cost axis in the other direction — a priced tool can be a pure read 0.5ms
✓
classifies arming a send the same as sending 0.3ms
✓
treats stopping sends as safe, unlike starting them 0.2ms
✓
treats an unknown tool as consequential, not as a read 0.2ms
✓
never writes unclassified down as if it were a decision 0.8ms
gateForAttention · 10 tests
✓
never blocks an interactive turn, whatever the effect 0.4ms
✓
lets an unattended run read freely — that is what makes diagnose safe on a schedule 0.3ms
✓
blocks a consequential tool when the run has no grant at all 0.5ms
✓
allows exactly what the grant names 0.2ms
✓
blocks a tool the cron does not currently call but might tomorrow 0.2ms
✓
names the tool and the authority so a block is reviewable 0.1ms
✓
refuses an external tool listed in the ordinary tool list, and says why 0.1ms
✓
allows an external tool only when named in externalTools 0.1ms
✓
ships with no grant that authorises an external action 0.6ms
✓
blocks an unclassified tool even under a grant that does not name it 0.1ms
src/runtime/refund-eligibility.vitest.ts
zero yield · 6 tests
✓
counts a lead search that found nothing 1.7ms
✓
does NOT count a lead search that found something 0.3ms
✓
does NOT count an errored call — that is already the error counter’s job 0.2ms
✓
does NOT count a clean audit that legitimately found zero 0.3ms
✓
treats a MISSING count as "no claim", not as zero 0.3ms
✓
keeps the eligible set small and deliberate 0.7ms
refund eligibility · 5 tests
✓
offers the claim when the only call found nothing 0.3ms
✓
still offers it when every call errored — the original behaviour, unchanged 0.2ms
✓
offers it when one call failed and the other yielded nothing 0.5ms
✓
does NOT offer it when something on the turn actually delivered 0.2ms
✓
does NOT offer it on a turn that ran no tools at all 0.2ms
endedByAsking · 5 tests
✓
does not offer a refund on the same card that asks for money 0.2ms
✓
suppresses a refund on an ERRORED turn that ends in a gate too 0.2ms
✓
still refunds a zero-yield turn that ends with an ANSWER 0.2ms
✓
treats a missing flag as "did not ask", so existing callers are unchanged 0.1ms
✓
does not resurrect a turn that was never eligible 0.1ms
src/tools/deliverability-wave7.vitest.ts
cloudflare_fix_email_dns · 9 tests
✓
is external and unpriced — no cost gate stands in front of it 1.8ms
✓
accepts the three fixes the code can actually apply 1.1ms
✓
rejects mx_missing, which the code cannot perform 1.2ms
✓
rejects dkim_missing, which the code cannot perform 0.5ms
✓
rejects spf_multiple, which the code cannot perform 0.3ms
✓
rejects anything_at_all, which the code cannot perform 0.3ms
✓
accepts the empty call — omitting fixes applies every safe issue found 0.3ms
✓
rejects the retired domain alias 0.3ms
✓
the enum matches the branches the implementation has 1.5ms
domain_email_readiness_audit · 3 tests
✓
accepts the empty call and its two flags 0.3ms
✓
rejects the retired aliases 0.3ms
✓
no longer reads the undeclared fallback flag 2.4ms
generate_dns_fix_prompt · 3 tests
✓
accepts the empty call and a focused issue 0.3ms
✓
takes any issue id, because it only produces text 0.1ms
✓
rejects the retired domain alias 0.2ms
the alias era is over · 1 test
✓
no alias seams remain in the drift ledger 1.0ms
src/tools/generate-emails-schema.vitest.ts
the arguments the dispatch has always read are now declarable · 5 tests
✓
declares contact_ids, which the dispatch reads and the registry omitted 2.1ms
✓
declares list_names, which the dispatch reads and the registry omitted 0.3ms
✓
declares campaign, which the dispatch reads and the registry omitted 0.2ms
✓
still declares the three it always had 0.4ms
✓
lets the model target specific contacts, several lists, or a campaign 1.8ms
targeting is constrained · 6 tests
✓
accepts a realistic single-list call with an angle 0.4ms
✓
rejects an invented contact id shape rather than dropping it silently at save time 0.6ms
✓
rejects a mode outside the two the dispatch implements 0.7ms
✓
rejects an off-schema field instead of silently ignoring it 0.8ms
✓
states that targeting fields are mutually exclusive 1.1ms
✓
rejects a sentence long enough to be obviously not a list name 0.5ms
the dead shortcuts are gone · 3 tests
✓
draft_for no longer claims its protocol message 50.1ms
✓
draft_mode no longer claims its protocol message 24.1ms
✓
draft_contact still fires — it is live and parses only a uuid 2.4ms
model-facing copy · 2 tests
✓
tells the model to carry the user's angle rather than defaulting to generic copy 0.2ms
✓
names no vendor and no USD price 0.6ms
src/tools/keywords-wave1.vitest.ts
seo_keyword_metrics · 5 tests
✓
accepts the one declared name 2.4ms
✓
rejects the retired query alias 0.4ms
✓
rejects the retired topic alias 0.2ms
✓
requires the keyword — a paid lookup must not run on nothing 0.2ms
✓
explains a rejection in words a user can read 0.6ms
seo_enrich_keywords · 3 tests
✓
accepts an omitted list 0.3ms
✓
rejects the retired singular alias 0.2ms
seo_list_keywords · 4 tests
✓
accepts the empty call it actually makes 0.5ms
✓
rejects the invented argument {"limit":10} instead of ignoring it 0.2ms
✓
rejects the invented argument {"filter":"saas"} instead of ignoring it 0.2ms
✓
rejects the invented argument {"site":"example.com"} instead of ignoring it 0.1ms
the deleted fallbacks are actually gone · 4 tests
✓
seo_keyword_metrics no longer coalesces query/topic 0.2ms
✓
seo_enrich_keywords no longer reads a singular keyword 0.1ms
✓
leaves the still-legacy tools their fallbacks 0.2ms
✓
the drift ledger no longer lists them as open 0.4ms
src/tools/system-scope.vitest.ts
the scope map is exhaustive, both ways · 3 tests
✓
every part has exactly one scope entry, and every entry matches exactly one part 4.9ms
✓
every scope names a family that exists, or one of the three conditions 1.5ms
✓
V2_SYSTEM is the parts joined — nothing that reads the full prompt changed 0.3ms
what a call receives · 6 tests
✓
with tiering off (and the two conditions on), the flat prompt: every part, no stubs 1.3ms
✓
a settled tenant on a CORE ask gets core only, plus one stub per unloaded family with a stub 1.2ms
✓
a loaded family brings its guidance and drops its stub 1.0ms
✓
a multi-scope part rides with any of its families 1.3ms
✓
onboarding and the capabilities ask are conditions, not families 2.0ms
✓
order is the original order — a family loaded later appends nothing out of place 0.8ms
the per-call budget (a ratchet — lower it with the work, never raise it silently) · 4 tests
✓
the core-only prompt stays under its ceiling 0.3ms
✓
the CORE tool schemas stay under their ceiling 0.5ms
✓
a WHY question preloads the family the stub points at, so the guidance arrives on the first call 4.4ms
✓
a content-quality ask preloads seo, so seo_content_quality is visible and read_url is not the fallback (bklink 2026-09-18) 1.0ms
the loop composes the prompt on every iteration · 1 test
✓
sets messages[0] from composeSystemPrompt with the run's families, tiering, onboarding and the capabilities ask 0.9ms
the Jev shortlist stub (2026-09-19) · 2 tests
✓
a shortlisted turn is told where the everyday tools went; a full-CORE turn is not 3.0ms
✓
the email surface gets its own stub, never the one saying email tools are missing (A7, 2026-09-24) 0.6ms
src/seo/cluster-structure.vitest.ts
the exclusions are what make this brief truthful · 6 tests
✓
does NOT report a site: operator query as cannibalisation 2.9ms
✓
does NOT report a PUNCTUATED brand form as cannibalisation 0.7ms
✓
does NOT report the brand name as cannibalisation 0.3ms
✓
DOES report a real commercial query on two pages 1.8ms
✓
ignores a query that only one page answers 0.2ms
✓
ranks overlaps by how many clicks are being split 0.4ms
a hub is only named when something actually leads · 3 tests
✓
names the highest-earning page as the de facto hub 0.8ms
✓
names NO hub when nothing in the group earns anything 0.3ms
✓
does not call a page or two a cluster 0.6ms
the decision carries the clause that gets ignored · 6 tests
✓
says narrow rather than start another 1.1ms
✓
names the specific query to resolve first 0.3ms
✓
states that the linking half is advice, not a reading 0.3ms
✓
keeps the internal-link hypothesis untested and says why precisely 0.3ms
✓
keeps capacity with the user — it decides how wide is safe 0.4ms
✓
separates "no reading" from "nothing wrong" 0.5ms
no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps field and table names out of the prose 0.5ms
src/seo/keyword-scoring.vitest.ts
classifyIntent · 3 tests
✓
reads buying modifiers as transactional, comparison as commercial 1.9ms
✓
defaults an unmodified seed to informational, not commercial 0.3ms
✓
is case-insensitive 0.2ms
computeKES · 4 tests
✓
is volume × cpc ÷ difficulty 0.3ms
✓
treats a missing difficulty as 1 rather than dividing by zero or bailing 0.2ms
✓
floors difficulty at 1 so a zero-difficulty row cannot produce Infinity 0.3ms
✓
is 0 when there is no volume or no cpc, not NaN 0.5ms
strikingDistanceWeight · 4 tests
✓
weights positions 11–20 highest — one push lands page 1 0.4ms
✓
discounts already-won positions rather than rewarding them 0.5ms
✓
gives partial credit for a known-impressions/unknown-rank row 0.2ms
✓
is continuous across every boundary (no gap that zeroes a band) 0.4ms
computeOpportunityScore · 5 tests
✓
blends estimated and behavioural demand 0.2ms
✓
ranks a GSC keyword with real impressions ABOVE a KES-0 row — the regression it exists for 0.2ms
✓
still scores a pure-estimate row with no GSC data 0.1ms
✓
is 0, not NaN, for a row with nothing known 0.1ms
✓
never returns negative for any sane input 0.2ms
src/seo/link-feasibility.vitest.ts
page strength counts VOICES, not links · 4 tests
✓
ten links from one domain are one referring domain 1.7ms
✓
keeps the best DR and a followed link when a domain links twice 1.2ms
✓
excludes dead links — support that has already decayed supports nothing 0.2ms
✓
matches target URLs the way the content join does 0.3ms
the four verdicts, and the two that are absences · 5 tests
✓
linked: at or above the median of the site's own linked pages 0.5ms
✓
thin: below this site's median, and the median is reported as the basis 0.3ms
✓
orphan: the site HAS links and none point here — that is a measurement 0.4ms
✓
unknown when no links are stored at all — never orphan 0.4ms
✓
unknown when Search Console attributes no page to the term 0.5ms
ordering surfaces the crossable distances, and drops nothing · 3 tests
✓
ranks linked, then unknown, then thin, then orphan 0.6ms
✓
keeps every keyword — an orphan term is slower, not absent 0.9ms
✓
puts unknown ABOVE thin — not knowing is not evidence of weakness 0.2ms
the note claims nothing it cannot support · 4 tests
✓
says nothing at all when no links are stored 0.2ms
✓
names the orphan case as a link problem, not an on-page one 0.3ms
✓
states the median as the basis for calling a page thin 0.2ms
✓
calls an unattributed term unknown rather than poor 0.2ms
src/seo/no-clean-verdict-without-reading.vitest.ts
no brief claims a clean result when nothing was read · 13 tests
✓
cluster_structure does not assert a clean finding on an empty input 3.0ms
✓
vitals_priority does not assert a clean finding on an empty input 1.2ms
✓
crawl_budget does not assert a clean finding on an empty input 0.6ms
✓
page_conversion does not assert a clean finding on an empty input 0.7ms
✓
migration_runbook does not assert a clean finding on an empty input 0.7ms
✓
backlink_policy does not assert a clean finding on an empty input 0.6ms
✓
keyword_map does not assert a clean finding on an empty input 0.7ms
✓
eeat_proof does not assert a clean finding on an empty input 0.7ms
✓
competitor_counter_plan does not assert a clean finding on an empty input 1.1ms
✓
recovery_programme does not assert a clean finding on an empty input 0.8ms
✓
generative_clicks does not assert a clean finding on an empty input 1.0ms
✓
rich_result_eligibility does not assert a clean finding on an empty input 0.6ms
✓
video_decision does not assert a clean finding on an empty input 0.6ms
the invariant is real — it catches the shape it exists for · 3 tests
✓
flags the exact sentence Q08 shipped 0.2ms
✓
flags the exact sentence Q23 shipped 0.2ms
✓
does not flag an honest unmeasured sentence 0.1ms
src/seo/query-quality.vitest.ts
classifyQuery — measured against the owner's real export · 8 tests
✓
excludes every operator dork in the export 1.9ms
✓
excludes the generated test tokens that reached the index 0.3ms
✓
FLAGS pasted assistant prompts without excluding them 0.9ms
✓
leaves every genuine human query alone 0.5ms
✓
catches a non-English pasted prompt on sentence structure alone 0.2ms
✓
does not mistake a domain name for a sentence boundary 0.2ms
✓
needs BOTH length and instruction shape before calling something a prompt 0.3ms
✓
treats an empty or blank query as real rather than junk 0.2ms
assessQueryQuality — the denominator is the finding · 4 tests
✓
separates excluded from real, and keeps flagged prompts inside real 0.7ms
✓
bands positions over REAL queries only 0.3ms
✓
reports zero click-through as measured, not as null 0.2ms
✓
returns null click-through when there is nothing to divide 0.3ms
queryQualityNotes — both disclosures, separately · 4 tests
✓
says what was removed and that it is not a judgement 0.2ms
✓
says what was FLAGGED and why it was kept 0.1ms
✓
leads the band read with the top-3 absence, which is the actionable part 0.1ms
✓
says nothing at all when there is nothing to disclose 0.8ms
src/seo/rank-cron-test-tenant.vitest.ts
processSEOCron skips test tenants · 3 tests
✓
never scans, bills or balance-checks a TEST_CAP_USER_IDS tenant 10.1ms
✓
control: with no test tenants configured, the same fixture scans both tenants 8.7ms
✓
matches the id case-insensitively, as isTestCapUser does everywhere else 1.8ms
processSEOCron honours a tenant who stopped the scan · 2 tests
✓
never scans, bills or balance-checks a tenant who stopped it 2.1ms
✓
fails closed: when the stop list cannot be read, nobody is scanned, it is reported and the run rejects 2.8ms
processSEOCron resolves only when it did its work · 6 tests
✓
P1-06-F04: a failed tracked_keywords read rejects instead of being console.logged away 1.3ms
✓
every tenant's measurements failing: each tenant reports its lost week; the hand-over still succeeded 2.3ms
✓
every tenant's snapshot write failing: each write failure is reported and the tenant reads as failed 2.0ms
✓
control: one tenant failing while another is scanned 2.4ms
✓
no queue binding: nobody is scanned, it is reported, and the tick rejects 1.0ms
✓
a hand-over that fails is reported, and a tick where every hand-over failed rejects 1.0ms
runSovWeeklyCron resolves only when it did its work · 5 tests
✓
an unreadable opt-in list is reported and rejects (it used to return, and check in ok) 1.1ms
✓
control: one tenant's run throwing is reported and the day still resolves 1.4ms
✓
every tenant's run throwing rejects 0.7ms
✓
a tool refusal for every tenant is an outcome, not a failed run 0.6ms
✓
no opt-ins is a day with nothing to do, not a failure 0.2ms
src/seo/seo-route-covering-cache.vitest.ts
seoRoute: a larger cached pull serves a smaller request (P4-06-F07 reopened) · 5 tests
✓
backlinks rows 25 then rows 10 → one purchase, the second served as the first 10 5.7ms
✓
a smaller cached pull does NOT answer a larger request (no silent short answer) 1.0ms
✓
competitor_keywords rows 25 then rows 10 → one purchase, top 10 by volume 1.1ms
✓
mode absent and mode as_is are ONE key; a different mode or offset is not 0.8ms
✓
rows_complete is re-derived for the smaller request 0.6ms
the off-page audit accepts a cached pull covering its need, on every plan · 11 tests
✓
free: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (backlinks-first) 2.4ms
✓
free: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (audit-first) 0.7ms
✓
paid: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (backlinks-first) 0.6ms
✓
paid: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (audit-first) 0.7ms
✓
appsumo1: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (backlinks-first) 0.5ms
✓
appsumo1: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (audit-first) 0.5ms
✓
appsumo2: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (backlinks-first) 0.6ms
✓
appsumo2: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (audit-first) 0.5ms
✓
appsumo3: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (backlinks-first) 0.5ms
✓
appsumo3: seo_backlinks and seo_offpage_audit on one site buy the backlinks pull once (audit-first) 0.5ms
✓
with no cache the free audit still buys its own 10 rows (the need lowers what it ACCEPTS, not what it buys) 0.6ms
src/seo/sov-basis.vitest.ts
contributingEngines — the basis a share was measured on · 5 tests
✓
excludes an engine with a null share and no mentions 2.2ms
✓
names Google AI Overviews as the sole basis of the 40% point 0.4ms
✓
names ChatGPT as the sole basis of the 100% the audit read 0.3ms
✓
counts a zero share that was genuinely measured 0.3ms
✓
returns nothing rather than throwing on an artifact with no by_engine 0.4ms
basisKey — two points on one line, or two different measurements · 2 tests
✓
sees the live basis change that was reported as growth 0.5ms
✓
is stable under engine ordering 0.4ms
engineWords — never the internal keys · 2 tests
✓
names the surfaces the way the user sees them 0.3ms
✓
says "no engine" rather than an empty string 0.4ms
normalizeEngineKeys — the stored field carries three shapes, only one of them clean · 5 tests
✓
passes the clean shape through untouched (83 rows) 0.4ms
✓
strips the model suffix — a CLAUDE.md §4 leak, not a cosmetic one 0.6ms
✓
drops a token that is not an engine at all 0.2ms
✓
never prints an unrecognised token verbatim 0.1ms
✓
does not throw on a malformed or absent field 0.2ms
syntheticContributed — shared with the SOV-unification work · 2 tests
✓
is true when Google AI Overviews drove the share 0.2ms
✓
is false when only real answers produced it 0.2ms
src/seo/synthesis-joins.vitest.ts
J5 — a page that earns traffic is carrying faults · 2 tests
✓
finds the page with real sessions, and ignores the one with none 16.5ms
✓
emits nothing when analytics is absent — never guesses stake from the crawl alone 0.8ms
J6/J7 — the site-level checks the crawl summary was throwing away · 3 tests
✓
duplicate titles are a defect no per-page check can see 0.7ms
✓
a FAILED domain probe is a finding; an UNREPORTED one is not 0.6ms
✓
emits nothing at all when the summary was never captured 0.2ms
J11 — SSL expiry, the first honest Predictive item (RULING-2) · 4 tests
✓
fires inside the window and STATES ITS METHOD, which is what the gate requires 0.5ms
✓
stays silent far from expiry — a date months out is not a prediction worth making 0.3ms
✓
reports an ALREADY-expired certificate as fact, not as a forecast 0.2ms
✓
ignores a missing or unparseable date rather than inventing one 0.6ms
J8 — quality on a page that already ranks · 2 tests
✓
is SUGGESTIVE — a low score on an earned position is headroom, not a fault 0.5ms
✓
says nothing about a page that ranks and scores well 0.2ms
J9 — ranks in Google, absent from AI answers · 2 tests
✓
is ADVISORY: both sides measured, the causal reading is not 0.4ms
✓
does not fire for a site that is visible in both, or measured in neither 0.2ms
J10 — tracked keywords with no coverage · 1 test
✓
names only the terms with no ranking anywhere, highest volume first 0.5ms
the synthesis set as a whole · 2 tests
✓
every finding is legal on the provenance axis (FR-031) 0.6ms
✓
emits NOTHING from an empty tenant — no source, no finding 0.3ms
src/leads/shared/locality-accent.vitest.ts
156 · the normalisation expression is identical on both sides of the join · 3 tests
✓
every normalisation in the migration uses the same wrapper 1.8ms
✓
the writer normalises the stored column and the reader normalises the argument 1.1ms
✓
the join is on the normalised key, scoped to the country 0.3ms
156 · the refresh is additive, because a rebuild would race live searches · 3 tests
✓
inserts with ON CONFLICT DO NOTHING 0.2ms
✓
never deletes or truncates the variant map 0.3ms
✓
only stores forms that differ from their own key 0.2ms
156 · the alias function still does everything 151 did · 3 tests
✓
returns the input unconditionally, group or no group 0.3ms
✓
still expands curated synonymy through locality_alias group_key 0.2ms
✓
unions the observed variants ON TOP of base, not instead of it 0.5ms
156 · it does not touch the query plans it was designed around · 2 tests
✓
does not redefine search_candidates 0.4ms
✓
creates no index on an unaccent expression 0.4ms
156 · the self-verification checks all four things that can fail apart · 5 tests
✓
asserts the gap is closed for both named cities 0.2ms
✓
asserts the cities that already worked did not regress 0.2ms
✓
asserts migration 155's California guard survives 0.2ms
✓
asserts the US is bit-for-bit unchanged until the backfill runs 0.1ms
✓
asserts the alias arrays stay narrow 0.1ms
src/admin/telemetry-primitives.vitest.ts
timingSafeEqual · 5 tests
✓
matches identical strings, including empty 1.8ms
✓
rejects a differing character at any position 0.3ms
✓
rejects a PREFIX of the real secret 0.3ms
✓
rejects a value that is longer than the secret 0.2ms
✓
compares BYTES, so multi-byte characters cannot alias 0.3ms
betaPosteriorSummary · 5 tests
✓
brackets the mean and returns a valid interval 1.3ms
✓
is WIDE with no evidence — the property that stops a 3-sample "trend" 0.6ms
✓
narrows as evidence accumulates at the same rate 2.1ms
✓
never reports certainty from a one-sided sample 0.7ms
✓
is symmetric under swapping successes and failures 4.0ms
mergeGenAiModelStats · 3 tests
✓
joins failures onto totals by model and sorts by volume 1.3ms
✓
a failure-only model absent from totals does not crash the join 0.2ms
✓
missing latency aggregates become null, not NaN 0.3ms
accumFeatureRow · 2 tests
✓
merges ok/fail counts across sources and keeps the newest lastSeen 0.4ms
✓
drops unparseable or non-positive durations instead of poisoning percentiles 0.3ms
src/admin/waste-meter-surface.vitest.ts
toWasteApiRow — the new keys are whitelisted, and so are their VALUES · 2 tests
✓
surface keys and target_shape survive; an injected email and any unknown key are dropped 4.4ms
✓
(neg) a whitelisted KEY carrying an address or prose is dropped, not trusted 0.4ms
the fold — surface from the turn's render row, and every run with its time · 3 tests
✓
reads the surface of the LAST render row; rows written before the change read null 2.7ms
✓
tool_runs carry `at` and target_shape, and the report orders by `at` whatever the ledger order 2.4ms
✓
counts shortlist calls and the A5 same-set Jev rows per turn 1.7ms
reportWaste over the audited session · 6 tests
✓
surface per label, and r = email-only turns on general ÷ surfaced turns 0.6ms
✓
a7: the surface-independent email baseline reproduces the audit (n 3, 16,952 / 17,005 / 19,177), and the keep rule reads 0.5ms
✓
a11: asked on both leads-preloaded turns, one vetoed, no leads needed after → no kill 0.2ms
✓
a11 kill rule: a vetoed turn that then needed leads 2.2ms
✓
m19: the 70dfb970 detour — list_contacts before the enrich write — is 13,081, the audit's A5 0.3ms
✓
probable search_tools rounds (heuristic): none in the audited session 0.3ms
the probable search_tools round heuristic · 1 test
✓
a prompt jump >= 1,500 with no tool_run between two rounds counts the earlier round 0.6ms
the report rides the roll-up, never the flags · 3 tests
✓
rollupWaste carries report; with no turns it is empty and every keep rule reads null 0.7ms
✓
the config takes its constants from their owners 0.2ms
✓
an email-only turn: only email/lookup tools, and at least one write 0.2ms
src/billing/quote-target.vitest.ts
the estimator prices a KNOWN target · 4 tests
✓
quotes per address when the count is handed in, the ceiling when it is not 2.6ms
✓
a known EMPTY target is zero, not the ceiling — the dispatch answers it with a picker 0.4ms
✓
priceOfTool threads the count through, so a shortcut card reads the same number 0.4ms
✓
the count only speaks for target-sized tools 1.0ms
resolving the target the dispatch will bill for · 4 tests
✓
reads every spelling the gate may see before the validator folds them 0.8ms
✓
a list resolves to its member count; explicit ids win over a list 2.9ms
✓
the user's own limit cuts the count, as it cuts the run 1.0ms
✓
nothing named → undefined (picker, priced by the estimator at zero); a missing list → zero 0.4ms
THE QUOTE IS THE BILL: the count is narrowed exactly as the dispatch narrows it (2026-09-24) · 4 tests
✓
the 09-21 list — 25 members, 24 already verified — is quoted for the 1 it will bill 0.9ms
✓
every member already verified → 0, the answer on file at no spend (not the ceiling) 0.7ms
✓
an explicit re-check (verified: 'any') is quoted for every member with an email 0.6ms
✓
(neg) a throwing read → undefined, so the estimator keeps its ceiling (never throws) 2.1ms
every gate that knows the tenant asks for the count · 3 tests
✓
the agent loop gate 1.0ms
✓
the chip-dispatched (next_action) gate 0.3ms
✓
the plan-initiative Execute gate — it passed undefined, the catalogue ceiling, for every tool 0.6ms
src/campaigns/enrich-contacts.vitest.ts
enrich_contacts cap arithmetic · 6 tests
✓
never attempts more than the fan-out cap 1.6ms
✓
counts the remainder instead of dropping it — the whole defect 0.3ms
✓
reports no remainder when the list fits 0.2ms
✓
never reports a negative remainder if the page outruns a stale count 0.2ms
✓
excludes the already-enriched in the QUERY, which is what the cap then applies to 0.8ms
✓
and drops that exclusion when the user asked to redo the work 0.2ms
the continue promise must be keepable · 2 tests
✓
orders the refresh fan-out by enrichment age, so "the next 10" is a different ten 0.5ms
✓
keeps a created_at tiebreak, so the default mode is unchanged 0.3ms
enrich_contacts result rendering · 7 tests
✓
shows the remainder sentence the dispatch produced 5.0ms
✓
discloses when no list was named and we chose the target 0.4ms
✓
says nothing about scope when the user DID name a list 0.3ms
✓
offers a one-click continue chip naming the same list 1.1ms
✓
names what it actually found, not just how many 0.3ms
✓
says nothing extra when the research came back empty 0.2ms
✓
offers no continue chip when nothing is left 0.2ms
src/campaigns/verify-readiness.vitest.ts
when it must say nothing · 8 tests
✓
stays silent when the caller ALREADY asked to skip checked addresses 2.3ms
✓
stays silent when `verified` is ABSENT — the dispatch default is unchecked (#469), so nothing is re-bought 0.5ms
✓
(neg) speaks for an explicit re-check — the one call that does buy the checked rows again 1.6ms
✓
stays silent when no target is named — that turn is a picker, not a purchase 0.4ms
✓
says nothing about a trivial number of re-checks 0.3ms
✓
says nothing about a trivial SHARE, even when the count is large 0.3ms
✓
says nothing when nothing has been checked — the ordinary, correct case 0.2ms
✓
says nothing about an empty target 0.2ms
when it speaks, the number is the one that would happen · 3 tests
✓
quotes the re-checked count and offers the one-click fix 0.6ms
✓
says ALL when it is all of them, rather than "100 of 100" 0.3ms
✓
adds the staleness clause only when it changes the advice 0.4ms
the query mirrors the dispatcher, not a reasonable-sounding rule · 4 tests
✓
counts a PROVIDER CLAIM as unchecked — migration 050, and it decides money 0.4ms
✓
scopes every count to the tenant 0.3ms
✓
counts stale as a subset of CHECKED, never of the whole target 0.2ms
✓
reads list_name as well as filter.in_lists — the gate runs UPSTREAM of the validator 0.3ms
src/chat/answer-budget.vitest.ts
nothing is dropped — it is deferred, named and offered · 4 tests
✓
every fragment is either kept or deferred, never lost 8.8ms
✓
names what was held back and offers a chip for it 5.9ms
✓
does not describe the deferred material as missing 0.5ms
✓
stays silent when everything fits 1.9ms
three things can never be deferred · 3 tests
✓
keeps the LEAD however long it is — an answer that defers its answer is useless 0.6ms
✓
keeps the CAVEAT — deferring a qualifier while keeping the claim is the one misleading cut 0.5ms
✓
keeps an ASK — a question held back is a question never asked 0.6ms
ordering is not the budget's business · 2 tests
✓
preserves the order it was given 0.3ms
✓
fills in order rather than picking the shortest fragments 0.9ms
labels · 4 tests
✓
uses a fragment's own label over the topic default 1.3ms
✓
falls back to a topic label when the fragment names nothing 0.4ms
✓
dedupes fragments that share a topic instead of repeating one chip 0.3ms
✓
caps the chip row at three 0.3ms
degenerate inputs · 2 tests
✓
handles empty, null and single-fragment lists 8.9ms
✓
drops blank fragments rather than emitting empty paragraphs 0.6ms
src/chat/continuation.vitest.ts
trimToSentenceBoundary · 4 tests
✓
keeps a cleanly-terminated reply unchanged 2.0ms
✓
cuts a mid-sentence truncation back to the last full sentence 0.3ms
✓
cuts a truncated list item back to the last completed line 0.3ms
✓
returns the text unchanged when no usable boundary exists 0.2ms
stitchContinuation · 4 tests
✓
dedupes the overlap a model re-emits 0.3ms
✓
joins non-overlapping parts with a single space 0.4ms
✓
handles empty continuation / empty partial 0.3ms
✓
nudge forbids repetition and restarts 0.4ms
a continuation that RESTARTS is not stitched, it replaces · 7 tests
✓
detects the restart 0.6ms
✓
keeps the rewrite alone — the partial is cut off, the rewrite is not 0.7ms
✓
does NOT mistake a genuine continuation for a restart 0.3ms
✓
needs a meaningful partial before it will call anything a restart 0.2ms
✓
still prefers verbatim overlap when the model repeats its last words 0.1ms
✓
trims the head to a sentence boundary before joining a non-overlapping continuation 0.2ms
✓
keeps a short head intact rather than trimming most of it away 0.2ms
src/chat/report-judge.vitest.ts
scoreReportDimensions · 10 tests
✓
every dimension key has a passing fixture (fixtures stay in sync with the dimension set) 2.3ms
✓
scores 1.0 and no failure modes when every dimension passes 0.8ms
✓
surfaces every distinct failure mode, not just the first-failing dimension 0.3ms
✓
maps a single failing dimension to its taxonomy bucket, not just the first key 0.3ms
✓
a thin-but-honest report fails sufficient_depth into thin_report (the 2026-07-09 gap) 0.3ms
✓
a self-contradicting report fails internally_consistent (the 2026-07-14 forensic gap) 0.3ms
✓
a mislabelled/out-of-range composite fails scores_sound 0.3ms
✓
dedupes when two failing dimensions share the same failure_mode bucket 0.3ms
✓
treats missing/undefined dimensions as false, not a crash 0.5ms
✓
ignores unknown extra keys and only scores the fixed dimension set 0.2ms
a defective artifact caps the score, however sound the data underneath · 5 tests
✓
blank sections cap at 0.5 even when all eight data dimensions pass 0.9ms
✓
a rendered self-contradiction caps too — the KPI-vs-section case 0.2ms
✓
the actual report: blank sections AND a contradiction 0.1ms
✓
the cap is a CEILING, never a floor — a bad report does not get lifted to 0.5 0.1ms
✓
a clean artifact is unaffected — the mean still governs 0.2ms
src/chat/seo-audit-routing.vitest.ts
the judged-20% turn · 2 tests
✓
routes the reported prompt to the full audit, not the crawl-budget picker 40.0ms
✓
does not reach onpage_start, whose handler answers with a depth question 7.0ms
the adjacency class — a scope word separated from "seo audit" by one qualifier · 6 tests
✓
run a full technical seo audit -> full_seo_audit 0.5ms
✓
run a complete technical seo audit -> full_seo_audit 2.3ms
✓
full technical SEO audit please -> full_seo_audit 1.0ms
✓
can you run a complete technical seo audit and tell me what to fix first -> full_seo_audit 0.6ms
✓
leaves the plain "full seo audit" phrasing exactly as it was 1.3ms
✓
routes "run every seo audit" to the full audit instead of asking which one 1.0ms
what must NOT change — the depth picker is right when on-page IS the ask · 7 tests
✓
run an on-page audit -> onpage_start 1.7ms
✓
run an on-page seo audit -> onpage_start 0.9ms
✓
run a technical seo audit -> onpage_start 0.4ms
✓
audit my pages -> onpage_start 0.9ms
✓
keeps off-page and Serpdex on their own intents 1.1ms
✓
keeps the bare "audit my site" on the route picker, which asks WHICH audit 0.4ms
✓
does not swallow a lead search that merely mentions SEO 1.3ms
src/chat/turn-budget.vitest.ts
a stated limit is read · 3 tests
✓
the live message that started this 2.4ms
✓
the ways people write a ceiling 0.8ms
✓
THE SMALLEST STATED AMOUNT WINS 0.2ms
and a number that is not a budget is left alone · 4 tests
✓
needs the word tokens AND a limiting phrase 0.4ms
✓
ignores an amount too small to buy a turn 0.2ms
✓
empty input is not a budget 0.2ms
✓
is not stateful across calls — AMOUNT_RE is /g 0.4ms
the ceiling reuses the existing gate rather than growing a second one · 5 tests
✓
is min(balance, stated) — a budget larger than the balance does not unlock money 1.9ms
✓
the accumulator still applies, so a fan-out cannot walk past it one tool at a time 2.1ms
✓
the scaled-down offer sizes off the CEILING, not the balance 1.7ms
✓
names the limit that actually bound, instead of telling them to top up 1.7ms
✓
null falls through to the balance — no invented default 3.4ms
the budget is derived where EVERY path passes · 3 tests
✓
is set in setUserMessage, not inside the agent loop 5.0ms
✓
the model is told the limit before it plans 5.8ms
✓
and it tells the model to plan, not just to stop 3.9ms
src/chat/turn-plan.vitest.ts
derivePlan · 5 tests
✓
returns a multi-step plan for a genuinely compound ask 20.9ms
✓
returns null for a single-intent ask (no plan worth persisting) 6.1ms
✓
returns null for a no-ask turn 0.7ms
✓
caps step count so a match storm cannot write a runaway plan 0.6ms
✓
truncates the stored original message 0.4ms
markStepDone · 3 tests
✓
marks a matching step and reports the change 0.5ms
✓
is a no-op for a tool not in the plan (caller can skip the KV write) 0.2ms
✓
is idempotent — re-running the same tool does not re-report a change 0.2ms
isPlanComplete · 2 tests
✓
is false while any step remains 0.6ms
✓
is true once every step is done 0.3ms
planStatusLine · 4 tests
✓
names completed steps as do-not-repeat and remaining steps in order 0.6ms
✓
says nothing is done yet when the plan has not started 0.2ms
✓
returns empty string for a complete plan (nothing to inject) 0.2ms
✓
returns empty string for an empty plan 0.1ms
turnPlanKey · 1 test
✓
is tenant- and session-scoped 0.6ms
src/db/migration-193.vitest.ts
the two files, against the migration history · 3 tests
✓
_clear.json is exactly 049's user-role INSERT on shared_lead_list_item, and nothing else 7.1ms
✓
the AFTER file is one drop of that INSERT, and touches no other permission 0.8ms
✓
no migration between 049 and 193 touched the user role's permissions on the table, so 049 IS the before shape 2.8ms
193_apply.sh against the stand-in · 12 tests
✓
drops 049's INSERT, keeps SELECT exactly, verifies itself, and a re-run writes nothing 413.3ms
✓
--dry-run reports the one change and writes nothing 103.9ms
✓
--clear re-grants exactly 049's INSERT (recovery only), and a forward run then drops it again 565.1ms
✓
already absent is a no-op that still proves the state 181.5ms
✓
a drifted INSERT is a STOP before anything is written — including the two ways someone would "fix" the route 400.7ms
✓
a refused drop changes nothing, proves that by re-reading, and a re-run applies 366.5ms
✓
a drop whose reply is lost (a 502 after it applied) is recognised, proved and reported as applied 181.5ms
✓
proof (b) is an independent read: a user-role schema still exposing the roots fails the run 183.8ms
✓
SELECT must survive: a drop that took it too fails the run, after re-creating exactly what was read 185.9ms
✓
proof (a) compares SELECT with itself: a drop that NARROWED it fails the run and says so 186.2ms
✓
refuses to run from edited migration files: an AFTER file that drops SELECT instead is a STOP before any read 45.7ms
✓
proof (c): inconsistent metadata fails the run 196.6ms
src/drip/start-sequence.vitest.ts
the gate, not the appetite for risk · 3 tests
✓
is declared external — starting is at least as consequential as enrolling 2.0ms
✓
carries a preflight assessor, so it cannot be an ungated external tool 1.0ms
✓
loads with the campaigns family, beside the two moves that precede it 0.3ms
what the start is about to do, said first · 3 tests
✓
leads with the blocker when the tenant cannot send at all 0.5ms
✓
states the volume when a start commits to real mail 0.3ms
✓
says nothing about an ordinary small start 0.2ms
the reply distinguishes the three actions · 3 tests
✓
a start says what leaves and when 4.9ms
✓
a pause is explicit that nobody was unenrolled 0.4ms
✓
an error reads as an error 2.0ms
nobody enrolled is not a success · 6 tests
✓
a start that flips zero enrolments is reported as an error, not as started 0.3ms
✓
gives zero its reason — three causes, three sentences 0.2ms
✓
treats a failed census as unknown, never as zero 0.2ms
✓
refuses a sequence with no steps rather than starting an empty send 0.1ms
✓
reuses handleSequenceStatus instead of writing a second status mutation 0.1ms
✓
resolves the sequence with two scoped queries, never one _or 0.1ms
src/email/reply-triage.vitest.ts
reply triage — decision table · 7 tests
✓
no triage (flag off, empty body, failure) is exactly the old behaviour 2.0ms
✓
an out-of-office at high confidence keeps the sequence running and is not a reply 0.6ms
✓
an out-of-office that Jev is not sure about, or that does not read as automatic, falls back to the pause 0.2ms
✓
a stop request unsubscribes at the lowest bar, whatever the intent label says 0.9ms
✓
interest and refusal set the contact status the filters and dashboard already offer 0.4ms
✓
a question or a wrong-person reply pauses like before but says what happened 0.4ms
✓
thresholds are stakes-based: stop is the lowest bar, out-of-office the highest 0.4ms
reply triage — state and questions · 3 tests
✓
the state names the reply as data, caps it, and carries the subject 0.4ms
✓
the intent choice covers every label, and the two nouls are literal single conditions 0.8ms
✓
is rolled out and gated on its own flag word 0.5ms
reply triage — handler wiring (src/email/inbound.ts, called by email()) · 3 tests
✓
the reply branch triages before it writes, and every write is driven by the decision 0.5ms
✓
a null leadStatus skips the contact write instead of stringifying it 0.3ms
✓
unsubscribe stamps unsubscribed_at like the manual route; interested never overwrites unsubscribed 0.2ms
the send and the contact never contradict each other · 2 tests
✓
no branch marks the contact replied without marking the send replied 0.5ms
✓
and the legacy fallback still does both, because an unknown reply IS a reply 0.2ms
src/leads/described-product.vitest.ts
described-product: the incident conversation · 5 tests
✓
picks the opening description and nothing else 3.5ms
✓
classifies every turn the way the conversation reads 1.4ms
✓
scores the bare domain at ZERO prose — it is a fact, not a description 0.3ms
✓
never reads a confirm token as prose, however long the uuid 0.2ms
✓
would have carried the description into the scan turn 0.2ms
described-product: precision guards · 6 tests
✓
rejects a long message that claims no ownership 0.8ms
✓
rejects a short ownership claim — it is worse context than a scanned page 0.3ms
✓
accepts the common phrasings a founder actually uses 0.3ms
✓
keeps the newest messages when more than the cap qualify 1.4ms
✓
never exceeds the prompt cap 0.3ms
✓
returns empty for a conversation with no description 0.3ms
isSubstantiveBrief: nothing may be derived from a name · 4 tests
✓
rejects the exact brief the incident produced 0.2ms
✓
accepts a real compiled brief 0.2ms
✓
rejects empty, null and whitespace without throwing 0.2ms
✓
rejects two lines that are still only a name 0.1ms
src/leads/person-name.vitest.ts
sanitizePersonName — real values observed in production · 9 tests
✓
salvages the person out of "Jeferson (tolefitness.com)" rather than trusting or dropping it 2.3ms
✓
rejects "Wallace (teamcastro.co)" — a .co domain still reads as a domain 0.3ms
✓
KEEPS a real person — the case that must not regress 0.3ms
✓
rejects role and generic inboxes rather than greeting "Hi Wizard," 0.3ms
✓
rejects a bare domain, an address, and digits 0.3ms
✓
rejects an organisation, and a sentence masquerading as a name 0.3ms
✓
handles null, empty and whitespace without throwing 0.2ms
✓
is idempotent — sanitizing a clean name changes nothing 0.2ms
✓
works with no email supplied (CSV import, manual add) 0.5ms
personFirstName drives the greeting · 3 tests
✓
gives a first name for a real person 0.2ms
✓
gives null for the polluted values, so the caller says "Hi there," 0.3ms
✓
rejects a single-letter first name — "Hi J," is not a greeting 0.1ms
briefForPrompt bounds the product brief · 3 tests
✓
leaves a short brief untouched 0.1ms
✓
caps a long brief and MARKS the truncation so the model knows it is an excerpt 0.3ms
✓
handles null/undefined as an empty string, never the text "null" 0.1ms
src/llm/model-failure-surface.vitest.ts
a failed attempt records its latency (defect 1) · 5 tests
✓
catch block 0 emits a gen_ai span 1.4ms
✓
catch block 1 emits a gen_ai span 0.2ms
✓
records the span as a FAILURE, or it pollutes the success series 0.3ms
✓
carries the duration — the whole point 0.4ms
✓
separates timeouts from other errors in the task name 0.2ms
the two producers are distinguishable (defect 2) · 2 tests
✓
each throw site names itself 0.4ms
✓
keeps the marker OUTSIDE the phrase existing consumers match on 0.5ms
the chat path translates model failures (defect 3) · 6 tests
✓
maps the exact Sentry string to a sentence with no model slug and no milliseconds 0.5ms
✓
distinguishes a timeout from an unavailable chain 0.6ms
✓
covers the tools path's own exhaustion message, not just the timeout one 0.2ms
✓
returns null for anything that is NOT a model-chain failure 0.2ms
✓
is wired into BOTH chat exits — streaming and non-streaming 0.8ms
✓
still runs the message through scanOutbound 0.3ms
Sentry suppression is unchanged by the refactor · 2 tests
✓
the timeout sentence keeps the shape isExpectedToolOutcome matches 1.6ms
✓
and a genuine novel error still reports, so the check is not vacuous 2.5ms
src/llm/router-truncation.vitest.ts
callOpenRouterFull — finish_reason reaches the caller · 4 tests
✓
reports finish=stop / truncated=false on a clean completion 3.7ms
✓
reports truncated=true when a LONG completion hit the output ceiling 1.6ms
✓
reports finish='?' rather than 'stop' when the provider sent no finish_reason 0.6ms
✓
surfaces the WINNING attempt’s finish_reason after a failover, not the failed one 1.4ms
callOpenRouter — the bare-string wrapper is unchanged · 1 test
✓
still returns only the text of a truncated completion 1.1ms
failOnTruncation is OFF by default · 1 test
✓
does not fail over, throw, or alter text on a truncated-but-long completion 0.8ms
failOnTruncation: a truncated generation is a FAILED one, not a short one · 5 tests
✓
retries the next model in the chain instead of returning the partial 1.6ms
✓
throws when every model in the chain truncates 2.7ms
✓
describes the cause as truncation rather than empty/short content 1.5ms
✓
leaves a clean completion completely unaffected 0.4ms
✓
reaches the bare-string wrapper, which cannot otherwise see truncation 1.0ms
hidden reasoning is disabled — failOnTruncation callers included (2026-08-29) · 4 tests
✓
sends reasoning:{enabled:false} when the caller cannot tolerate truncation 1.3ms
✓
now covers prose callers too — the old predicate was the defect 0.5ms
✓
NEVER overrides a reasoning option the caller set deliberately 0.5ms
✓
applies on every model in the chain, not just the first 1.7ms
src/routes/voice-assistant.vitest.ts
R5-P1-02-F01: no code from the voice gateway runs in the nqz.ai origin · 8 tests
✓
/: the launcher is added, and no <script src> on the gateway origin is 11.2ms
✓
/about: the launcher is added, and no <script src> on the gateway origin is 2.4ms
✓
/privacy: the launcher is added, and no <script src> on the gateway origin is 3.1ms
✓
/terms: the launcher is added, and no <script src> on the gateway origin is 1.7ms
✓
/refund-policy: the launcher is added, and no <script src> on the gateway origin is 1.8ms
✓
every script block the snippet appends is inline (no src attribute) 1.1ms
✓
pages it never touches are passed through untouched (gating unchanged) 1.2ms
✓
the public pages' CSP no longer allows scripts from the gateway; its frame and microphone stay allowed 1.3ms
R5-P1-02-F01 sweep: no source file loads a script from the voice gateway · 2 tests
✓
scans a real population (a vacuous sweep is not a pass) 0.5ms
✓
no <script src> names the gateway, literally or through VOICE_GATEWAY_ORIGIN, and no file but the two owners names it at all 92.3ms
R5-P1-02-F01: the launcher works without the gateway script, and answers only its own panel · 5 tests
✓
renders the launcher; opening it frames the gateway panel with the referrer and microphone the panel needs 156.8ms
✓
a signed-in visitor: the panel gets the 2-minute signed token, addressed to the gateway origin only 50.6ms
✓
a visitor who is not signed in: the panel is told null, and no identity call is made 41.5ms
✓
ignores a request from any other origin, any other window, or before the panel exists 59.2ms
✓
the panel's close button and Escape close it 23.3ms
src/scoring/leaderboard.vitest.ts
GET /api/leaderboard performs no tenant-table read (P1-08p-F03) · 7 tests
✓
serves the published snapshot and never calls GraphQL 29.4ms
✓
with no snapshot published it answers 200 "updating", warns, and does NOT fall back to a live read 2.1ms
✓
with KV unbound it answers 200 "updating", warns, and does not fall back to a live read 1.1ms
✓
a KV read failure answers 200 "updating", reports the error and warns, with no live read 1.3ms
✓
a published snapshot raises no warning and carries no status marker 0.8ms
✓
PAGE: the public page renders the updating state as its message, not as a failure or an empty board 1.3ms
✓
WIRING: the public handler source names no GraphQL seam and no tenant-table fetch 0.6ms
the published board carries no row attributable to a tenant · 6 tests
✓
buildLeaderboardEntries masks identity, drops unverified + excluded, ranks by points 1.1ms
✓
INITIALS ONLY: no name longer than initials appears in the public response 3.7ms
✓
publicInitials: one code point per word, at most three, masked-email fallback gives one initial 0.4ms
✓
publishPublicLeaderboard reads the tenant tables ONCE and writes one snapshot to KV 1.4ms
✓
a failed tenant read keeps the previous snapshot in place and reports it 1.0ms
✓
with KV unbound the publisher reports and does nothing 0.5ms
the nightly scoring job publishes the board (inside its own cron check-in + budget) · 1 test
✓
runUserScoresCron publishes after scoring, and still attempts the publish when scoring throws 3.9ms
the public response shape is unchanged by the snapshot split · 1 test
✓
paginates the snapshot with limit/offset and carries the same fields as before 1.6ms
src/runtime/observation.vitest.ts
observe · 5 tests
✓
DE-DUPLICATES — 30 calls against one connector are one observation, not thirty 2.7ms
✓
keeps distinct resources distinct 1.1ms
✓
is bounded, so a pathological run cannot make one flush unbounded 0.8ms
✓
ignores empty refs rather than writing a row that says nothing 0.4ms
✓
truncates a long ref instead of storing an unbounded string 0.3ms
flushObservations · 4 tests
✓
writes one row per distinct resource, carrying the run correlation 1.7ms
✓
clears the buffer so a second request cannot inherit the first request one 0.5ms
✓
writes nothing when there is no tenant to attribute it to 0.5ms
✓
SWALLOWS a write failure — an audit gap must never break a turn 1.2ms
retention · 3 tests
✓
prunes past a stated window rather than accumulating forever 0.8ms
✓
a failed prune rejects instead of reporting zero 1.1ms
✓
the retention window is a real limit, not effectively infinite 0.2ms
what is never recorded · 3 tests
✓
records the connector NAME, never a secret or a row of tenant data 0.5ms
✓
records the provider+operation, never the request payload 1.2ms
✓
records the egress HOST, never the full URL with its query string 1.9ms
src/tools/preflight-ask.vitest.ts
a call that cannot run is caught before the money question · 7 tests
✓
asks who, for a people search with no audience at all 2.8ms
✓
speaks to the person, not to the schema 0.5ms
✓
says nothing when any one handle is present 0.6ms
✓
covers the local-business shapes a user can also answer 0.5ms
✓
never blocks a call the validator would have accepted 0.4ms
✓
returns null — not a thrown error — for a failure a user cannot answer 2.7ms
✓
is inert for tools with no schema 0.3ms
the disambiguation chip reads as English · 1 test
✓
strips the leading verb so the chip does not say "find" twice 0.5ms
the chip prefix has ONE definition · 1 test
✓
matches both the current and the legacy chip forms 0.6ms
the saved audience is read before the user is asked · 6 tests
✓
the lead path passes userId so it CAN load personas 4.5ms
✓
the lead path also passes the chip decision, or Tier −1 answers a question nobody asked 3.8ms
✓
structureLeadArgs loads __personas__ and the brief 3.0ms
✓
an explicit ask still wins over the stored persona 3.9ms
✓
refuses to invent an audience when nothing is saved 2.9ms
✓
names the persona on the approval card so a wrong target can be caught 3.4ms
src/seo/competitor-joins.vitest.ts
join 3 — what find_competitors is allowed to persist · 6 tests
✓
screens out the directories a "<brand> alternatives" SERP is full of 2.0ms
✓
keeps a real product domain 0.8ms
✓
rejects empty input rather than storing a blank competitor 0.2ms
✓
merging keeps user-confirmed entries ahead of auto-discovered ones 0.5ms
✓
merging dedupes, so re-running discovery cannot grow the set forever 0.9ms
✓
merging caps the set, so discovery cannot blow past the stored limit 0.6ms
join 3 — the write is conditional in source · 3 tests
✓
only persists for the tenant's own brand, never another company's rivals 0.4ms
✓
screens before storing rather than trusting the reader to re-screen 0.3ms
✓
reports what it saved instead of changing the set silently 0.6ms
join 2 — the gap resolves the saved set before spending · 6 tests
✓
competitor_domain is no longer a required argument 0.3ms
✓
the fallback resolves BEFORE the balance gate — never after a cost click 0.3ms
✓
asks when several are saved rather than guessing "top" from an unranked list 0.2ms
✓
the picker turn carries chips, so the question it asks is answerable by clicking 0.2ms
✓
BOTH competitor picks halt the loop verbatim, so the rivals are always offered as chips (2026-09-15) 1.2ms
✓
points at discovery when nothing is saved, instead of a bare refusal 0.2ms
src/seo/content-performance.vitest.ts
URLs match the way a human would compare them · 3 tests
✓
ignores scheme, www, trailing slash, query and hash 1.8ms
✓
does not collapse two different pages 1.0ms
✓
sums variants of one page rather than letting the last one win 1.3ms
the three absences are not one absence · 6 tests
✓
earning: clicks measured 0.3ms
✓
seen_not_clicked: impressions but no clicks is a FINDING 0.2ms
✓
unmatched: no row at all is an absence of measurement, and clicks stay NULL not 0 0.4ms
✓
too_new beats every other empty verdict inside the grace window 0.5ms
✓
but a young page that IS earning is reported as earning 0.2ms
✓
an unpublished piece is not in the list at all 0.5ms
clicks are the outcome; impressions are the denominator · 5 tests
✓
leads with clicks when anything is earning 13.8ms
✓
names the zero-click case as a titles problem, not a rankings one 0.4ms
✓
calls an unmatched page an absence of measurement, and names the causes 0.2ms
✓
says a young piece is too new to judge rather than failing 0.2ms
✓
says nothing when nothing was published 0.2ms
ordering · 1 test
✓
puts what works at the top and the unjudgeable at the bottom 0.4ms
src/seo/page-stake.vitest.ts
signal 1 — stake concentration · 3 tests
✓
reports how many affected pages earn, and what share of the site they carry 2.1ms
✓
matches URLs across protocol/www/trailing-slash differences 0.4ms
✓
says nothing rather than 0% when no affected page earns anything 0.3ms
the fix list is ordered by stake, not by volume · 3 tests
✓
a smaller issue on pages that EARN outranks a bigger one on pages that do not 0.4ms
✓
falls back to volume when there is no performance data — unchanged behaviour 0.2ms
✓
an issue with stake outranks one with none at all 0.2ms
signal 2 — CTR against the SITE'S OWN median (FR-031) · 3 tests
✓
finds the page losing clicks it has already earned the ranking for 14.3ms
✓
says NOTHING when the band is too thin for a trustworthy median 0.4ms
✓
ignores pages with too few impressions for CTR to mean anything 0.7ms
signal 3 — indexed and earning nothing · 3 tests
✓
finds an indexed page that competes for no query 0.4ms
✓
frames it as a targeting gap, never as a fault 0.2ms
✓
emits nothing when performance could not be read — never guesses from absence 0.2ms
the report stops apologising once it can see stake · 3 tests
✓
stakeGap goes silent when per-page performance exists 0.2ms
✓
the "what we cannot see yet" panel disappears from the rendered report 14.3ms
✓
a CTR underperformer renders as a Fix, an idle indexed page as a Try 0.6ms
src/seo/rank-scan-fanout.vitest.ts
V9-seo-F01: one Sunday scans every eligible tenant, once · 3 tests
✓
68 eligible tenants at ~1 s a SERP call: all 68 scanned, every keyword once, none twice 191.7ms
✓
the tick is a hand-over, not a scan: a handful of subrequests, and no tenant in one invocation nears the cap 89.7ms
✓
waves: tenants are released 10 at a time, 30 s apart, within the queue's 24 h delay limit 3.3ms
V9-seo-F01: a redelivered message never scans, bills, counts or emails twice · 5 tests
✓
every message delivered twice (once concurrently, once as a retry): one scan, one check, one refusal each 95.0ms
✓
a cron re-triggered the same week hands everyone over again and scans nobody again 50.2ms
✓
next Sunday is a new week: everyone is scanned again, exactly once more 62.1ms
✓
a claim that cannot be written throws (so the queue retries) and nothing was checked or spent 3.9ms
✓
a late message from last week cannot take this week's claim 2.0ms
the claim key is the ISO week, and orders as text · 1 test
✓
names the ISO week, across a year boundary, zero-padded 1.4ms
V9-seo-F01: the subrequest budget holds for every plan · 2 tests
✓
every plan's weekly depth fits the per-tenant SERP cap, and the cap fits 90% of the Workers limit 0.7ms
✓
the deepest plan finishes well inside its own wall-clock budget at production latency 0.4ms
V9-seo-F04: the cron's monitor read and run records · 1 test
✓
reads the monitor diff only for tenants it measured, with no run_id in scope, and records each run with run_id null 30.2ms
V9-seo-F04: a tenant the run reached but measured nothing for gets no monitor read · 1 test
✓
every SERP call failing: no monitor diff, no digest, a failed run record, and Sentry hears of it 2.2ms
a scraped position and its rivals are stamped with the provider that answered · 1 test
✓
rank and rival rows carry seoRouteSerp's provider, not a name written into the cron 2.2ms
the queue consumer routes rank-scan messages before the Serpdex cast · 1 test
✓
handles kind rank_scan_tenant, acks it, retries only a throw, and dead-letters with a report 1.0ms
src/seo/rival-pressure.vitest.ts
an outranking claim needs BOTH positions · 4 tests
✓
counts a rival above us as outranking 3.7ms
✓
does not count a rival BELOW us 0.7ms
✓
counts an unknown own position separately, never as a loss 0.5ms
✓
treats a null own position as unknown, not as zero 0.4ms
a scan that has not run is not a finding · 2 tests
✓
reports scanned:false with no rows 0.3ms
✓
says nothing at all rather than "you have no competitors" 0.4ms
only the most recent scan is summarized · 4 tests
✓
counts keywords and rivals from the latest run alone 0.7ms
✓
names a domain absent from the previous run as new 0.5ms
✓
claims no movement when there is no previous run 0.9ms
✓
suppresses movement entirely when the read was truncated 0.6ms
ordering puts pressure first, not noise · 2 tests
✓
ranks the domain that beats us above one merely present everywhere 0.4ms
✓
counts one standing per rival per keyword even with duplicate rows 0.3ms
the note says which of the two problems this is · 3 tests
✓
names the rival, the count and the basis 0.2ms
✓
distinguishes an arriving competitor from a page that got worse 0.2ms
✓
does not claim a defeat when our position is unknown 0.2ms
src/leads/shared/corpus-relevance.vitest.ts
the Jev path (2026-09-17) · 4 tests
✓
maps the three bands onto the rubric's scores through the probabilities 2.6ms
✓
asks one choice per candidate, criteria as a map, the state carrying the filtered-already rule 0.8ms
✓
uses Jev when rolled out and never calls the model; the reason is a template 1.9ms
✓
falls back to the model when Jev fails, and stays on the model when not rolled out 1.9ms
decideRelevance · 2 tests
✓
is unknown below 3 scored rows — a coin toss is not a verdict 0.3ms
✓
no_fit when the median is under 40, fit at or above it 0.6ms
parseRelevanceScores · 2 tests
✓
reads the JSON, clamps, and never returns more scores than candidates 0.3ms
✓
garbage is an empty sample, not a throw 0.3ms
describeRelevanceAsk / describeCandidate · 1 test
✓
states role, subject and place in the user's terms 0.6ms
assessCorpusRelevance · 3 tests
✓
a low-scoring sample is no_fit, with examples for the reply and its own ledger label 0.6ms
✓
FAILS OPEN: a model failure, a garbled answer or too few rows all leave the rung alone 0.5ms
✓
a matching sample is fit 0.2ms
the judged ask is role and subject only · 3 tests
✓
drops industry and place — the database already applied them and the rows cannot show them 0.3ms
✓
the prompt tells the model the filters already ran and scores a related role 50-79 0.5ms
✓
an ask with only an industry has nothing to judge — the gate stays open 0.2ms
client/send-outcome.vitest.ts
the Sent badge reads the row as it is · 2 tests
✓
a held row (sending) is Delivery unconfirmed, with the next step as its tooltip — it used to read "Sent" 2.6ms
✓
the other statuses are unchanged 0.7ms
a single Send reads three answers, not two · 2 tests
✓
sent; sent but not recorded (the note); unconfirmed; refused (still a draft); refused and held; already gone 0.7ms
✓
a thrown 5xx means the server answered and nothing was sent; any other throw is a dropped connection 0.4ms
"Send all" always says how it ended · 3 tests
✓
everything went: the old sentence 0.4ms
✓
a mixed run — which said NOTHING before: counts, grouped reasons, the held one, and a retry of only the drafts 0.6ms
✓
no retry offer when nothing is still a draft 0.3ms
Resend anyway in the Sent panel · 4 tests
✓
only a held row of the person's own sends gets the button — never a drip step, never a sent one 0.6ms
✓
it asks first, saying plainly it may arrive twice and that nothing is sent by the click 0.6ms
✓
the release's answers: back in Drafts, or kept in Sent with the server's sentence 0.4ms
✓
a draft the server cancelled (its recipient opted out) is badged Not sent, never Sent 0.3ms
the Sent panel: no button on a send still settling, and a count of confirmed sends only · 3 tests
✓
a held row gets the button only when the server says it has settled 0.2ms
✓
a held row still settling says it is waiting, not to go and resend it 0.3ms
✓
the count beside Sent is confirmed sends: held and cancelled rows are listed, never counted 0.3ms
client/sentry-identity.vitest.ts
a signed-in user is identified the way the worker identifies them · 5 tests
✓
sets the Sentry user block with id and email 3.8ms
✓
uses the WORKER'S tag names, so one query works across both projects 0.6ms
✓
trusts the SERVER for internal, never a client guess 0.7ms
✓
an internal account that is NOT an admin is still tagged internal 0.9ms
✓
an admin is tagged on both axes 0.4ms
signing out is a state, not an absence · 2 tests
✓
clears the user block 0.3ms
✓
writes false rather than leaving the tags unset 0.3ms
the loader stub has no setUser — buffer, do not throw · 3 tests
✓
defers through onLoad when only the stub is present 0.7ms
✓
the LAST identity wins when the SDK arrives after a sign-out 0.7ms
✓
does nothing at all when Sentry is absent (ad blocker, offline) 0.9ms
the real call sites · 4 tests
✓
BOTH /api/user/me readers identify — not just one 0.6ms
✓
each reader passes the SERVER'S internal flag, not a local guess 0.6ms
✓
signing out clears the Sentry identity 0.3ms
✓
the loader-stub guard is present at the real call site 0.2ms
scripts/lib/tag-provenance.vitest.mjs
versionFromSource · 3 tests
✓
returns null rather than guessing when the constant is absent 0.4ms
✓
is not fooled by the file's own prose mentioning the name 0.2ms
buildSetterMap — first appearance wins · 3 tests
✓
maps a version to the FIRST commit that set it, not a later carrier 0.7ms
✓
omits versions nothing set — the absence is the finding 0.2ms
✓
skips commits whose version.ts cannot be read (shallow boundary) 0.3ms
classifyTag — the four states, from real measurements · 5 tests
✓
exact: on main, at the setter 0.3ms
✓
off_main: the squash-merge orphan this whole change exists for 0.2ms
✓
off_main wins even when no setter exists — unreachable is the stronger fact 0.4ms
✓
version_never_on_main: a tag naming a release that never shipped 0.2ms
✓
not_setter: on main, but the range would be wrong 0.2ms
isRepairable — a repair needs somewhere to move the tag TO · 3 tests
✓
off_main and not_setter have a setter to move onto 0.2ms
✓
a phantom is NOT repairable — inventing a target is the defect, not the fix 0.1ms
✓
an exact tag is not something to repair 0.1ms
scripts/lib/unit-report-source.vitest.mjs
fetchCheckResults — the check job's results for THIS tree, or a stated reason · 6 tests
✓
reads the newest live artifact named for the tree and returns its results 14.3ms
✓
no token: a reason, and not a single request 1.3ms
✓
no artifact for this tree (a branch merged without being up to date): a reason, never another tree's numbers 0.3ms
✓
an artifact whose own provenance names a different tree is refused 1.2ms
✓
HTTP errors, a network throw, a malformed document: each is a reason, none throws 0.9ms
✓
the token comes from the dedicated name first, and its value is never part of a reason 0.6ms
renderUnitReport — from a provided results document · 2 tests
✓
states the provided counts, the build commit and WHEN THE TESTS RAN, not when it rendered 2.0ms
✓
relPath strips the machine that ran the tests, whichever it was 0.4ms
the fallback — the previous report, unchanged, dated · 4 tests
✓
reads the date and commit of a pre-2026-10-25 report from its header line 0.7ms
✓
adds ONE banner naming the results' date and commit; the rest of the page is byte-identical 2.5ms
✓
prefers the newer results of the live page and the committed copy; an unreachable live page is not fatal 0.6ms
✓
with no previous report anywhere, the page states the gap and carries no count 0.4ms
scripts/unit-test-report.mjs — what `npm run deploy` actually runs · 2 tests
✓
with no results available it does NOT run vitest, exits 0, and republishes the previous report dated 56.8ms
✓
given a results document it renders that document — still without running vitest 56.6ms
src/admin/judge-model-health.vitest.ts
computeJudgeModelHealth — a failover counts against the requested model · 10 tests
✓
requested ≠ served → one attempt and one failure for the requested model, reason from judge_attempts 3.1ms
✓
a cooldown skip is the reason when the pick was skipped without a call 0.6ms
✓
no attempt chain → reason "failover" 0.3ms
✓
a PARSE RETRY with no failover adds no failure — the original model already wrote its own judge_failure row 0.4ms
✓
a parse retry AFTER a failover charges the requested model once, with its own outcome 0.5ms
✓
the reason is the REQUESTED model's own hop, wherever it sits in the chain 0.2ms
✓
…and still when the retry ALSO fails, so no verdict row is ever written 0.5ms
✓
requested === served, and old rows without judge_requested, change nothing 0.3ms
✓
ensemble rows are still skipped; an api_error row (the asked model, no judge_requested) is not a failover 0.7ms
✓
five mistral failovers in a day put it over the 17.1.1 line (> 20%) 0.3ms
scoreAgainstJudge writes the evidence the reader above needs (source) · 2 tests
✓
a parse failure names the model this call asked for, with the chain its served hop marked unparseable 0.5ms
✓
the retry carries that chain and its verdict row joins it ahead of its own 0.2ms
the daily cron reads one page of 1,000 quality rows — the Jev metering rows stay out of it · 1 test
✓
judge_shadow and reply_delivered are excluded at the source 0.3ms
the daily cron pushes a failing judge model to Sentry · 1 test
✓
one reportError per model over 20% with at least 5 attempts, beside the 17.1.1 path 0.5ms
src/admin/provider-balances.vitest.ts
provider-balances — Composio usage (derived from logs) · 4 tests
✓
counts executions in the 30d window and surfaces failures, stopping at the window edge 16.8ms
✓
populates quota_limit (for a usage %) when COMPOSIO_MONTHLY_QUOTA is set 0.7ms
✓
reports an error entry (never throws) when the logs endpoint fails 0.6ms
✓
omits Composio entirely when COMPOSIO_API_KEY is not configured 0.3ms
provider-balances — OmegaIndexer usage (quota − ledger, no balance API) · 5 tests
✓
shows remaining = quota − all-time usage when OMEGA_INDEXER_QUOTA is set 0.6ms
✓
shows credits-used only when OMEGA_INDEXER_QUOTA is not set 0.3ms
✓
treats a null ledger sum as 0 used (no submits yet) 0.3ms
✓
reports an error entry (never throws) when the ledger query fails 1.4ms
✓
omits Omega entirely when OMEGA_INDEXER_KEY is not configured 0.8ms
provider-balances — GitHub Actions billing · 5 tests
✓
reports an error (not a network call) when GITHUB_TOKEN is not set 0.5ms
✓
reports minutes used vs included, and sends the token as a Bearer header 0.7ms
✓
flags paid overage minutes distinctly from within-plan usage 0.6ms
✓
gives the exact scope fix on a 404 (default-scope token lacks billing access) 0.4ms
✓
reports a generic error entry (never throws) on other failures 0.3ms
src/admin/telemetry-tables.vitest.ts
computeOperationsTable — quality score averaging · 3 tests
✓
averages correctly when every score is a number 3.2ms
✓
does not corrupt the average when some scores are strings (Sentry NQZAI/admin advisory bug, 2026-07-23) 0.6ms
✓
ignores a non-numeric score instead of pushing NaN 0.4ms
computeToolRunHealth · 5 tests
✓
buckets every status and computes success_rate over EXECUTED runs only (excludes capped/rejected from the denominator) 0.7ms
✓
a tool with only capped/rejected runs (never actually executed) gets success_rate 0, not NaN or 1 0.3ms
✓
an unlabeled tool falls back to its raw id, not a blank label 0.3ms
✓
sorts by volume descending and keeps the newest last_seen per tool 0.3ms
✓
defaults a missing meta.status to ok, matching the writer default (trackApiCall status defaults unset -> treated as success) 0.2ms
computeDailySpendAndForecast — honours the requested window · 6 tests
✓
defaults to 14 days when no window is passed (back-compat) 1.8ms
✓
returns 30 days when 30 is requested 0.4ms
✓
returns 90 days when 90 is requested — the case the hardcoded slice silently truncated 0.5ms
✓
keeps the NEWEST days, not the oldest 0.4ms
✓
never returns more days than exist, however wide the window 0.3ms
✓
clamps a nonsense window to at least one day rather than returning everything 0.2ms
src/billing/debit-event-keys.vitest.ts
an LLM call the provider did not name — one call, one row · 7 tests
✓
[fail-first] a Jev call metered twice (its own write and the caller's onUsage) is one row, and the replay is already_recorded 37.7ms
✓
[fail-first] replaying the same usage in a later write answers already_recorded and writes nothing 15.4ms
✓
two Jev calls asking the identical question in one turn are two rows (no false collision) 6.7ms
✓
the same question in two different turns is two rows 3.8ms
✓
[fail-first] a Jev row names the provider that served it (R3-P0-02-G3-F01) 2.7ms
✓
[fail-first] an OpenRouter response with no id: the router's write and a caller re-logging result.usage are one row 4.2ms
✓
a named OpenRouter response keeps its provider-id key, unchanged since #643 2.1ms
a provider row whose caller holds the event's name — one event, one row · 5 tests
✓
[fail-first] the same email's send fee reaching the ledger twice, by two paths, is one fee 3.2ms
✓
two different emails are two fees, and one email id under two tenants is two rows 3.1ms
✓
an empty email id is no key at all, never a shared one 0.7ms
✓
[fail-first] trackApiCall with the job's name: a job finalised twice records one completion row 10.1ms
✓
[fail-first] every platform send fee site passes the emails_sent row as its key 6.2ms
a key the writer had to derive, or mint, is labelled · 2 tests
✓
[fail-first] a direct caller with no key inside a unit of work gets a derived (v8) id and meta.key_basis = writer 4.8ms
✓
[fail-first] outside any request scope the key is minted, and that is reported every time 2.8ms
src/billing/run-attribution.vitest.ts
LLM cost resolution + provenance · 6 tests
✓
prefers the provider-reported cost and labels it measured 2.1ms
✓
falls back to the rate table when no cost is reported, labelled estimated 0.5ms
✓
a reported cost of exactly 0 does NOT bypass the free-model floor 0.3ms
✓
a floored free-model turn still bills something, at the same ×10 as everything else 0.3ms
✓
a merely-cheap model keeps its real rate — the floor is only for $0 on BOTH sides 0.3ms
✓
a negative or non-finite reported cost never becomes a bill 0.3ms
platform overhead buckets · 4 tests
✓
covers every background spender found in the Phase 0 audit, plus unrecovered spend 0.3ms
✓
the render marker can never become a charge 0.9ms
✓
unrecovered spend is excluded from what users are billed 0.5ms
✓
the judge is platform overhead — reverting would re-charge users for our own QA 0.2ms
executeTool tool_run meta · 4 tests
✓
the write exists where the tests expect it 0.2ms
✓
the write carries the tail 0.2ms
✓
records caller_aborted only when the signal fired 0.1ms
✓
spreads the tool's run_meta only through the pickRunMeta allowlist 0.5ms
src/chat/evidence-gaps.vitest.ts
what counts as a gap · 7 tests
✓
records a page that would not load, with the status 2.4ms
✓
records our own site WITHOUT repeating the internal instruction 0.7ms
✓
counts a search that RAN and found nothing — status ok is not an answer 0.2ms
✓
says a REFUSAL is a refusal — the reader can act on that 0.4ms
✓
separates rate-limiting, timeout and size from a refusal 0.6ms
✓
is silent for a call that worked 0.3ms
✓
ignores tools whose failure is an ERROR, not a gap in evidence 0.2ms
the footer · 6 tests
✓
renders nothing when nothing failed — silence is the common answer 0.2ms
✓
names what it costs the answer, not just what failed 0.7ms
✓
deduplicates a retried target — three attempts are one gap 0.9ms
✓
caps the list and says how many are hidden 0.3ms
✓
drops a gap with no target rather than printing an empty bullet 0.2ms
✓
never names the tool that failed — the user cares what, not which internal tool 0.2ms
the guardrail backstop (v2.346.2) · 1 test
✓
strips the internal instruction if the model recites it anyway 8.0ms
src/chat/full-audit-scope-words.vitest.ts
every scope word reaches full_seo_audit, not the picker · 8 tests
✓
"run a full seo audit" 44.9ms
✓
"run a complete seo audit" 3.3ms
✓
"run a comprehensive seo audit" 2.6ms
✓
"run a thorough seo audit" 0.6ms
✓
"run a entire seo audit" 0.7ms
✓
"run a whole seo audit" 0.4ms
✓
the scope word survives an inserted "technical" 1.6ms
✓
the phrasings the pattern advertises actually reach it 1.0ms
the two halves cannot drift again · 2 tests
✓
the exclusion defers to the SAME regex the pattern uses 0.6ms
✓
adding a scope word to the constant is enough on its own 0.5ms
what must NOT change — the picker is not the defect · 4 tests
✓
a genuinely ambiguous ask still gets the disambiguation 2.1ms
✓
on-page and off-page keep their own intents 2.1ms
✓
the crawl-depth picker reply still routes 13.2ms
✓
"deep" is deliberately NOT a scope word 1.0ms
src/chat/history-digest.vitest.ts
digestRenderedTables — older assistant messages only · 9 tests
✓
a drafts table in an older assistant message loses Body and keeps Recipient and Subject, with the row count 3.5ms
✓
the latest assistant message is byte-identical, bodies and HTML and all 0.4ms
✓
no HTML tag survives in an older message; a link keeps its text and its URL 0.4ms
✓
contacts and enrich tables are unchanged apart from HTML stripping 0.3ms
✓
users are never touched, and a clean history comes back as the same array and objects 0.4ms
✓
an angle-bracketed address or placeholder survives; real tags are still handled 0.2ms
✓
an escaped \| inside a cell does not split it 0.9ms
✓
the dropped column is the generate_emails presenter's own label 0.8ms
✓
digest before trim: the older drafts turn keeps every recipient inside the 1,200-character clip 0.9ms
the verbatim window keeps its bodies · 3 tests
✓
a drafts table one exchange back keeps every body (its HTML still goes) 0.4ms
✓
the same table, one exchange later (out of the window), loses Body 0.4ms
✓
the window is history-trim's own constant 0.2ms
wiring · 2 tests
✓
the model copy is redacted, then digested, then trimmed 0.2ms
✓
the transcript write never digests 1.2ms
src/chat/record-blocks-guard-exits.vitest.ts
agent loop: every cell of a records block meets the guardrail with the exit's own options · 4 tests
✓
the send log: a model-written subject and the provider's failure reason are read like the reply; the tenant's own recipient and campaign show as they are 257.8ms
✓
the restored conversation shows the table exactly as the person read it 55.3ms
✓
numbers keep their units and stay numbers; a clean table gets no note and no event 21.2ms
✓
a reply the guardrail blocked ships no table beside its safety sentence 38.7ms
shortcut (a plan item's Execute chip): the table it renders is read like the reply · 2 tests
✓
a model-written subject and the provider's reason are read; the tenant's own recipient and campaign show as they are 18.4ms
✓
a key in a cell is withheld whole and reported; a price for what nqzai charges and a "free" claim are redacted 14.7ms
a saved sequence or contact-list name counts as the tenant's once saved · 4 tests
✓
a sequence the model named and saved is announced under that name 25.0ms
✓
the saved sequences table names each as it is; the same name in a model's sentence does not show 44.1ms
✓
the contacts a person just saved are theirs in the table 26.7ms
✓
a saved list is named as it is; a list the model asked for that does not exist stays the model's 43.0ms
the wiring · 4 tests
✓
finishChatReply reads every block FIRST — before any card is judged altered or shown (#613) — and states the count before the judgement 0.9ms
✓
the blocks are read with the exit's own options, the same three guardChips builds 0.5ms
✓
both places a presenter builds blocks record the provenance the exit reads 0.3ms
✓
a blocked reply tears its records down with its artifact 0.4ms
src/chat/scan-offer.vitest.ts
the gate records what it offered · 3 tests
✓
writes the pending offer before returning the chip 2.7ms
✓
the offer is scoped to the conversation that made it 1.0ms
✓
and the turn reports what it cost, like the branch thirty lines above it 0.6ms
accepting the offer runs the offer, not a re-planned turn · 9 tests
✓
the site comes from KV, never from re-reading the message 0.4ms
✓
runs scan_product and NOTHING else 0.5ms
✓
clears the offer, so it cannot be redeemed twice 0.3ms
✓
a FAILED scan falls through instead of reporting success 0.3ms
✓
uses the same composer as the onboarding scan 0.3ms
✓
offers the original ask back, now that it can be answered well 0.5ms
✓
an absent or expired offer falls through rather than guessing a domain 0.3ms
✓
only an ACCEPTANCE triggers it — a message that merely mentions scanning does not 0.7ms
✓
the loop consults that predicate rather than re-implementing it 0.3ms
a compound ask is not an AEO ask · 2 tests
✓
the shortcut stands down when the message also asks for something else 0.2ms
✓
asks the SAME registry the misroute guard reads 0.2ms
src/connectors/notion-blocks.vitest.ts
markdownToNotionBlocks structure · 7 tests
✓
maps heading levels, lists and quotes 3.2ms
✓
collapses h4-h6 onto heading_3 instead of emitting a block type Notion rejects 0.4ms
✓
joins a soft-wrapped paragraph into ONE block 1.2ms
✓
does not swallow the construct that ends a paragraph 0.3ms
✓
keeps a fenced code block intact, newlines and all 0.3ms
✓
terminates on an unterminated fence rather than looping 0.3ms
✓
emits a divider for a thematic break 0.3ms
inlineRichText · 4 tests
✓
marks bold, italic and code runs 0.4ms
✓
links http and mailto targets 0.8ms
✓
renders a javascript: link as plain text, never a clickable block 0.3ms
✓
SPLITS past the 2000-char API limit instead of truncating 0.6ms
notionLanguage · 1 test
✓
resolves aliases and falls back to plain text on anything unknown 0.3ms
chunkBlocks · 2 tests
✓
splits into request-sized batches so a long article is not silently cut at 100 blocks 0.2ms
✓
returns nothing for an empty document 0.1ms
src/email/bounce-class.vitest.ts
classifyBounce · 7 tests
✓
reads 5.1.1 (no such user) as a dead address 2.3ms
✓
reads 4.x.x as transient — the address is fine, the mailbox was not ready 0.5ms
✓
reads a full mailbox as transient even though 5.2.2 is a PERMANENT code 0.2ms
✓
reads "Action: delayed" as transient — the MTA has not given up yet 0.2ms
✓
falls back to the bare SMTP reply when there is no enhanced status 0.4ms
✓
does NOT read "undeliverable" in a subject as permanent 0.4ms
✓
classifies an unreadable bounce as unknown rather than guessing 0.2ms
bounceBlocksSend · 7 tests
✓
lets a contact through when there is no bounce history at all 0.3ms
✓
blocks permanently on a hard bounce 0.9ms
✓
lets a single soft bounce through — this is the lead the old gate threw away 0.2ms
✓
gives up once the softs reach the tolerance 0.4ms
✓
blocks on an UNKNOWN class — an unparseable bounce keeps the pre-fix behaviour 0.2ms
✓
blocks on a NULL class — rows that bounced before migration 058 must not be unblocked 0.3ms
✓
one hard bounce outweighs any number of softs 0.1ms
src/email/email-consent-guard.vitest.ts
the caller half — the shape that cost 5,371 sends · 3 tests
✓
passes on the current tree 102.5ms
✓
catches a marketing call site that drops userId 193.5ms
✓
catches a kind RECLASSIFIED to marketing at a call site that has no id to give 194.8ms
the gate half — four assertions that stayed green through the outage · 8 tests
✓
catches the consent gate being removed outright 131.3ms
✓
catches the gate being moved AFTER the row insert 135.9ms
✓
catches the gate no longer failing closed on an unreadable consent state 132.8ms
✓
the fail-closed assertion survives the message being REWORDED 197.4ms
✓
catches the deleted-account block disappearing 137.0ms
✓
catches the unsubscribe block disappearing 132.6ms
✓
catches a template added without a consent class 134.4ms
✓
catches a second operatorTestSend bypass appearing 166.4ms
it refuses to pass vacuously · 3 tests
✓
fails rather than passing when the template parse finds nothing 136.5ms
✓
fails rather than passing when the call-site parse finds nothing 194.2ms
✓
is wired into the gate 0.4ms
src/email/inbound-attribution.vitest.ts
a bounce that carries no tracking identity changes nothing · 6 tests
✓
an "Undeliverable" subject and X-Failed-Recipients (the audit reproduction) 28.5ms
✓
a mailer-daemon sender with a Final-Recipient line 1.4ms
✓
a null sender and a delivery-status report with our id stripped 1.3ms
✓
a well-formed tracking id we never issued, addressed to the tracking mailbox 1.6ms
✓
is recorded for operators, without the address it named 2.6ms
✓
an unknown tracking id is recorded as such, not as "no id" 1.0ms
a tracking id is one tenant's capability, and reaches no other tenant's rows · 4 tests
✓
a DSN for tenant A's send cannot stop tenant B's sequence, even when A's row names B's contact 3.1ms
✓
a reply to tenant A's tracking address cannot stop tenant B's sequence (P1-08p d7) 3.4ms
✓
the shared writer refuses a recipient lookup that names no tenant 0.7ms
✓
the shared writer refuses a tracking id that belongs to a different tenant than the caller named 0.4ms
genuine mail still lands on the right send · 4 tests
✓
a genuine DSN marks the send it names as bounced, stops that sequence and tells that tenant 2.0ms
✓
a DSN addressed to the tracking mailbox itself is attributed by the address 0.7ms
✓
a bounce of platform mail stamps the transactional row 0.5ms
✓
a genuine reply marks the send replied and pauses that tenant's sequence 1.0ms
src/leads/verify-contacts-deadline.vitest.ts
the deadline stops new rounds and reports the remainder · 6 tests
✓
REPRODUCES THE INCIDENT AND RETURNS AN ANSWER: 24 addresses, ~7s a round, 21s of budget 5.1ms
✓
bills only what it asked about 0.9ms
✓
does not report the unreached addresses as a provider failure 0.6ms
✓
ALWAYS DOES ONE ROUND — an empty result with a charge of nothing is still a wasted turn 0.5ms
✓
a run that fits reports no remainder and does not claim it stopped 0.6ms
✓
the shipped deadline leaves the caller room to return inside the 30s default 0.3ms
a verdict is still only written when one was produced · 1 test
✓
leaves the stored status alone on an unverified address 1.2ms
the caller's deadline and signal bound every address · 7 tests
✓
aborted before the start → no address is asked, nothing billed, and it says so 0.8ms
✓
aborted during round 1 → no round 2, and the signal reached every fetch 0.9ms
✓
a deadline 12 s away → each check gets at most the 9 s left, and no second round 0.9ms
✓
a window under VERIFY_MIN_FETCH_MS (3000 ms) → no round, even the first, when the caller named a deadline 0.5ms
✓
(neg) no caller deadline → the 10 s per-address ceiling, and the first round always runs 0.6ms
✓
progress is monotonic and ends at asked = settled = target 6.0ms
✓
billed moves before the verdict write lands; verdicts only after it 52.4ms
src/middleware/sov-domain-helpers.vitest.ts
registrableCore — the token brand matching runs against · 4 tests
✓
takes the SLD, not the full host 2.0ms
✓
handles two-part TLDs so the core is not the country suffix 0.3ms
✓
does not mistake a subdomain for the brand 0.2ms
✓
degrades without throwing on junk 0.2ms
isNoiseHost / isGenericPlatform · 2 tests
✓
matches the host itself and its subdomains, not arbitrary substrings 0.4ms
✓
keeps a genuine competitor domain out of both buckets 0.3ms
isDefinitionQuery — the ambiguous-brand signal · 2 tests
✓
catches dictionary and translation lookups 0.6ms
✓
does NOT catch a buyer-intent query that merely mentions a product 0.3ms
domainFromChunk — unwrapping Gemini grounding · 4 tests
✓
prefers a domain-shaped title over the vertex redirect URI 0.5ms
✓
falls back to the URI host when the title is prose, not a domain 0.3ms
✓
returns the title rather than throwing on an unparseable URI 0.3ms
✓
returns empty for an empty chunk instead of undefined 0.1ms
normDomain · 2 tests
✓
strips scheme, www and path to a bare host 0.1ms
src/middleware/tap-provisional-share.vitest.ts
the provisional-share rule has ONE definition · 2 tests
✓
lives with the code that produces the share, and both surfaces read it 1.9ms
✓
an ABSENT leaderboard is provisional, not permissive 0.7ms
a provisional share cannot produce an impressions count · 6 tests
✓
withholds the derived figure — null, not zero 0.8ms
✓
keeps the MEASURED half intact 0.3ms
✓
withholds it per query too 0.2ms
✓
states WHY, so the absence is never read as zero 0.4ms
✓
keeps stage 4 in the funnel, carrying its reason instead of a volume 0.3ms
✓
advises what would CLOSE it, and drops the advice written from the figure 0.3ms
a measured share still produces the number · 2 tests
✓
computes impressions when the comparator set supports it 0.6ms
✓
0% against a real field is a FINDING, not a withheld figure 13.4ms
the artifact does not print a withheld figure as 0 · 2 tests
✓
shows an em dash and says it was not estimated 15.8ms
✓
leads with the impressions figure when there IS one 0.4ms
the forensic contract holds the rule even if the arithmetic drifts back · 2 tests
✓
a provisional share carrying an impressions count is a violation 0.4ms
✓
the withheld shape passes, and so does a measured one 0.4ms
src/reports/full-audit-report.vitest.ts
full_seo_audit — §17 gold standard · 9 tests
✓
leads with the constraint, not with how many sub-audits ran 2.1ms
✓
keeps the two half-scores as context cards with their fix prompts 0.7ms
✓
renders all FOUR directive groups, each stating its own absence (GS-011 / FR-030) 0.3ms
✓
an artifact predating the join says so instead of claiming nothing was found (GS-004) 0.5ms
✓
renders cross findings by directive with both sides of the evidence 0.7ms
✓
states what it could not check as a consequence, not as a step list 0.4ms
✓
overall score is the average of PRESENT scores and always <= 100 (was 119/100) 0.7ms
✓
a blocked half reports the consequence, never the vendor or the raw error 0.4ms
✓
has a feedback mount and no "Cluster N" headers 0.6ms
full_seo_audit — the source ledger (spec §5.4) · 3 tests
✓
names every source, its age, and whether it was on file at all 0.5ms
✓
drops the old "Audit evidence" grid — it restated the on-page report verbatim (FR-040) 0.4ms
✓
an Expect item renders with its method visible, not just its conclusion 0.4ms
full_seo_audit — a single-source finding is never sold as a join · 2 tests
✓
counts probes as faults but does NOT claim they came from the join 0.4ms
✓
says how many DID need the join when some genuinely did 0.4ms
src/reports/publish-controls.vitest.ts
planPublishControls — live state decides, every time · 4 tests
✓
nothing connected → connect routes for both, plus the coding-agent fallback 2.5ms
✓
WordPress connected later → publish appears (no regeneration) 1.2ms
✓
Notion connected later → send appears 0.5ms
✓
both connected → both, no fallback 0.4ms
planPublishControls — the stack fingerprint cannot outrank live state · 3 tests
✓
non-WordPress stack + WordPress NOT connected → no WordPress route (correct) 0.3ms
✓
non-WordPress stack + WordPress CONNECTED → publish shows anyway 0.2ms
✓
Notion is never suppressed by stack — a private workspace is not the site CMS 0.3ms
planPublishControls — unknown state never guesses · 2 tests
✓
unknown → no publish and no connect controls, fallback only 0.2ms
✓
unknown names the stack when it knows it 0.6ms
planPublishControls — the subtitle always describes the buttons shown · 3 tests
✓
connect-only state mentions connecting, not just copying 0.3ms
✓
live state names the live destinations 0.2ms
✓
suppressed WordPress + nothing live → mentions only Notion 0.2ms
planPublishControls — surface differences are explicit, not accidental · 2 tests
✓
panel leads with publish-live; chat leads with draft 0.8ms
✓
both surfaces offer the SAME destinations — only the order/emphasis differs 0.3ms
src/routes/legal-pages.vitest.ts
Terms of Service · 6 tests
✓
is a business-use contract under Pennsylvania law with individual arbitration 29.2ms
✓
caps liability at three months of fees and puts every obligation under the cap 1.9ms
✓
the customer indemnity names the outbound-email and contact-data risks and a procedure 1.7ms
✓
allocates outbound-email duties on both sides, and never claims to have no role 2.2ms
✓
AI outputs, third-party data and roadmap items are disclaimed; content is licensed, never trained on 1.5ms
✓
refunds are governed only by the Refund Policy, and the Terms no longer say "non-refundable" 2.0ms
Privacy Policy · 6 tests
✓
is a notice, not a contract, and separates the roles 1.6ms
✓
keeps the Google Limited Use disclosure and scopes verbatim 1.5ms
✓
the sub-processor schedule names the providers the code actually calls 2.0ms
✓
states the retention periods the infrastructure actually implements 1.9ms
✓
deletion says what remains, including undeleted contacts, and gives corpus removal 1.3ms
✓
regional rights sections exist and the transfer position names a DPA on request 1.3ms
Refund Policy · 2 tests
✓
is the operative refund text and settles the negative-balance and chargeback questions 1.0ms
✓
all three pages carry the same contact address and the same date 1.4ms
src/runtime/public-tool-budget.vitest.ts
the shared daily token budget · 6 tests
✓
stops the reservation that would exceed it and reports why 28.8ms
✓
fails CLOSED when the counter cannot be reached: a budget that cannot be read is a budget that is spent 1.5ms
✓
is inactive when the counter is unbound (local dev, tests) — unbound is not failing 0.6ms
✓
is ONE budget shared by both LLM routes: spend on one is spend on the other 13.0ms
✓
a counter that cannot be reached answers a plain "try again later" and calls no model 2.2ms
✓
a cache hit costs no budget: the same URL twice runs the model once and spends once 7.0ms
the budget is RESERVED before the run, so a concurrent burst cannot pass it · 5 tests
✓
12 concurrent calls with room for two reservations run exactly two models 27.5ms
✓
the V12-edge reproduction: at 1,999,800 used, a burst of 12 runs nothing and the cap is never passed 8.3ms
✓
settle returns the unused part of the reservation, and adds an excess 2.7ms
✓
a run that throws returns its whole reservation 2.8ms
✓
wrangler binds PUBLIC_BUDGET to DailyBudgetDO with its own migration, and the entry exports the class 8.5ms
the cache key is a canonical form of the URL · 3 tests
✓
ignores the fragment, tracking parameters, parameter order and host case 3.3ms
✓
still tells two genuinely different pages apart 2.0ms
✓
a query-string decoration no longer buys a fresh model call 1.9ms
src/runtime/scope-bleed-harness.vitest.ts
source 1 — two concurrent requests in one isolate · 1 test
✓
each ledger row is owned by the request that wrote it, however the awaits interleave 41.8ms
source 2 — two tenants in one cron invocation (the real Monday SOV loop) · 2 tests
✓
tenant A's deferred ledger write, landing while tenant B's window is open, is still A's 9.6ms
✓
a tenant scope inherits the invocation (entry, unit, env) and nothing of the previous tenant 1.0ms
source 3 — two sibling tools fanned out in one turn · 2 tests
✓
each sibling owns its run: distinct run_ids, its own run_tool, both ownsRun — while the turn stays one 7.1ms
✓
the child scope owns exactly RUN_SCOPE_FIELDS and passes every other field through to the turn 2.8ms
source 3b — a background job run inline from inside a turn · 1 test
✓
the job's own window opens and closes without touching the turn's identity, tokens or turn id 2.4ms
G3(d) marker — a mismatch is an IDENTITY disagreement, never a closed turn · 3 tests
✓
a run that settles after its turn closed is NOT flagged — recorded as caller_turn_closed 3.7ms
✓
a run that settles under ANOTHER user's context IS flagged scope_mismatch, its real status kept in exit 4.4ms
✓
a run that settles while ANOTHER run owns the context is flagged; the run's own context is clean 1.1ms
wiring — src/index.ts runs on the primitives this file proves · 5 tests
✓
the sibling fan-out gives each tool call its own child run scope 0.7ms
✓
executeTool mints its run through openRunScope and closes it through closeRunScope 0.9ms
✓
the G3(d) marker stamps the closure caller and writes scope_mismatch when the context disagrees 0.7ms
✓
every inline background-job callback runs the job in its own tenant scope 1.5ms
✓
every per-message loop in the queue consumer enters a tenant scope first 0.6ms
src/runtime/tool-caps.vitest.ts
EXTERNAL_TOOL_CAPS completeness · 3 tests
✓
covers every tool with a provider cost estimate 2.1ms
✓
aliases resolve to existing canonical buckets 0.8ms
✓
cap labels never name a backend vendor (CLAUDE.md §2) 1.1ms
resolveRunLimit for a test-cap tenant · 3 tests
✓
search_leads is a DAILY allowance (default 3), not free's 3-per-lifetime 0.5ms
✓
a signed-up user is untouched by the test allowance 0.3ms
✓
every other tool still resolves to the FREE count for a test-cap tenant 0.2ms
isTestCapUser · 2 tests
✓
is false when TEST_CAP_USER_IDS unset 0.2ms
✓
matches ids case-insensitively in a comma list with spaces 0.2ms
checkExternalToolCap scope · 3 tests
✓
NEVER caps a signed-up user, even with an exhausted bucket 0.5ms
✓
caps a test tenant on an exhausted bucket 186.2ms
✓
ignores tools without a cap entry even for test tenants 0.4ms
effectiveSendLimits · 3 tests
✓
prod tenants keep the S3 constants 0.4ms
✓
test tenants get the testing defaults 0.2ms
✓
env overrides apply, junk values fall back 0.2ms
src/tools/aeo-visibility-schema.vitest.ts
the previously-undeclared arguments are now part of the contract · 4 tests
✓
declares engines, which the dispatch has always read 1.9ms
✓
declares brand, which the dispatch has always read 0.4ms
✓
declares brand_aliases, which the dispatch has always read 0.2ms
✓
has no required fields — an omitted site resolves to the saved domain 1.0ms
engines — the cost lever · 5 tests
✓
accepts every engine we actually price, bare 0.9ms
✓
accepts the picker's real "engine:model" values, slashes and dots included 0.4ms
✓
rejects an engine we do not price — it would run with no cost estimate 0.3ms
✓
rejects a sentence where an engine belongs 0.2ms
✓
states in its own text that engines are the cost lever 1.0ms
the remaining fields are bounded · 5 tests
✓
accepts a realistic full call 0.4ms
✓
rejects a country that is not a two-letter code 0.3ms
✓
rejects a sentence in site rather than measuring the wrong brand 0.2ms
✓
rejects an off-schema field instead of silently ignoring it 0.2ms
✓
names no vendor and no USD price in the model-facing definition 0.4ms
src/tools/router-contradictions.vitest.ts
settled rulings are not re-opened elsewhere in the same prompt · 4 tests
✓
never tells the model to ask which lead source to use (R3, owner 2026-07-30) 2.5ms
✓
still states the rule positively, so the absence is a decision and not an omission 0.4ms
✓
does not list the source question among the mandated gates either 0.6ms
✓
routes the shortfall to the paid source rather than to a question 0.3ms
the prompt does not contradict itself about calling search_leads · 1 test
✓
says both "never speculatively" and how the user asks for it, without a third rule 0.4ms
a request that names WHO does not get the existing-or-new gate · 4 tests
✓
does not carry the unconditional "list_contacts first" order any more 0.5ms
✓
states the specified-request branch positively, so its absence would be a failure 0.5ms
✓
keeps the check-existing branch for the ask it was actually written for 0.4ms
✓
agrees with the list_contacts description instead of contradicting it 0.6ms
the judge is graded against the rules that actually ship · 4 tests
✓
does not tell the judge the source question is mandatory 0.3ms
✓
tells the judge that a named audience goes straight to the search 0.3ms
✓
still tells the judge the ask is mandated when nobody was named 0.2ms
✓
splits on the SAME discriminators as the agent prompt 1.6ms
the substitution above is only sound while these tools are always sent · 1 test
✓
search_leads and list_contacts are CORE 0.3ms
src/tools/semantic-enum.vitest.ts
the SaaS failure, replayed · 5 tests
✓
is the semantic-distance case: zero lexical candidates 2.9ms
✓
rejects — but now hands the model the full vocabulary to map into 3.8ms
✓
accepts the mapped retry 0.3ms
✓
does not ship the whole taxonomy when five candidates suffice 1.7ms
✓
gives a sentence no vocabulary 1.6ms
droppable marking respects structure · 2 tests
✓
marks the optional enum filter droppable 1.4ms
✓
never marks a cross-field rule droppable 0.4ms
degrade, don't die — the shared implementation the seam actually runs · 7 tests
✓
DEGRADES ON THE FIRST FAILURE — the retry it used to wait for does not happen 1.3ms
✓
degrades on the second failure of the same field, and says what it dropped 1.8ms
✓
the rescue does not depend on a counter the caller increments AFTERWARDS 5.1ms
✓
the AGENT path states the drop itself — it is not left to the model 4.7ms
✓
a REQUIRED field is still never dropped — degrading structure is not a rescue 0.2ms
✓
refuses to degrade when dropping would leave nothing to search on 1.3ms
✓
never drops a schema-required field 0.3ms
src/seo/aeo-presence.vitest.ts
readAeoPresence — the live "effectively absent" run · 6 tests
✓
does not grade a cited site absent 2.4ms
✓
counts the field the citation sat in, and where in it 0.4ms
✓
keeps citation, mention and share of voice as three numbers (AEO-003) 0.4ms
✓
states the honest reading in answers RECEIVED (AEO-001) 0.4ms
✓
names absence as the reading this run does not support 0.3ms
✓
carries the vintage of the snapshot it read 0.2ms
readAeoPresence — the states that are genuinely absent · 5 tests
✓
grades a run with no citation and no mention as absent 0.4ms
✓
separates mentioned-but-not-cited from absent 0.4ms
✓
reports "not measured" rather than absent when no answer came back 0.6ms
✓
grades a top-of-field citation as present 0.5ms
✓
never claims a field size for a run that captured no sources (trap 14) 0.4ms
readAeoPresence — a silent engine is not an answer (AEO-002) · 3 tests
✓
counts only the engines that actually answered 0.3ms
✓
states the honest denominator rather than the execution count 0.2ms
✓
still prefers the stored count when the snapshot carries one 0.2ms
src/seo/ai-optimization.vitest.ts
aioReferencesFromItem · 2 tests
✓
parses top-level and nested element references, dedupes, derives domain from url 2.7ms
✓
returns empty for an item without references 0.7ms
DFS engine map · 1 test
✓
covers the four consumer engines used by seo_geo_visibility 0.2ms
distillSeedKeyword · 4 tests
✓
strips question framing + stopwords down to keyword-shaped terms 0.6ms
✓
falls back to raw words when everything is a stopword 0.2ms
✓
returns empty string for empty input 0.2ms
AI Mode is a separate surface, not a fifth engine · 3 tests
✓
stays out of the engine matrix, so a user cannot deselect it as if it were a model 0.5ms
✓
is priced per query and costs more than the AI-Overview check 0.6ms
✓
is inside the fan-out estimate the approval card quotes 0.2ms
AI Overview references come only from known organic elements · 4 tests
✓
counts the element types the live response actually returns 0.3ms
✓
keeps the block-level references alongside them 0.3ms
✓
does NOT count references from an element type it does not recognise 1.2ms
✓
reports an unknown type rather than skipping it quietly 1.6ms
src/seo/audit-freshness.vitest.ts
reading the last run · 4 tests
✓
reads the snapshot store for the two audits, each under its own audit_type 2.4ms
✓
counts only COMPLETED spider runs 0.4ms
✓
scopes to the tenant and the site 0.4ms
✓
does not query at all without a site — nothing to compare against 0.6ms
when it must say nothing · 3 tests
✓
is silent when the site was never measured — the run is the whole point 0.4ms
✓
is silent in the grey zone rather than guessing 0.3ms
✓
treats a future timestamp as a clock problem, not a finding 0.2ms
when it speaks · 5 tests
✓
names the age and leaves the decision alone 0.8ms
✓
says "earlier today" rather than "0 days ago" 0.5ms
✓
pluralises, and uses each tool's own words 0.3ms
✓
never names a backend vendor (CLAUDE.md §2) 0.6ms
✓
fires right up to the threshold and stops exactly at it 0.2ms
age arithmetic · 2 tests
✓
is null for an unparseable or absent stamp, never 0 0.2ms
✓
measures in whole and fractional days from the stamp 0.2ms
src/seo/bing-ai-report.vitest.ts
parsing · 6 tests
✓
reads the real export: BOM stripped, percent shares as fractions, empty topic kept empty 4.2ms
✓
handles commas, quotes and newlines inside quoted fields 0.4ms
✓
reads a Pages export by its URL column, and thousands separators in counts 0.5ms
✓
refuses a file that is not an AI Performance export, naming its columns 0.4ms
✓
a share column with no "%" and values ≤ 1 is read as a fraction 0.3ms
✓
takes the export date from Bing's file name 0.6ms
numbers · 4 tests
✓
headroom = citations other sites took, from Bing's definition of share 0.3ms
✓
share is a share of the whole, not an average of per-query shares 0.8ms
✓
compares two exports: totals, added and dropped queries, biggest movers first 1.0ms
✓
low-share queries need demand and are ranked by headroom, not by share alone 0.3ms
page matching (deterministic floor) · 2 tests
✓
shortlists by overlap with the slug and the title 0.6ms
✓
labels what it is: a word match, the most-cited page, or none 0.6ms
panel suggestions (step 3) · 2 tests
✓
spreads across topics, skips near-duplicates and one-word queries, and respects the existing panel 0.6ms
✓
uses a supplied match over the slug floor 0.5ms
src/seo/full-audit-needs-audits.vitest.ts
the deliberate empty path is not an error · 6 tests
✓
full_seo_audit returns guidance, never `error` 1.6ms
✓
aeo_full_audit returns guidance, never `error` 0.3ms
✓
full_seo_audit ships the executable chips FR-051 promised 0.2ms
✓
aeo_full_audit ships the executable chips FR-051 promised 0.1ms
✓
the SEO chips are the SAME strings the picker offers, not a paraphrase 0.9ms
✓
detectSoftFailure still tests `error` first — which is WHY the field name mattered 0.3ms
the empty case renders as a report, not a bare sentence · 1 test
✓
full_seo_audit has a needs_audits branch, like its AEO twin 0.4ms
every author agrees the tool runs no crawl · 3 tests
✓
the chip no longer promises a crawl it cannot do 0.2ms
✓
the registry no longer ROUTES THE MODEL to it at all — one author fewer 0.6ms
✓
the timeout comment no longer describes the removed nested runs 0.3ms
the nothing-measured result survives every consumer · 4 tests
✓
formatToolResult returns the guidance instead of throwing on result.onpage 5.6ms
✓
the crash is pinned: the old shape would have read .score off nothing 1.2ms
✓
the chips reach the user, and are the tool’s own 1.6ms
✓
a REAL error still formats as an error — the branch is not a catch-all 0.2ms
src/seo/geo-position-band.vitest.ts
the report states where you rank, and admits what it could not see · 5 tests
✓
renders the band and its measured citation rate 7.0ms
✓
says plainly when the page is not in the top 10, rather than implying it does not rank 0.4ms
✓
discloses the top-10-vs-top-20 truncation through the generic *_note pass 0.2ms
✓
shows the user's own page signals beside the competitors' 0.3ms
✓
does not JSON-dump the result 0.4ms
#57 changed the cost, so the estimate changed with it · 4 tests
✓
prices the added SERP lookup 0.3ms
✓
carries a per-call estimator, because the plan narrows what it runs 0.7ms
✓
quotes a free-tier run at the ONE engine it actually bills, not at four 0.4ms
✓
falls back to the static ceiling when the plan is unknown 0.5ms
the visibility check shows movement, because the history was already there · 5 tests
✓
reports the lift against the previous run 13.4ms
✓
reports a drop just as plainly 0.3ms
✓
calls a FIRST check a baseline, not "no change" 0.4ms
✓
says no change only when the number genuinely did not move 2.0ms
✓
a basis change reports NO delta and says why — the case the old field could not express 0.3ms
src/seo/google-ads-keywords.vitest.ts
parsing what Google actually returns · 5 tests
✓
reads volumes that arrive as strings 3.3ms
✓
an idea with no metrics is null volume, NOT zero 0.4ms
✓
keeps a genuine zero distinct from a missing one 0.3ms
✓
lowercases and de-duplicates, because two seeds converge on one idea 0.4ms
✓
survives a shape that is not a result list 0.6ms
the seed is exactly one of three shapes · 3 tests
✓
maps each to the field Google expects 0.5ms
✓
never sends more than 20 seeds — Google 400s rather than truncating 0.3ms
✓
sends exactly one seed field, never two 0.5ms
it says why it cannot run · 2 tests
✓
names the missing credential instead of returning a bare empty list 0.6ms
✓
makes no request when it is not configured 1.0ms
the live call · 4 tests
✓
authenticates with the broker token header, not Authorization 24.9ms
✓
always bounds pageSize — the unbounded response is thousands of ideas 0.8ms
✓
degrades with a named reason rather than throwing 3.8ms
✓
distinguishes an access revocation from an ordinary failure 1.3ms
src/seo/revenue-attribution.vitest.ts
revenue-attribution · 12 tests
✓
every attribution query carries include_all_channels + skip_snapshot (organic-filter guard) 1.7ms
✓
classifies every AI engine referrer as AI Chat Engines 0.6ms
✓
classifies search/social/email/direct/referral/other buckets 0.2ms
✓
never classifies (direct)/(not set) as AI 0.1ms
✓
share-of-voice shares sum to ~100 and AI bucket survives low volume 1.1ms
✓
guards AOV/conversion division by zero and flags missing ecommerce 0.3ms
✓
degrades per-section on partial failure without tripping the advisory 0.3ms
✓
returns a single error when every query fails 0.2ms
✓
formats GA4 dates and sorts the daily trend 7.5ms
✓
fetchPropertyCurrency falls back to null on non-200 and returns the code on 200 26.2ms
✓
fetchRevenueAttribution requires Google connected 0.9ms
✓
fetchRevenueAttribution assembles stubbed query results end-to-end 1.1ms
fetchSeoGoogleMerge regressions (attribution must never break the organic join) · 2 tests
✓
REGRESSION: attribution failure leaves organic rows/insights intact 9.0ms
✓
REGRESSION: successful attribution attaches without altering the organic row shape 0.6ms
src/seo/stack-fingerprint.vitest.ts
detectStackFingerprint — frameworks · 3 tests
✓
nextjs pages-router via __NEXT_DATA__ 25.5ms
✓
nextjs app-router via /_next/ without __NEXT_DATA__ 0.8ms
✓
nuxt / sveltekit / gatsby / astro / remix markers 0.9ms
detectStackFingerprint — CMS and builders · 4 tests
✓
wordpress + yoast plugin 0.3ms
✓
wordpress + rank math 0.4ms
✓
shopify / webflow / wix / squarespace / framer 0.3ms
✓
generator meta fallback is medium confidence 0.3ms
detectStackFingerprint — hosting + unknowns · 3 tests
✓
host detection from headers 0.5ms
✓
bare react is low confidence; empty page is null/low 0.5ms
✓
accepts a real Headers object 1.2ms
stackGuidance — prompt placement snippets · 4 tests
✓
nextjs app-router points at app/layout.tsx 0.5ms
✓
wordpress+yoast prefers the plugin UI over code 0.2ms
✓
no-code builders route to settings pages, static files flagged unsupported 0.2ms
✓
low-confidence and null fingerprints yield NO guidance (generic fallback) 0.2ms
client/plan-open-telemetry.vitest.ts
the counts are transported, not recounted · 3 tests
✓
reads all five numbers off the server-baked marker 3.1ms
✓
a report with no marker yields null — never a zero-filled object 0.4ms
✓
a malformed attribute degrades to 0 rather than NaN 1.0ms
the server authors the counts · 3 tests
✓
bakes a plan-open-marker carrying all five attributes 1.6ms
✓
executable uses the SAME condition that renders the Execute button 0.5ms
✓
the marker is inside the plan branch only 0.6ms
both entry points emit, and only for plans · 5 tests
✓
the live panel and the stored artifact each call trackPlanOpened 0.4ms
✓
each emission is GATED on the marker being present 1.8ms
✓
trackPlanOpened is imported, not shadowed by a local helper 0.6ms
✓
the event carries executable_count and the precomputed had_executable 0.3ms
✓
source distinguishes the live plan from a snapshot 0.2ms
the event has a reader · 2 tests
✓
plan_opened is in the admin panel TRACKED_EVENTS list 0.2ms
✓
the panel family that raised this question is also read now 0.3ms
src/admin/defect-class.vitest.ts
it never guesses · 3 tests
✓
a session with no render manifest is UNCLASSIFIED, not a defect 2.1ms
✓
NEVER assigns a root cause 1.5ms
✓
carries the EVIDENCE, not a restatement of the label 0.3ms
the classes, each pinned to a session that really happened · 8 tests
✓
judge — scored 1.00 and delivered nothing 0.2ms
✓
presentation — 21 rows reached the user and it still scored 0.68 0.2ms
✓
functional — tools ran, zero rows 0.2ms
✓
interface — a tool ran and reported an empty outcome 0.3ms
✓
usability — never got past being asked things 0.3ms
✓
performance — slow, and nothing to show for it 0.6ms
✓
none — delivered and judged acceptably 0.2ms
✓
an ARTIFACT counts as delivery even with no rows 0.3ms
ordering is a decision, not an accident · 2 tests
✓
a judge defect outranks everything it would otherwise hide 0.2ms
✓
a slow session that DID deliver is not a performance defect 0.1ms
src/billing/count-turn-platform-sends.vitest.ts
countTurnPlatformSends — the query · 2 tests
✓
counts platform_send rows of THIS tenant and THIS turn, filtered on provider 3.3ms
✓
the literal matches the provider send_emails itself writes, one row per sent email 1.5ms
countTurnPlatformSends — null, never a false 0 · 11 tests
✓
no turn id or no user id → null, and nothing is asked 0.6ms
✓
a failed read → null 1.2ms
✓
a non-numeric count (null count) → null, never 0 0.3ms
✓
a non-numeric count (empty-string count) → null, never 0 0.4ms
✓
a non-numeric count (numeric string) → null, never 0 0.2ms
✓
a non-numeric count (missing aggregate) → null, never 0 0.2ms
✓
a non-numeric count (missing aggregate root) → null, never 0 0.5ms
✓
a non-numeric count (null response) → null, never 0 0.2ms
✓
a non-numeric count (NaN) → null, never 0 0.2ms
✓
a non-numeric count (negative) → null, never 0 0.1ms
✓
a real zero is 0 — the ledger answered, and it holds no sends 0.3ms
src/billing/failover-not-billed.vitest.ts
a turn with one failover and one answer charges only the answer · 12 tests
✓
the router records BOTH attempts — the failed one under :failover 35.9ms
✓
[fail-first] the balance (legacy billing) is debited the answer only 8.4ms
✓
[fail-first] the balance (cost billing) is debited the answer's cost only 11.7ms
✓
the per-turn usage footer already counted the answer only (control) 3.1ms
✓
[fail-first] the refund bound for the turn is the answer only, so a refund cannot return tokens never charged 3.5ms
✓
[fail-first] the usage page reports the answer only, and agrees with the balance 5.2ms
✓
[fail-first] the usage-breakdown tool reports the answer only, and agrees with the balance 11.9ms
✓
[fail-first] the usage page and breakdown leave platform overhead out, as the balance does 8.3ms
✓
[fail-first] the usage event reports the failed attempt as a failure 3.7ms
✓
a row with no context still counts — the exclusion must not drop NULLs (SQL: NULL NOT LIKE x is unknown) 1.4ms
✓
credits are untouched: a grant still lifts the balance 3.0ms
✓
isFailoverContext names only the suffix 0.7ms
the admin cost view still sees both attempts — nqzai paid for them · 1 test
✓
tenant economics counts the failed attempt's cost and tokens 9.7ms
src/billing/onpage-resume-uncarried-ceiling.vitest.ts
V12b-money-F01 Gap1 — the world reproduces the verifier's run · 2 tests
✓
the card is 509,500; 20 rendered pages cost 150,000, 50 cost 375,000; off-page at 1.5x its line is 509,250 3.1ms
✓
a turn with no card leaves its uncollected crawl ceiling-less (both trees) 61.6ms
V12b-money-F01 Gap1 — re-ask: a CARD resumes the ceiling-less crawl and its pages fetch fails again · 3 tests
✓
[fail-first] the verifier's run: card total ≤ 509,500, the excess absorbed (was: 659,250) 60.9ms
✓
[fail-first] 50 rendered pages, off-page at its line, "Check crawl results": 509,500 with 205,000 absorbed and the note (was: 714,500) 31.8ms
✓
[fail-first] the same, collected by asking again and taking the 25K depth chip: the crawl settles against the card that resumed it 26.3ms
V12b-money-F01 Gap1 — the depth chip resumes the ceiling-less crawl · 1 test
✓
[fail-first] the chip's printed 25K holds when the resumed crawl leaves uncollected again (was: 375,000) 12.1ms
V12b-money-F01 Gap1 — a queued job resumes the ceiling-less crawl · 2 tests
✓
[fail-first] the job's own ceiling and unit go on the marker; "Check crawl results" then holds at its 170,000 share (was: 375,000) 13.6ms
✓
[fail-first] the hourly sweep collects it: a no-card job left it, a carded job resumed it — held at the carded job's 170,000 (was: 375,000) 62.8ms
V12b-money-F01 Gap1 — controls (both trees) · 3 tests
✓
a resume by a turn that has no card either carries nothing: billed in full when collected 10.1ms
✓
a resumed crawl that ALREADY carries an earlier card keeps it: the second card neither re-labels it nor gives up its own room 25.7ms
✓
a job resuming its OWN crawl (the marker already names its unit) leaves the marker as it is 5.0ms
V12b-money-F01 Gap1 — "Check crawl results" never runs under a ceiling of its own, pinned · 2 tests
✓
it has no price, so no card can name it 0.4ms
✓
the onpage_check shortcut opens no ceiling before it runs 4.0ms
src/billing/tool-costs.vitest.ts
tool-costs — cost gate · 13 tests
✓
has valid cost-estimate values 2.9ms
✓
formats token counts 0.3ms
✓
builds the cost-gate message 0.4ms
✓
builds the cost-approval card 0.3ms
✓
resolves cost approval by mode 0.6ms
✓
pins the cost-gate threshold 0.2ms
✓
write→consume happy path 2.1ms
✓
consume of a missing record is expired 0.2ms
✓
double consume is one-shot 0.5ms
✓
fails closed when KV is unbound 0.2ms
✓
recalibrated AEO fan-out costs scale with engines × prompts 0.4ms
✓
recalibrated aeo_visibility covers the 2026-07-13 incident's real max spend 0.1ms
✓
every tool implicated in the 2026-07-13 audit now has a declared estimate 0.1ms
src/billing/tool-repricing-2026-09.vitest.ts
entity_audit is priced against what it actually costs to deliver · 3 tests
✓
quotes the measured p90, not the median 1.9ms
✓
the pre-2026-09-12 value would under-quote the p90 0.4ms
✓
does not cross the cost gate 0.2ms
the structural trap: a table entry is not a quote · 3 tests
✓
priceOfTool exceeds the raw table entry on the agent route, by exactly the floor 0.3ms
✓
costOfCall is still provider+llm only — the floor is added above it 0.2ms
✓
a shortcut dispatch pays no orchestration floor 0.2ms
the repricing sweep lands on measured p90 · 7 tests
✓
seo_content_ideas p90 is the measured figure with only the SERP leg re-priced (DECISIONS #126) 0.2ms
✓
seo_content_brief quotes its p90 (n=61) 0.2ms
✓
generate_emails quotes its p90 (n=30) 0.4ms
✓
seo_content_ideas quotes its p90 (n=41) 0.2ms
✓
only tools with a tier-A sample were touched 0.3ms
✓
none of them crosses the gate — repricing must not smuggle in a confirm card 0.2ms
✓
seo_write_content is knowingly left under-quoted, and still does not gate 0.2ms
src/chat/aeo-brief-misroute.vitest.ts
the three turns that produced this fix · 4 tests
✓
"dashboard" no longer opens the engine selector 17.4ms
✓
"cmo" no longer opens the engine selector 4.2ms
✓
"omnibus" no longer opens the engine selector 0.2ms
✓
each names well past the three-subject floor 0.5ms
REAL visibility asks still route — the fix must not eat its own intent · 6 tests
✓
still claims: "Check my AI visibility for detailingdevils.com" 0.6ms
✓
still claims: "Analyze how AI answer engines discover, describe and" 0.4ms
✓
still claims: "am I cited by chatgpt" 1.1ms
✓
still claims: "Run an AEO check" 0.2ms
✓
still claims: "is my brand visible in AI search" 0.6ms
✓
TWO subjects is still a question, not a brief 0.4ms
the count is a SHAPE, not a keyword list · 3 tests
✓
a phrasing nobody has written yet is still caught 0.3ms
✓
does not disturb the carve-outs that already existed 0.6ms
✓
a message naming no subject at all is not a brief 0.1ms
src/chat/backup-wired.vitest.ts
the nightly backup stays plugged in · 8 tests
✓
passes on the current tree 38.1ms
✓
a deleted workflow is the CODE breaking the rule — exit 1, not the stale-parser exit 2 73.0ms
✓
still exits 2 when the workflow is present and the patterns stop matching 70.6ms
✓
catches a schedule that has been removed 74.1ms
✓
catches a dump that no longer dumps 67.8ms
✓
catches a size floor that has been deleted — an empty dump would upload green 69.0ms
✓
catches an upload nobody reads back 68.7ms
✓
catches a missing-secret branch that passes instead of failing 67.6ms
the restore side, because a backup nobody can restore is a file · 4 tests
✓
catches a runbook that stopped stating RPO/RTO 69.8ms
✓
fails once the last drill is older than 90 + 21 days 67.2ms
✓
fails when the drill log is gone — a drill nobody recorded is a drill nobody can date 68.9ms
✓
names the drill scripts it requires, so deleting one cannot go unnoticed 0.4ms
the guard is wired, or it is a script nobody runs · 1 test
src/chat/capped-totals.vitest.ts
P4-06-F01: seo_list_keywords names the registry, not the page · 4 tests
✓
the reply says 1,258 saved and that 200 are shown — never "200 saved" 21.0ms
✓
the table footer counts the registry 0.9ms
✓
the cut note names the ranking pool when the registry outgrew the fetch 0.4ms
✓
the denominator is an aggregate count, not the length of a capped fetch 1.7ms
P4-06-F01: list_contacts — a count is about the table, membership is a lookup · 3 tests
✓
the model's copy holds no rows and says it cannot judge membership 1.3ms
✓
list_contacts can look one address up across every saved contact 1.1ms
✓
the shortcut formatter does not call a ten-row table the whole set 0.5ms
P4-06-F01 sweep: the same shape elsewhere · 6 tests
✓
ga4_report_v2 footer uses the property row count 0.3ms
✓
content ideas name the real count when 15 are shown 0.7ms
✓
backlink tables cut at ten carry the domain count 0.6ms
✓
a top-20 GSC / GA sum is not called the site total 0.5ms
✓
an enrich run cut by the plan says so 1.4ms
✓
the 10-page losers table counts every page that fell 0.4ms
src/chat/chip-guard-exits.vitest.ts
agent loop: an option the guardrail would alter never ships as a chip · 4 tests
✓
the probe: an option naming a supplier is dropped, and the clean options beside it ship 161.1ms
✓
an option quoting a price, or calling something free, is dropped 43.4ms
✓
an answer whose every option is dropped keeps the generic three, never no chips at all 23.3ms
✓
a confirm chip the guardrail would alter is dropped AND reported, never quietly 45.0ms
shortcut: a suggested search the model wrote is read like the reply · 1 test
✓
the scan reply drops the search naming a supplier and keeps the others 54.5ms
the tenant's own records and the product's own chips keep their chips · 5 tests
✓
agent loop: a figure the person typed is theirs in a chip too (the exit's own userEcho) 13.3ms
✓
agent loop: a saved competitor that is a supplier's domain keeps its chip; the model naming that supplier any other way does not 26.6ms
✓
agent loop: a campaign the tenant named after a supplier keeps the chip the tool builds for it 52.9ms
✓
shortcut: the resume confirm of that campaign keeps its chips, and the chip under the card resumed it 37.6ms
✓
agent loop: the send card ships with its own confirm chip bound to it, and the product chips beside it 35.9ms
the wiring · 3 tests
✓
finishChatReply reads every chip after the rewrites that add chips and before anything is offered, judged or bound from them 0.9ms
✓
the guard drops, never rewrites, reads with the exit's options and the tenant records, and reports a confirm chip 0.6ms
✓
the agent loop hands the exit its fallback only when its chips were the model's own options 2.1ms
src/chat/cot.vitest.ts
classifyTurnComplexity (cost governor) · 5 tests
✓
simple turns stay simple 2.7ms
✓
multi-step: two+ detected intents or explicit sequencing 0.4ms
✓
reasoning: numeric/multi-constraint or deliberative cues 0.5ms
✓
long deliberative message → reasoning 0.3ms
✓
multi_step dominates reasoning when both cues present 0.2ms
cotRolloutAllows (default OFF — no prod change until flipped) · 3 tests
✓
simple turns never get CoT regardless of flag 0.3ms
✓
off / unknown / undefined disables all classes 0.3ms
✓
per-class flags gate correctly 0.3ms
cotBlockFor · 1 test
✓
returns the class-appropriate block or null 0.7ms
stripReasoning (Phase 1: reasoning improves the answer but is not exposed) · 4 tests
✓
removes a closed scratchpad and keeps the answer 0.6ms
✓
drops an unterminated scratchpad entirely (never ships a truncated one) 0.3ms
✓
passes through text with no scratchpad unchanged 0.2ms
✓
is case-insensitive and handles multiple blocks 0.1ms
src/chat/frame-fields-guard.vitest.ts
the cost card advisory (the audience-fit assessor writes it) · 2 tests
✓
its line reads as the guardrail leaves it; a chip the guardrail would alter is dropped, never rewritten 6.5ms
✓
a key in the line withholds the advisory whole, and leaves the cost card itself 0.5ms
the insight card (the search reasoning, or a trend) · 2 tests
✓
"Why this segment" reads as the guardrail leaves it 0.6ms
✓
a trend's metric names: the tenant's saved competitor keeps its name; a supplier's host does not 1.4ms
the document card (a model wrote the article; its saved report is scanned) · 2 tests
✓
the excerpt and what Copy puts on the clipboard read as the saved report does 0.6ms
✓
a key in the article withholds the card (the report itself is then blocked too) 0.3ms
the evidence list (hosts taken from the reply before the guardrail rewrote it) · 2 tests
✓
a supplier's host the answer named is dropped; the pages read and the tenant's own site stay 1.6ms
✓
a host the person typed keeps its entry (DECISIONS #45) 1.2ms
a reply the guardrail blocked ships none of the parts that belong to its message · 1 test
✓
insight, evidence and the document card leave with it; the cost card stays 0.7ms
CONTROL: clean parts ship exactly as written · 1 test
✓
nothing changes and nothing is counted 0.7ms
the parts the app renders are the parts this reads · 1 test
✓
every text the insight card and the advisory block render is in the list 0.6ms
wiring: finishChatReply reads them before anything is judged from the reply · 2 tests
✓
right after the record blocks, before shown-ness is read 0.2ms
✓
with the exit's options and the tenant records the chips use 0.4ms
src/chat/judge-delivery.vitest.ts
the delivery note fires on real non-delivery · 3 tests
✓
a record tool ran and nothing reached the screen 1.8ms
✓
and NOT when the turn produced an artifact, a gate, or rows 0.4ms
✓
and NOT on an HONEST EMPTY — the defect this file already paid for once 0.3ms
the clamp is reachable from BOTH judge branches · 3 tests
✓
caps a nothing-delivered turn at 0.4 0.3ms
✓
the REPORT branch applies it too — it did not, and that is the 1.00 row 8.1ms
✓
leaves a genuinely good turn alone 0.3ms
the gate reads every tool the turn ran, not the last one · 2 tests
✓
a four-tool turn is not judged on whichever finished last 7.2ms
✓
and the turn actually passes its tool list to the judge 3.4ms
the delivery test keeps exception-only presenters out, and the clamp follows the note · 5 tests
✓
ranRecordTool excludes EXCEPTION_ONLY_PRESENTERS, beside the toolsRun pin 1.6ms
✓
clean-empty is read from the RESULT, and the clamp is decided per rubric kind 0.9ms
✓
both verdict rows record BOTH facts: the note fired (delivered_nothing) and the clamp applied (delivery_clamp) 0.7ms
✓
a staged card is a pending decision for BOTH the note and Jev 0.4ms
✓
the send fact is read from the ledger only on a send turn, and a disagreement is reported 0.9ms
src/chat/next-action-wiring.vitest.ts
next_action_exec admits before anything else happens · 10 tests
✓
calls admitNextAction with this request's user and session 2.0ms
✓
admission precedes resolveTargetCount(, and a refusal returns before it 0.6ms
✓
admission precedes preflightForGate(, and a refusal returns before it 0.4ms
✓
admission precedes getCostApprovalPlan(, and a refusal returns before it 0.3ms
✓
admission precedes writeCostPending(, and a refusal returns before it 0.3ms
✓
admission precedes runShortcutTool(, and a refusal returns before it 0.3ms
✓
the refusal answers in a sentence and runs nothing 0.7ms
✓
runs the ADMITTED action and arguments, never the message's 0.4ms
✓
nothing else in index.ts reads the protocol payload itself 1.5ms
✓
a refusal is observable: trace, rate, and the route it took 0.5ms
every chip the server emits is signed · 2 tests
✓
the one live emitter signs for the user and session, and it is the only one 1.1ms
✓
the capability payload awaits it with the request identity 0.2ms
the client posts the signature back · 1 test
✓
the chip click carries sig 0.2ms
src/chat/offered-tools.vitest.ts
the decision: only what this call offered runs · 7 tests
✓
reads names from function-style and bare definitions 2.2ms
✓
a name the model is never given is refused, whatever it would have done 0.6ms
✓
a real model tool that is off THIS call's surface is refused too 0.5ms
✓
a call the loop wrote itself is not judged as the model's 0.3ms
✓
an empty surface runs nothing 0.2ms
✓
tells the model plainly that nothing ran, and never names a tool it cannot call 0.6ms
✓
the model-authored name is only ever a bounded label 0.3ms
the wiring in runChatV2 · 6 tests
✓
captures the surface it sends, before the call 0.3ms
✓
splits the model's calls after salvage, and before anything prices, stages or runs them 0.9ms
✓
drops the refused calls from the round, so nothing downstream can see them 0.3ms
✓
answers each refused call with our own sentence, paired to its call id 0.4ms
✓
records every refusal, and pages on a name the model is never given 0.3ms
✓
exempts exactly one call: the pair completion the loop injected itself 0.3ms
src/chat/site-resolution.vitest.ts
the transcript that produced this file · 2 tests
✓
recovers the domain the user typed earlier 2.4ms
✓
still resolves when the picker CHOICE is the message 0.4ms
precedence, and why each rung is where it is · 4 tests
✓
the CURRENT message overrides the stored site 0.7ms
✓
the stored site beats conversation history 0.2ms
✓
the LAST domain in a message wins — a correction is the live one 0.3ms
✓
no site anywhere returns null, so the caller ASKS 0.2ms
what it must NOT resolve — the ways a naive scan goes wrong · 5 tests
✓
NEVER reads the assistant's own turns 0.3ms
✓
placeholder hosts are not sites even when a USER types one 0.3ms
✓
files and endpoints are not hostnames 0.6ms
✓
a bare name with no TLD is not a domain 0.2ms
✓
survives junk input rather than throwing 0.3ms
BOTH pickers use it — a fix on one of two is a fix on none · 2 tests
✓
the SEO audit picker resolves the site BEFORE showing the menu 5.2ms
✓
the AEO picker uses the SAME resolver, not its own regex 6.1ms
src/chat/tenant-data-cards.vitest.ts
the tenant's own records show on a card as they are (owner ruling 2026-10-18, #43) · 5 tests
✓
a recipient on a vendor-named domain: the send card ships whole, shows the address, and its chip sends (V5 W4) 243.7ms
✓
a campaign the tenant named after a vendor: the resume card ships whole and its chip resumes (V5 W9 shape) 49.1ms
✓
a keyword panel built from the site's own Search Console terms, one naming a vendor: the card ships whole and its chip saves those terms (V5 W8 shape) 52.3ms
✓
the DNS card quoting a record already on the zone that names a vendor: it ships whole and its chip applies the change 29.7ms
✓
the shortcut path too: a send staged by the "Send all 2 drafts" chip ships whole with the vendor-named recipient 27.9ms
what a model or the product wrote still never names a vendor · 5 tests
✓
a model-written subject naming a vendor withholds the send card beside a vendor-named recipient: only the subject is blamed, and once edited the card ships whole and sends 53.2ms
✓
a panel prompt the model chose naming a vendor stays withheld — even word for word what a keyword panel would build from a search term the site really has 25.9ms
✓
a keyword panel whose NAME the model chose names a vendor stays withheld — only the name is blamed — and renamed, it ships whole with the site's own terms 44.6ms
✓
product copy naming a vendor: a record WE would write that names one withholds the DNS card, though the zone's own record would have shown 27.9ms
✓
a standing instruction quoting a vendor-named address is still the model's text: withheld 26.7ms
the exemption is decided before shown-ness, in the same exit · 3 tests
✓
M1 with a tenant card: the send card quoted only inside a withheld instruction is not shown, and a typed confirm sends nothing 50.3ms
✓
history: the next model call and the restored transcript hold the card the person received, whole 28.8ms
✓
the wiring: finishChatReply decides the tenant exemption before it judges shown-ness, and records the turn when it rewrote the reply 3.9ms
src/commerce/metrics.vitest.ts
computeOrderEconomics · 4 tests
✓
matches the live drill orders exactly (#1001 + #1002) 2.2ms
✓
NetRevenue = GrossSales − Discounts − Refunds (invariant holds under refunds) 0.3ms
✓
excludes cancelled and test orders but counts them transparently 0.8ms
✓
tax and shipping stay out of merchandise revenue 0.3ms
computeProfitRollup · 5 tests
✓
known contribution margin covers only costed variants; coverage reported honestly 0.8ms
✓
excluded (cancelled/test) order lines contribute nothing 0.4ms
✓
estimated layer: uncovered lines assumed at 50% of selling price, clearly labelled 0.6ms
✓
estimated layer absent at 100% coverage 0.2ms
✓
empty window degrades to zeros, no division blowups 0.6ms
rankProductMargins · 4 tests
✓
ranks by margin RATE (margin_pct), not absolute margin 0.5ms
✓
products with no cost coverage are unrankable, never guessed into the ranking 0.4ms
✓
worst list is worst-first and disjoint ordering holds with >10 products 0.6ms
✓
empty and all-unrankable inputs degrade honestly 0.3ms
src/connectors/oauth-state.vitest.ts
the state document is refused on its shape · 5 tests
✓
control: a well-formed crafted document with the matching cookie is accepted 28.1ms
✓
an expiry that is not a finite number is refused — the NaN defect at its root 2.6ms
✓
a document without the purpose marker is refused, even if every other field is right 1.2ms
✓
an expiry further out than one TTL is refused (mintOAuthState cannot have produced it) 206.0ms
✓
the pre-fix "uid:ts" plaintext is refused 2.3ms
minting · 6 tests
✓
the state is URL-safe as minted — no provider or HMAC canonicalisation can re-encode it 0.9ms
✓
a tenant flow uses a host-only __Host- cookie; an admin flow on admin.<app host> uses the parent domain 1.3ms
✓
a tenant flow started from any host but the app host is refused BEFORE consent, with a sentence 0.5ms
✓
an admin flow from an unrelated host is refused too 0.5ms
✓
without KV it fails closed: a state that cannot be consumed would be replayable 0.8ms
✓
APP_BASE_URL moves the app host with it 0.5ms
consumption · 2 tests
✓
a verified state clears its cookie (both Domain variants for an admin flow) 1.5ms
✓
a cookie of the right name but another value is unbound — and the attempt still burns the state 251.6ms
src/connectors/wordpress-credentials.vitest.ts
connecting WordPress stores the password encrypted · 3 tests
✓
the connector declares the password as its credential 4.0ms
✓
secret = the password; meta = site URL + username, and no password anywhere readable 27.9ms
✓
other connectors keep the first-field default (a Slack webhook is still the secret) 3.3ms
a legacy connection is read correctly and migrates on first use · 1 test
✓
reads the URL from the old secret and the password from meta, then re-saves it the right way round 2.8ms
publishing works — it never did before this fix · 2 tests
✓
new connection: posts to the site URL with username:password 17.3ms
✓
legacy connection: posts to the site URL with username:password 3.3ms
the admin backfill · 2 tests
✓
dry run counts; apply seals; a second pass finds nothing; nothing is lost 4.2ms
✓
a row whose old secret cannot be opened is left untouched and counted as failed 2.3ms
a redirect on the publish request is refused, never followed with the credential · 5 tests
✓
301 -> https://elsewhere.example/wp-json/wp/v2/posts: no credential leaves for the redirect target and no post is created 6.4ms
✓
302 -> https://elsewhere.example/wp-json/wp/v2/posts: no credential leaves for the redirect target and no post is created 2.1ms
✓
307 -> https://elsewhere.example/wp-json/wp/v2/posts: no credential leaves for the redirect target and no post is created 1.9ms
✓
308 -> https://elsewhere.example/wp-json/wp/v2/posts: no credential leaves for the redirect target and no post is created 1.8ms
✓
301 -> https://blog.example.com/wp-json/wp/v2/posts/: no credential leaves for the redirect target and no post is created 1.7ms
src/email/send-bounded.vitest.ts
the HTTP providers: the call has a ceiling of its own · 10 tests
✓
resend never answers and the caller passed no signal: the call ends at SEND_CALL_DEADLINE_MS as an abort, after exactly one provider call 304.6ms
✓
sendgrid never answers and the caller passed no signal: the call ends at SEND_CALL_DEADLINE_MS as an abort, after exactly one provider call 301.3ms
✓
mailjet never answers and the caller passed no signal: the call ends at SEND_CALL_DEADLINE_MS as an abort, after exactly one provider call 300.2ms
✓
mailtrap never answers and the caller passed no signal: the call ends at SEND_CALL_DEADLINE_MS as an abort, after exactly one provider call 300.9ms
✓
gmail never answers and the caller passed no signal: the call ends at SEND_CALL_DEADLINE_MS as an abort, after exactly one provider call 302.1ms
✓
a caller signal SHORTENS the ceiling: aborted at 20 ms, the call ends then with the caller's reason 21.3ms
✓
a caller signal that never fires does not lift the ceiling 300.8ms
✓
CONTROL: a provider that answers is unchanged 25.6ms
✓
SOURCE: all six transport calls carry the combined ceiling, and none carries the caller's signal alone 1.2ms
✓
the ceiling is the hold's own number: a call that misses it is a claim old enough to release only after the call is over 0.3ms
SMTP: the dial is bounded, and a dial that misses it is a refusal (nothing was written) · 3 tests
✓
a handshake that never completes ends at SMTP_CONNECT_TIMEOUT_MS as ok:false and NOT unconfirmed; no command crossed the wire 13.3ms
✓
the dial limit is a connect-scale number, well inside the session ceiling 0.5ms
✓
CONTROL: a dial that completes sends the message as before 5.3ms
src/email/sent-totals.vitest.ts
the dashboards · 3 tests
✓
Vitals "Emails sent": the five confirmed sends — never a held row, even one with a send time 4.8ms
✓
the dashboard's Outbound section: "Emails sent" and the rates over it 13.4ms
✓
diagnose evidence: the outbound counts the chat reads 1.7ms
the Sent panel and the send log · 2 tests
✓
GET /api/emails/sent: its totals count confirmed sends; its list still shows the held ones, labelled, with what Resend anyway needs 27.0ms
✓
list_sent_emails: "sent" is every delivered status, and "all" adds the failures and the held sends 6.2ms
the campaign reports · 2 tests
✓
campaign stats: the open rate's denominator is confirmed sends, not every row of the campaign 0.9ms
✓
the campaign dashboard: the funnel's first stage and every rate 1.8ms
what the product tells the person, and what it scores them on · 3 tests
✓
playbook anchors: "has sent email" counts confirmed sends 2.2ms
✓
user scores: emails_sent is confirmed sends 4.4ms
✓
adoption facts cited back to the person: "N sent" is confirmed sends; a failure is an unsent draft 2.3ms
the three readers a test cannot reach, held by the text of their documents · 3 tests
✓
the lead panel's per-contact "sent" (src/index.ts handleContactActivity) 4.9ms
✓
"has this tenant sent email" behind the revenue refusal (src/seo/tool-dispatch.ts SendEvidence) 1.5ms
✓
the admin funnel's f_sent, in both of its queries (src/admin/telemetry.ts) 0.8ms
src/email/suppression-reimport.vitest.ts
control: the harness can send, and replacement alone changes nothing · 1 test
✓
a contact with no suppression history is mailed, before and after it is replaced 34.1ms
an unsubscribe survives the contact row · 5 tests
✓
unsubscribe link, then delete and re-import: the new row is refused and nothing is sent 3.0ms
✓
unsubscribe link, then RENAME the old row and insert the address again: refused 1.5ms
✓
a reply asking to stop, then delete and re-import: refused 7.9ms
✓
the unauthenticated link pressed repeatedly records the opt-out once 3.9ms
✓
control: another tenant's unsubscribe of the same address does not stop this tenant 6.6ms
a hard bounce or a complaint survives the contact row · 4 tests
✓
provider webhook hard bounce, then delete and re-import: refused 12.0ms
✓
provider webhook spam complaint, then delete and re-import: refused, and the refusal says it was a complaint 12.9ms
✓
a bounce notice attributed by tracking id (the DSN path), then delete and re-import: refused 3.5ms
✓
control: a SOFT bounce (mailbox full) is not a suppression — the re-imported row is mailed 2.3ms
a failed verification survives the contact row, and only a later verdict clears it · 2 tests
✓
verified invalid, then delete and re-import with a self-asserted "valid": refused 2.4ms
✓
control: re-verifying the new row and getting a real "valid" verdict lets it send again 3.5ms
the choke point fails CLOSED when the ledger cannot be read · 1 test
✓
an unreadable suppression list refuses the send in a sentence; nothing reaches the provider 1.0ms
src/leads/verify-email.vitest.ts
verifyEmail MillionVerifier mapping · 5 tests
✓
treats catch_all as valid, not risky 24.7ms
✓
treats unknown as valid, not risky 0.6ms
✓
still treats disposable as risky 0.6ms
✓
still treats invalid mailboxes as invalid 0.5ms
✓
still treats ok as valid 0.8ms
verifyEmail strict mode (guessed permutations) · 5 tests
✓
downgrades catch_all to risky so a guessed address is discarded 0.5ms
✓
downgrades unknown to risky for the same reason 0.5ms
✓
still accepts an affirmatively confirmed mailbox 0.4ms
✓
still rejects a dead mailbox 1.4ms
✓
leaves disposable risky 0.6ms
verifyEmail honours the caller · 3 tests
✓
an aborted caller signal → unverified, and nothing is billed 0.8ms
✓
timeoutMs is honoured: a hung check ends at the caller's bound, unbilled 52.1ms
✓
(neg) a live signal and a normal answer still verify and bill once 0.7ms
src/llm/stream-parse.vitest.ts
readToolStream — content · 5 tests
✓
concatenates deltas and reports each one exactly once 25.0ms
✓
keeps the usage object, including cost — an unbilled turn is a revenue hole 1.2ms
✓
does not treat the usage chunk as content 0.6ms
✓
survives the payload being split at EVERY byte 2.8ms
✓
ignores keep-alive comments and the DONE sentinel 0.4ms
readToolStream — tool calls · 5 tests
✓
CONCATENATES argument fragments instead of parsing one 1.3ms
✓
reassembles correctly even split at every byte 5.0ms
✓
keeps parallel calls apart by index, in index order 0.6ms
✓
announces the first tool-call delta exactly once 1.0ms
✓
does not announce a tool call when the turn is pure text 0.4ms
readToolStream — degrading · 3 tests
✓
skips malformed JSON rather than failing the turn 0.3ms
✓
never lets a display callback break the model call 0.4ms
✓
returns an empty turn for a bodyless response instead of throwing 0.2ms
src/middleware/gemini-location.vitest.ts
geminiGroundedQuery — location rejection · 4 tests
✓
retries once and records the recovery and where the first request left from 330.2ms
✓
a second refusal returns a classified error, never a generic HTTP 400 302.3ms
✓
any other 400 is untouched: no retry, no trace, no code 1.0ms
✓
still classifies when the trace endpoint is unreachable 302.2ms
egressTrace · 2 tests
✓
reads colo and loc from the trace body 0.8ms
✓
returns null on a non-200 0.4ms
Share-of-Model matrix · 3 tests
✓
a location refusal does NOT fall back to the second model — it would be refused the same way 303.7ms
✓
a recovered cell counts as answered and is still reported as a rejection 303.8ms
✓
no rejection means no field at all 0.8ms
reporting · 2 tests
✓
sends one line per run with the egress colos and countries 1.3ms
✓
stays silent with nothing to report, and a throwing sink never breaks the caller 1.2ms
admin AI Discovery message · 2 tests
✓
names where the refused request left from and says to re-run 0.3ms
✓
other failures keep the provider message 0.2ms
src/planner/report-emitters.vitest.ts
planner report emitters · 13 tests
✓
emits one row per not-indexed page plus canonical and sitemap findings 3.3ms
✓
caps not-indexed emission at 5 pages 0.4ms
✓
emits nothing on error or healthy report 0.6ms
✓
unverified canonical is not a finding 0.2ms
✓
turns top_priorities into ordered rows grounded in audit scores 0.9ms
✓
emits nothing without synthesis or on error 0.3ms
✓
anchors dedupe to the campaign id so generic advice stays per-campaign 1.8ms
✓
emits nothing without a next step 0.3ms
✓
fills source fields, hash, and recheck_at (default 14d, override honored) 1.6ms
✓
stamps campaign report rows with a replies measurement contract and baseline 0.4ms
✓
stamps full SEO audit rows with an on-page score contract when evidence exists 0.4ms
✓
keeps report rows without a numeric observable in the non-learning class 0.6ms
✓
same advice re-emitted hashes identically (rerun collapses into existing row) 0.3ms
src/reports/aeo-adjacent-report.vitest.ts
tap_volume — §17 gold standard · 3 tests
✓
renders a signal bento with the model outputs + growth levers 2.0ms
✓
has plain headers and a feedback mount 0.6ms
✓
free-tier run shows the 3-prompt cap note + a token top-up section; paid shows neither 0.6ms
aeo_visibility — free-tier cap upsell · 2 tests
✓
free run: hero cap note + top-up section naming all four engines 0.6ms
✓
paid run: no cap note, no top-up section 0.5ms
sov_trend — §17 gold standard · 2 tests
✓
renders a signal bento — SoV, trend direction, tracking coverage 0.4ms
✓
has plain headers and a feedback mount 0.3ms
aeo_full_audit — §17 gold standard (composite) · 3 tests
✓
renders a top-level pillar signal bento 0.3ms
✓
carries exactly ONE feedback mount (nested sub-report mounts stripped) 0.5ms
✓
still stitches the three sub-reports 0.3ms
seo_geo_visibility — a capped sample must not be coloured like a full run · 3 tests
✓
colours a full run with confidence 0.5ms
✓
greys the score when the run was capped to one engine and a short prompt set 4.3ms
✓
still says a capped run happened, in the hero, without naming a vendor or a price 0.4ms
src/reports/google-merge-report.vitest.ts
seo_google_merge report — the merge finally gets a card · 10 tests
✓
renders an HTML report, not null (the plain-text regression) 2.0ms
✓
aggregates date+page rows into page-level totals 0.4ms
✓
renders GSC and GA4 columns side by side (the merge is the point) 0.4ms
✓
shows all four opportunity lists 0.3ms
✓
renders compare deltas when compare was requested 0.2ms
✓
shows top queries and join diagnostics 0.2ms
✓
advice items are rule-built from the insight lists (copy buttons come from adviceSection) 0.3ms
✓
error and truly-empty results (no attribution either) fall back to plain text 0.2ms
✓
states cost explicitly in the footer — never silent about a free tool (CLAUDE.md §4) 0.5ms
✓
is a background (Tier-C) tool and produces an artifact for the async completion 0.3ms
seo_google_merge report — empty organic join, populated attribution still gets a card · 3 tests
✓
renders an HTML report — no organic rows is not "nothing to show" 0.2ms
✓
shows the share-of-voice breakdown, channels table, and AI-engine line 0.2ms
✓
still states cost even on the empty-organic path 0.1ms
src/reports/publish-affordance.vitest.ts
stored artifact — carries a slot, never frozen connector state · 6 tests
✓
emits a publish slot 28.0ms
✓
bakes no live control — both connected 0.9ms
✓
bakes no live control — neither connected 0.6ms
✓
bakes no live control — flags absent entirely 0.4ms
✓
bakes no live control — non-WordPress stack 0.5ms
✓
the connector flags do not change the stored markup at all 0.6ms
stored artifact — the fallback is true regardless of connectors · 2 tests
✓
offers the coding-agent prompt, which needs no connector 0.4ms
✓
names a known stack in the fallback copy 0.5ms
stored artifact — carries everything hydration needs · 5 tests
✓
passes the stack fingerprint through as data 0.6ms
✓
empty stack when unknown, so the client reads null rather than a guess 0.3ms
✓
carries the article payload the publish handlers read 0.3ms
✓
carries the agent prompt for the fallback copy button 0.3ms
✓
subtitle is a hydration target, so it can never describe absent buttons 0.2ms
src/routes/pillar-simulator.vitest.ts
the slot contract, across both pillar pages · 7 tests
✓
.v-out is green and .v-sup is red — the colours the labels have to agree with 1.8ms
✓
/ai-visibility-answered: v-out always reads as a ruling-out, v-sup never does 25.8ms
✓
/ai-visibility-answered: renders the shared simulator, not a hand-rolled copy 1.2ms
✓
/ai-visibility-answered: exactly one chip starts active 1.9ms
✓
/seo-questions-answered: v-out always reads as a ruling-out, v-sup never does 2.0ms
✓
/seo-questions-answered: renders the shared simulator, not a hand-rolled copy 1.3ms
✓
/seo-questions-answered: exactly one chip starts active 1.1ms
pillarSimulatorHtml · 6 tests
✓
defaults to the SEO vocabulary 0.8ms
✓
a page may override the words 0.5ms
✓
the first example is rendered server-side — a reader with no JS still sees an answer 0.3ms
✓
inlines every example, so switching chips needs no request 0.3ms
✓
verdictsHtml pairs each tag with its own label 0.2ms
✓
an overridden head replaces the caption 0.1ms
src/runtime/cost-gate-recovery.vitest.ts
the window · 3 tests
✓
is 600s, the same as every sibling gate 2.7ms
✓
would have covered the click that was lost 0.5ms
✓
writes the authorisation short and the receipt long 2.8ms
recovery after expiry · 3 tests
✓
keeps the tools and the QUOTE so a re-armed card cannot change the price 1.6ms
✓
lets the receipt identify WHICH card expired 0.5ms
✓
re-arming mints a NEW id and a fresh authorisation 0.8ms
the replay guard · 4 tests
✓
destroys the receipt when the authorisation is SPENT 0.5ms
✓
a second click after a successful run recovers NOTHING 0.3ms
✓
destroys the receipt when the user says no 0.8ms
✓
clears the receipt on the legacy array-shaped record too 0.6ms
degradation · 3 tests
✓
is inert with no KV bound 0.4ms
✓
still returns a usable card id when only the RECEIPT write fails 0.5ms
✓
ignores a corrupt receipt rather than throwing 0.2ms
src/runtime/tool-deadline.vitest.ts
combineSignals · 4 tests
✓
aborts when either input aborts, with that input's reason 2.3ms
✓
is already aborted when an input already is 0.4ms
✓
removes its listeners from every input once it has aborted 3.1ms
✓
a timeout input aborts it on its own 60.3ms
settleWithin · 3 tests
✓
settles with the value 0.7ms
✓
settles with a rejection, without throwing 0.5ms
✓
times out on a promise that has not settled 20.7ms
the WeakMaps · 4 tests
✓
return undefined for a signal nobody registered, and for no signal 0.5ms
✓
hold what was set, per signal 0.9ms
✓
progress is a snapshot: a later mutation by the tool does not rewrite what was read 0.4ms
✓
annotations merge: the loop's re-check source rides beside its probability 0.2ms
pickRunMeta — the ledger row takes only allowlisted strings · 2 tests
✓
keeps recheck, recheck_p, skipped, grounded, units, target_shape, legs_failed 0.4ms
✓
(neg) drops anything else, any non-string, and anything that is not an object 0.3ms
src/runtime/untrusted-egress-sweep.vitest.ts
godmode-diagnostics — a Location header and a child sitemap are the crawled server’s choice · 3 tests
✓
followRedirectChain records an inward hop but never connects to it (P1-13b-F08) 29.0ms
✓
diagnoseGodModeCanonical still follows an ordinary apex→www redirect 10.7ms
✓
fetchSitemapUrls never reads a child sitemap that points inward (P1-13b-F07) 3.6ms
publish-detect — the weekly cron reads child sitemaps with no person in the turn (P1-13b-F07) · 2 tests
✓
the production default fetch is the choke point: a child sitemap that redirects inward is not followed 3.5ms
✓
a sitemap may not walk to a look-alike domain — the registrable match is on a label boundary 1.8ms
link-verify — the referring pages a backlink provider reported · 1 test
✓
neither pass connects to a reported internal page or a reported page that redirects inward 2.7ms
commerce — the bulk-export URL a store API returned · 2 tests
✓
a provider-named internal URL is refused before any connection 2.0ms
✓
a provider-named URL that redirects inward is refused at the hop 0.9ms
serp-spider — sitemap and SERP URLs probed for status (census row it could not resolve) · 2 tests
✓
probeUrlStatus reports an inward redirect as a fetch error and never connects to it 3.2ms
✓
fetchAndParseRobotsTxt does not follow robots.txt inward 0.7ms
reads of the user’s own site re-check every redirect · 3 tests
✓
auditLocalPresence 1.2ms
✓
probeSeedStatus and needsJsRendering 0.8ms
✓
ragReadiness, on the production path (no injected fetch) 0.9ms
src/tools/leads-family-rules.vitest.ts
every rule from the deleted LEADS block still reaches the model · 10 tests
✓
(1) a request that NAMES who they want goes straight to search_leads 2.0ms
✓
(1b) and the measurement that motivated it survives 0.6ms
✓
(2) a request that names NOBODY calls list_contacts first and asks 0.4ms
✓
(3) the price, the worked example, and SCALE-DON'T-REFUSE 0.3ms
✓
(3b) never ask which lead source to use 0.3ms
✓
(3c) the shortfall goes to the paid card, not back to a question 0.2ms
✓
(3d) search_leads is never called speculatively 0.3ms
✓
(4) an in-flight search is reported as in-flight, never as empty — THE MOVED RULE 0.4ms
✓
(5) list_contacts reads what is already saved and cannot find anyone new 0.5ms
✓
(6) enrich_contacts adds a homepage summary and recent news 0.3ms
and the duplication is actually gone · 3 tests
✓
V2_SYSTEM no longer carries a LEADS FAMILY routing block 0.3ms
✓
the price is stated ONCE, on the tool that charges it 0.3ms
✓
V2_SYSTEM stays under its ratchet 0.2ms
src/seo/crawl-run-replay.vitest.ts
a replayed phase runs once · 5 tests
✓
fetch: the same batch a second time crawls nothing and answers the stored count 37.0ms
✓
verify: the same cursor a second time contacts no link target 5.3ms
✓
expand: runs once; a replay adds nothing and leaves the run as it was 3.6ms
✓
the per-run phase counter refuses past the ceiling with a plain sentence 24.6ms
✓
a fetch after expand grows the batch, so the longer slice IS crawled (not a replay) 4.0ms
concurrent duplicates of one unit of work crawl it once · 4 tests
✓
six concurrent fetches of one batch: one crawl; the rest are told to retry; a retry reads the store 32.3ms
✓
four concurrent verifies of one cursor contact the link targets once 36.9ms
✓
a crawl that FAILS releases its claim, so the retry crawls at once 182.3ms
✓
a claim whose claimant died is reclaimable after the lease 2.7ms
a claim is held for as long as its work runs (V12b-edge-F03) · 4 tests
✓
fetch: a duplicate arriving after the lease, while the first crawl is still running, is told to retry and crawls nothing 10.0ms
✓
verify: the same for a slow verify cursor (250 targets, 8 at a time, 10 s each) 4.5ms
✓
a claimant that stops renewing (its isolate died) still frees the unit one lease later 1.8ms
✓
a renewal never creates a claim: a finished or released unit stays free 2.1ms
src/seo/grounded-signals.vitest.ts
readGroundedSignals · 7 tests
✓
reads every field the renderers were missing 2.8ms
✓
drops a claim with no source — the section promises "which source fed this" 1.0ms
✓
returns null when the leg errored or never ran, so nothing renders an empty shell 0.3ms
✓
an absent array and an empty array are the same READ but never invent rows (trap 14) 0.4ms
✓
fan-out 0 and fan-out null are different facts 0.4ms
✓
carries the per-engine coverage note and names the engine (AEO-014 / AEO-008) 0.4ms
✓
derives the reading ONCE so the artifact and the panel cannot word it differently 0.4ms
aeo_visibility artifact renders the grounded payload (R-B) · 6 tests
✓
shows fan-out, its reading, the vocabulary and the coverage note 27.6ms
✓
shows which source produced which claim — and only sourced ones 1.0ms
✓
leads with entity collision — it is the CAUSE of the tables under it 0.6ms
✓
a run whose grounded leg failed renders NO grounded sections, not empty ones 0.5ms
✓
an artifact stored before R-B has no share_of_model at all and still renders 0.4ms
✓
no collision on a healthy brand — the banner is a finding, not a header 0.4ms
src/seo/hosting-footprint.vitest.ts
subnet24 · 2 tests
✓
truncates dotted-quad to /24 1.9ms
✓
rejects anything that is not a dotted quad, including IPv6 0.4ms
isSharedInfra · 2 tests
✓
matches on ASN first 0.3ms
✓
falls back to the operator name when the ASN is unknown 0.6ms
computeHostingFootprint — the bklink defects it must not reproduce · 3 tests
✓
counts a repeated domain once, no matter how many links it carries 1.5ms
✓
does not call a Cloudflare cluster a footprint 0.5ms
✓
excludes unresolved domains from the denominator and reports them by reason 1.0ms
computeHostingFootprint — verdicts · 6 tests
✓
flags a real footprint when a non-CDN IP dominates 0.7ms
✓
calls a one-domain-per-server profile diverse 0.8ms
✓
refuses a verdict below the resolved-domain floor and says so 0.4ms
✓
states the basis — how many resolved, and how many did not — in the note 0.3ms
✓
prefers the announced prefix over an assumed /24 for prefix diversity 0.2ms
✓
counts an AAAA-only domain as a resolved distinct host 0.2ms
src/seo/rank-cron-weekly-reach.vitest.ts
processSEOCron: the scan phase has its own clock · 1 test
✓
a slow balance-check phase does not eat the scan budget — all 8 keywords are measured 15.0ms
processSEOCron: every tracked tenant gets its balance check · 2 tests
✓
30 tenants at the measured ~1 s per check all get checked and scanned (each in its own invocation since V9-seo-F01) 38.6ms
✓
overlapping checks never see another tenant's request context 11.5ms
processSEOCron: the gate prices the scan the cards quote · 1 test
✓
reserves the plan depth at the per-keyword price, as an asserted ceiling — not keyword research 2.8ms
processSEOCron: a refused scan tells the person the real figure and a way out · 2 tests
✓
the email names what the run needs (not 0) and the activity offers a stop chip the router understands 31.9ms
✓
a notice with no known figure says nothing about the figure rather than "Needed: 0" 0.7ms
processSEOCron: the rank scan pauses itself after 4 refused Sundays in a row · 4 tests
✓
refusals 1-3 are ordinary notices; the 4th switches the scan off and emails once; the 5th Sunday sends nothing 10.0ms
✓
after a resume (switch 1, streak 0) the next refusal is an ordinary notice and pausing again takes 4 more Sundays 4.3ms
✓
a Sunday the check passes resets the streak, so refusals must be in a row 3.4ms
✓
an unreadable streak never pauses and never overwrites the stored count 1.9ms
processSEOCron: a scan cut short by its time budget says so · 1 test
✓
a search refused for lack of time stops the searching, fails nothing, and raises the stopped-short alarm 3.1ms
processSEOCron: the scan buys at most 20 fallbacks, and a keyword past them is stopped short · 2 tests
✓
every search shares one allowance of 20 2.3ms
✓
a failure the cap refused to fall back is reported as stopped short (fallback cap), not as a failure 2.5ms
src/seo/request-indexing.vitest.ts
runRequestIndexing · 13 tests
✓
with no URLs and no Serpdex gaps: asks for URLs, does not submit 3.0ms
✓
free (no top-up): returns an upsell with the count, never submits or charges 0.7ms
✓
paid: submits, charges per URL, and confirms 3.1ms
✓
paid but insufficient balance: refuses, never submits or charges 0.6ms
✓
reserves the cost of the URLs it is about to submit 0.5ms
✓
asserts isCeiling, because the submitted array IS the whole spend 0.8ms
✓
a submit is never gated before the paid-feature upsell 0.5ms
✓
paid but provider unconfigured: clean error, no submit 0.3ms
✓
pulls the latest Serpdex gaps when no URLs are passed 1.1ms
✓
never submits a competitor run: skips other-domain tasks and picks the tenant's own 0.5ms
✓
only competitor runs on file: refuses, submits nothing, flags it to telemetry 0.5ms
✓
no saved site: refuses to guess which run was the tenant's own 0.3ms
✓
drops off-site URLs found inside the tenant's own task 0.6ms
src/seo/sov-write.vitest.ts
persistSovPoint — one writer, one stamped basis · 5 tests
✓
writes exactly one `sov` row and stamps what the share was measured on 4.0ms
✓
returns the SAME stamped object the row carries, so the caller embeds one share not two 0.5ms
✓
writes nothing when there is no share — an absent share is not a zero (AEO-002) 0.4ms
✓
stamps a matrix-only run as measured on no engine at all, not as ChatGPT 0.5ms
✓
the two live records now carry ONE basis where they carried two 0.7ms
the count a run reports about itself · 5 tests
✓
records answers separately from cells, because cells are prompts x engines 0.4ms
✓
stores an empty engine list rather than a default, so absence is not read as four engines 0.7ms
✓
never stores an engine key carrying a model slug — that is a vendor name (CLAUDE.md §4) 0.5ms
✓
drops a token that is not an engine at all rather than passing it through 0.6ms
✓
omits answers_received rather than guessing when the caller has no count 0.4ms
storedSovBasis — snapshots of both shapes keep rendering · 3 tests
✓
reads the stamp on a v2.491.0+ row 0.3ms
✓
recomputes from by_engine on a row written before the stamp existed 0.3ms
✓
does not invent a basis for a row with no share block at all 0.2ms
src/leads/shared/keep-warm.vitest.ts
corpusKeepWarm · 11 tests
✓
does not touch the database when the rung is off for everyone 9.6ms
✓
runs when the flag names tenants, not just on the literal 1 5.4ms
✓
pings with the INDEXED domain lookup, not the browse branch 5.3ms
✓
reports how long the ping took, because that IS the observation 3.5ms
✓
does not ping an IDLE corpus — no demand, no compute-hours 4.1ms
✓
pings while somebody is actually searching 5.1ms
✓
lets the compute go once the session is over 5.0ms
✓
fails OPEN — a KV outage must not stop keeping a BUSY corpus warm 4.1ms
✓
the ping never renews its own demand stamp 1.0ms
✓
REJECTS a failed ping, so its Sentry monitor records the run as failed 9.4ms
✓
a SKIPPED ping (flag off, no demand) resolves — nothing to do is not a failure 6.7ms
the cron and the module agree · 2 tests
✓
is actually scheduled in wrangler.toml 0.5ms
✓
fires with real margin against the suspend timeout, not a one-minute race 0.3ms
src/leads/shared/org-country-presence.vitest.ts
157 · organization.country_code is never written · 2 tests
✓
no UPDATE sets organization.country_code 2.1ms
✓
the fix is a side table, not a rewrite 0.3ms
157 · the presence table is derived from country DISAGREEMENT · 2 tests
✓
only rows where the two country codes differ 0.2ms
✓
joins the person to its primary employer 0.2ms
157 · the refresh is additive and only fills nulls · 2 tests
✓
never deletes or truncates the presence table 0.3ms
✓
the conflict arm coalesces rather than overwrites 0.3ms
157 · 153's two arms survive byte-for-byte · 3 tests
✓
still scopes the organization arms by country 0.3ms
✓
adds exactly two new arms, both country-scoped 0.9ms
✓
passes country and region to all four arms 0.4ms
157 · both new arms are index-served · 1 test
✓
mirrors the organization trigram indexes onto the presence table 0.3ms
157 · the self-verification is bounded, not merely positive · 3 tests
✓
asserts the US is unchanged, both as row count and as predicate output 0.2ms
✓
bounds the India gain BELOW a measured figure, not just above the old value 0.1ms
✓
asserts both indexes exist 0.1ms
src/leads/shared/query-embedding.vitest.ts
the model contract with the index · 3 tests
✓
names the SAME model_id the corpus was embedded with and 085 indexed 2.1ms
✓
requests the pinned dimension count from the provider 5.9ms
✓
REJECTS a wrong-width vector here rather than letting Postgres reject it 0.8ms
null is a first-class answer, never a throw · 5 tests
✓
no API key configured — a deployment state, not a runtime failure 0.4ms
✓
provider returns a non-2xx 1.0ms
✓
provider throws or the request is aborted 1.1ms
✓
provider answers with a malformed payload 0.8ms
✓
empty query — nothing to embed 0.6ms
caching · 5 tests
✓
does not pay the provider twice for the same query 1.3ms
✓
normalizes so trivially different spellings share one entry 1.0ms
✓
a BROKEN cache degrades to a paid call, never to a failed search 0.9ms
✓
stores no raw search text in the key — it is hashed and model-scoped 0.9ms
✓
caches only what it would return — a rejected vector is never stored 0.7ms
scripts/lib/csv-stream.vitest.mjs
csvRecords · 10 tests
✓
parses a plain record 5.3ms
✓
KEEPS a newline inside a quoted field in the same record 2.0ms
✓
survives several newlines in one field 0.9ms
✓
handles an escaped quote inside a quoted field 0.8ms
✓
keeps commas inside quotes as data 5.4ms
✓
handles CRLF without leaving a stray carriage return in the last field 4.8ms
✓
emits a final record with no trailing newline 1.8ms
✓
does NOT emit a phantom empty record for a file ending in a newline 0.9ms
✓
preserves empty fields rather than collapsing them 1.5ms
✓
reads a quoted field spanning a 1 MB chunk boundary 120.2ms
headerIndex · 2 tests
✓
finds a column by any accepted spelling, case-insensitively 0.4ms
✓
returns -1 rather than 0 for an absent column 0.2ms
scripts/lib/merge-worktree.vitest.mjs
mergeWorktreePath · 1 test
✓
is unique per run, even for the same PR and pid, and never the old fixed path 2.9ms
acquireMergeLock · 6 tests
✓
a second run on the same PR is refused and told who holds it; release frees it 1.9ms
✓
runs on different PRs do not block each other 0.5ms
✓
a lock older than STALE_MS is taken over and reported, and the old holder cannot release it 0.7ms
✓
a young lock is respected even when its content is unreadable (judged by file age) 0.5ms
✓
eight processes racing for one PR: exactly one gets the lock 213.5ms
✓
a lock released from a process exit handler is gone after process.exit(1), the path every die() takes 34.5ms
staleMergeWorktrees · 2 tests
✓
collects only old merge worktrees in the parent dir, including the legacy fixed path 0.6ms
✓
never collects a live run: a young merge worktree, a session worktree, or one in another dir 1.1ms
merge-pr.mjs wiring · 3 tests
✓
takes the worktree path from mergeWorktreePath and never deletes a path before creating it 0.5ms
✓
takes the per-PR lock before the first write and releases it on exit 0.3ms
✓
registers the worktree for removal on exit, so die() inside the rebase does not leave it behind 0.1ms
src/admin/broadcast-segments.vitest.ts
segment catalogue · 3 tests
✓
ids are unique and every segment says who it is AND what to send them 2.4ms
✓
covers every scoring tier, including ones that are currently empty 1.0ms
✓
rejects unknown ids rather than falling through to everyone 0.5ms
inSegment — tier matching · 2 tests
✓
matches a user to exactly their own tier 0.8ms
✓
all_verified takes everyone, scored or not 0.3ms
inSegment — unscored users are their own segment · 3 tests
✓
a user with no score row is "unscored", not a drifter 0.2ms
✓
a scored user is never "unscored", whatever their tier 0.3ms
✓
treats an empty-string tier as unscored rather than as a tier 0.2ms
segments partition the user base · 2 tests
✓
every user lands in exactly one targeting segment 0.6ms
✓
an unknown tier value matches NO targeting segment 0.3ms
exclusion counts are scoped to the segment · 2 tests
✓
counts only members of the segment 0.3ms
✓
reconciles: in-segment = sendable + exclusions drawn from the segment 0.2ms
src/admin/eval-verdict.vitest.ts
classifyEvalRun · 12 tests
✓
calls a case that was reliably passing a REGRESSION 2.5ms
✓
does NOT fail the build for a case that has been failing on and off 0.6ms
✓
a case with ONE scattered prior failure is still treated as newly broken 0.4ms
✓
THE BUG THE FIRST DRAFT HAD: a case failing EVERY run is broken, never "flaky" 0.4ms
✓
a case failing MORE often than it passes is degraded, not flaky — and stays red 0.4ms
✓
a case that mostly passes stays flaky and green — measured d-rank-track at 4/5 0.4ms
✓
scattered failures with at least one pass ARE flaky 0.3ms
✓
separates a real regression from flakes in the SAME run 0.4ms
✓
is green and quiet when nothing failed 1.0ms
✓
refuses to judge with no history rather than calling day one a regression 0.4ms
✓
only looks back HISTORY_WINDOW runs, so ancient failures do not excuse a fresh break 0.3ms
✓
deduplicates a case reported twice in one run 0.2ms
src/admin/exempt-ip.vitest.ts
IPv6 /64 expansion · 2 tests
✓
expands compressed forms to the same prefix as the full form 2.1ms
✓
returns null for anything that is not a plain IPv6 address 0.7ms
isExemptIp · 4 tests
✓
matches the listed IPv4 addresses exactly 0.4ms
✓
matches any address inside a listed /64, whatever the interface identifier 0.3ms
✓
does NOT match a neighbouring /64 — the prefix is one line, not the ISP 0.3ms
✓
rejects empty and nullish input 0.2ms
every public tool rate limiter honours the exemption · 6 tests
✓
website health check never blocks an exempt address 1.0ms
✓
website health check still blocks an address that is not exempt 0.4ms
✓
GEO scorecard never blocks an exempt address 1.1ms
✓
GEO scorecard still blocks an address that is not exempt 0.3ms
✓
AI-search prompt generator never blocks an exempt address 0.7ms
✓
AI-search prompt generator still blocks an address that is not exempt 0.2ms
src/admin/gsc-trend.vitest.ts
zeroFillDailySeries · 2 tests
✓
inserts missing days as zeros — Search Console omits no-data days entirely 3.3ms
✓
leaves an already-dense series untouched 1.0ms
sumPeriod · 3 tests
✓
recomputes CTR from summed clicks and impressions, never averaging daily CTRs 0.3ms
✓
weights position by impressions and ignores zero-impression days 0.2ms
✓
reports null position when nothing was seen at all 0.2ms
comparePeriods · 5 tests
✓
compares equal-length halves and reports real improvement 0.6ms
✓
treats a falling position as an improvement (rank 8 -> 3 is better, not worse) 0.3ms
✓
returns null percent (not Infinity) when the previous period was zero 0.2ms
✓
does NOT call rising impressions with flat clicks an improvement 0.5ms
✓
returns null for a series too short to halve 0.2ms
toWeeklyBuckets · 2 tests
✓
buckets into 7-day groups tagged with the week start 0.5ms
✓
keeps a trailing partial week rather than dropping it 0.3ms
src/admin/preflight-rate.vitest.ts
sample size is part of the answer · 3 tests
✓
quotes NO rate below the floor — a percent sign on six events is an anecdote in costume 4.6ms
✓
null is not zero — a suppressed rate must not read as "never fires" 1.0ms
✓
quotes a rate once the floor is cleared 0.7ms
what the number means · 4 tests
✓
never calls the rate a false-alarm rate — that needs the proceeded-anyway signal 0.6ms
✓
keeps a tool that never spoke, because silent and unwired look identical without the denominator 0.7ms
✓
says so when nothing ran at all, and points at the wiring guard 0.4ms
✓
degrades to a posture, not an exception, when the service account is unset 0.3ms
the override rate — the half that actually answers §9 · 5 tests
✓
quotes it once enough findings reached a DECISION 0.5ms
✓
refuses it below the outcome floor, and says what it is waiting for 0.7ms
✓
never folds silence into either bucket 0.8ms
✓
never reports negative unobserved when outcomes straddle the window edge 0.6ms
✓
still refuses to call the SPOKE rate a false-alarm rate 0.3ms
src/admin/provider-usage-grouped.vitest.ts
buildGroupedAggregateQuery · 8 tests
✓
emits one aliased aggregate per pair, in order 1.9ms
✓
filters each alias on its OWN provider+operation, not a shared/loose match 0.3ms
✓
reuses ONE $since variable across every alias rather than declaring one per pair 1.1ms
✓
[fail-first] emits, per pair, a second alias p<i> that sums the SAME group under user_id = $platform, declared once 1.0ms
✓
declares a distinct $provN/$opN pair per alias, matching the pair count 0.5ms
✓
requests count and cost sum — the two fields the caller reads 0.2ms
✓
produces a valid query for zero pairs (the caller short-circuits before this, but the builder must not throw) 0.7ms
✓
MAX_PAIRS leaves real headroom over the measured reality (49 pairs, 2026-08-15) 0.2ms
buildRepresentativeMeta · 4 tests
✓
keeps the FIRST row per (provider, operation) — the sample is created_at desc, so first = most recent 0.9ms
✓
keys strictly on provider AND operation — same operation under a different provider is a different group 0.3ms
✓
records null meta as null, not as "missing" 0.3ms
✓
is empty for an empty sample 0.1ms
src/admin/telemetry-tables-operations-exact.vitest.ts
computeOperationsTable — exact api groups · 7 tests
✓
without exactApiGroups, behaves exactly as before (existing callers/tests unaffected) 2.9ms
✓
replaces the sample total with the exact grouped total for a non-apify provider (direct OP_MAP route) 0.7ms
✓
routes an apify group through the SAME special-case (SEO_APIFY_OPS) as the row-level path 0.4ms
✓
routes an apify group NOT in SEO_APIFY_OPS to lead.search, matching row-level behaviour 0.3ms
✓
excludes provider="quality" from exact groups, matching the row-level exclusion 0.2ms
✓
combines llm (exact, from token_by_model) and api (exact, from the grouped total) into one row cost 0.3ms
✓
an empty exactApiGroups array is treated as "no exact data", not as "zero api cost" 0.4ms
computeOperationsTable — unmapped-provider catch-all · 5 tests
✓
an unmapped provider no longer vanishes — its cost lands in the platform cluster 0.5ms
✓
keys on provider:operation, not bare operation — two unmapped providers cannot merge under one label 0.8ms
✓
does not apply the catch-all to a provider that WAS matched by OP_MAP 0.4ms
✓
applies to the row-level (sample) path too, not only the exact-groups path 0.3ms
✓
still excludes provider="quality" before reaching the catch-all 0.1ms
src/billing/aeo-selector-quote.vitest.ts
engine selector quote · 12 tests
✓
perplexity × 18 avg: the selector's arithmetic equals the card's quote 1.8ms
✓
perplexity × 18 p90: the selector's arithmetic equals the card's quote 0.2ms
✓
perplexity × 12 avg: the selector's arithmetic equals the card's quote 0.2ms
✓
perplexity × 12 p90: the selector's arithmetic equals the card's quote 0.2ms
✓
chatgpt+claude+gemini+perplexity × 18 avg: the selector's arithmetic equals the card's quote 0.2ms
✓
chatgpt+claude+gemini+perplexity × 18 p90: the selector's arithmetic equals the card's quote 0.1ms
✓
chatgpt × 3 avg: the selector's arithmetic equals the card's quote 0.3ms
✓
chatgpt × 3 p90: the selector's arithmetic equals the card's quote 0.1ms
✓
gemini+claude × 7 avg: the selector's arithmetic equals the card's quote 0.5ms
✓
gemini+claude × 7 p90: the selector's arithmetic equals the card's quote 0.2ms
✓
the per-prompt legs are not a rounding term — they exceed a Perplexity call 0.3ms
✓
the picker carries the quote and the plan cap; the client reads both and no longer trusts its mirror first 6.6ms
src/billing/backlinks-pricing.vitest.ts
dfsBacklinksCostUsd — the published formula · 6 tests
✓
reproduces DFS's own worked example exactly 1.6ms
✓
prices the task fee at 667x a single row — the fact that decides which dial to turn 0.4ms
✓
shows that 100x the rows costs only 2.46x the money 0.3ms
✓
charges for the extra REQUESTS when rows exceed one call, never pretending it is one task 0.3ms
✓
never bills below one task, because a request was still made 0.3ms
✓
honours an explicit task count above the row-derived minimum (summary + list) 0.2ms
free-tier caps on the backlink family · 4 tests
✓
caps the free gap by DOMAINS, and paid gets the provider row ceiling 0.2ms
✓
bounds seo_backlink_verify even though it spends NO provider money 0.3ms
✓
never widens beyond what the caller asked for 0.5ms
✓
shows the free domain cap saves cents while runs save the unavoidable floor 0.2ms
GAP_DFS_TASKS — reproduces a real invoice · 2 tests
✓
matches what DFS actually billed for the dock.io run 0.2ms
✓
is FOUR, because each of the two legs is a summary call plus a list call 0.2ms
src/billing/free-tier-visibility-quote.vitest.ts
the free tier can now afford the capability the product is named for · 8 tests
✓
aeo_visibility: a bare call fits inside the signup grant 14.5ms
✓
aeo_visibility: the free quote REPLACES the table ceiling rather than being floored by it 0.4ms
✓
aeo_visibility: PAID is untouched — an uncapped run still asks for the real ceiling 0.2ms
✓
aeo_visibility: the plan really does narrow it — the cap is not fiction 0.8ms
✓
seo_geo_visibility: a bare call fits inside the signup grant 0.3ms
✓
seo_geo_visibility: the free quote REPLACES the table ceiling rather than being floored by it 0.2ms
✓
seo_geo_visibility: PAID is untouched — an uncapped run still asks for the real ceiling 0.2ms
✓
seo_geo_visibility: the plan really does narrow it — the cap is not fiction 0.2ms
membership requires BOTH halves · 2 tests
✓
both tools are registered as tier-aware 0.5ms
✓
search_leads is deliberately NOT — its bare estimate invents a request shape 0.2ms
one implementation, so the two halves of "AEO & GEO" cannot diverge · 2 tests
✓
both estimators route through the shared plan-capped helper 1.6ms
✓
an uncapped plan returns null, never a fabricated discount 0.2ms
src/billing/stripe-refund.vitest.ts
charge.refunded — ownership · 4 tests
✓
ignores a sibling product's refund without touching the ledger 29.3ms
✓
escalates when a charge CLAIMS our metadata but its session is not ours 1.0ms
✓
escalates — never silently drops — when the session IS ours and no credit row exists 0.9ms
✓
treats a charge with no Checkout Session as not ours 0.7ms
charge.refunded — the reversal · 5 tests
✓
debits the full grant on a full refund, as a POSITIVE row 3.6ms
✓
debits proportionally on a partial refund 1.5ms
✓
writes only the DIFFERENCE when a partial refund is followed by the rest 1.9ms
✓
writes nothing on a redelivered event 6.0ms
✓
lets the balance go negative when the tokens were already spent, and says so 9.2ms
the reversal moves the balance under BOTH billing models · 3 tests
✓
cost-based: a stripe_refund row is counted in TOKEN space, not as zero-cost spend 0.7ms
✓
legacy: unchanged, because it sums total_tokens over everything 0.9ms
✓
the reversal is excluded from the user-facing spend breakdown 10.5ms
src/billing/topup-packs-guard.vitest.ts
the price a customer is charged matches the tokens they get · 3 tests
✓
passes on the current tree 44.9ms
✓
catches a pack mispriced against the rate every other pack uses 86.1ms
✓
catches a label that no longer states the charge it makes 87.2ms
one author for the price — a second copy is how two prices happen · 3 tests
✓
catches a pack id hardcoded outside the packs endpoint 94.1ms
✓
catches a bare pack price written into client copy 92.5ms
✓
leaves a COMMENTED pack id alone — that is where this defect is documented 93.6ms
a shared Stripe account cannot infer ownership, so the metadata must carry it · 3 tests
✓
catches createTopUpCheckout dropping the statement-descriptor suffix 86.0ms
✓
catches the product marker being dropped from the session metadata 89.2ms
✓
catches a reversal that fires BEFORE it checks who owns the charge 0.8ms
it refuses to pass vacuously · 3 tests
✓
fails rather than passing when the pack parse finds nothing 89.6ms
✓
has a floor at all, and it is the first thing after the parse 0.3ms
✓
is wired into the gate 0.2ms
src/billing/usage-read-honesty.vitest.ts
/api/usage/me on a healthy read · 1 test
✓
reports real consumption against granted credits 26.9ms
/api/usage/me on a failed read · 4 tests
✓
does NOT answer 200 — a failure must be legible as a failure 0.6ms
✓
invents no numbers at all 5.2ms
✓
does not leak the raw provider error to the browser 0.8ms
✓
reports the fault — an unreadable balance is not a nothing 1.9ms
the client renders unknown, not zero · 7 tests
✓
has actually found the code it claims to test 0.4ms
✓
routes every vitals tile through a fetch that throws on a bad status 0.4ms
✓
paints the rows through the renderer module, not by hand 0.3ms
✓
still hides the boot splash when the balance read fails 0.4ms
✓
shows one honest line when the vitals read fails, and reports the fault 0.3ms
✓
keeps the token bar on its own read, so one failure does not blank the other 0.2ms
✓
the Profile panel never claims a zero balance it did not read 0.8ms
src/chat/backlinks-presenter.vitest.ts
seo_backlinks now renders its own rows · 6 tests
✓
produces a block instead of leaving the rows to the model 2.0ms
✓
reads the valuation body in BOTH shapes it arrives in 0.5ms
✓
does NOT price links when real_backlinks is false 0.3ms
✓
DOES price them once the provider confirmed the sample 0.2ms
✓
never prices a domain with no DR, verified or not 0.2ms
✓
returns null rather than an empty table when there are no links 0.3ms
the model no longer holds the rows it was transcribing · 1 test
✓
strips domains from the model copy, and keeps everything else 1.1ms
modelResultView strips nested consumed paths · 5 tests
✓
removes value.links — the rows the user is NOT looking at and cannot trust 0.3ms
✓
keeps the rest of value, because the synthesis needs the aggregates and the note 1.2ms
✓
still removes the top-level domains it always did 0.3ms
✓
leaves untouched siblings alone 0.4ms
✓
a flat-only consumed list still behaves exactly as before 0.2ms
src/chat/delivered-summary.vitest.ts
delivered summary (feature 004) · 12 tests
✓
keeps terminal steps only and the LAST state of a repeated step wins 2.3ms
✓
stays silent only when a lone step has nothing to say 0.7ms
✓
builds outcome lines from allow-listed numeric result fields only 0.7ms
✓
covers the report composites and falls back to the generic numeric allow-list 0.5ms
✓
covers create_marketing_plan / show_marketing_plan (nested plan_score, not top-level) 0.2ms
✓
renders counts and names failed steps honestly 0.2ms
✓
tolerates malformed trace input 0.4ms
✓
accepts a rephrase that reuses only fact numbers 0.4ms
✓
rejects any number absent from the facts 0.6ms
✓
allows the step-count number itself 0.2ms
✓
rejects empty, oversized, or scratchpad-carrying output 0.3ms
✓
accepts numbers sourced from the outcome line, rejects others 0.2ms
src/chat/diagnostic-recognition.vitest.ts
the typo that cost a session · 4 tests
✓
recognises the exact message the user sent 4.4ms
✓
and the correctly spelled one, as it always did 1.5ms
✓
handles the other three single-edit shapes, not just transposition 0.9ms
✓
TRANSPOSITION specifically — the case plain Levenshtein scores as 2 0.4ms
the imperative form — the same question without the question mark · 4 tests
✓
"increase my leads" 0.3ms
✓
"boost my traffic" 0.3ms
what must NOT become a diagnosis — a false redirect is not free · 4 tests
✓
sends a real spend request to a read-only tool if it fires wrongly 1.3ms
✓
explicit action requests still route to their tools 0.4ms
✓
fuzzy matching is length-gated — short words are too close together 0.3ms
✓
an exact verb is GROWTH_ASK_RE's job, not the fuzzy path 0.2ms
src/chat/public-activity.vitest.ts
public activity projection · 12 tests
✓
maps explicitly approved Google tools without exposing their internal name 5.7ms
✓
omits unknown tools rather than inventing a generic progress step 0.3ms
✓
does not leak banned vendor names from tool identifiers or phase strings 0.9ms
✓
keeps trace DTOs to public fields only 0.3ms
✓
describes the content-quality workflow with a real user-facing operation 0.3ms
✓
covers deterministic audit result checks without provider disclosure 0.4ms
✓
has an explicit public activity policy for every LLM-callable tool 0.4ms
✓
assigns every mapped tool an operation-cluster group 0.3ms
✓
extracts counts only from allow-listed array fields 0.7ms
✓
attaches counts on terminal success only — never on running or failed steps 0.4ms
✓
carries the group through phase projections for sub-steps 0.3ms
✓
carries real elapsed + heartbeat details through phase projections, scanned 0.5ms
src/chat/render-manifest.vitest.ts
it counts what was sent, not what was intended · 7 tests
✓
a rendered-but-EMPTY table is visible as such 1.7ms
✓
counts rows across every block 0.3ms
✓
an approval card is recorded as a decision asked, not an answer given 0.3ms
✓
a prose-only turn shows no blocks and no chips — the picker shape 0.4ms
✓
an artifact is detected however it was attached 0.3ms
✓
records WHICH router produced the turn 0.2ms
✓
survives a malformed payload rather than throwing 1.8ms
once per turn, whichever author gets there first · 1 test
✓
a second call for the same turn does not write again 26.3ms
the platform_render meta is a whitelist, the surface keys included (2026-09-24, token-waste audit §6 gap 3) · 4 tests
✓
writes exactly the named keys, every value a string 1.3ms
✓
a shortcut turn (no surface, no contact-set record) writes empty strings, never a guess 0.5ms
✓
no key can carry a name, an address or message text 0.7ms
✓
recordRenderManifest writes this meta, read from the turn's reqCtx 0.6ms
src/chat/rls-smoke-wired.vitest.ts
a real violation reports itself, not the guard · 4 tests
✓
passes on the current tree 37.2ms
✓
a dropped secret is exit 1 naming THAT secret — not the stale-parser exit 2 68.7ms
✓
a deleted workflow is exit 1 — the smoke being scheduled nowhere is the loudest thing here 70.2ms
✓
still exits 2 when the workflow is present and the guard stops finding things to judge 74.4ms
the workflow stays scheduled, complete and fail-closed · 4 tests
✓
catches a removed schedule — a smoke on dispatch runs when someone remembers 73.1ms
✓
catches a workflow that no longer invokes the smoke 69.2ms
✓
catches RLS_ALLOW_WRITES being turned off — the run would prove reads only 71.3ms
✓
catches a missing-secret branch that passes instead of failing 70.4ms
the smoke script still proves what it claims · 3 tests
✓
catches the cross-tenant read being removed 72.6ms
✓
catches the script ignoring a secret the workflow passes it 67.3ms
✓
the guarded files exist at the paths the guard names 0.5ms
the guard is wired, or it is a script nobody runs · 1 test
src/chat/send-flow-e2e.vitest.ts
I4: the chip gives a card, the typed approval sends exactly that card · 4 tests
✓
two user turns, no model round, no Jev on the chip, 9 sent — the ones previewed 68.4ms
✓
the exact chip on the card sends without Jev 4.7ms
✓
a subset reply never sends: count rail first, no Jev call, the model takes it and can only re-stage 9.9ms
✓
a conditional reply Jev scores low never sends 2.7ms
the adjacency rail: a card with anything after it is not approvable in words · 1 test
✓
an assistant message between card and reply → no Jev call; the model's confirm:true re-stages; the chip then sends 7.1ms
model prose that imitates the card is not the card · 3 tests
✓
"Ready to send 3 emails…" in prose over a 9-email record → no Jev call, nothing sent 6.5ms
✓
the same count with the card's own ask, but not the card → not live either 2.5ms
✓
the card with anything appended to it is not the card 2.7ms
I1: an unrelated "yes" never sends · 2 tests
✓
with a cost card pending, "yes" is the cost card's answer and Jev is never asked 3.4ms
✓
a card staged in another conversation is not approvable here, and its chip re-stages 4.1ms
I2: an expired card re-previews · 1 test
✓
the chip after expiry says nothing was sent and shows a fresh card 4.3ms
the paraphrase band stages only on Jev's yes · 1 test
✓
"send the drafts" at 0.93 stages; at 0.5 the model takes it 2.4ms
src/chat/send-outcome-format.vitest.ts
what went out is counted, never contradicted · 6 tests
✓
all went out: terse, unchanged 8.2ms
✓
1 ok, 1 failed: the count, the one that failed and why, a retry of only that one 0.6ms
✓
all failed for one reason: "None went out" — the one case where it is true 0.4ms
✓
several failed for one reason while one went out: grouped, and no "none went out" 0.4ms
✓
mixed reasons: each reason once, single-address reasons as "address — reason" 0.3ms
✓
a single email that failed reads as one email, not a run 0.2ms
what nobody can confirm is said, held, and never offered again (DECISIONS #52) · 5 tests
✓
no answer from the email service: Delivery unconfirmed with the next step, and no retry offer 0.7ms
✓
nothing went out but one is unconfirmed: still never "None went out" 0.5ms
✓
an outcome that could not be recorded: named, held, and kept out of the retry count 0.6ms
✓
rows another run took are named as such, not as failures 0.3ms
✓
the retry count comes from the dispatcher when it says so — never from a held row 0.3ms
the next step is a button · 1 test
✓
a retryable failure gets Open Drafts and the product send string; a held-only run does not 0.7ms
src/chat/turn-evidence.vitest.ts
call identity · 3 tests
✓
collapses two reads of one URL that differ only by the extract HINT 1.8ms
✓
separates searches that differ by site scope 0.8ms
✓
is case- and whitespace-insensitive, so trivial variation is still a repeat 0.2ms
what counts as new evidence · 3 tests
✓
a repeat is never novel, however good the result 0.4ms
✓
a GAP is recorded but is not novelty 0.3ms
✓
a search that ran and found nothing is not novelty either 0.3ms
when it stops — and when it must NOT · 6 tests
✓
does not stop while anything new is still arriving 0.2ms
✓
stops when a turn made calls and learned nothing 0.3ms
✓
a turn made ENTIRELY of repeats counts as calls, and stops 0.5ms
✓
a turn of pure thinking is NOT stagnation 0.3ms
✓
the ledger spans the RUN, not one turn — a page fetched on turn 1 is known on turn 4 0.4ms
✓
only evidence tools participate — a campaign write repeated is a different question 0.2ms
src/chat/turn-floor.vitest.ts
the turn floor · 2 tests
✓
is the cheapest turn ever measured, not a guess 1.4ms
✓
is larger than the estimate buffer — the buffer could never have done this job 0.3ms
the check runs BEFORE the model, not at tool dispatch · 6 tests
✓
gates on the balance and returns without calling a model 0.4ms
✓
the gating read is STRICT — a failed ledger must not read as a zero balance 0.2ms
✓
REUSES the existing turnBalance read instead of adding a second one 0.2ms
✓
an UNKNOWN balance proceeds — a failed read must not lock out a paying user 0.2ms
✓
does not report the refusal as a fault 0.2ms
✓
names the action that helps and stays token-denominated 0.2ms
deterministic shortcuts stay reachable at zero balance · 1 test
✓
the floor sits inside runChatV2, which runs only after tryChatShortcut 0.9ms
the model chain leads with the one that caches · 3 tests
✓
deepseek leads TOOL_MODELS 0.4ms
✓
every tier leads with deepseek 0.4ms
✓
llama is retained as the fallback — deleting it leaves no tool-capable backup 0.2ms
src/connectors/notion-token.vitest.ts
the invented expiry is gone · 2 tests
✓
the callback records an expiry only when Notion states one 1.8ms
✓
and so does the refresh path, so it cannot reintroduce the same lie 0.3ms
nothing that is not a token leaves as one · 4 tests
✓
the raw-secret fallback is gone 0.3ms
✓
a legacy plain-string secret is accepted only if it could be a bearer token 0.2ms
✓
a parsed document with no access_token returns null, which routes to the connector gate 0.2ms
✓
the token is trimmed — a trailing newline is the classic malformed-header cause 0.2ms
a refresh failure does not lose a token that never expired · 2 tests
✓
falls back to the stored token rather than null or a blob 0.3ms
✓
and reports the failure instead of swallowing it 0.2ms
the header itself was never the problem · 1 test
✓
notionApi has always sent Bearer, which is why the value was the suspect 0.4ms
a failed refresh repairs the record that caused it · 3 tests
✓
writes expires_at back to 0, so the refresh is tried once per connection, not once per publish 0.3ms
✓
reports it as a log, not a fault — the token is valid and the publish proceeds 0.3ms
✓
and a failed repair does not break the publish it was trying to help 0.2ms
src/db/db-timeout.vitest.ts
the database seam: every call ends inside a limit, and a timeout is a typed, reported failure · 7 tests
✓
the default limit follows the entry: 10 s where a person waits, 30 s everywhere else 4.0ms
✓
a hung database on a request path rejects with DbTimeoutError naming the operation, and Sentry hears it 107.3ms
✓
the same call on a cron path waits the longer budget 153.3ms
✓
a database that sends headers and then stalls is the same hang 153.7ms
✓
an override is honoured, and an outer abort is rethrown as it is, not reported as a timeout 229.9ms
✓
CONTROL: a database that answers is unchanged, and the call still carries the signal 1.8ms
✓
what the person reads: a route gets its own sentence, never the database text 43.4ms
the calls allowed past the default limit · 2 tests
✓
each override equals the deadline that already races the call, so the two cannot drift 61.8ms
✓
the override register is the complete list: a new long call is a deliberate edit here 202.8ms
a hung database on the real request, cron and queue paths · 3 tests
✓
GET /api/sequences answers with its own sentence inside the limit, and the timeout is reported with its operation 74.4ms
✓
the 08:00 cron completes inside its limit and reports the timeout under the cron budget 350.3ms
✓
a queue batch completes inside its limit, its message is settled, and the timeout is reported under the queue budget 927.6ms
src/leads/audience-fit.vitest.ts
when NOT to ask — every one of these is a wasted interruption · 4 tests
✓
no product brief: there is nothing to judge the audience against 1.8ms
✓
a one-line brief cannot support a mismatch claim 0.3ms
✓
no audience: preflightAsk already owns that case and asks a better question 0.2ms
✓
asks in the one case that motivated it 0.2ms
parsing the model answer — a bad response must not become a bad card · 4 tests
✓
reads a well-formed mismatch 0.8ms
✓
DOWNGRADES a mismatch with no reason — a warning you cannot act on is noise 0.3ms
✓
treats anything unparseable as no finding, never as a mismatch 0.7ms
✓
bounds the strings so a runaway answer cannot flood the card 0.3ms
what the user actually sees · 4 tests
✓
renders nothing at all unless there is a real mismatch 0.5ms
✓
ALWAYS leaves the user a way through, without inventing a second protocol token 0.3ms
✓
offers the brief as a repair too, because a mismatch never says which side is wrong 1.1ms
✓
is phrased as an observation before spending, not as a refusal 0.2ms
src/metrics/registry.vitest.ts
metric registry — canonical formatting · 4 tests
✓
a score/100 never renders as a bare percent (the 87%-vs-12/22 mislabel class) 2.1ms
✓
a non-finite value formats as an honest blank, never NaN%/undefined/100 0.7ms
✓
an unknown metric id defaults to percent formatting (safe fallback) 0.3ms
✓
metricLabel returns the canonical label, id as fallback 0.2ms
metric stamping + cross-report consistency (Dim 5) · 6 tests
✓
stampMetric emits canonical text + machine-readable data-* attributes 0.4ms
✓
a blank value stamps an empty data-value, not "NaN" 0.2ms
✓
extractMetricStamps round-trips what stampMetric emits 1.0ms
✓
checkMetricConsistency catches the same metric showing two values in one epoch 1.0ms
✓
the same metric across DIFFERENT epochs is not a violation (reports are frozen artifacts) 0.6ms
✓
consistent values across reports pass 0.4ms
epochOf — stable data-epoch derivation · 2 tests
✓
prefers a persisted snapshot identifier over anything time-based 0.3ms
✓
falls back to a deterministic per-result token for live one-shot data (never wall-clock) 0.2ms
src/middleware/entity_audit.vitest.ts
nameCorresponds / normEntityName · 4 tests
✓
strips legal suffixes and punctuation 2.3ms
✓
same entity across legal-form and short/long variants → corresponds 0.4ms
✓
a different same-word namesake → does NOT correspond 0.2ms
✓
cannot judge when a name is missing → corresponds (no invented collision) 0.2ms
kgSearch verdicts · 5 tests
✓
REGRESSION (glenindia.com): a same-type DIFFERENT company is an identity collision, not partial 27.1ms
✓
a thin but corresponding entity is still partial 0.6ms
✓
corresponding + detailedDescription → recognized 0.6ms
✓
wrong TYPE is still a (type) collision 0.4ms
✓
no result → invisible 0.8ms
entityAudit summary · 1 test
✓
glenindia.com run: 1 identity collision → collision=1, health=15 (not partial/45) 1.3ms
entityAudit competitor comparison · 2 tests
✓
audits competitors separately and NEVER folds them into the own-brand summary/health 2.6ms
✓
omits the comparison entirely when no competitors are passed 0.6ms
src/reports/godmode-indexing.vitest.ts
god_mode indexing section — gold standard · 3 tests
✓
sources coverage from the live index with no quota language 1.9ms
✓
shows the free-tier upsell 0.3ms
✓
adds a site: check link + copy-fix prompt + submit-for-indexing action 0.9ms
god_mode signal overview — §17.1 EVERY dimension aggregated · 3 tests
✓
renders one signal card per dimension (problems + healthy), fix buttons only on problems 0.5ms
✓
detail accordions are collapsed by default (bento is the primary surface) 0.3ms
✓
appends result.insights_html so async delivery matches the sync artifact (keep-both parity) 0.5ms
god_mode telemetry — honest run-cost footer · 2 tests
✓
reports the real URLs-checked count and the billed index checks on paid tier 0.6ms
✓
says "included" on the free tier and only "no extra token cost" when nothing was checked 0.8ms
god_mode health score — a partial measurement must not read as a confident grade · 4 tests
✓
renders a letter grade and a confident colour only when every component was measured 0.8ms
✓
withholds the grade, greys the score and NAMES the missing signals when components are absent 0.6ms
✓
treats a sampled index check as provisional even when every component IS present 0.6ms
✓
leaves artifacts saved before the field existed on their original confident rendering 4.5ms
src/routes/free-tool-cache.vitest.ts
the key is bounded BY CONSTRUCTION, not by a remembered truncation · 4 tests
✓
the URL that actually broke it produces a legal key 1.8ms
✓
any input length yields a key well under the 512-byte KV limit 6.2ms
✓
distinct URLs that share a long prefix do NOT collide 1.4ms
✓
the same URL always yields the same key — a shared link must show the shared score 0.7ms
a cache can never fail the request · 6 tests
✓
a THROWING get still returns the computed result — the live 414 0.8ms
✓
a THROWING put still returns the computed result 0.6ms
✓
unparseable cached JSON recomputes instead of throwing 0.6ms
✓
no KV binding at all still works 0.5ms
✓
a HIT is served from cache and does not recompute 1.1ms
✓
writes under the shared TTL so a shared link outlives the visit 0.7ms
both free tools use the one implementation · 2 tests
✓
src/routes/geo-scorecard.ts delegates instead of building its own key 0.7ms
✓
src/routes/ai-search-prompt-generator.ts delegates instead of building its own key 0.4ms
src/runtime/async-jobs-ledger.vitest.ts
F4 — a failed job writes an async_job ledger row · 3 tests
✓
failAsyncJob (terminal) writes status=failed keyed by the job, with the error CLASS not its text 5.2ms
✓
a non-terminal (retrying) failure is marked terminal=0 0.6ms
✓
deadLetterAsyncJob writes status=dead_lettered, keyed so a DLQ redelivery writes no second row 0.8ms
F4 — a balance refusal writes a refused tool_run row (wiring, index.ts is not importable) · 2 tests
✓
the preflight refusal branch writes tool_run status=refused before returning 0.4ms
✓
the serpdex dead-letter consumer writes the same dead_lettered row 0.3ms
F7 — sweepStalledAsyncJobs · 7 tests
✓
marks a job running past its SLA as stalled, with ledger rows, a Sentry Issue and the failure email 2.1ms
✓
the stalled tool_run row carries the caller like the other three writers (V12b-scope-F01): the job's own user 2.7ms
✓
a months-old stuck row (the r14 2026-07-12 one) is marked and reported but NOT mailed 0.8ms
✓
a job that finished between the read and the write keeps its outcome (guarded update, raced) 0.9ms
✓
asks only for rows past the SLA, and a failed listing throws so the cron reports it 1.7ms
✓
a row it marked is never filed again: the second sweep over the same table reports nothing 0.8ms
✓
runs on the hourly arm inside its own wall-clock budget 4.3ms
src/runtime/guardrail-empty-message.vitest.ts
guard 1 — the rule substitutes, like its siblings · 5 tests
✓
no longer empties a reply that is only the leaked directive 5.0ms
✓
still redacts it — the leak does not survive 1.4ms
✓
keeps the surrounding prose when the directive is embedded 1.0ms
✓
no REDACT rule may empty a non-empty string 2.1ms
✓
a real BLOCK still blocks and still returns the fallback 0.3ms
guard 2 — an emptied message is treated as a block, not a deletion · 4 tests
✓
assigns the fallback rather than deleting the message 0.2ms
✓
tears down the artifact, exactly as the BLOCK path does 0.3ms
✓
still deletes the four OPTIONAL fields when they empty 0.2ms
✓
reports it — an unreachable branch that fires is news 0.5ms
guard 3 — the client never renders a raw payload · 2 tests
✓
has no JSON.stringify fallback left anywhere 0.5ms
✓
falls back to honest copy instead 0.3ms
one voice for "cannot show this" · 1 test
✓
index.ts no longer carries its own copy of the sentence 0.5ms
src/runtime/public-error-routes.vitest.ts
publicErrorText: what a route may put in front of the person for a failure · 4 tests
✓
a supplier's error constant, or its name in a sentence, never reaches the person 9.3ms
✓
a model-chain failure becomes the sentence the router writes for it, with no model slug 0.7ms
✓
a string the guardrail would alter or block, or nothing at all, becomes the route's own sentence — never a half-redacted one 0.9ms
✓
CONTROL: an ordinary sentence is left as it is 2.5ms
the routes a signed-in browser reaches · 2 tests
✓
POST /api/keywords/refresh: the provider's refusal reaches the Keywords panel as a sentence without its name 81.6ms
✓
POST /api/contacts/verify: the run is reported in tokens; what the verifier charged in dollars stays on the server 8.8ms
GET /api/dashboard: an engine that could not be asked says so without the engine vendor's own words · 1 test
✓
the "why?" text on an errored engine meets the guardrail 48.3ms
the wiring: every one of these routes returns its failure through publicErrorText · 5 tests
✓
the keyword refresh, the verify and the research catches 2.0ms
✓
the verify route drops the dollar figure before it answers 1.1ms
✓
the product scan, on both of its failure answers 1.0ms
✓
the draft generator's partial errors 0.7ms
✓
the dashboard's engine errors 0.9ms
src/tools/competitors-wave2.vitest.ts
seo_competitor_gap · 3 tests
✓
accepts the declared name 2.2ms
✓
rejects the retired domain alias 0.4ms
✓
accepts the empty call — the saved competitor set is the fallback (2026-08-11) 0.2ms
find_competitors · 3 tests
✓
accepts the empty call — "my competitors" is the common case 0.2ms
✓
accepts a named third-party domain 0.2ms
✓
rejects an invented argument 0.3ms
the dispatch now matches what it declares · 4 tests
✓
find_competitors reads the site it declares 0.4ms
✓
find_competitors skips the saved set when another brand is named 0.2ms
✓
seo_competitor_gap no longer coalesces domain 0.7ms
✓
leaves still-legacy tools their fallbacks 0.3ms
the clarify gate asks about fields that exist · 2 tests
✓
seo_competitor_gap probes the field the tool actually takes 0.3ms
✓
does not gate seo_enrich_keywords on its own default mode 0.2ms
src/tools/confirm-rescue.vitest.ts
the disagreement that produced the dead turn · 3 tests
✓
preflightAsk lets these arguments PAST the cost card 4.2ms
✓
but the schema rejects them, which is what ended the turn 1.4ms
✓
so the confirmed call rescues them instead of refusing 1.7ms
the rescue keeps what the user got right · 3 tests
✓
drops only the unaccepted member, not the whole filter 2.7ms
✓
falls back to dropping the field when NO member survives 1.3ms
✓
leaves a fully valid call alone 0.3ms
what it refuses to rescue · 3 tests
✓
never rescues by silence — the dropped part is always returned 1.4ms
✓
returns null when there is nothing droppable to rescue 0.4ms
✓
never rescues a cross-field conflict by dropping one half of it 0.5ms
the note the user reads · 3 tests
✓
says what could not be applied and that the rest was 0.3ms
✓
is empty when nothing was dropped, so a clean run stays clean 0.2ms
✓
does not repeat a value dropped from two fields 0.8ms
src/tools/poll-budget.vitest.ts
pollDeadlineMs — a poll loop cannot outlive the harness timing it · 4 tests
✓
is strictly inside the tool budget 1.7ms
✓
reserves headroom for the work AFTER the last poll 0.3ms
✓
never returns a nonsensically small deadline for a short-budget tool 0.3ms
✓
the graceful degradation is reachable — 240s never was, under a 120s budget 0.4ms
the graceful outcome is not a defect · 2 tests
✓
"taking longer than usual" is an EXPECTED outcome 2.8ms
✓
a real crash is still reported 2.0ms
no tool polls past its own timeout budget · 1 test
✓
every literal poll deadline is inside its enclosing tool budget 134.7ms
composite budgets contain their nested children (owner 2026-07-28) · 2 tests
✓
full_seo_audit outlives the on-page crawl it nests, with room to spare 0.3ms
✓
the on-page budget is the 3 minutes the crawl actually needs 0.6ms
seo_serp_spider — the same inversion, found 2026-08-31 · 3 tests
✓
the poll is derived from the budget, so the two-turn fallback is reachable 0.3ms
✓
the crawl budget matches its sibling crawl, and covers the measured 144s run 0.3ms
✓
seo_keyword_metrics is off the 30s default it kept overrunning by 4-5s 0.1ms
src/seo/corroboration-sources.vitest.ts
the premise is measured, not assumed · 4 tests
✓
rules the crowd premise OUT when the category does not read that way 1.9ms
✓
a rival site is NOT independent corroboration 0.4ms
✓
the decision refuses the spend, and carries the honest coverage line 0.9ms
✓
the situation names the actual diet rather than a category average 0.2ms
when the crowd premise DOES hold · 3 tests
✓
independent corroboration survives and leads 2.3ms
✓
forums-on-best-X is measured on the COMPARISON prompts, not the whole panel 1.0ms
✓
no comparison prompt is a different sentence from "forums are absent" 0.7ms
what it will not do · 5 tests
✓
local presence is untested BY DECISION, and says so 1.4ms
✓
thread influence needs comparable runs, and names the panel as the fix 2.2ms
✓
never tells the user to buy reviews 3.2ms
✓
an ungrounded run says the models answered from memory 7.4ms
✓
a high unclassified share is disclosed rather than absorbed 1.0ms
src/seo/crawl-evidence.vitest.ts
IP ranges · 3 tests
✓
matches IPv4 and IPv6 CIDRs, and never crosses families 2.6ms
✓
reads the published list shape every engine uses 0.8ms
✓
a name from outside the list is spoofed; a list that failed to load is unverifiable, never verified 0.5ms
access logs · 4 tests
✓
parses combined format and Cloudflare Logpush JSON alike 1.6ms
✓
matches the specific bot token, case-insensitively 0.3ms
✓
counts verified and spoofed hits apart, AI referrals only for pages, and keeps no addresses 2.3ms
✓
says which bots could not be verified 0.5ms
referrers and engines · 3 tests
✓
maps AI app hosts; Google search is not an AI referral 0.7ms
✓
AI Mode referrals are unmeasurable (sent as google.com), not zero 0.5ms
✓
Googlebot counts for both AI Mode and Gemini 0.6ms
DataFast adapter · 2 tests
✓
yields the same shape as a log upload; unknown bots kept but never counted toward an engine 0.9ms
✓
a failed referrer call leaves referrals unknown, not zero 0.2ms
src/seo/crawler-access.vitest.ts
the contradiction between our fetch and the crawler · 7 tests
✓
is reported for the live case 2.2ms
✓
says NOTHING when the crawler got in — the ordinary case must stay silent 0.4ms
✓
says NOTHING when the site is genuinely down for us too 0.3ms
✓
treats an UNKNOWN probe as agreement, never as contradiction 0.2ms
✓
matches the root even when the crawl returned other pages first 0.3ms
✓
handles www and scheme differences in the stored url 0.2ms
✓
survives junk urls without throwing 1.0ms
the rest of the report agrees with the disclosure · 5 tests
✓
does NOT tell them to fix a page it just said is not broken 5.2ms
✓
does NOT present a hygiene grade over a crawl that was refused 0.6ms
✓
keeps the status code the guardrail would otherwise redact 0.4ms
✓
points at the issues in the direction they actually are 0.4ms
✓
an ordinary refused-free report is completely unchanged 0.3ms
src/seo/enrich-keywords-readiness.vitest.ts
the denominator is what the RUN will process · 5 tests
✓
uses the named set, not the stored set — a never-seen keyword still gets bought 2.7ms
✓
windows the stored set in the QUERY, the way the dispatcher windows it 0.6ms
✓
does not window a NAMED set — the user asked for exactly those 0.4ms
✓
never reports more fresh than total 0.4ms
✓
dedupes and lowercases the named set the way the dispatcher does 0.5ms
what counts as fresh · 3 tests
✓
requires a real number, not just a recent stamp 0.3ms
✓
scopes both counts to the tenant 0.3ms
✓
uses the same 30-day window the volume path already treats as fresh 0.3ms
when it speaks · 4 tests
✓
says nothing about a trivial number or share of re-buys 0.5ms
✓
says nothing when nothing is fresh — the ordinary, correct case 0.3ms
✓
names how many actually need refreshing, not just how many are wasted 0.3ms
✓
says ALL when there is nothing to gain at all 0.2ms
src/seo/gsc-property-scoping.vitest.ts
a GSC property is never borrowed from another domain · 4 tests
✓
uses the property that matches the audited host 1.9ms
✓
REFUSES the connector default when it is a different domain 0.4ms
✓
accepts the default only when the default IS the audited host 0.3ms
✓
returns nothing when there is no host to match 0.2ms
the report names the CAUSE, so the remedy fits it · 5 tests
✓
connected, but this domain is not a verified property — never says "connect Google" 27.1ms
✓
connected and matched, but the check returned nothing — never blamed on the site 0.5ms
✓
genuinely not connected — this is the only case that says so 0.4ms
✓
a reason is never rendered as coverage data 0.5ms
✓
real coverage still renders as coverage 0.8ms
the full-audit gap list distinguishes the same four causes · 3 tests
✓
names the property gap instead of blaming the connection 0.4ms
✓
does not name a CAUSE it never measured 0.3ms
✓
still says "not connected" when that is actually true 0.2ms
src/seo/onpage-resume.vitest.ts
on-page crawl — resume before restart · 8 tests
✓
resumes the in-flight crawl for the same site at the same depth 1.9ms
✓
resumes a DEEPER in-flight crawl for a shallower request — it can answer it 0.4ms
✓
never serves a SHALLOWER crawl under a deeper request 0.2ms
✓
never crosses sites — the marker is keyed per user, not per site 0.2ms
✓
matches domains the way the rest of the SEO stack does (protocol/www/case) 0.2ms
✓
does not reuse a crawl older than the working session 0.2ms
✓
still reuses a recent one, and a marker with no timestamp 0.3ms
✓
falls back to a fresh crawl on a missing, unreadable or task-less marker 0.4ms
on-page crawl — the deadline branch is observable and does not bill twice · 4 tests
✓
reports the overrun to Sentry and to the feature table 0.8ms
✓
carries how far the crawl actually got, not just that it stopped 0.2ms
✓
no longer instructs the user to run it again — that meant paying twice 0.3ms
✓
only writes the marker on a fresh start, so a resume cannot shrink the stored ceiling 0.1ms
src/seo/revenue-attribution-classify.vitest.ts
aiEngineLabel · 4 tests
✓
names the engines a user would recognise 2.0ms
✓
maps every alias of one engine to a single label 0.5ms
✓
matches subdomains but NOT lookalike domains 0.4ms
✓
returns null for a non-AI source rather than guessing 0.3ms
isAiEngineSource · 3 tests
✓
does not treat direct or unset traffic as AI 0.3ms
✓
normalizes scheme and www before matching 0.2ms
✓
is case-insensitive 0.2ms
classifyMacroChannel · 5 tests
✓
routes AI traffic to AI Chat Engines even though GA4 files it as Referral 0.3ms
✓
splits search into Google vs Other 0.5ms
✓
keeps DuckDuckGo in search, NOT in AI Chat Engines 0.3ms
✓
maps the remaining groups and falls back to Other 0.3ms
✓
is case-insensitive on the channel group 0.1ms
src/seo/sov-schedule.vitest.ts
the daily dispatcher is actually registered · 3 tests
✓
every cron expression the worker branches on exists in wrangler.toml 3.8ms
✓
has no day-of-week field, so the platform DOW offset cannot apply 0.4ms
✓
the cron gates on the tenant day — a daily tick without it runs 7x a week 0.3ms
isSovDueToday · 3 tests
✓
defaults to Sunday, which is the day the old weekly tick fired 0.4ms
✓
fires on exactly one day per week for a given tenant 0.4ms
✓
an out-of-range or junk day falls back to Sunday rather than never running 0.4ms
the weekly config round-trips all three fields independently · 5 tests
✓
keeps a frozen panel, engines and day together 1.1ms
✓
a day-only config is still a config 0.3ms
✓
dedupes and bounds stored prompts 0.6ms
✓
caps a stored panel 0.7ms
✓
rejects a junk day instead of storing it 0.3ms
setting one field does not wipe the others · 1 test
✓
the dispatcher merges against the stored config 3.5ms
src/seo/sov-weekly-panel.vitest.ts
weekly AI-visibility panel · 5 tests
✓
runs 12 prompts on a paid plan — not silently clamped by the plan cap 1.8ms
✓
defaults to THREE engines, with Claude deliberately not in the recurring run 1.8ms
✓
still lets a paid user CHOOSE Claude — dropped from the default, not removed 0.5ms
✓
holds the free tier to one engine, so the cron cannot run for them 0.4ms
✓
the cron builds its rotation from the SHARED constant, never a literal 0.6ms
the free-tier plan gate announces itself · 3 tests
✓
does not silently continue past the sov_weekly plan gate 0.3ms
✓
offers the action that actually resolves it 0.3ms
✓
the balance gate still announces itself too — both gates, same standard 0.2ms
a frozen panel is priced by what will run, not by what the plan allows · 4 tests
✓
THE LIVE CASE: 8 frozen against a cap of 12 counts as 8 0.5ms
✓
a rotating panel still fills the cap 0.2ms
✓
a frozen panel LARGER than the cap is bounded by the cap 0.3ms
✓
never returns zero — a zero would price a run at nothing 0.2ms
src/seo/tool-outcome.vitest.ts
seo_monitor writes exactly one outcome record per run · 4 tests
✓
a run that compared history leaves ONE record, outcome ok, naming the sections 21.3ms
✓
nothing to compare leaves ONE record under its own name — not ok 0.9ms
✓
a FAILED history read is a failed run: one failure record, no ok, and the user is not told "no history" 4.1ms
✓
a record that cannot be written never takes the answer away, and is reported 0.8ms
seo_generate_llms_txt writes exactly one outcome record per run · 5 tests
✓
a reachable site leaves ONE record, outcome ok, carrying the generated file 33.1ms
✓
a site that never answered is NOT ok: one site_unreachable record, and no "looks clean" claim 1.4ms
✓
a 404 robots.txt is absent, not unreadable — nothing blocks the bots, and the site was reached 2.5ms
✓
a site whose sitemap answered was reached, even when robots.txt could not be read 1.5ms
✓
a run that THREW leaves one failure record, never an ok 3.1ms
run records are not measurements — the readers that listed every audit_type · 3 tests
✓
diagnose evidence still sees the on-page audit behind 40 newer run records 1.2ms
✓
the signup digest lists audits, not run records 0.6ms
✓
the account export carries the tenant's llms.txt and outcome, never our run id 0.6ms
src/seo/video-decision.vitest.ts
the answer is do not commission, stated plainly · 5 tests
✓
says it in as many words 2.3ms
✓
frames it as the rule applied, not as a gap 0.6ms
✓
the ask makes the refusal the deliverable 0.4ms
✓
confirms the stay-as-text default on the ABSENCE of the precondition 0.5ms
✓
flips once a video platform is connected 0.6ms
what it will not claim · 3 tests
✓
never says the results pages do or do not show video 0.3ms
✓
never rules the audience in or out — it reports that nothing can see 0.4ms
✓
keeps the two-indexes point as a rule rather than dressing it as a finding 0.5ms
the free fix it does find · 3 tests
✓
flags embeds that never reached a live address 1.0ms
✓
does not flag them once they are published 0.4ms
✓
always states the packaging rules for anything that does get made 0.8ms
no internal vocabulary reaches the user (GS-005) · 1 test
✓
keeps field and table names out of the prose 0.5ms
src/seo/visibility-signals.vitest.ts
problems sort to the front · 2 tests
✓
orders problem → unmeasured → ok, so the broken card is read first 5.6ms
✓
a healthy panel still renders cards, marked ok, with no action button 0.4ms
an engine we could not reach is never a zero · 3 tests
✓
reports coverage as unmeasured and names the engine 0.4ms
✓
does not claim an engine spread while an engine is missing 0.3ms
✓
flags a real spread only when it is worth acting on 0.3ms
invisible questions — the most actionable card · 2 tests
✓
counts only prompts we could actually test 0.4ms
✓
says so plainly when there is no gap 0.3ms
competitive card · 2 tests
✓
names who is ahead and by how much 0.4ms
✓
is ok when we lead 0.5ms
cards decline to appear rather than invent a number · 3 tests
✓
emits nothing measurable when there is no visibility detail at all 0.2ms
✓
an unmeasured pillar says unmeasured, never 0 0.3ms
✓
the weakest page names what is holding it back when the scorer said so 0.2ms
src/seo/website-health-phases.vitest.ts
chunked and single-shot agree · 2 tests
✓
produces an identical report for the same site 54.1ms
✓
splits into more than one batch when the site is larger than a batch 5.1ms
verification turns a guess into a measurement · 3 tests
✓
reports a link that resolves as live, not broken 6.0ms
✓
reports a link that 404s as broken, and charges for it 7.9ms
✓
without the verify phase, nothing is called broken and nothing is charged 4.2ms
subrequest budget · 5 tests
✓
discovery stays far under the ceiling 2.1ms
✓
one fetch batch spends at most one request per URL in the batch 60.5ms
✓
one verify batch spends at most one request per target 1.2ms
✓
scoring makes no requests at all 3.0ms
✓
the declared budgets cannot be edited past the platform ceiling 0.3ms
expansion actually crawls what it discovers · 2 tests
✓
places new URLs in a batch range that will be fetched 0.9ms
✓
expands into linked pages the sitemap never listed 2.7ms
src/leads/shared/consumer-mailbox-list.vitest.ts
158 · it adds exactly the reviewed set · 3 tests
✓
inserts 40 domains 2.5ms
✓
covers the highest-volume gap in each non-US country 1.6ms
158 · no real employer domain is ever classified consumer · 2 tests
✓
none of them is in the insert list 1.2ms
✓
the migration asserts it at apply time too 0.3ms
158 · the derivation requires BOTH signals · 3 tests
✓
the candidates function tests self-domain rate and modal employer share 0.2ms
✓
and excludes what is already listed, so re-running proposes only new work 0.2ms
✓
the function PROPOSES and never writes 0.4ms
159 · the tool warns the next person with a measured number · 4 tests
✓
states the one-in-three false-positive rate and forbids bulk insertion 0.6ms
✓
names the employers the tool actually proposed, so the warning is checkable 0.4ms
✓
verifies its own comment landed 0.3ms
✓
changes nothing but the comment 0.3ms
scripts/lib/code-only.vitest.mjs
codeOnly · 11 tests
✓
keeps the length and every newline, so indices and line numbers still point at the original 2.3ms
✓
a call in a line comment, a block comment, a string or a dead template text is not a call 0.6ms
✓
a call inside a template INTERPOLATION is a call — the ledger readers build their GraphQL that way 0.4ms
✓
THE URL TRAP: `//` inside a string, a template or a regex does not open a comment 0.5ms
✓
division is not a regex: a / b / c, and a comment after it still is one 0.3ms
✓
a postfix ++/-- ends an expression: `x++ / 2` is division, so the call after it is still a call (V-lows-F07) 0.3ms
✓
one lex per source text: the same file asked twice is the same string, both forms from one pass (V-lows-F01) 0.5ms
✓
a regex after a keyword is a regex (return /…/), not division 0.2ms
✓
escaped quotes do not end a string early 0.5ms
✓
keepStrings blanks comments only 1.0ms
✓
isCodeAt: a position inside a string is not code; its opening quote and the code around it are 0.3ms
src/admin/corpus-rung.vitest.ts
what an operator is told · 6 tests
✓
says OFF FOR EVERYONE when the flag is unset — the case nobody could see 2.0ms
✓
distinguishes a tenant ON the list from one that is not 0.4ms
✓
reports the ROLLOUT WIDTH without naming who is on it 0.4ms
✓
answers NULL, not false, when no tenant was named 0.2ms
✓
separates "no database" from "flag off" — different failures, different fixes 0.2ms
✓
says armed-for-everyone when the flag is 1 0.3ms
reveal billing is reported separately from access · 5 tests
✓
says billing is OFF when the flag is unset, whatever access says 0.3ms
✓
tracks the two flags independently 0.2ms
✓
does not claim a no-verdict reveal is free, because it is not 0.8ms
✓
still says a reveal prices from the verification behind it 0.3ms
✓
only a proven bounce and an unscopeable verdict are free 0.3ms
src/admin/feature-detail.vitest.ts
sanitiseFeatureFields · 5 tests
✓
accepts ordinary attribute names 2.3ms
✓
trims whitespace around names 0.4ms
✓
drops anything that is not an attribute name 0.3ms
✓
handles absent input 0.3ms
the reader keeps null and empty distinguishable · 2 tests
✓
the handler reports WHY there are no rows rather than only that there are none 0.8ms
✓
always requests the message column, which is the stable contract 0.5ms
the numeric pass is separate on purpose · 4 tests
✓
asks for the typed accessor for numeric attributes 0.3ms
✓
issues it as a SECOND request rather than one combined field list 0.6ms
✓
a failed numeric pass never costs the string attributes 0.4ms
✓
never overwrites a value the string pass already resolved 0.2ms
src/admin/gsc-reconcile.vitest.ts
buildReconciliation — the live window that started it · 4 tests
✓
splits the 23 days into the 7 that had ad spend and the 16 that did not 2.9ms
✓
on clean days the two tools agree — 36 DataFast visitor-days vs 29 GSC clicks 0.4ms
✓
estimates the untagged paid part with the stated formula, and ~87% of DataFast "Google" is paid 0.7ms
✓
keeps every day, with each source per day 1.1ms
buildReconciliation — a missing source is named, never zeroed · 2 tests
✓
without DataFast the analytics side is null and the summary says why 0.5ms
✓
without Ads data, ad days fall back to TAGGED visits and the basis says so 0.4ms
time zones · 3 tests
✓
knows IST, PDT and PST offsets 14.6ms
✓
turns a local wall-clock time into its UTC instant 0.8ms
✓
re-buckets Ads hours from the account zone onto Pacific days (rows from the live GAQL probe) 2.1ms
fetchers · 2 tests
✓
DataFast: Pacific-Time day buckets, the filters as sent, null when not configured 26.9ms
✓
Google Ads: one GAQL call through the broker, a day wider than the window, clicks parsed from strings 1.1ms
src/admin/gsc-scan.vitest.ts
startAdminGscScan · 7 tests
✓
exact-probes the universe and buckets the not-indexed URL 56.2ms
✓
with a queue binding: enqueues chunk 1 and advances one chunk at a time (no inline drain) 38.3ms
✓
watchdog resurrects a stalled running scan (enqueues one chunk), leaves a fresh one alone 1.7ms
✓
records and reads submitted URLs (merge + de-dupe across calls) 0.8ms
✓
stop halts a running scan and preserves progress so far — owner kill switch (2026-08-01, no way to stop a paid scan mid-flight) 0.7ms
✓
stop is a no-op on a scan that already finished 0.6ms
✓
errors cleanly when there is no URL universe 38.5ms
probeIndexed — GSC-first fallback logic · 4 tests
✓
with no admin Google connection (gsc=null), goes straight to paid ValueSERP — unchanged prior behavior 1.7ms
✓
an admin connection + quota + an unambiguous Google verdict answers for FREE — ValueSERP never called 1.1ms
✓
an ambiguous Google verdict (NEUTRAL → null) falls through to paid ValueSERP for that URL 1.3ms
✓
quota exhausted for the day skips the free attempt entirely and goes straight to paid 1.4ms
src/admin/publish-register.vitest.ts
publish-register.mjs · 11 tests
✓
a clean register publishes (dry run): the recon seed plus the phase, proposed severities kept apart 189.9ms
✓
exits 2 (blind) on a missing or empty register, never publishing nothing as if it were clean 69.8ms
✓
refuses a UUID: a user or session id never belongs in the register 176.2ms
✓
refuses an email address, and does not echo it 198.0ms
✓
refuses a figure for a sub the catalogue does not define 194.3ms
✓
rates nothing without an owner ratification record: a proposal is never a rating 193.8ms
✓
an owner ratification record rates every PROPOSED severity, and only those 185.2ms
✓
refuses a malformed ratification record instead of rating by accident 1080.1ms
✓
an override may rate a finding that had no proposal, but only with a note saying who rated it 595.3ms
✓
refuses a tree sha that is not a full sha 373.3ms
✓
refuses a scored figure that is not a register figure 200.1ms
src/admin/visibility-page-match.vitest.ts
questions · 1 test
✓
one choice per query over its shortlist plus none_fits; queries addressed by key, never by position 3.2ms
decision · 5 tests
✓
takes Jev's page at or above the floor and keeps the slug verdict beside it 1.2ms
✓
below the floor the slug match stands, with Jev's answer recorded 0.7ms
✓
"none fits" means no page answers it — not the most-cited page 0.4ms
✓
an unsure "none fits" is not a finding: the slug floor stands 0.4ms
✓
a choice that is not on the shortlist is ignored 0.2ms
run · 5 tests
✓
flag off: the slug floor for every query, and no request leaves 1.3ms
✓
flag on: Jev's pick is used and the platform is metered under its own context 27.8ms
✓
a Jev failure falls back to the slug floor and is counted 1.4ms
✓
a fresh cached decision is reused without asking again 0.6ms
✓
a cached decision made against a different catalogue is asked again 0.9ms
src/auth/account-deletion.vitest.ts
softDeleteAccount · 4 tests
✓
sets the lock marker, blanks PII, and revokes credentials — caller-scoped 5.2ms
✓
reports disable_auth_user as a FAILED step when the mutation throws 0.9ms
✓
marker step failure → ok:false, but later failures are isolated (best-effort) 0.5ms
✓
accountDeletedKey is per-user and namespaced 0.3ms
account deletion confirmation · 4 tests
✓
sends the confirmation, and does it LAST — after the lock, scrub and revocations 1.1ms
✓
actually uses the email parameter it has always accepted 0.5ms
✓
uses the exact kind the consent gate exempts 0.8ms
✓
dedupes on the user, with no time window 0.3ms
PII_SETTING_KEYS coverage · 2 tests
✓
every PII key is a real settings key, so erasure targets something that exists 5.5ms
✓
scrubs the business address — the most identifying field we store about the user 0.4ms
the tenant email-provider credentials are deleted with the account (K3 sweep, 2026-09-23) · 1 test
✓
deletes the caller's own __smtp__ row, scoped by user id 0.7ms
src/billing/affordability-gate.vitest.ts
the check lives on the shared path, not on one gate · 3 tests
✓
getCostApprovalPlan reads the balance itself 1.4ms
✓
the agent loop no longer carries its own copy 4.3ms
✓
card and dispatch gate share ONE boundary 0.3ms
an unreadable ledger is NOT a refusal · 1 test
✓
the balance read FAILS OPEN 5.1ms
what the user is told instead · 3 tests
✓
names needed, held and short — and never a Confirm button 0.3ms
✓
the reply offers the one action that changes the outcome 0.3ms
✓
prices are TOKENS, never dollars (CLAUDE.md §4) 0.3ms
coverage is enforced by a guard, not by memory · 2 tests
✓
check-affordability-gates passes over the real tree 47.9ms
✓
it is wired into npm run check 0.8ms
a gate that overrides the plan feeds its own numbers back in · 1 test
✓
aeo_visibility passes the fan-out figures to getCostApprovalPlan 4.3ms
the overrun alarm states an observation, not a conclusion · 1 test
✓
no longer asserts "missing a leg" 6.6ms
src/billing/cost-gate-economics.vitest.ts
fixtures exist · 1 test
✓
found a cheap, an expensive and an always-confirm tool to reason about 1.7ms
the threshold applies in EVERY mode · 3 tests
✓
does not gate a sub-threshold tool, even in confirm mode 0.7ms
✓
does not gate a sub-threshold tool in the default (unset) mode 0.5ms
✓
does not gate a sub-threshold tool in auto mode 0.2ms
gates that are worth their cost still fire · 3 tests
✓
gates an over-threshold tool in confirm and default modes 0.3ms
✓
ALWAYS gates an always-confirm tool, at any size and in any mode 0.8ms
✓
gates a mixed batch when any member qualifies 0.3ms
the threshold is economically coherent · 1 test
✓
is meaningful relative to what a gate itself costs 0.2ms
the two tools marked for SAFETY, not economy (owner ruling 2026-08-09) · 3 tests
✓
verify_contacts confirms by the threshold, not always (owner 2026-09-17) — the re-buy guard lives at dispatch 1.5ms
✓
aeo_visibility always confirms, because its WORST run was its cheapest 0.6ms
✓
marking a tool always-confirm never removes a gate — it can only add one 0.3ms
src/billing/usage-labels.vitest.ts
every context production writes has a name · 3 tests
✓
labels all 64 of them 3.0ms
✓
and the old map would have lost 97.9% of the tokens 0.5ms
✓
puts 97.9% of all spend under Conversations, which is the true answer 0.4ms
the two rules that keep the table small · 2 tests
✓
:failover is a suffix, not a task 0.5ms
✓
the chat family matches by prefix, so a new variant is named the day it ships 1.1ms
what must NOT get a bucket · 2 tests
✓
credits and top-ups are not usage 0.4ms
✓
an unknown context returns null rather than "Other" 0.4ms
provider rows are labelled by what the tenant asked for, never by vendor · 4 tests
✓
maps the providers that actually appear in the ledger 0.5ms
✓
splits one provider by what it was used FOR 0.7ms
✓
drops zero-cost attribution rows instead of charting them 0.3ms
✓
never returns a vendor name as a label (CLAUDE.md §4) 1.2ms
src/campaigns/scope-note-voice.vitest.ts
the note the USER reads · 4 tests
✓
never addresses the model in the second person 1.7ms
✓
still makes the disclosure that the 2026-08-05 defect needs 0.4ms
✓
says nothing when the result is empty — both siblings now follow one rule 0.2ms
✓
offers the user the correction, not a function signature 0.3ms
count_note got the same split, a day later, for the same reason · 4 tests
✓
never addresses the model in the second person 0.4ms
✓
still states the denominator, which is the disclosure that must survive 0.2ms
✓
says nothing when there is nothing — "included below" under an empty set is false 0.2ms
✓
and the instruction survives, where only the model sees it 0.2ms
the directive only the MODEL reads · 3 tests
✓
carries the argument instruction 0.5ms
✓
is rendered NOWHERE — that is the whole point of the split 6.5ms
✓
is not named like a disclosure, so the rendering guard does not demand it 0.3ms
src/chat/bare-ack-probe-surface.vitest.ts
the bare-ack probe reports as a log, not a fault · 3 tests
✓
uses reportSentryLog at warn level 1.5ms
✓
does NOT raise an Error Issue 0.4ms
✓
still fires on the same condition — the signal is not being dropped 0.2ms
the fields that discriminate are QUERYABLE, which was the point · 8 tests
✓
carries model as a log attribute 0.3ms
✓
carries cot_on as a log attribute 0.2ms
✓
carries cot_complexity as a log attribute 0.2ms
✓
carries compound_intent_count as a log attribute 0.3ms
✓
carries history_turns as a log attribute 0.2ms
✓
keeps the identity needed to divide eval traffic from real 0.4ms
✓
flattens history_tail to a scalar, because attributes are not arrays 0.2ms
✓
never lets an absent model become an empty bucket again 0.3ms
src/chat/confirm-card-shipped.vitest.ts
a card the reply did not carry is not shown — whatever the tool returned · 6 tests
✓
E1: a records block in the same turn never deletes the send card's own recipients, and the chip sends exactly them 240.9ms
✓
E1, tools the other way round: when the records tool ran last, its presenter does not strip the card either 50.6ms
✓
E2: after a shown 2-recipient card, the round that re-stages five beside a block still shows the five it would send 54.5ms
✓
S2: a standing instruction the guardrail erased from its card is never saved by the chip — however often it is clicked 47.4ms
✓
D2: keywords the guardrail erased from their card are not tracked by its chip 46.5ms
✓
positive control: a card that did reach the screen still confirms on its first click (loop path and shortcut path) 51.0ms
the weekly share-of-voice card switches on the plan it quoted, or re-quotes · 5 tests
✓
H1: a config change between the card and the chip (3 engines quoted, 4 after) switches nothing on and quotes the new plan 55.4ms
✓
a change to only the engines after the card was shown needs a new card 30.1ms
✓
a change to only which frozen prompts (same count) after the card was shown needs a new card 34.2ms
✓
a change to only the day after the card was shown needs a new card 27.7ms
✓
the card quotes the plan the confirm would run, including engines named on the same call 25.9ms
src/chat/disclosure-live-path.vitest.ts
withDisclosures puts the tool-authored sentence into a model-authored message · 5 tests
✓
appends a note the model did not mention 1.8ms
✓
does NOT duplicate a note the model already narrated 1.0ms
✓
is a no-op over formatToolResult output, so the shortcut path is unchanged 4.4ms
✓
leaves a message alone when the tool disclosed nothing 0.3ms
✓
carries EVERY *_note, not just the one that exposed the bug 0.2ms
the disclosure survives the surfaces that REPLACE the composed message · 6 tests
✓
rides the document handoff, which states the very count the note qualifies 12.5ms
✓
rides the report chip, as HTML, because that message ships is_html:true 0.7ms
✓
escapes note text into the chip rather than injecting markup 0.4ms
✓
omits the note block entirely when there is nothing to disclose 0.5ms
✓
appears on the SAVED ARTIFACT, which is the thing the user opens 14.2ms
✓
does not put a note block on a saved artifact that disclosed nothing 0.6ms
src/chat/doc-freshness.vitest.ts
the guard counts what the repo can count · 2 tests
✓
passes on the current tree 40.0ms
✓
--print reports the values a handover should be written from 36.7ms
it fails when a living document drifts · 4 tests
✓
catches a stale count and names the file, the claim and the truth 90.7ms
✓
catches the SAME fact written a different way 95.0ms
✓
catches a guard count stated with no qualifier at all 88.0ms
✓
leaves a SUBSET count alone — "the 3 guards that cover billing" is not the total 111.3ms
what it deliberately leaves alone · 2 tests
✓
does not scan dated records — an August handover keeps its August numbers 0.6ms
✓
is wired into the gate, or it is a script nobody runs 0.2ms
the readiness score must sum · 3 tests
✓
the headline equals the sum of the ten axis rows 1.6ms
✓
the guard rejects a headline that does not sum 78.4ms
✓
--fix REFUSES to edit the score, because the headline is the output 76.4ms
src/chat/honest-zero.vitest.ts
buildOutcomeNote — an honest empty is not a failure · 4 tests
✓
tells the judge the run COMPLETED and that zero is the verified outcome 2.1ms
✓
still asks the judge to grade how the empty was HANDLED 0.5ms
✓
leaves the failure note EXACTLY as it was for a genuine failure 0.3ms
✓
is unchanged when the flag is absent — no silent behaviour change for other callers 0.3ms
the classifier that decides which note is used · 2 tests
✓
treats the real zero-yield strings as expected outcomes 2.3ms
✓
does NOT treat a real provider fault as an expected outcome 2.9ms
resultYield — a paid-boundary stop is not a provider zero · 5 tests
✓
returns null when the turn stopped to offer a paid source 0.4ms
✓
still measures a real zero once the paid source HAS run 0.2ms
✓
a PARTIAL success still measures, so it can clear the streak 0.5ms
✓
counts a user intent ONCE across the escalation handshake, not twice 0.3ms
✓
leaves the existing exclusions and real counts untouched 0.3ms
src/chat/lead-shortfall.vitest.ts
a short result explains itself · 4 tests
✓
states the gap, where the leads came from, and what the rest would cost 7.0ms
✓
says NOTHING when the search was fully satisfied 0.5ms
✓
never names the vendor — the operation, not the provider 0.3ms
✓
prices in TOKENS, never dollars 0.3ms
the yes is one click, and it costs what it says · 4 tests
✓
offers the paid chip FIRST — it answers the question they are left with 1.2ms
✓
offers no such chip when nothing is short 0.3ms
✓
keeps verification ahead of drafting, as before 0.5ms
✓
works on the no-list path too 0.3ms
a FULL 0-of-N miss with a real shortfall (live 2026-08-15, owner-reported) · 3 tests
✓
offers the paid-source chip even when found is 0, not just on a partial fill 0.5ms
✓
never offers to verify or draft 0 contacts 0.3ms
✓
a true 0-of-N miss with NO shortfall still gets the old fallback chips, not the paid offer 0.7ms
src/chat/loop-waste.vitest.ts
D7 — a memoized read is drawn once · 3 tests
✓
the render seam is keyed on the memo key, not on the call 2.3ms
✓
the repeat is announced to the model, because silence is what let it loop 0.3ms
✓
the memo key travels with the result so the seam can see it 0.6ms
D4 — the shortlist already answered what search_tools asks · 3 tests
✓
search_tools is withheld on the first call behind a confident shortlist — never on the email surface 0.4ms
✓
the model calls go out on the filtered set, not the unfiltered one 0.7ms
✓
a shortlisted family still carries its own tools, so withholding costs nothing 1.0ms
D6 — a chip that cannot complete its own action · 2 tests
✓
the create_sequence enrol chip populates instead of firing 1.4ms
✓
enroll_in_sequence still refuses without a list — the chip was wrong, not the guard 1.2ms
D2b — a name we refuse is a name we mention · 3 tests
✓
the presenter says which names were dropped and why 0.8ms
✓
says nothing when every name was accepted 0.3ms
✓
the dispatch records the rejection rather than discarding it 1.1ms
src/chat/send-flow-wiring.vitest.ts
Jev approves in one place, before the router, after the cost card · 4 tests
✓
decideSendApproval is called exactly once, before the router runs 2.8ms
✓
only under judge_send_reply, and an approval only rewrites the reply to the chip text 1.2ms
✓
the contextual block reads the cost card first and gives it precedence 1.1ms
✓
sendApprovedBy is a local of the turn, set only there (never reqCtx: a concurrent request could write it) 1.1ms
only send_confirm sends, and only while authorised · 5 tests
✓
withSendAuthorisation is opened exactly once in src, inside send_confirm, around the one confirm call 271.3ms
✓
send_emails honours confirm only inside the scope, for its own tenant 2.2ms
✓
send_emails with confirm: true appears exactly once in index.ts, inside send_confirm 2.2ms
✓
armed only by sendConfirmArmed over the KV record and its context, AND the card this conversation showed 1.2ms
✓
nothing armed here → a fresh card and a return, never a fall-through to the model 1.7ms
the start handler only ever stages · 1 test
✓
passes no confirm, and a paraphrase needs Jev 1.5ms
the dead belt is gone · 1 test
✓
no `intentMatch?.id === 'send_emails'` handler (send_emails is registered only on llmIntentRouter) 0.9ms
src/chat/send-report-format.vitest.ts
send_emails failure reporting collapses by reason · 4 tests
✓
25 recipients failing for ONE reason prints that reason ONCE — the incident case 7.4ms
✓
tells the user their drafts survived — the first thing they want to know 0.4ms
✓
distinct reasons stay distinct — collapsing must not hide a second problem 0.3ms
✓
a fully successful send says nothing about failures 0.3ms
send_emails confirm preview renders a table · 3 tests
✓
emits a markdown pipe table, not bullets 0.5ms
✓
a full preview renders every row, and no remainder 1.1ms
✓
names the remainder when the preview is shorter than the total 0.3ms
mdCell · 3 tests
✓
escapes a pipe so a subject cannot break the row 0.2ms
✓
collapses newlines, which would end the row outright 0.5ms
✓
renders an em dash for empty values rather than an empty cell 0.3ms
generate_emails relays a partial run · 1 test
✓
surfaces the deferred note — a field the formatter does not read never reaches the user 0.3ms
src/chat/shared-case-partial-shapes.vitest.ts
aeo_visibility — the answer-citation leg failed · 4 tests
✓
never quotes the blend as a citation rate 20.3ms
✓
says the citation leg did not run, and why 0.6ms
✓
keeps what DID run, and the blend names only the surfaces in it 0.5ms
✓
claims no movement and no run cost for a leg that did not run 2.4ms
aeo_visibility — one Google surface failed · 1 test
✓
the blend does not list the missing surface as 0% 0.6ms
aeo_visibility — every leg failed · 1 test
✓
says nothing was measured instead of headlining a rate 0.3ms
seo_geo_visibility (standalone) — the fields only the composite carries · 2 tests
✓
a standalone run is not told it is a "first check" — it never carries the movement 0.4ms
✓
a run where no engine answered has no citation rate, and does not print 0% 0.7ms
aeo_page_check — the retrieval-readiness leg failed · 3 tests
✓
prints no null or undefined field from a leg that did not run 0.6ms
✓
leads with the combined score and keeps the checks that ran, with their fixes 0.5ms
✓
says the retrieval test did not run — without naming the service behind it 0.3ms
src/chat/visibility-state.vitest.ts
the line states what actually ran · 3 tests
✓
carries the date, the shape and the rate 1.8ms
✓
forbids the exact false sentence that was shipped 0.3ms
✓
tells the model to name the OPERATION, not a tool 0.2ms
an UNGROUNDED run is a third state, not one of the other two · 1 test
✓
says a check ran but refuses to call it a measurement of citations 0.5ms
silence is the safe default, in BOTH absent cases · 2 tests
✓
injects nothing when no run exists 0.2ms
✓
injects nothing when the READ FAILED — never "no check has run" 0.2ms
the topical gate spends a query only when it might matter · 3 tests
✓
fires on visibility questions 0.8ms
✓
does not fire on unrelated turns 0.3ms
✓
is a SPEND gate, not a routing predicate 8.1ms
it is wired into the turn, not merely written · 2 tests
✓
the line joins briefStatusText, which is what the model receives 0.5ms
✓
a failed read degrades to silence at the call site too 0.2ms
src/connectors/google-bridge-verify.vitest.ts
with the verifier on, the browser that started the connect completes it · 1 test
✓
start binds the browser; each consent is redeemed for the starter; finalize then connects 47.1ms
a consent link opened in any other browser connects nothing · 5 tests
✓
the victim's browser (no binding) is refused, the grant is failed at the source, and the attacker's finalize adopts nothing 30.3ms
✓
a victim's OWN binding does not adopt the attacker's connection 12.0ms
✓
a cookie that names an account without its nonce is refused (a binding cannot be forged) 6.4ms
✓
a binding older than its lifetime connects nothing 10.2ms
✓
a grant on an earlier start's link is not recorded against the current start 7.9ms
without the vendor verifier, finalize still requires both legs verified · 1 test
✓
a grant completed elsewhere and activated by the vendor is not adopted by the starter (the F01 harm) 3.7ms
both legs, not one · 1 test
✓
finalize's test needs BOTH connections verified, each by its own id 0.5ms
the flag is OFF by default · 2 tests
✓
flag off: the verify route redeems nothing and connects nothing (a misconfiguration, not a refusal) 3.5ms
✓
flag off: finalize keeps the pre-verifier behaviour (the residual the owner closes by flipping it) 5.3ms
start refuses before any vendor call when the binding could not reach the callback host · 1 test
✓
a start served from another host is refused with a sentence 1.8ms
src/email/smtp-unconfirmed.vitest.ts
after DATA, a lost answer is unconfirmed — never a refusal that invites a retry · 7 tests
✓
the server closes the connection after the message, with no reply 33.8ms
✓
the connection resets after the message 2.3ms
✓
a 250 is a delivery even when closing the session fails 1.9ms
✓
a reply cut off after the message (no code) is unconfirmed 1.5ms
✓
CONTROL: a 451 after the message is the server saying no 2.2ms
✓
CONTROL: a refusal before the message is sent stays a refusal 1.1ms
✓
CONTROL: a clean session is a delivery 1.3ms
the send deadline closes a session that went quiet · 4 tests
✓
quiet after the message: closed at the deadline, and unconfirmed (it may have been queued) 31.2ms
✓
quiet before anything was sent: closed at the deadline, and a refusal (nothing went out) 31.3ms
✓
a deadline already passed opens no socket at all 1.4ms
✓
CONTROL: a clean session under a deadline is a delivery, and the socket is not closed by it 1.8ms
src/leads/derived-artifacts.vitest.ts
every derivation the scan starts is registered to outlive the response · 4 tests
✓
personas and brand kit are awaited together, not left dangling 2.2ms
✓
the pair is handed to waitUntil, with an await when there is no ctx 0.5ms
✓
the keyword seed is protected too — it writes the numbers the reply itemises 0.4ms
✓
no bare fire-and-forget remains on the settings writes 0.5ms
the plan does not call a waiting candidate an absence · 4 tests
✓
reads the candidate set before declaring there are no competitors 0.4ms
✓
keeps CONFIRMED as the only set the plan may name from 0.4ms
✓
points at the one click instead of telling them to go and search 0.5ms
✓
still gives the plain message when there is genuinely nothing 0.4ms
the scan reply never claims work that did not survive · 3 tests
✓
the personas line is gated, like every other line in that list 2.5ms
✓
reads whether personas EXIST, not whether generation was started 1.7ms
✓
a failed read-back reports personas false, never true 0.3ms
src/leads/geo-country.vitest.ts
resolveApifyCountry · 4 tests
✓
maps the recurring failure — Chennai → India 1.7ms
✓
resolves known cities to their country 0.6ms
✓
resolves aliases and exact country names (case-insensitive) 0.5ms
✓
returns null for unrecognized geography (caller omits the filter, no 400) 0.4ms
resolveCountryISO · 2 tests
✓
resolves names, aliases and known cities to lowercase ISO-2 0.4ms
✓
returns null for unrecognized geography 0.2ms
enum coverage · 2 tests
✓
every country we can emit is a country the provider accepts 0.5ms
✓
an unmapped country degrades to null, never to a wrong code 1.6ms
findCountryCueISO · 3 tests
✓
finds a cue anywhere in a query — name, alias, or city 1.0ms
✓
longest match wins — "new zealand" is not read as stray words 0.3ms
✓
null when no cue present 0.3ms
src/llm/jev.vitest.ts
rollout · 1 test
✓
needs the key AND the context in JEV_ROLLOUT (or "1") 2.2ms
an evaluation · 6 tests
✓
posts state + questions with the bearer key, returns the answers, bills the usage 26.3ms
✓
throws on a non-2xx and on a body with no answers — the caller owns the fallback 2.9ms
✓
detached: no implicit ledger row, the live window untouched, and onUsage still gets the usage 0.9ms
✓
jevEvaluateFull passes detached through and still returns the usage 0.9ms
✓
the self-metering callers run detached (content_verify, reply_triage, gsc query taxonomy) 0.6ms
✓
is priced at the gateway rate, never a promotional zero 0.3ms
sub-group narrowing is gated separately (2026-09-20) · 1 test
✓
the hook applies a sub-group only when tool_shortlist_subgroup is rolled out 7.9ms
tool shortlist question (2026-09-19) · 1 test
✓
offers every family plus general_or_core, off the same hints the model reads in search_tools 1.5ms
the veto and email answers ride the shortlist call (2026-09-24, token-waste audit A11/A7) · 2 tests
✓
asks leads_work / email_only only when told to, and returns their finite answers 1.2ms
✓
(neg) not asked → neither the question nor the field; a non-number answer is dropped 1.4ms
src/middleware/lee-signals.vitest.ts
extractLeeSignals — each predictor · 7 tests
✓
counts comparison language, and weights a comparison TABLE higher than the phrase 3.0ms
✓
measures query-term coverage against the topic's content words 0.4ms
✓
returns NULL coverage when no topic was given — not 0 0.3ms
✓
ignores stopwords in the topic, so "the best CRM" is not 33% covered by "the" 1.0ms
✓
counts heading depth 0.3ms
✓
normalises stats and first-person per 1,000 words 0.4ms
✓
scores primary-source as own-numbers versus borrowed links 0.3ms
a citable page outscores a first-person blog page · 4 tests
✓
scores the comparison/structured page higher than the lived-experience one 2.3ms
✓
puts lee_signals on every successful report 0.9ms
✓
advises REDUCING first-person, and says why it contradicts the SEO tool 0.8ms
✓
does not penalise a page for a topic nobody supplied 1.0ms
src/planner/follow-through.vitest.ts
nextOpenInitiative · 2 tests
✓
asks for ONE proposed initiative of THIS tenant whose window is still open, in plan order 2.6ms
✓
nothing open, a blank action, or a failed read → null 0.7ms
planNudgeChip · 2 tests
✓
carries the id and the initiative in the plan's own words, bounded 0.5ms
✓
a long action is cut at a word boundary with an ellipsis, never mid-word 0.3ms
shouldOfferPlanNudge · 2 tests
✓
an ordinary turn gets the reminder 0.4ms
✓
gates, pickers, spend stand-downs, control tokens and plan turns do not 0.4ms
once per session per day · 1 test
✓
unset → not nudged; set → nudged; no KV → never blocks 0.4ms
planFollowThroughSummary · 1 test
✓
counts real tenants only and names the three states 0.9ms
wiring (source pins) · 3 tests
✓
the v2 handler appends the chip on ordinary turns and marks the session 4.7ms
✓
the client renders __execute: chips as a real button on the plan execute path 2.0ms
✓
the digest carries the follow-through line for real tenants 0.4ms
src/reports/contracts-inherited.vitest.ts
aeo_visibility inherits the retired legs' invariants · 7 tests
✓
a sound composite passes 2.4ms
✓
fires on an out-of-range share_of_model coverage — the leg nests one level deeper 0.4ms
✓
fires on the phantom-citation contradiction (coverage > 0, nobody "ours" in the leaderboard) 0.2ms
✓
fires when more prompts cite us than were answered 0.4ms
✓
fires on the AI-overview rate ordering (cited > present) 0.2ms
✓
stays SILENT when a leg errored — a failed leg is a reported absence, not a soundness bug 0.2ms
✓
stays silent when a leg is absent entirely (free tier runs fewer legs) 0.2ms
aeo_page_check inherits the retired rag_readiness reconciliation · 4 tests
✓
a sound page passes 0.3ms
✓
fires when the stated deductions do not account for the score 0.5ms
✓
a clamped-at-zero page may OVERSTATE deductions without failing 0.2ms
✓
stays silent on rows stored before score_breakdown existed 0.2ms
src/reports/onpage-report.vitest.ts
seo_onpage_audit — §17 gold standard · 11 tests
✓
aggregates issues into a findings bento with self-contained fix prompts 2.0ms
✓
high-affected issues render in alert red, keeps the distribution chart + feedback mount 0.6ms
✓
uses plain section headers, not "Cluster N" labels (§17 F) 0.7ms
✓
drops the legacy Agent-Readiness "copy fix" button that trailed the footer 0.7ms
✓
same case powers seo_onpage_results 0.4ms
✓
renders all three directive groups in fixed order, empty ones stating their absence 0.8ms
✓
an error-page count IS a measured defect — the Fix group can never contradict the KPI 0.6ms
✓
classifies EVERY issue before capping, so a class is never empty because of volume 0.5ms
✓
never tells the user to fix the highest-volume issue first 0.5ms
✓
states that it cannot rank by stake, rather than implying it can 0.3ms
✓
classifies EVERY issue type, not the top 8 the chart shows 0.6ms
src/runtime/guardrail-user-amounts.vitest.ts
a budget the user typed survives the reply, in whatever spelling the reply uses · 4 tests
✓
typed "300 dollars", the reply writes "$300" 5.1ms
✓
typed "$300 budget", the reply writes "300 dollars", "300 USD" or "$300.00" 0.6ms
✓
a scaled figure is matched with its scale: "$5M" typed survives as "$5 million" and "5,000,000 dollars" 0.3ms
✓
no violation is recorded for the user's own figure — it is not a redaction at all 1.0ms
what nqzai charges is still never shown in dollars · 5 tests
✓
a reply quoting their budget AND our price keeps theirs and hides ours 0.5ms
✓
a different amount is a different claim, in every spelling 0.4ms
✓
a scale the user did not write is not theirs: "5 dollars" typed does not rescue "$5M" 0.3ms
✓
a number with no currency in the user text rescues nothing 0.2ms
✓
with no user text at all, every dollar figure is redacted as before 0.5ms
every exit that scrubs model text reads the user corpus · 2 tests
✓
the reasoning scan and the streamed reasoning lane 0.7ms
src/runtime/vendor-text-channels.vitest.ts
F04: a mail provider's refusal reaches the person only as words that met the guardrail · 3 tests
✓
the V6 refusal (unknown shape, naming suppliers and a price) becomes the sentence 7.8ms
✓
CONTROL: a plain refusal still passes as it is 0.5ms
✓
is what both REST sends return (the single send and Send all) 0.7ms
#55 (a): a database failure names no vendor, and a route gives its own sentence for one · 3 tests
✓
neither throw in nhostGraphQL opens with the vendor's name 0.6ms
✓
publicErrorText answers any database failure with the route's sentence, wrapped or not 0.5ms
✓
the code that classifies a database failure reads the neutral prefix, never a copy of the old one 0.9ms
#55 (b): what nqzai pays reaches the model in tokens, never dollars · 3 tests
✓
a provider-cost key becomes its token equivalent, at any depth; the tenant's money keeps its currency 1.9ms
✓
CONTROL: a result with no such key is handed over as the same object 0.5ms
#55 (c): the Google connect protocol names no vendor, client and server together · 1 test
✓
the start body, the return parameter, the finalize route and the statuses 7.7ms
the sweep holds · 1 test
✓
no leak text in any of the rewritten sentences 0.3ms
src/tools/graphql-required-columns-guard.vitest.ts
baseline · 1 test
✓
passes on the current tree and says what it checked 823.3ms
an insert that omits a NOT NULL, no-default column cannot land · 3 tests
✓
catches the exact pre-fix prompt-library write, naming the file, line and column 667.6ms
✓
checks EVERY object of an inline list, not just the first 0.6ms
✓
finds the object argument in any position (on_conflict first is legal GraphQL) 0.3ms
what the rule deliberately does not flag · 3 tests
✓
a variable payload has no literal to read and is skipped 869.1ms
✓
a depth-0 `data:` is the table's own column, not a nested-insert wrapper 0.3ms
✓
a NOT NULL column WITH a default is not required (templates.user_id defaults to 'default') 2.3ms
the role-preset allowance is scoped, reasoned, and cannot go stale · 2 tests
✓
omitting contact_lists.user_id is allowed ONLY in the file whose JWT branch relies on the preset 0.4ms
✓
an allowance that no longer matches any insert fails the run 682.3ms
a blind guard says so (exit 2), never OK · 2 tests
✓
a snapshot without the `required` capture 38.7ms
✓
a tree with too few inline inserts to trust 710.4ms
src/util/html-context.vitest.ts
safeUrl · 5 tests
✓
never returns a URL a browser would parse to a non-http(s) scheme (default options) 3.7ms
✓
refuses every script-capable scheme, however it is spelled 0.8ms
✓
entity-encoded schemes are not decoded by a URL parser — they stay relative, and urlAttr escapes the & 0.3ms
✓
keeps ordinary links intact 1.1ms
✓
opt-in schemes stay opt-in 0.5ms
escapeHtml / urlAttr · 2 tests
✓
escapes every character that can end a quoted attribute or open a tag 0.3ms
✓
urlAttr: a refused URL becomes the fallback, an allowed one is attribute-escaped 0.3ms
cssValue / rawHtml (FC-H1, 2026-10-25) · 4 tests
✓
passes a single honest CSS value through unchanged 0.6ms
✓
refuses anything that could end the declaration, the attribute or fetch a URL 0.8ms
✓
its output can never carry an HTML-special character, so it is attribute-safe as well 0.3ms
✓
rawHtml is the identity — a marker, never an escaper 0.2ms
src/seo/aeo-failed-leg.vitest.ts
P4-06-F06 — the selected model is refused: the engine still answers, and says so · 3 tests
✓
[fail-first] the app's default `openai/gpt-4o` falls back to the engine's verified model 30.3ms
✓
[fail-first] the chain tries each model once — requested, engine default, fallback — then stops 2.2ms
✓
a model the engine accepts is used as asked, with no substitution recorded 0.9ms
P4-06-F06 — a leg that returned no answer: not charged, recorded as failed, plain words · 3 tests
✓
[fail-first] the live run, replayed: ChatGPT on the default model now answers, and the substitution is stated 37.9ms
✓
[fail-first] a cell the provider BILLED that came back empty is absorbed, never charged 8.2ms
✓
[fail-first] an engine that answered nothing is named in plain words — no code, no provider 12.2ms
P4-06-F06 — the composite reply · 3 tests
✓
[fail-first] a stored raw provider error is re-translated, and a leg with no answers is not scored as zero 2.0ms
✓
[fail-first] the composite leaves a leg with no answers out of the blend, and names the failed legs 3.6ms
✓
[fail-first] executeTool records a run whose engines answered nothing as a soft failure, not ok 7.2ms
P4-06-F06 sweep — share of model: prompts that answered nothing are not in the charge · 2 tests
✓
[fail-first] aggregate splits the billed cost from the cost of failed prompts 3.0ms
✓
plain words are idempotent and never carry a code 3.4ms
src/seo/keyword-metrics-upsert.vitest.ts
competition reaches the registry · 2 tests
✓
is sent on the object, not silently dropped 3.3ms
✓
is overwritten on conflict when the batch actually knows it 1.4ms
a null-carrying writer cannot clobber · 4 tests
✓
omits competition entirely when no object in the batch has one 0.5ms
✓
omits volume and cpc too — the same hazard, not a competition special case 0.6ms
✓
one knowing row in a mixed batch is enough to update the column 0.5ms
✓
a filtered-out row cannot vouch for a column 0.4ms
what is always written · 2 tests
✓
stamps metrics_updated_at unconditionally 0.3ms
✓
writes nothing at all for an empty batch 0.4ms
competition stays out of the opportunity score · 3 tests
✓
computeKES does not read it — same inputs, same score 0.6ms
✓
high CPC RAISES the score — so competition as a divisor would fight it 0.3ms
✓
is consumed as a difficulty TIER instead, which is the honest use 0.5ms
src/seo/onpage-sweep.vitest.ts
sweepAbandonedOnpageCrawls · 11 tests
✓
delivers a finished crawl against its ORIGINAL job row 6.9ms
✓
the fetch is what records the spend — the sweep never bills separately 1.3ms
✓
leaves a still-running crawl alone 1.0ms
✓
skips a young crawl — the inline poll still owns it 0.7ms
✓
records unrecovered spend when the owning job cannot be identified 1.3ms
✓
a dead task is recorded and dropped, never re-fetched forever 0.9ms
✓
one broken marker does not stop the next tenant being delivered 1.2ms
✓
no-ops without the provider credentials or a session store 0.4ms
✓
passes the marker's seedStatus to the crawl fetch 1.1ms
✓
a listing that fails outright rejects, so the monitor records the run as failed 2.0ms
✓
a listing that fails on a later page still sweeps what it listed, then rejects 1.5ms
src/seo/own-site-scoping.vitest.ts
isTenantOwnHost — the one ownership predicate · 4 tests
✓
accepts the site itself, however it was written down 2.6ms
✓
accepts a subdomain — a blog on blog.acme.com belongs to acme.com 0.5ms
✓
REFUSES a different domain, including the suffix trick 0.4ms
✓
treats unknown ownership as NOT owned 0.6ms
the keyword registry only takes the tenant's own topics · 2 tests
✓
gates the tracked_keywords write on site ownership 0.4ms
✓
never registers behind the user's back OR silently declines to 0.3ms
the stored stack fingerprint is only claimed for the tenant's own site · 5 tests
✓
entity_audit: no fingerprint on a foreign domain 0.5ms
✓
entity_audit: the local-presence leg only reads the tenant's OWN site 0.5ms
✓
aeo_page_check: the stored fallback takes the same test the save takes 0.8ms
✓
aeo_page_check: SAVING still demands an exact host match, not a subdomain 0.4ms
✓
seo_generate_llms_txt: deploy instructions never assume the tenant's stack for another domain 0.4ms
src/seo/rival-capture.vitest.ts
captureRivalsFromSerp · 9 tests
✓
stores the rivals for a keyword the tenant tracks 4.6ms
✓
NEVER stores a query the tenant does not track 0.5ms
✓
does nothing when the tenant has no site to be a rival relative to 0.3ms
✓
does not write the same keyword twice in a day 0.5ms
✓
records nothing, and says so, when the SERP held no other domains 0.7ms
✓
matches the registry case-insensitively — the caller's casing is not the registry's 0.3ms
✓
escapes LIKE wildcards — real keywords contain % and _ 0.3ms
✓
never throws — a capture must not cost the caller the answer it went to fetch 0.9ms
✓
checks tracked-ness and same-day in ONE round trip, before any insert 0.7ms
seoRoute wiring · 2 tests
✓
captures on an open-web serp and NOT on a site:-restricted one 0.4ms
✓
is fire-and-forget so a capture cannot delay or fail the caller 0.3ms
src/seo/serp-rivals.vitest.ts
extractRivals · 11 tests
✓
keeps the rival domains a SERP response already contains 2.7ms
✓
excludes the tenant themselves — a tenant is not their own competitor 0.4ms
✓
normalises www and scheme so the domain joins to __competitors__ 0.4ms
✓
matches the tenant regardless of www/scheme form 0.9ms
✓
records TRUE SERP position, never the index into the filtered output 0.4ms
✓
counts a domain once even when it holds two positions 0.3ms
✓
drops non-domains rather than storing junk in a table joined on host 0.3ms
✓
accepts `url` as well as `link` — providers disagree on the field name 0.3ms
✓
is safe on empty/absent input — the cron must never throw on a thin SERP 0.3ms
✓
still returns rivals when the tenant has no site set 0.3ms
src/seo/timeout-attribution.vitest.ts
a timeout names the thing that actually timed out · 6 tests
✓
blames the USER SITE when the crawl target was slow 2.1ms
✓
blames OUR OWN budget when the step ran out of its allotted time 0.5ms
✓
still blames the PROVIDER when the provider is what timed out 0.3ms
✓
still blames the MODEL, the attribution fixed on 2026-08-29 0.3ms
✓
gives four DIFFERENT answers — the point is discrimination, not four branches 0.4ms
✓
leaks no internal token while reattributing 1.1ms
Sentry volume is unchanged by the reattribution · 5 tests
✓
site crawl stays suppressed as an expected outcome 1.1ms
✓
tool budget stays suppressed as an expected outcome 0.8ms
✓
provider stays suppressed as an expected outcome 0.5ms
✓
the model-timeout message keeps its own suppression too 0.2ms
✓
and a genuine novel error is still REPORTED, so the rule has not been widened 2.6ms
src/seo/visibility-derived.vitest.ts
citedPages — which of OUR pages AI actually cited · 6 tests
✓
counts a URL once per PROMPT, not once per engine 3.5ms
✓
excludes competitor domains — this table is about our own pages 0.5ms
✓
collapses www, trailing slash and hash to one page 1.0ms
✓
keeps the query string — ?v=2 can be genuinely different content 7.3ms
✓
ignores errored cells and malformed URLs instead of throwing 0.4ms
✓
returns nothing rather than guessing when no run captured citations 0.3ms
classifyPromptTopic · 1 test
✓
prefers the more specific and more actionable shape 1.4ms
topicPerformance · 2 tests
✓
excludes prompts no engine could answer, rather than scoring them as losses 0.5ms
✓
sorts worst first — the table says where to write next 0.5ms
citationConcentration · 2 tests
✓
translates HHI into what it means for the reader 0.4ms
✓
returns null on runs stored without a share-of-voice block 0.3ms
src/seo/visibility-tldr.vitest.ts
the score is never presented as more certain than it is · 3 tests
✓
calls a 15-cell sample directional and refuses to read a +33 as progress 2.5ms
✓
states movement plainly once the sample is big enough to carry it 0.5ms
✓
says the number describes the past when nothing has been measured for weeks 0.4ms
it distinguishes the three ways a pillar can be absent · 3 tests
✓
an unmeasured pillar is excluded, not scored zero 0.3ms
✓
an unreachable engine is named, not silently read as poor visibility 0.3ms
✓
names the weakest pillar against the strongest 0.2ms
the competitive read · 2 tests
✓
says the engines are answering without you when citations are zero 0.3ms
✓
compares shares when you do hold some 0.3ms
it declines to speak when it has nothing to say · 3 tests
✓
returns null when nothing has ever been measured 0.6ms
✓
survives a missing visibility detail without inventing a sample size 0.4ms
✓
always ends with exactly one next action when it can name one 0.3ms
src/leads/shared/country-filter.vitest.ts
the country backstop asserts what was REQUESTED, not a constant · 7 tests
✓
keeps a GB row on a GB request — the case that returned nothing 1.8ms
✓
keeps a CA row on a CA request 0.3ms
✓
still keeps a US row on a US request — the path that already worked 0.2ms
✓
STILL DROPS a row from the wrong country — this is a backstop, not a no-op 0.3ms
✓
treats an unspecified country as US, because that is what the RPC does 0.3ms
✓
reads the default from ONE place shared with the sender 0.3ms
✓
is case- and whitespace-insensitive on both sides 0.3ms
every other compliance check is untouched · 4 tests
✓
still drops a non-active entity 0.2ms
✓
still drops a source that is disabled or not distributable 0.5ms
✓
still drops a source not licensed for this purpose 0.3ms
✓
still drops a candidate carrying an invalid identifier 0.3ms
src/leads/shared/normalization.vitest.ts
shared lead normalization · 11 tests
✓
normalizes domains without retaining URL transport details 2.1ms
✓
normalizes valid email and rejects malformed input 0.4ms
✓
converts US phone formats to E.164 and rejects extensions/non-US prefixes 0.5ms
✓
normalizes a GB number to +44 instead of mangling it into a US number 0.5ms
✓
normalises AU numbers, and refuses the shapes the export is full of 0.5ms
✓
normalises NZ numbers, and rejects the foreign numbers that dominate that column 0.4ms
✓
normalises IN numbers, keeping the Delhi landlines a NANP-shaped rule would discard 0.4ms
✓
keeps the two PHONE_RULES copies from drifting on which countries exist 1.0ms
✓
REFUSES rather than guesses when the region is unsupported or missing 0.5ms
✓
keeps normalizeUsPhone byte-compatible so US call sites are unchanged 0.3ms
✓
creates a deterministic person-name key without punctuation or accents 0.5ms
scripts/lib/honesty.vitest.mjs
honesty — "free" is a claim, not a word · 3 tests
✓
flags a claim, and quotes the text around it 4.4ms
✓
does not flag a negation — that is the product saying what §4 requires 3.2ms
✓
does not flag product nouns or idioms 0.5ms
honesty — universal rules judge our prose, not the tenant's rows · 2 tests
✓
a "free" inside a rendered block is data when the caller passes prose 0.3ms
✓
per-row assertions still see the whole reply, table included 0.3ms
honesty — a negated work word is not a claim of work · 4 tests
✓
does not flag "haven't been verified yet" on a tool-backed reply with no number 0.5ms
✓
does not flag an adjective — "four saved competitors on file" ([8.2.1], 2026-09-15) 0.4ms
✓
does not flag a zero stated before the noun — "No contacts found for that query" ([3.1.3], 2026-09-16) 0.5ms
✓
still flags an unnumbered positive claim 0.5ms
honesty — the tenant's own money stays in currency · 1 test
✓
a tenantMoney row may quote the scanned site's price and its free plan 0.4ms
src/admin/gsc-sortable.vitest.ts
compareValues — missing values sink · 7 tests
✓
sorts null LAST when ascending, not first as position zero 2.2ms
✓
sorts null LAST when descending too — absent is not an extreme 0.4ms
✓
treats empty string as missing, so a blank label does not sort as "before A" 7.2ms
✓
ties between two missing values are stable (0), not arbitrary 0.4ms
✓
compares numbers numerically, not lexically (10 is not less than 9) 0.3ms
✓
compares strings with localeCompare 0.3ms
✓
does not treat 0 as missing — a real zero is a real value 0.4ms
nextSort — first click lands on the useful end · 3 tests
✓
starts a metric column descending (biggest first) 0.3ms
✓
starts position ASCENDING — rank 1 beats rank 90, so best-first is the useful end 0.5ms
✓
toggles direction when the same column is clicked again 0.3ms
src/billing/gate-telemetry.vitest.ts
dispatchGateBasis — which number refused the user · 5 tests
✓
SEARCH_LEADS, 2026-08-21: a per-call estimate silently replaced by the static ceiling 1.8ms
✓
VERIFY_CONTACTS, 2026-09-21: the same shape, three weeks later, on a different tool 0.3ms
✓
an asserted ceiling is trusted and says so — the #473 fix must read as its own case 0.2ms
✓
a genuinely expensive call is NOT flagged — this must not cry wolf 0.3ms
✓
falls back to `tokens` on either side when no ceiling is declared 0.2ms
buildGateBlockMeta — the row a refusal leaves behind · 5 tests
✓
carries the 2026-09-21 incident in numbers rather than in a sentence 1.4ms
✓
every value is a string — api_usage.meta is a string map and a number comes back as one 0.5ms
✓
omits what the caller does not know instead of guessing it 0.4ms
✓
never writes a negative shortfall or a divide-by-zero ratio 0.5ms
✓
the provider string is one constant, so the writer and the sweep cannot drift 0.2ms
src/billing/tier-aware-ceiling.vitest.ts
seo_serp_spider prices at the tier that asked · 5 tests
✓
the free ceiling is what a free run can actually cost 1.9ms
✓
the paid ceiling is EXACTLY unchanged from the static row 0.5ms
✓
THE CHURN CASE: a free user can now afford it, and could not before 0.3ms
✓
an explicit page count is also capped to the tier 0.3ms
✓
NO tier given → the paid shape, which over-reserves rather than under 0.2ms
NO tool outside the opt-in set may have its reservation lowered · 2 tests
✓
every static ceiling is still reserved for non-members 2.0ms
✓
membership requires an estimator that actually reads the plan 2.0ms
both authors price at the tier — the gate AND the card · 3 tests
✓
requireSufficientBalance resolves the plan when given no override 0.4ms
✓
getCostApprovalPlan prices the card at the same tier 0.6ms
✓
a per-call override is never overwritten by the tier shape 0.3ms
src/campaigns/verify-targets.vitest.ts
the 09-21 list: 25 members, 24 with a verdict on file · 5 tests
✓
bills the ONE address with no verdict and skips the 24 that have one 5.8ms
✓
every member already verified → nothing to bill 1.1ms
✓
a member with no email is never a target — it is counted, once, as noEmail 1.2ms
✓
verified: 'any' re-checks every member WITH an email 1.1ms
✓
list_name is folded like filter.in_lists — the card may see the call before the validator 0.7ms
the user limit and the plan cap apply AFTER narrowing · 2 tests
✓
limit 3 over 10 unchecked → 3 (not 3 of the 25 members, most of them already checked) 0.7ms
✓
the free plan caps at 10 0.7ms
what a bad target does · 3 tests
✓
(neg) a named list with no members does not throw — it names the miss for the picker 0.6ms
✓
(neg) a not_in_lists that cannot be resolved propagates — the exclusion is never silently dropped 2.0ms
✓
(neg) an id that is not the tenant's names nothing 0.4ms
src/chat/aeo-routing.vitest.ts
a named page is never answered with a site-wide sweep · 2 tests
✓
the live regression: one URL + one query does not open the engine selector 17.7ms
✓
any URL with a PATH is page-level, whatever else the sentence says 21.7ms
site-level asks still reach the engine selector · 5 tests
✓
"am I cited by AI for kakunin.ai" still routes to the selector 15.1ms
✓
"check my AI visibility" still routes to the selector 0.6ms
✓
"am I visible in AI search?" still routes to the selector 0.5ms
✓
"is https://kakunin.ai ai-visible" still routes to the selector 3.1ms
✓
"run an AEO check" still routes to the selector 0.7ms
the older carve-outs still hold · 3 tests
✓
a full AEO audit is the composite, not the visibility-only selector 0.6ms
✓
"write X in AEO mode" is the writer, not the selector 1.0ms
✓
page-readiness phrasing stays with the page checker 0.4ms
src/chat/capped-gap-replies.vitest.ts
seo_competitor_gap never calls the capped top-N the competitor's whole set · 5 tests
✓
no gap in the top 25: says it compared their top 25 of 4,812, not "them all" 20.5ms
✓
a gap of 20: the head names the cut, the covered line counts within it 0.5ms
✓
when the provider total says the pull IS the whole set, "all" is allowed 0.4ms
✓
an unknown provider total never reads as complete 0.2ms
✓
the presenter's ranking table carries the real total, so its footer reads "25 of 4,812" 0.7ms
seo_backlink_gap: an empty gap over a capped pull is not "every referring domain" · 2 tests
✓
100 checked of 2,300 known: names the 100, never "every referring domain" 0.4ms
✓
a complete pull may still say every one 0.3ms
gapBasisNote: a 500-row read is not "the queries your site gets impressions for" · 3 tests
✓
a capped GSC read says it is the top 500 by impressions 0.4ms
✓
a capped registry read says it read 500 of them 0.5ms
✓
an uncapped read keeps the exact count wording 0.3ms
src/chat/concealed-failure-disclosure.vitest.ts
it asks the judge's question one step earlier · 2 tests
✓
reuses the SAME two functions the judge uses 1.4ms
✓
fires only when the failure is CONCEALED, never merely present 0.3ms
the acknowledgement check is what keeps this quiet on honest turns · 3 tests
✓
a reply that owns the failure needs no note 0.5ms
✓
no failure at all needs no note 0.2ms
✓
a confident answer over a failed run is NOT acknowledged — the case that churns users 0.7ms
one note per turn, and the specific one wins · 3 tests
✓
rejected-and-nothing-ran takes precedence over concealed-failure 0.3ms
✓
neither fires on an approval card 0.2ms
✓
the stand-down names the tool, so it is countable per tool 0.2ms
the matched intent is now recorded · 2 tests
✓
reqCtx carries it and the judge writes it 6.0ms
✓
is captured SYNCHRONOUSLY, next to the other reqCtx reads 0.3ms
src/chat/confirm-chip-exact.vitest.ts
a confirm chip carries its own card · 5 tests
✓
every confirm chip on a shown card comes with that card's id, and a newer card gets a new one 234.0ms
✓
the chip under an EARLIER card sends nothing, even though a send is staged and shown — the current card is shown instead 77.2ms
✓
typed text cannot carry an id: it keeps the most-recently-shown rule 29.7ms
✓
a CONFIRM_GATES chip (seo_rank_track) under an earlier card tracks nothing 63.6ms
✓
the standing-instruction chip under an earlier card saves nothing 39.3ms
`Yes, start "<name>" now` starts exactly the contacts on its card · 5 tests
✓
contacts enrolled after the button was shown are not started by it, and get a new card 32.6ms
✓
a start button from an older card starts nothing and shows the current one 45.7ms
✓
the cron reminder's card is honoured by its id in any conversation, and starts only its rows 13.7ms
✓
typed, a card staged elsewhere (the reminder, another tab) is not this conversation's card 8.4ms
✓
typed in a conversation that never showed the card, it starts nothing and shows who it would start 11.5ms
src/chat/filter-notes.vitest.ts
adjusted filters · 2 tests
✓
never reports an applied filter as "Not applied" 7.2ms
✓
says what actually happened 0.5ms
dropped filters — unchanged · 1 test
✓
still reports a removed filter as not applied 0.3ms
both at once — the case neither of us had covered · 3 tests
✓
shows BOTH notes, not just the first 0.3ms
✓
leads with what ran before what did not 0.4ms
✓
does not leak the raw marker fields into the body 0.3ms
neither · 2 tests
✓
adds no note at all on a clean run 0.3ms
✓
treats empty arrays as absent 0.3ms
the live two-note turn, built from the real filter helper · 2 tests
✓
renders the widened band AND every unfilterable owned-tier attribute 5.7ms
✓
says nothing about those three when the paid provider ran 0.9ms
src/chat/growth-ask.vitest.ts
a growth ask is a why-question in different clothes · 7 tests
✓
recognises the exact phrasing that failed live 2.8ms
✓
recognises the family, not just that one string 1.2ms
✓
still requires a subject the platform actually measures 0.7ms
✓
does not match across a sentence boundary 0.3ms
✓
leaves product questions and plain how-tos alone 0.8ms
✓
stands down when the user asked for an action outright 13.8ms
✓
treats the paid indexation audit as evidence-first gated 0.3ms
diagnose owns its next steps · 3 tests
✓
surfaces the tool's own horizon chips first 1.7ms
✓
offers to MEASURE when stored evidence could not settle the question 0.7ms
✓
never returns more than four 0.3ms
src/chat/honest-zero-judged.vitest.ts
an empty list is a MEASURED zero, not an unreadable shape · 3 tests
✓
list_campaigns reads as yield 0 1.8ms
✓
list_sequences reads as yield 0 0.3ms
✓
and a populated one still reads as its count 0.2ms
so the judge is told it is an honest empty, not a non-delivery · 4 tests
✓
classifies as an honest empty 0.2ms
✓
the DELIVERY note is suppressed — this is the note the judge obeyed 0.3ms
✓
and the OUTCOME note tells it a stated zero is the verified answer 0.4ms
✓
without the fix, the delivery note fires — the exact 0.1 turn 0.3ms
the widening did not arm the wrong signal · 3 tests
✓
an empty `failures` array is NOT a zero yield 0.3ms
✓
an empty `applied` array is NOT a zero yield either 0.5ms
✓
an unknown shape still reads as NO MEASUREMENT, never as zero 0.2ms
src/chat/judge-no-grok.vitest.ts
x-ai literals exist only in the allowlisted non-judge files · 3 tests
✓
the set of files is EXACTLY the allowlist — no new use, and no stale entry 86.5ms
✓
no allowlisted file is a judge in disguise (no judge ledger context) 1.2ms
✓
the judge pool module holds no x-ai id at all 0.3ms
the Python eval gate · 2 tests
✓
defaults to a non-x-ai judge 0.3ms
✓
asserts the model three times: configured (first line of __init__), and served on both transports 0.5ms
both judge endpoints refuse a forbidden model, asked for or served · 5 tests
✓
handleEvalJudgeCompletion: refuses the request (400) before any call, and a forbidden SERVED model (502) 0.6ms
✓
handleAdminJudge: refuses the request (400) before any call, and a forbidden SERVED model (502) 0.5ms
✓
the eval endpoint writes its spend BEFORE refusing a forbidden served model 0.5ms
✓
the admin endpoint defaults to the anchor head 0.7ms
✓
the conversation judge checks the picked AND the served model 0.6ms
src/chat/paid-escalation.vitest.ts
a total miss with a paid option · 4 tests
✓
QUOTES the wider search — the number that was computed and never shown 1.7ms
✓
does NOT blame the query for our coverage gap 0.3ms
✓
still offers the one-click paid chip beside the prose 1.3ms
a total miss WITHOUT a paid option keeps the original advice · 2 tests
✓
retains the retry guidance 0.2ms
a structural note is preserved AND priced · 3 tests
✓
keeps the structural explanation 0.2ms
✓
appends the price rather than dropping it 0.3ms
✓
sentence-cases the note at the seam 0.5ms
a partial fill is unchanged · 1 test
✓
still states the shortfall and its price 0.3ms
src/chat/query-classifier.vitest.ts
tokenize · 2 tests
✓
lowercases, strips punctuation, drops stopwords and 1-char tokens, stems plural/tense 3.0ms
✓
stems common verb/noun suffixes so tense/plural line up with the base form 0.6ms
fuzzyOverlapScore · 3 tests
✓
scores 0 with no overlap 0.4ms
✓
scores 1 when the message covers every intent keyword 0.2ms
✓
is recall against the intent vocabulary, not punished by message length/filler 0.3ms
keywordsForIntent · 1 test
✓
derives from the label and bonusKeywords already authored on the intent 1.6ms
PatternClassifier — fuzzy fallback catches honest paraphrases · 4 tests
✓
classifies a paraphrase the exact pattern misses on word proximity 44.6ms
✓
still prefers an exact pattern match over fuzzy when one exists 0.5ms
✓
returns null on a short, generic message with no real signal 6.8ms
✓
never fuzzy-matches shortcut (chatRouter) intents — only LLM-owned intents 0.6ms
src/chat/reply-frame-exits.vitest.ts
shortcut: the send confirm ships the reply, never the raw send result or its cost in dollars · 5 tests
✓
a recipient the mail service refused in the vendor's own words: the frame carries the guarded sentence and not the raw text 311.3ms
✓
the restored conversation says what the person read, not the raw send result (GET /api/chat/history) 54.0ms
✓
the restored reply keeps the tenant's own recipient as it is, even at a supplier's domain (DECISIONS #45) 69.7ms
✓
CONTROL: a shortcut reply the guardrail did not touch keeps the history it was written with 37.8ms
✓
the usage footer keeps its token counts, including the send fee, and no figure in dollars 48.7ms
agent loop: the frame carries the guarded table, never the raw rows behind it · 3 tests
✓
the send log: the provider's failure reason reaches the browser only as the guarded cell 45.8ms
✓
CONTROL: a created campaign still hands the app its id, and nothing else of the result 25.9ms
✓
a confirmation gate tells the app it is one, and carries nothing else of the result 21.6ms
shortcut (a plan item's Execute chip): the frame carries the guarded table, never the raw rows · 2 tests
✓
the provider's failure reason reaches the browser only as the guarded cell 25.4ms
✓
CONTROL: the admin smoke harness (behind the admin secret) keeps the whole result its eval reads 13.9ms
src/chat/tool-data-marker.vitest.ts
the marker · 5 tests
✓
opens and closes with the same per-run id, and keeps the JSON intact between them 2.7ms
✓
a page cannot close the block early: only the real close carries the id 0.4ms
✓
a result that echoes the id back cannot forge the close either 0.2ms
✓
the id is fresh per run and not guessable from the last one 2.4ms
✓
strips a leaked marker and nothing else 0.4ms
it never reaches the user · 2 tests
✓
the outbound rail removes a marker the model repeated 3.4ms
✓
and never empties a reply that was nothing but the marker 0.7ms
the wiring in runChatV2 · 3 tests
✓
draws one id per run, before the loop 0.3ms
✓
marks every executed result the model reads — the model's copy only, after the presenter 0.7ms
✓
our own sentences are not dressed up as tool data 0.4ms
src/chat/xml-tool-call-salvage.vitest.ts
the call is RECOVERED, not apologised for · 4 tests
✓
parses the exact message siriiusblack0 received 2.7ms
✓
honours string="false" — a typed value is not passed through as text 0.4ms
✓
is PREFIX-AGNOSTIC — the dialect family, not one vendor token 0.6ms
✓
the JSON dialect it always handled still works 0.3ms
it never guesses · 3 tests
✓
an UNREGISTERED name is not salvaged 0.2ms
✓
the REDACTED name cannot resurrect a call 0.2ms
✓
ordinary prose containing angle brackets is untouched 0.2ms
the backstop, for when salvage cannot recover it · 3 tests
✓
the detector now SEES the XML dialect it was written for 0.5ms
✓
still gated on delivery — a turn that delivered is never rewritten 0.7ms
✓
report HTML is not mistaken for a typed tool call 0.6ms
src/db/jwt-reads.vitest.ts
6c: request-context reads carry the JWT · 10 tests
✓
handleActivityPoll takes userToken and passes it to the dual seam 1.9ms
✓
handleGetKeywords takes userToken and passes it to the dual seam 7.1ms
✓
handleSerpSpiderTasks takes userToken and passes it to the dual seam 0.6ms
✓
listConnections takes userToken and passes it to the dual seam 0.4ms
✓
the routes hand the request token to the three handlers 7.8ms
✓
listConnections receives the token from the tool paths that have one 4.7ms
✓
getChatFeedbackRecord states why it stays on the admin seam 0.3ms
✓
handleSerpSpiderResults states why it stays on the admin seam 0.3ms
✓
fetchSitePerformance states why it stays on the admin seam 1.0ms
✓
handleCommerceAuthedRoute states why it stays on the admin seam 0.3ms
src/db/migration-196.vitest.ts
the two shapes · 2 tests
✓
BEFORE is exactly migration 188's AFTER for the user role's emails_sent INSERT and UPDATE 3.8ms
✓
AFTER takes out exactly the seven — status from both, the six server-written columns from the UPDATE — and nothing else 3.8ms
196_apply.sh against the stand-in · 7 tests
✓
applies from 188's shapes, proves itself, and a re-run changes nothing 432.5ms
✓
--dry-run reports and writes nothing 184.3ms
✓
--clear puts 188's shapes back, and says what it re-opens 380.2ms
✓
a failed create restores the permission exactly as read, and a re-run resumes 378.7ms
✓
a drifted live permission (a column 188 never granted) is a STOP before anything is written 187.4ms
✓
a status column whose default would not make a draft is a STOP before anything is written 101.3ms
✓
a schema that still lets the user role write one of the seven fails the proof, whatever the metadata says 198.5ms
the files must say what the script does · 1 test
✓
an AFTER file that still grants one of the seven is a STOP before anything is read 77.8ms
src/email/list-unsubscribe.vitest.ts
listUnsubscribeHeaders · 1 test
✓
produces the RFC 8058 pair 2.0ms
every provider forwards the headers · 6 tests
✓
mailjet: headers reach the request body 26.2ms
✓
resend: headers reach the request body 0.9ms
✓
sendgrid: headers reach the request body 0.7ms
✓
mailtrap: headers reach the request body 0.7ms
✓
gmail: headers are lines in the raw MIME message 1.3ms
✓
smtp: both header lines are in the DATA payload of a real run 19.3ms
the callers · 3 tests
✓
a contact send always carries the one-click headers for that send 8.0ms
✓
our own transactional mail carries them only when the kind is marketing 1.0ms
✓
the one-click POST lands on a handler that exists 6.3ms
render.vitest.ts
Email
10 /10
9ms · 1 suite
PASS
src/email/render.vitest.ts
email render · 10 tests
✓
keeps paragraphs as <p> blocks 1.6ms
✓
preserves paragraph breaks in the plain-text alternative 0.5ms
✓
preserves inline anchors and escapes the rest 3.5ms
✓
keeps paragraphs in both parts when composing 0.7ms
✓
does not click-wrap the unsubscribe link 0.2ms
✓
click-wraps body links 0.7ms
✓
adds UTM to body links 0.6ms
✓
does not overwrite existing UTM 0.5ms
✓
keeps the unsubscribe link UTM-free 0.5ms
✓
injects the open pixel and signature 0.3ms
src/email/transactional.vitest.ts
transactional templates · 4 tests
✓
renders seo rank digest with movement-first copy 1.5ms
✓
renders seo rank digest highlights-only check-in copy 0.3ms
✓
renders inactivity reminder with progress highlights 0.2ms
✓
renders setup nudge with concrete blockers 0.2ms
isPermanentEmailFailure · 6 tests
✓
treats a provider suppression as permanent 0.3ms
✓
treats a hard bounce as permanent 0.2ms
✓
does NOT treat a quota failure as permanent 0.2ms
✓
does NOT treat a rate-limit failure as permanent 0.1ms
✓
handles the real multi-provider error string from NQZAI-7W 0.4ms
✓
is false for empty/missing errors 0.2ms
src/guard-proofs/check-cost-refs.vitest.ts
check-cost-refs — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (×10 margin on actual cost)) · 10 tests
✓
the unmutated sandbox exits 0 60.5ms
✓
CR-1: exits 1 naming the violation — the on-page audit bills against the replaced apify cost key instead of the live one 62.6ms
✓
CR-2: exits 1 naming the violation — a catalog entry for a gated tool quotes a hand-typed t() literal instead of priceOfTool 57.4ms
✓
CR-3: exits 1 naming the violation — the off-page audit (whose gate verdict flips on the orchestration floor) is quoted off-resolver 58.3ms
✓
CR-4: exits 1 naming the violation — the retail rate is halved to $1/M — every token now sells at ×5 of its cost 59.0ms
✓
CR-5: exits 1 naming the violation — apiCostToTokens converts provider cost at the RETAIL rate (×1: provider spend passed through at cost) 58.9ms
✓
CR-6: exits 1 naming the violation — the LLM path bills a 'discounted' half of its cost through billedTokensFor 58.4ms
✓
CR-7: exits 1 naming the violation — outcome-rollup's dependency-free copy of the cost basis drifts from usage.ts 57.2ms
✓
CR-8: exits 1 naming the violation — the top-up packs are priced at $1 per million while the retail rate says $2 57.4ms
✓
every mutant was restored: the sandbox exits 0 again 56.5ms
src/leads/apify-poll-ownership.vitest.ts
apifyCheckAndStore ownership · 6 tests
✓
refuses a poll for a run owned by a different tenant 5.1ms
✓
refuses when the run meta carries no owner at all 0.8ms
✓
refuses when there is no run meta at all 0.9ms
✓
refuses an anonymous caller even when the run has an owner 0.7ms
✓
lets the real owner through to the run lookup 9.0ms
✓
lets the trusted queue job through without an owner in meta 1.5ms
apifyCheckAndStore reads only the owned run's own dataset · 4 tests
✓
refuses a dataset id that is not the owned run's, and never reads it 30.3ms
✓
reads the run's own dataset when the ids agree 8.1ms
✓
a run record with no dataset of its own reads nothing 1.3ms
✓
a path-shaped dataset id cannot steer the request to another Apify resource 1.1ms
src/leads/dropleads.vitest.ts
filters: only keys measured to narrow are sent · 3 tests
✓
maps role, country, city, domain, technology and keyword; never the ignored location scopes 3.5ms
✓
a search with no role, domain or keyword has no target and never pages the whole database 0.3ms
✓
spells the industry the way the provider does 0.3ms
parsing the provider shapes seen live · 2 tests
✓
reads a search page 1.3ms
✓
builds a lead from an enrich, carrying the provider's verdict as the provider's claim 0.5ms
the rung: free search, paid enrich to the shortfall, misses counted · 4 tests
✓
validates the industry with a free count, drops and declares it when the provider holds no such label 28.6ms
✓
keeps the industry when the count could not be read — an unreadable count is not evidence 1.3ms
✓
a search failure is said and charged nothing; no enrich is attempted 1.3ms
✓
is absent without the broker token 0.7ms
the price is in the table and matches the measured credit rate · 1 test
✓
dropleads_enrich = 0.2 credit at the account rate; search is free and visible 0.3ms
src/leads/us-states.vitest.ts
US_STATE_MAP · 2 tests
✓
has exactly 50 entries 2.6ms
✓
every value is a 2-letter uppercase code 1.5ms
US_STATE_ENUM · 2 tests
✓
is title-cased, matching the schema enum this repo's other lists use 0.6ms
✓
has one entry per state 0.3ms
resolveUsStateCode · 6 tests
✓
resolves a title-cased name 0.3ms
✓
resolves a lowercase name 0.2ms
✓
resolves an uppercase abbreviation 0.2ms
✓
resolves a multi-word state name 0.3ms
✓
returns undefined for garbage input 0.5ms
✓
returns undefined for an empty string 0.2ms
src/reports/publish-capture.vitest.ts
the artifact card carries the row a publish should close · 2 tests
✓
passes content_piece_id through when the tool recorded one 2.0ms
✓
omits it rather than sending an empty string when no piece was recorded 0.4ms
a DRAFT is not a publication · 3 tests
✓
the WordPress branch records only on status=publish 0.5ms
✓
records only when the connector actually returned a URL 0.2ms
✓
the capture never gates the publish response 0.2ms
a PARTIAL Notion page is not the article · 2 tests
✓
is excluded from capture, matching what the client already refuses to celebrate 0.3ms
✓
records with connector provenance when the page is whole 0.3ms
the client echoes the row id back on both paths · 3 tests
✓
the document card carries it as a data attribute 0.3ms
✓
both publish calls send it, and neither sends an empty one 1.0ms
✓
reads the id off the card even when title/content were passed in 0.3ms
src/routes/about-schema.vitest.ts
/about structured data · 6 tests
✓
emits parseable JSON-LD 26.0ms
✓
describes the page as an AboutPage whose mainEntity is the organization 1.1ms
✓
reuses the homepage organization @id so the two nodes merge into one entity 0.8ms
✓
names the operating company and its postal address 1.1ms
✓
carries a sameAs for the nqzai entity itself, not just its parent company 1.9ms
✓
never breaks out of the script tag 0.8ms
/quality-test crawlability · 4 tests
✓
links to both reports with real anchors, not buttons 0.4ms
✓
carries a noscript fallback for agents that do not run JavaScript 0.2ms
✓
emits a CollectionPage listing both reports 0.7ms
✓
keeps the quality gates OUT of the page sitemap 0.6ms
src/routes/pillar-page-css.vitest.ts
the pillar stylesheet is defined once and shared · 10 tests
✓
is substantial — an emptied export would silently unstyle both pages 1.8ms
✓
/ai-visibility-answered emits the shared block, not a copy 25.2ms
✓
/ai-visibility-answered sets data-theme, or every token resolves to nothing 1.2ms
✓
/ai-visibility-answered emits robots as a META TAG, never a bare string 1.5ms
✓
/ai-visibility-answered carries the three JSON-LD blocks the template requires 1.7ms
✓
/seo-questions-answered emits the shared block, not a copy 1.4ms
✓
/seo-questions-answered sets data-theme, or every token resolves to nothing 1.0ms
✓
/seo-questions-answered emits robots as a META TAG, never a bare string 1.2ms
✓
/seo-questions-answered carries the three JSON-LD blocks the template requires 1.2ms
✓
neither page carries its own copy of the pillar rules 0.7ms
src/routes/ugc-noindex.vitest.ts
shared GEO scorecard results (/geo-scorecard?url=) · 3 tests
✓
is noindex (header + meta) with the canonical on the bare tool page; the share card keeps its own og:url 32.0ms
✓
a page GET never runs the scorecard; it reads a cached result for the share card or shows the generic card 8.4ms
✓
the bare tool page stays indexable 3.9ms
/verify-email and /auth/verify · 3 tests
✓
the address from the query string is escaped in HTML and cannot close the <script> (reflected XSS, 2026-10-27) 1.6ms
✓
both are noindex (header + meta) 2.3ms
✓
the confirmed-address page escapes the address too 1.1ms
/unsubscribe/:id · 1 test
✓
is served with the noindex headers and meta 0.6ms
script-generated evidence pages (/quality-test, /quality-eval, /unit-test-report) · 2 tests
✓
are out of the pages sitemap 1.3ms
✓
get the header on the asset path, and the meta from the generators and the committed files 17.4ms
/app and /dashboard (the SPA shell) · 1 test
✓
the shell meta agrees with its noindex header, and search engines may fetch it to read that 1.4ms
src/runtime/llm-json.vitest.ts
parseLlmJsonArray · 7 tests
✓
parses clean output unchanged 2.6ms
✓
survives a real newline inside an email body 1.0ms
✓
handles tabs and carriage returns too 0.3ms
✓
finds the array inside surrounding prose 0.4ms
✓
still fails loudly on a truncated array 0.4ms
✓
still fails on genuinely broken structure 0.3ms
✓
rejects a JSON value that is not an array 0.4ms
parseLlmJsonObject · 1 test
✓
parses the personalized-opener shape 0.4ms
escapeControlCharsInStrings · 2 tests
✓
leaves structural whitespace alone 0.5ms
✓
does not double-escape an already-escaped sequence 0.2ms
src/runtime/public-ratelimit.vitest.ts
a KV error REFUSES the anonymous call instead of allowing it · 5 tests
✓
auth signup (and resend-verification): fails closed 3.2ms
✓
GEO scorecard: fails closed 0.7ms
✓
AI-search prompt generator: fails closed 0.6ms
✓
website health check: fails closed 0.4ms
✓
an UNBOUND store is still inactive (local dev and tests), which is not the same as a failing one 0.3ms
two IPv6 addresses in one /64 share a counter · 5 tests
✓
auth signup (and resend-verification): the /64 is the subject, not the address 1.5ms
✓
GEO scorecard: the /64 is the subject, not the address 1.0ms
✓
AI-search prompt generator: the /64 is the subject, not the address 0.8ms
✓
website health check: the /64 is the subject, not the address 0.6ms
✓
IPv4 counters keep their existing key shape, so in-flight counters survive the deploy 0.4ms
src/runtime/scan-stops-crons.vitest.ts
weekly store digest · 3 tests
✓
skips a tenant who stopped it and still emails the others 3.9ms
✓
reads its OWN switch: a stopped rank scan does not stop the digest 0.6ms
✓
fails closed: an unreadable stop list sends nothing, is reported and rejects the run 3.2ms
weekly published-content check · 2 tests
✓
skips a tenant who stopped it and still checks the others 0.9ms
✓
fails closed: an unreadable stop list checks nobody, is reported and rejects the run 0.9ms
the weekly jobs resolve only when they did their work · 5 tests
✓
digest: one shop failing is reported and the run still resolves 0.9ms
✓
digest: every shop failing rejects the run 1.1ms
✓
publish pass: an unreadable tenant list rejects (it used to read as "no tenants") 0.4ms
✓
publish pass: one tenant's read failing is reported and the pass still resolves 0.9ms
✓
publish pass: every tenant's read failing rejects 0.5ms
src/tools/backlink-routing.vitest.ts
the backlink family is DISCOVERABLE from the always-on pointer · 4 tests
✓
names backlinks in the words a user would use 1.9ms
✓
names each distinct backlink question the family answers 0.7ms
✓
warns that two pairs sound alike, which is the whole failure mode 0.4ms
✓
says several are paid, so cost is not inferred from the family name 0.2ms
and DISTINGUISHED once the family is loaded · 6 tests
✓
seo_backlink_value states its own routing rule 0.3ms
✓
seo_backlink_deep_scan states its own routing rule 0.2ms
✓
seo_backlink_verify states its own routing rule 0.2ms
✓
seo_backlink_gap states its own routing rule 0.2ms
✓
tells the model that WORTH is not the off-page audit — from BOTH sides 0.7ms
✓
marks the free ones free, so cost is not inferred from the family name 0.3ms
src/tools/redirect-consequence-gate.vitest.ts
connector actions are on the side-effect axis · 4 tests
✓
the four that write on a tenant-owned third-party account are external 2.0ms
✓
the route-backed connector actions are declared, and are actually reachable 6.0ms
✓
an outward publish that FAILS reports to Sentry — not only to the button 5.2ms
✓
the Google connector reads stay reads — url_inspection is a query, not a submission 0.3ms
the fix_redirect shortcut cannot write without a confirmation · 4 tests
✓
detects read-only, then stops — it does not write on this turn 0.4ms
✓
fails CLOSED when the confirmation store is unavailable 0.2ms
✓
reports detection failures rather than swallowing them 0.3ms
✓
presents CONSEQUENCE, not cost — the action is free and must not read as a price 0.3ms
the detect+write function is gone, not merely bypassed · 2 tests
✓
fixRedirectAuto no longer exists anywhere 1.0ms
✓
detectRedirectFixTool returns a tool NAME and performs no write 0.3ms
src/tools/seo-family-rules.vitest.ts
the three rules that were NOT already on their tool · 4 tests
✓
MOVE 1 — seo_offpage_audit says it covers ranking keywords, not just links 1.9ms
✓
MOVE 2 — seo_google_merge says compare=true is mandatory for a change question 0.5ms
✓
MOVE 3 — seo_backlink_value says a WORTH question is not the off-page audit 0.5ms
✓
and the mirror of MOVE 3 is on the tool that was wrongly chosen 0.3ms
the dead instruction is gone and must not come back · 2 tests
✓
nothing model-facing routes to full_seo_audit 0.4ms
✓
and "audit my site" is answered with tools the model CAN call 0.4ms
the duplication is actually gone · 4 tests
✓
the per-bullet routing table is not in V2_SYSTEM any more 0.3ms
✓
the never-say-free rule is stated ONCE, not once per family 0.4ms
✓
the pointer is an order of magnitude smaller than the block it replaced 0.6ms
✓
V2_SYSTEM stays under its ratchet 0.2ms
src/seo/ai-visibility-score.vitest.ts
computeAiVisibilityScore · 1 test
✓
is a weighted composite, normalized over PRESENT pillars only 2.0ms
aiVisibilityFromAudits — Dim-5 unification with the dashboard · 4 tests
✓
maps the three sub-audit results to the four pillars and matches computeAiVisibilityScore 0.4ms
✓
falls back to nested rag_readiness.rag_score when the top-level field is absent 0.3ms
✓
a failed sub-audit drops its pillar (normalized over the rest), not scored 0 0.2ms
✓
all sub-audits failed → null (caller surfaces an error, never a fake 0) 0.2ms
the two Google surfaces share one slice · 5 tests
✓
a score with no AI Mode computes EXACTLY as it did before AI Mode existed 0.2ms
✓
with both present, Google still carries 0.25 in total — not 0.50 0.3ms
✓
AI Mode alone carries the full Google slice when no Overview was measured 0.3ms
✓
averages the two surfaces when they disagree 0.5ms
✓
aiVisibilityFromAudits threads ai_mode_pct through 0.2ms
src/seo/backlink-store.vitest.ts
toStoredRows · 4 tests
✓
derives the referring domain and keeps the provider fields 2.9ms
✓
dedupes within a batch — a live index can return the same URL twice mid-scan 1.2ms
✓
drops rows with no usable URL rather than storing a blank referrer 0.3ms
✓
keeps missing numeric fields NULL instead of coercing them to zero 0.3ms
deepScanNote — warns about paying twice, never predicts what it cannot know · 6 tests
✓
says nothing when nothing is on file — an all-new scan needs no caution 0.2ms
✓
warns when the last scan was recent, and gives BOTH measured numbers 13.6ms
✓
stays quiet once enough time has passed for links to accrue 0.2ms
✓
warns that pages past the end of a profile cost a lookup and return nothing 0.3ms
✓
never forecasts how many new links exist — that number is the purchase itself 0.8ms
✓
asks for a site before anything else 0.4ms
src/seo/content-ideas-knows-what-we-wrote.vitest.ts
the dedup reads what we WROTE, not only what is published · 3 tests
✓
loads the tenant's content pieces for this site 1.5ms
✓
a failed read does not take the tool down 0.3ms
✓
written topics join the same dedup set the sitemap feeds 0.2ms
and the RESULT says so, so the model cannot deny it · 5 tests
✓
carries a count and the pieces themselves 0.2ms
✓
names the state, because published and drafted lead to different actions 0.2ms
✓
forbids the exact sentence that was wrong 0.2ms
✓
and tells the model publishing beats drafting when pieces are unpublished 0.4ms
✓
the note is omitted entirely when nothing has been written 0.2ms
the coverage note steers to publishing, not to another draft · 2 tests
✓
has a branch for "everything overlaps AND drafts are unpublished" 0.4ms
✓
which is checked BEFORE the generic overlap message 0.3ms
src/seo/content-verify.vitest.ts
extraction (code) · 4 tests
✓
lists linked sentences first, then numeric sentences without a link; headings and list counts never count 3.2ms
✓
reads outline sections from headings, H2: lines and numbered items, skipping boilerplate 0.8ms
✓
picks the source window that carries the claim's numbers 0.7ms
✓
page text drops scripts, styles and tags 0.8ms
judgments · 1 test
✓
one choice per claim with a contradicted outcome, one noul per section 0.5ms
presentation · 4 tests
✓
the note states counts the pass measured and names the missing sections 0.5ms
✓
the block lists the contradicted claim with its source and the unreachable source; nothing when there was nothing to check 0.5ms
✓
findings carry provenance judged so the report shows them as verdicts, not counts 0.6ms
✓
a skipped pass is said, never rendered as clean 0.5ms
wiring · 1 test
✓
the write tool verifies inline when its clock allows, otherwise in the background as an activity line; the chat renderer shows the block 3.9ms
src/seo/keyword-vs-prompt.vitest.ts
the two worlds are measured, not asserted · 6 tests
✓
counts word length and question-form on both sides 1.9ms
✓
different_languages survives, quoting both sides 0.6ms
✓
names the two SYSTEMS as its sources, not two fields of one 0.7ms
✓
no_shared_terms is a SEPARATE finding from the language gap 0.4ms
✓
an OVERLAPPING term flips it and is named 0.5ms
✓
comparison prompts are read for third-party share 0.3ms
what it refuses · 4 tests
✓
the rank-versus-prompt join is untested, and says WHY it cannot be approximated 0.5ms
✓
where the prompt language comes from is not ours to see 0.4ms
✓
no Search Console terms is a different sentence from no panel 0.9ms
✓
claims no trend — the keyword table keeps no history 0.6ms
src/seo/onpage-js-rendering.vitest.ts
detecting a site whose content is behind JavaScript · 4 tests
✓
the SPA shell that measured 1 page is detected 33.9ms
✓
a server-rendered site is NOT charged the 10x rate 1.5ms
✓
DEGRADES TO NO RENDERING when the probe fails 1.4ms
✓
markup alone is not content — script and style bodies do not count 1.0ms
the rendered crawl is priced as its own leg · 3 tests
✓
the JS rate is what the provider actually billed 0.3ms
✓
a rendered crawl costs an order of magnitude more, so it can never be the default 0.3ms
✓
the base rate is KNOWN-LOW and left alone on purpose 0.3ms
a zero-page crawl states what was observed, not a cause · 3 tests
✓
no longer tells the owner their site blocks crawlers 1.8ms
✓
says the crawl reached the site, and that nothing was charged 1.7ms
✓
distinguishes the case where rendering was ALREADY on 1.5ms
src/seo/serp-client.vitest.ts
the SERP client · 10 tests
✓
(a) posts {q, num:10} to the provider endpoint with the provider key header 28.4ms
✓
(a) a site-scoped call sends the site: operator inside q, and nothing else 1.0ms
✓
(b) the vendor feedback channel never leaves the client; the search data does 1.6ms
✓
(c) a non-OK answer records a serp:failed row with the status, and re-throws 3.0ms
✓
(c) the error the model sees carries a plain word, never a status, the vendor name or its body 6.0ms
✓
(c) a 400 is one call, not a retry: the old free-tier operator retry is gone 0.9ms
✓
(d) a success is ledgered once under the provider, priced by its API_COST key 0.7ms
✓
(e) an empty query makes no call, writes no row, and returns the empty result shape 0.8ms
✓
(e) a query over the 2048-character limit is cut to it, by code point 1.4ms
✓
a missing provider key makes no call, records nothing, and names neither vendor nor secret 0.7ms
src/seo/settings-tenant-scope.vitest.ts
getAllSettings with no tenant · 5 tests
✓
a undefined user id gets no other tenant's rows, and no unscoped read is issued 143.2ms
✓
nothing is cached under the undefined id: a second call is not served the first call's record 21.3ms
✓
a empty string user id gets no other tenant's rows, and no unscoped read is issued 24.6ms
✓
nothing is cached under the empty string id: a second call is not served the first call's record 21.4ms
✓
a no-tenant call between two tenants' reads neither reads nor disturbs their cache entries 28.0ms
two users' caches never cross · 2 tests
✓
concurrent first reads: each tenant is queried by its own id and gets only its own rows 17.4ms
✓
a cached read and a write invalidation stay on their own tenant 22.9ms
getProductBriefStatus with no tenant · 3 tests
✓
a undefined user id reads no brief, issues no unscoped read, and is reported as a read that did not happen 18.6ms
✓
a empty string user id reads no brief, issues no unscoped read, and is reported as a read that did not happen 22.0ms
✓
a tenant's own brief is still read, scoped by its id 16.7ms
src/seo/sov-weekly.vitest.ts
weekly config round-trip · 3 tests
✓
survives serialize → parse 2.4ms
✓
drops engines that are not real engines rather than passing them to the fan-out 0.4ms
✓
treats malformed stored config as absent, never throws 0.3ms
the quote is the same arithmetic the run will be billed · 2 tests
✓
prices through aeoVisibilityFanoutCostUsd, not a second estimate 0.3ms
✓
one engine costs materially less than four — the lever the copy tells them to pull 0.3ms
the offer states the cost · 4 tests
✓
an OFF state that offers the run must carry the number 0.6ms
✓
an ON state says which engines and where the choice came from 0.4ms
✓
quotes nothing rather than something vague when the resolver failed 0.3ms
✓
a plan that does not include the run says so instead of offering it 0.5ms
fmtTok · 1 test
✓
formats the ranges the copy actually uses 0.3ms
src/leads/shared/embed-candidate-predicate.vitest.ts
the candidate query requires something to embed · 3 tests
✓
demands at least one of the four fields composeContent uses 1.9ms
✓
ORs them — requiring all four would exclude almost everybody 1.3ms
✓
uses the SAME location expression the SELECT list does 0.2ms
the predicate is deliberately LOOSER than composeContent · 3 tests
✓
does not re-implement LOCATION_TITLE_RE in SQL 0.3ms
✓
does not re-implement GENERIC_BARE_TITLES in SQL 0.2ms
✓
composeContent still exists and still decides 0.2ms
161 · search_candidates pins hnsw.ef_search · 4 tests
✓
sets it on the function, not on a session or a role 0.3ms
✓
loads the vector library first, or the ALTER fails as an unrecognized parameter 0.3ms
✓
does not regenerate the function body 0.5ms
✓
asserts the three pre-existing pins survive 0.3ms
src/leads/shared/reveal-billing.vitest.ts
what the customer is actually charged · 5 tests
✓
charges the FULL-price key for a confirmed mailbox 3.2ms
✓
charges the HALF-price key for a domain-derived catch-all 0.7ms
✓
charges NOTHING at all for an address we proved bounces 0.9ms
✓
charges nothing when the corpus cannot say what it checked 0.4ms
✓
keeps the ledger amount and the charged key in step 0.6ms
the rollout gate — SHARED_LEADS_BILLING · 5 tests
✓
charges NOTHING when the flag is unset — the state every deploy lands in 0.5ms
✓
still records the reveal in the ledger at zero, not skipping the row 0.4ms
✓
charges when armed for everyone 0.5ms
✓
charges the NAMED tenant and nobody else 1.0ms
✓
fails closed on every ambiguous input 0.3ms
chip-card.vitest.ts
Core
9 /9
7ms · 3 suites
PASS
client/chip-card.vitest.ts
chipCardId · 2 tests
✓
reads the card the server attached to exactly this chip 2.0ms
✓
accepts only a card id: no map, an array, or a non-id value carries nothing 0.4ms
the armed chip · 4 tests
✓
posts the card when the message sent is the chip's exact text, once 0.4ms
✓
an edited message is the person's own typed text: no card, and the slot clears 0.2ms
✓
the last chip clicked wins; a chip with no card clears the earlier one 0.2ms
✓
the request field is present only with a card 0.7ms
client/main.ts posts it · 3 tests
✓
both chip renderers arm the slot with the card from chip_cards (chat reply and activity bubble) 0.9ms
✓
the send takes the armed card once and posts it beside the message, never in it 0.7ms
✓
no inline handler carries it (CSP, #560): every arm is inside an addEventListener closure 0.8ms
client/vitals-auth.vitest.ts
a vitals request carries the session, like every other data fetch · 3 tests
✓
sends the bearer token 9.3ms
✓
sends it on BOTH endpoints — the token bar is a separate fetch 3.8ms
✓
omits the header rather than sending "Bearer undefined" when signed out 2.8ms
a 401 is classified, not lumped · 3 tests
✓
a tokenless 401 reads as "no session", not as a fault 2.4ms
✓
a 401 WITH a token is still a real failure — the token is bad or expired 0.6ms
✓
still fails on non-401 errors, so the classification did not widen 1.3ms
the real call site still passes headers · 3 tests
✓
vitalsFetch calls fetch with an options object carrying authHeaderMap() 9.1ms
✓
the real call site still classifies a tokenless 401 4.7ms
✓
authHeaderMap is the shared helper, not a second copy 0.9ms
scripts/lib/prefilter-set-cap.vitest.mjs
createShardedHashSet — within-file dedup above the Set cap · 4 tests
✓
behaves like a Set for add/has 2.0ms
✓
counts distinct keys, and re-adding one does not grow it 1.4ms
✓
SPREADS across every shard, which is the whole point — capacity is shards x the cap 102.3ms
✓
defaults to many shards rather than one 0.7ms
seenStoreMerge — cross-file merge above the Set cap · 5 tests
✓
merges, dedupes, and returns a BigUint64Array 0.9ms
✓
KEEPS THE OUTPUT SORTED — seenStoreFind does a binary search on it 0.4ms
✓
handles either side being empty, and duplicates within one side 0.4ms
✓
does not over-allocate — the returned array is trimmed, not a view on the scratch buffer 0.2ms
✓
NEVER builds an intermediate Set — the structural property that removes the cap 0.6ms
advisory.vitest.ts
Core
9 /9
6ms · 2 suites
PASS
src/admin/advisory.vitest.ts
directionFor · 3 tests
✓
reports up when current exceeds previous beyond epsilon 1.6ms
✓
reports down when current is below previous beyond epsilon 0.3ms
✓
reports flat when the difference is within epsilon (avoids noise from float rounding) 0.2ms
computeChangesSinceLast · 6 tests
✓
returns null when there is no previous brief (first-ever run) 0.4ms
✓
returns null when the previous brief predates the economics/mandate schema (old shape guard) 0.3ms
✓
computes real economics deltas with direction, skipping fields that were null in either snapshot 1.0ms
✓
computes mandate revenue-impact deltas keyed by the exact mandate title, using the midpoint of low/high 0.6ms
✓
always returns all three mandate titles even if the previous brief is missing one (defensive against schema drift) 0.3ms
✓
reports days_since_previous as a non-negative number derived from generated_at 0.8ms
src/admin/defect-class-routing.vitest.ts
the routing class · 6 tests
✓
is registered on both axes 2.5ms
✓
catches the live session the console called clean 0.6ms
✓
does NOT fire when the tenant has a saved site 0.7ms
✓
does NOT fire when no site-scoped tool ran 0.2ms
✓
treats an UNREADABLE saved-site as unknown, never as absent 0.2ms
✓
is not reached when the signals are absent entirely (old callers) 0.3ms
ordering against the classes it sits between · 3 tests
✓
functional still wins — work that reached NOTHING outranks work missing a piece 0.3ms
✓
routing wins over presentation — a missing side effect outlives a badly-read reply 0.3ms
✓
judge still wins — a wrong instrument hides every class behind it 0.5ms
src/admin/gsc-query-page.vitest.ts
buildQueryPageMap · 9 tests
✓
picks the best-RANKING page, not the one with the most impressions 2.0ms
✓
breaks a position tie by impressions 0.3ms
✓
totals clicks and impressions across ALL pages, and weights position by impressions 0.4ms
✓
flags cannibalization when two of our pages both have real exposure 1.2ms
✓
does NOT call a single stray impression on a second URL cannibalization 0.4ms
✓
does not flag a query where every page is marginal 0.2ms
✓
handles a single page per query without inventing competitors 1.2ms
✓
ranks the map by impressions so unmet demand is at the top 0.3ms
✓
skips rows missing either dimension rather than creating an empty grouping 0.5ms
src/admin/internal-accounts.vitest.ts
internalAccounts · 4 tests
✓
reads emails and ids from env, merged and lower-cased 1.8ms
✓
tolerates whitespace, empty entries and trailing commas 0.3ms
✓
falls back to the known internal list when NOTHING is configured 0.5ms
✓
does NOT add the fallback on top of a configured list 0.3ms
isInternalAccount · 5 tests
✓
matches on email regardless of case or padding 0.2ms
✓
matches on user id too — a caller may hold only one identifier 0.3ms
✓
does not match a real customer 0.2ms
✓
handles missing identifiers without throwing 0.3ms
✓
does not treat a substring as a match 0.6ms
src/admin/mixpanel-time.vitest.ts
tzOffsetMs · 3 tests
✓
returns 0 for UTC 16.2ms
✓
handles DST on both sides of a transition (US/Pacific) 0.7ms
✓
handles eastern offsets (Asia/Kolkata, +5:30 year-round) 0.3ms
naiveProjectTimeToUtcIso · 4 tests
✓
converts a naive project-tz wall clock to true UTC 0.9ms
✓
accepts space-separated datetimes and missing seconds 0.4ms
✓
passes through values that already carry a zone 0.3ms
✓
returns null for junk 0.3ms
exportEpochToUtcIso · 2 tests
✓
undoes the project-timezone shift Mixpanel bakes into export epochs 0.6ms
✓
returns null for non-finite input 0.5ms
src/admin/prompt-cache.vitest.ts
handleAdminPromptCache · 5 tests
✓
refuses without the admin secret 28.5ms
✓
says WHY it cannot answer when the CF credential is absent, instead of returning zero 2.3ms
✓
computes per-row and total hit rates from the datapoints 2.1ms
✓
sends the window as a bounded day count 0.8ms
✓
surfaces an upstream rejection verbatim rather than reporting zero cache hits 1.1ms
the AE refactor leaves the default view unchanged · 2 tests
✓
returns exactly the pre-refactor body for a fixed dataset 1.3ms
✓
keeps each failure body: unreachable and non-JSON 1.3ms
queryPromptCacheByModel — the drift monitor's read · 1 test
✓
groups by model over a bounded window and throws rather than reading as zero hits 2.1ms
describeVerdict — an empty dataset is not a cold cache · 1 test
✓
separates no_data from not_caching 0.7ms
src/admin/quality-rows.vitest.ts
judgeScore · 4 tests
✓
reads the score the live judge actually writes — a string 1.8ms
✓
reads a numeric score, and the older quality_score spelling 0.4ms
✓
keeps a score of zero 0.2ms
✓
returns null rather than NaN for junk, so callers cannot compare against it 0.4ms
isJudgeScoreRow · 5 tests
✓
accepts a judged capability, including a variant key 0.4ms
✓
rejects every declared counter, shaped the way its writer shapes it 0.9ms
✓
rejects an undeclared future counter on shape alone 0.2ms
✓
accepts a scored row under a name nobody recognises — that alarm must still fire 0.2ms
✓
rejects a declared counter even if it starts carrying a score field 0.5ms
src/admin/release-ledger.vitest.ts
computeMetrics · 9 tests
✓
empty ledger → zeroed metrics, no alert 2.2ms
✓
lead time = deployed_at − build_time, median over builds that have a build_time 0.8ms
✓
deploy frequency counts only the 30-day window 0.4ms
✓
change-failure rate counts rollback OR incident; alerts only above 15% with ≥5 samples 0.6ms
✓
does not alert on a high rate built from too few samples 0.3ms
✓
MTTR = closed − opened, median over resolved incidents 0.3ms
✓
quality-at-release inherits the last judge digest on/before deploy day 0.5ms
✓
negative lead time (clock skew: build_time after deploy) is dropped, not negative 0.3ms
✓
digest line renders once something shipped 0.7ms
src/admin/synthetic-session.vitest.ts
the real ids, which have exactly one producer · 3 tests
✓
keeps client-generated sessions 2.9ms
✓
KEEPS `default` — it is the server's own fallback, not a probe 0.3ms
✓
an unknown/empty id is NOT synthetic — never invent an exclusion 0.2ms
the probe ids, taken verbatim from the contaminated window · 2 tests
✓
excludes every harness session actually observed 0.7ms
✓
catches a probe run under a REAL user's account 0.2ms
it is an ALLOWLIST, and that is the point · 2 tests
✓
a probe name nobody has invented yet is still excluded 0.2ms
✓
does not reject a real id for containing probe-ish words 0.2ms
the sessions view states what it could actually read · 2 tests
✓
reads newest-first, so truncation costs the OLDEST rows 1.0ms
✓
reports coverage rather than presenting a partial window as whole 0.9ms
src/admin/telemetry-truncation.vitest.ts
truncationFlag · 7 tests
✓
is not truncated below the cap 2.1ms
✓
IS truncated at exactly the cap — over-warning by one exact-fit window is the correct direction to be wrong in 0.4ms
✓
treats an empty list as complete, not as truncated 0.2ms
✓
reports true coverage when the unbounded total is known — "at least 25,000" read as nearly-complete when it was 9.7% of 257,523 0.6ms
✓
omits coverage when no total is available rather than inventing one 0.3ms
✓
never reports coverage above 1 when the sample outruns a stale aggregate 0.2ms
✓
treats a missing list as complete rather than throwing — a panel that never loaded is the error surface’s job, not this one’s 0.4ms
TELEMETRY_CAPS · 2 tests
✓
is one ceiling per list, derived from the page size and page count 0.4ms
✓
caps every list the console derives a displayed number from 0.7ms
src/billing/redelivery-no-resume.vitest.ts
the delivery count reaches nothing that could skip work · 7 tests
✓
Message.attempts is read by exactly the statements that read it today, all in src/index.ts 107.6ms
✓
inside the consumer bodies, the `attempts` token appears ONLY in those statements — whatever the message is called or how it is read (V11-money-F03) 4.6ms
✓
every queue consumer lives in src/index.ts (a consumer elsewhere would escape the check above) 76.8ms
✓
the retry_count column is written by markJobRunning and read back by nothing (a job path that reads it could resume on it) 80.3ms
✓
runAsyncJobInline hands the count only to the retry_count column, never to the job 4.2ms
✓
the rank scan reads its delivery count only after its claim failed — the whole run is skipped before any spend 1.3ms
✓
only the billing modules read the delivery from the request context 78.2ms
a record of prior progress is a decision, not an accident · 2 tests
✓
no new resume/checkpoint vocabulary appears in src without review 81.6ms
✓
the one consumer that resumes keeps its paid row caller-named, so it is never matched by position 1.0ms
src/billing/run-cap-before-card.vitest.ts
one resolver, so the card and the gate cannot disagree · 4 tests
✓
free search_leads is a LIFETIME allowance, not a resetting one 2.0ms
✓
a paid plan sets no run count — the balance is the bound 0.2ms
✓
a TEST tenant is held to FREE counts whatever its plan says 1.0ms
✓
window widths cover all three periods with one mechanism 0.3ms
the wiring, which no unit test can reach (getCostApprovalPlan is not exported) · 5 tests
✓
the card path peeks the cap WITHOUT consuming an allowance 0.4ms
✓
DISPATCH uses the same resolver, so the two cannot drift 0.5ms
✓
every gate treats "no runs left" exactly like "cannot pay" 0.6ms
✓
the cap OUTRANKS the price in the message 0.3ms
✓
it FAILS OPEN — an unreadable counter shows the card 0.5ms
src/billing/unbilled-crawls.vitest.ts
the hourly on-page sweep bills the crawl it delivers to the tenant it belongs to · 2 tests
✓
writes the crawl's ledger rows for that tenant (was: 0 rows, the meter ran with no identity) 99.0ms
✓
closes each tenant's window before the next marker: two tenants, each billed only for its own crawl 22.1ms
POST /api/seo/serp-spider/run: the chat path's gate and the tenant's window · 3 tests
✓
refuses before spending when the balance cannot cover the crawl (was: ran with no check) 15.6ms
✓
writes the crawl's ledger rows for the user who ran it (was: 0 rows) 42.7ms
✓
crawls no deeper than the plan the gate priced (the chat path's page cap) 14.0ms
a meter with no tenant window records under the platform's own id, never nowhere · 4 tests
✓
no window open: one row under PLATFORM_USER_ID, marked no_window (was: dropped) 1.7ms
✓
a window opened with no user: under PLATFORM_USER_ID, marked window_without_user 1.6ms
✓
a tenant's window still bills the tenant, with no platform marker 1.4ms
✓
outside any request scope there is no env to write with, so nothing is written 0.8ms
src/campaigns/consequential-confirm.vitest.ts
gated consequential tools · 9 tests
✓
resume_campaign stages a pending action and refuses to act unconfirmed 2.0ms
✓
cloudflare_fix_email_dns stages a pending action and refuses to act unconfirmed 0.3ms
✓
resume_campaign declares confirm in its schema 0.4ms
✓
cloudflare_fix_email_dns declares confirm in its schema 0.2ms
✓
stages the SUBJECT, not a bare flag, so one confirm cannot authorise another action 0.4ms
✓
does NOT gate pause_campaign — stopping mail is the safe direction 0.2ms
✓
does NOT gate enroll_in_sequence — arming is not sending 0.4ms
✓
does NOT gate set_campaign_sequence — arming is not sending 0.2ms
✓
keeps all four classified as external regardless of where the human check sits 0.6ms
src/chat/answer-chips.vitest.ts
options the model wrote become options you can click · 3 tests
✓
the Hinglish reply that listed report types 2.6ms
✓
the bundled ask that quoted a price it could not afford 0.4ms
✓
numbered options too 0.3ms
a statement is not an offer, and a button that does nothing is worse than none · 5 tests
✓
rejects findings and metrics written in the same bullet shape 0.3ms
✓
rejects a label that is too short, too long, or a URL 0.4ms
✓
ignores a rendered artifact — its bold headings are not options 0.2ms
✓
returns EMPTY for prose with no options, so the caller keeps its fallback 0.4ms
✓
dedupes and caps, so one answer cannot flood the chip row 1.1ms
the wiring · 1 test
✓
is consulted before the generic triple, and the triple survives as the fallback 7.1ms
src/chat/card-honesty.vitest.ts
the panel card promises no weekly measurement and no recurring cost · 3 tests
✓
adding a panel: the card says saving costs nothing and it is measured only when asked; the chip saves it 220.9ms
✓
listing panels: the reply and its budget carry no weekly or yearly figure 2.4ms
✓
no surface repeats the promise: the tool schema, its cost label, the router, the response contract, the gate copy, the activity label 7.8ms
a card that cannot be shown whole says why and offers the edit · 6 tests
✓
a subject that says something is free: one sentence, an edit chip, no confirm chip — and the click does not loop 89.2ms
✓
a subject with a price: the sentence names an amount in a currency, in tokens-only copy 17.1ms
✓
a subject that names a vendor: the sentence says a service name, and names no vendor 15.8ms
✓
a standing instruction the guardrail must alter: the sentence and a chip to reword it, never saved 43.4ms
✓
a withheld card inside a longer reply: the card is replaced by the sentence, the rest of the reply stays 26.0ms
✓
a card staged behind another card is not announced: only a card the reply carried altered gets the notice 22.5ms
src/chat/doc-lane.vitest.ts
doc lane — negative sample: every live cmd string · 2 tests
✓
has a real catalog to test against (not an emptied glob) 1.7ms
✓
never matches ANY live capability cmd phrasing 1.5ms
doc lane — positive cases (synthetic fixture, isolated from the negative-set caution) · 4 tests
✓
matches a "what does X do" question built from the entry's own label 0.6ms
✓
matches a "how does X work" explainer phrasing 0.4ms
✓
does not match when the fixture registry has no vocabulary overlap at all 0.4ms
✓
formats the answer as the tldr plus a link, not a raw field dump 0.5ms
doc lane — refuses non-meta phrasing regardless of vocabulary overlap · 3 tests
✓
does not match a direct task request even if it shares words with a doc-route label 0.3ms
✓
does not match a bare short message 0.2ms
✓
does not match an unrelated meta-shaped question with no real registry overlap 0.9ms
src/chat/judge-cost.vitest.ts
judgeAttemptCost · 4 tests
✓
the provider's reported cost wins and is labelled 'reported' 2.1ms
✓
an absent or zero reported cost falls back to the table, labelled 'estimated' — never 'reported' 0.7ms
✓
a free model is costed at the owner floor, labelled 'floor' 0.3ms
✓
no usage at all is 0 and 'estimated' 0.4ms
combineCostSources · 2 tests
✓
'reported' only when every part was reported 0.4ms
✓
an empty list measured nothing → 'estimated' 0.2ms
src/index.ts wiring · 3 tests
✓
no longer prices anything from the table directly — calcLlmCost( is gone 0.7ms
✓
every judge logApiUsage call passes a cost source as its 8th argument, never undefined 2.4ms
✓
the scan itself rejects the pre-fix shape (negative case) 0.7ms
src/chat/judge-label-ledger.vitest.ts
the conversational judge records the label it returned (P1-01b-F01) · 3 tests
✓
a dead_end verdict is written as dead_end and capped at 0.6 — not as other at 0.95 31.0ms
✓
every label in the rubric the judge was SENT reaches the ledger, and every capped one is capped 15.1ms
✓
the ensemble branch (5% of judged turns) records and caps it too 1.8ms
the content judge records every label its rubric offers · 1 test
✓
none of the content labels is coerced to other 6.2ms
the Jev shadow judge is offered, and keeps, the same labels · 2 tests
✓
its failure_mode question offers every label the conversation rubric names 2.6ms
✓
a dead_end answer is written to the ledger as jev_failure_mode dead_end 7.8ms
every other classifier the sweep found offers exactly the labels it accepts · 3 tests
✓
reply_delivered (delivery-verdict.ts): criteria == DELIVERY_CHOICES, NOT_DELIVERED within it 0.8ms
✓
reply_triage (reply-triage.ts): criteria == REPLY_LABELS 0.3ms
✓
content_verify claims (content-verify.ts): criteria == the three verdicts its answer is checked against 0.6ms
src/chat/pending-picker.vitest.ts
the questions the platform can leave open · 4 tests
✓
every registered picker is keyed by the id its route already reports 2.0ms
✓
carries the REAL chips, not a copy that can drift 0.5ms
✓
the depth chips are the strings the intent can actually match 0.5ms
✓
states the real tiers — 50 / 150 / 500 0.3ms
the wiring — a picker is recorded, re-offered, and closed · 5 tests
✓
every picker route records that it is now open 0.5ms
✓
answering it CLOSES it, so it is not re-offered afterwards 1.9ms
✓
re-offers it on the agent path when the turn wandered off 0.5ms
✓
A GATE STILL OUTRANKS IT — a Confirm chip is never replaced 0.4ms
✓
fails open — an unreadable KV must not break the reply 0.6ms
src/chat/persona-claim.vitest.ts
does the user name an audience · 7 tests
✓
Find me 10 new business owners in the US -> named=true 2.0ms
✓
find founders -> named=true 0.4ms
✓
find 10 managers -> named=true 0.2ms
✓
find me some CEOs -> named=true 0.2ms
✓
find leads for my business -> named=false 0.2ms
✓
get me 50 contacts -> named=false 0.1ms
✓
the shipped regex tolerates plurals 0.3ms
naming a persona is a claim, not a guess · 2 tests
✓
never claims the first persona by position 0.5ms
✓
claims one only when exactly one persona matches the targeting produced 0.6ms
src/chat/render-manifest-artifact.vitest.ts
what the live producers actually set · 4 tests
✓
a saved report chip counts — report_id is the field buildCapabilityChatPayload writes 1.7ms
✓
an artifact card counts 0.3ms
✓
inline artifact html counts 0.2ms
✓
a plain prose answer does not 0.3ms
the predicate must not read better than reality · 3 tests
✓
`is_html` alone is NOT an artifact — the capabilities MENU sets it 0.2ms
✓
`artifact_id` is NOT resurrected — nothing in the repo sets it 4.8ms
✓
an empty artifact field does not count 0.2ms
rows and chips keep working — the fix must not narrow the meter elsewhere · 2 tests
✓
rows are still summed across blocks 0.3ms
✓
chips still read suggestions 0.4ms
src/chat/scan-writes-identity.vitest.ts
the ownership question keys on the WRITE, not on the message · 3 tests
✓
fires when a scan claimed a site that is not the one on file 4.4ms
✓
keeps the original first-turn condition rather than replacing it 0.3ms
✓
does NOT fire when the scan confirmed the site already on file 0.4ms
the host is captured from the RESULT, not from the arguments · 2 tests
✓
reads the scan result 0.3ms
✓
a FAILED scan claims nothing, so it must not trigger the question 0.2ms
and the write is announced · 4 tests
✓
a turn that scanned says what was saved 0.5ms
✓
it names the HOST, so a third party is visibly a third party 0.3ms
✓
and offers the correction in the same breath 0.3ms
✓
is deterministic, not a prompt instruction 0.6ms
src/db/index-tenant-reference-wiring.vitest.ts
handleAddToList (probe f1) · 2 tests
✓
cuts the body's contact ids down to the caller's own before anything is written 1.7ms
✓
refuses in a sentence when none of the ids are the caller's 0.3ms
handleUpdateLeadStatus (P1-08t-F05) · 2 tests
✓
marks unsubscribed on the admin secret, scoped to the caller 0.3ms
✓
the user-token document never writes a suppression column, and is not built at run time 0.3ms
ensureFeedbackRecordFromBody (P1-08p-F02) · 1 test
✓
a refused upsert is reported and is not success 0.3ms
ownedContactIds / ownedBy · 4 tests
✓
keeps the caller's ids in input order and drops another tenant's, duplicates and malformed ids 3.1ms
✓
asks nothing when there is nothing to ask about 0.4ms
✓
fails closed without a tenant 1.4ms
✓
ownedBy matches the owner exactly and treats a missing owner as not owned 0.7ms
src/db/tenant-table-scope-guard.vitest.ts
an unscoped admin-secret query on a tenant table cannot land · 2 tests
✓
passes on the current tree 275.4ms
✓
catches a query with no user_id, no row id, no JWT and no stated reason 543.9ms
the three escape routes, each of which must keep working · 4 tests
✓
a user_id clause in the query is enough 558.4ms
✓
a row-id-keyed read is enough — one row cannot be a cross-tenant scan 564.8ms
✓
a written // tenant-scope: reason is enough 561.2ms
✓
but an EMPTY tenant-scope marker is rejected — the reason is the whole point 547.5ms
it refuses to pass vacuously · 3 tests
✓
exits 2 when the call scan stops finding admin-secret calls 551.0ms
✓
floors the tenant-table list too — an empty list would scope nothing 0.5ms
✓
is wired into the gate 0.6ms
src/drip/start-terminal-states.vitest.ts
a start moves the paused, and nothing else · 4 tests
✓
activates the paused enrolment 25.4ms
✓
leaves every enrolment the CONTACT settled exactly as it was 0.7ms
✓
does not disturb an enrolment that is already running 0.5ms
✓
resume behaves exactly as start — same set, same refusal 0.7ms
a pause moves the running, and nothing else · 2 tests
✓
pauses only the active row 0.7ms
✓
does not drag a replied or unsubscribed row into paused 0.5ms
the census the caller needs to speak accurately · 3 tests
✓
counts live and settled AFTER the write, so a start reports what it actually did 0.5ms
✓
counts under a SIGNED-IN caller's token, not only on the admin fallback (forensic audit P0-04) 0.4ms
✓
distinguishes "nobody enrolled" from "nobody left to start" 1.5ms
src/email/failure-reason.vitest.ts
the column exists and is reachable · 2 tests
✓
the migration is additive and nullable — an old failed row has no known reason 2.1ms
✓
the apply script grants the user role write access to it 0.5ms
the reason is written, and cleared · 4 tests
✓
recordSendOutcome carries the reason and bounds it 0.4ms
✓
a successful retry clears the previous failure's reason 0.2ms
✓
both failing send paths pass it 0.5ms
✓
the REST route and the Emails-panel single send pass it too — every failing path 0.6ms
the user can read it back · 3 tests
✓
a failed-sends view leads with why, not with six empty columns 1.4ms
✓
the normal sent view is unchanged 0.5ms
✓
the row is selected from the database, not invented in the presenter 0.6ms
src/email/sender-missing-sweep.vitest.ts
the bulk transport check is stricter than the one-off check · 2 tests
✓
hasBulkSendingTransport ignores Gmail; hasSendingTransport still accepts it 2.0ms
✓
the drip still forbids Gmail, which is why the stricter check exists 0.3ms
enrolment says whether the sequence can send · 4 tests
✓
the dispatch asks before answering 0.5ms
✓
the reply leads with the blocking fact, not with "paused until you start it" 5.3ms
✓
and offers the connector, not "Start the sequence" 1.8ms
✓
a tenant that CAN send is unchanged 0.3ms
a failed scheduled send reaches the user · 3 tests
✓
the cron narrates the failure once per tenant per day 0.3ms
✓
the provider case gets the connect chip; other causes state their own reason 0.2ms
✓
the reason is passed out of the send, not only logged 0.6ms
contacts.vitest.ts
Core
9 /9
9ms · 3 suites
PASS
src/leads/contacts.vitest.ts
sanitizeEmail · 5 tests
✓
strips a leading JSON-escaped ">" fragment (live bug: u003emakena_kelly@wired.com) 3.2ms
✓
peels other encoded/markup wrappers 0.9ms
✓
leaves clean addresses untouched (idempotent) 0.5ms
✓
rejects unrecoverable / non-emails as null 0.5ms
✓
does not corrupt a local part that merely contains hex-like runs mid-string 0.3ms
autoListName · 3 tests
✓
slugs significant words from a one-shot ask 0.5ms
✓
drops stopwords and numbers, caps length at 40 0.7ms
✓
falls back to lead-search on empty/stopword-only input 0.4ms
extractListName (still wins over auto-name when a list phrase is present) · 1 test
✓
parses "…to <name> list" 1.0ms
src/leads/icp-surface.vitest.ts
the schema is the fabrication guard, one layer down · 3 tests
✓
takes NO arguments at all 2.3ms
✓
tells the model it is a proposal, not a verdict about the user’s market 1.0ms
✓
routes the question and states that it costs no provider spend 1.0ms
what the user reads · 4 tests
✓
keeps the quote beside the reading 5.8ms
✓
says nothing about sourcing when everything is matchable 0.4ms
✓
offers to fix the INPUT when the brief is too thin, not to try again 1.2ms
✓
offers the search only AFTER the profile has been shown 0.4ms
the profile is rendered, never re-written by the model · 2 tests
✓
marks its result render_verbatim so the agent loop does not paraphrase it 1.8ms
✓
the loop honours the flag with a general check, not a tool-name list 5.4ms
research.vitest.ts
Core
9 /9
35ms · 3 suites
PASS
src/leads/research.vitest.ts
extractSocials — homepage-published profiles only · 3 tests
✓
picks company/profile links, ignores share + intent widgets 2.7ms
✓
does NOT invent links when the homepage has none 0.5ms
✓
excludes non-profile twitter routes (home/search/hashtag) 0.3ms
timezoneHintFromDomain — known ccTLDs only · 4 tests
✓
maps known country TLDs 0.5ms
✓
returns null for generic TLDs (never guess a location) 0.3ms
✓
treats ambiguous .co as unknown (Colombia vs startup TLD) 0.2ms
✓
handles null domain 0.2ms
researchContact — grounded-only homepage fields · 2 tests
✓
a model-returned homepageSummary with no homepage fetched comes out '' 26.0ms
✓
(control) with homepage text in the prompt, the same summary is kept — the fetch is what decides 4.1ms
src/planner/plan-score.vitest.ts
rankPositionToScore100 · 3 tests
✓
position 1 is a perfect score 1.8ms
✓
position 20 (the striking-distance floor) is zero 0.3ms
✓
clamps beyond the 1-20 window instead of going negative or over 100 0.2ms
computeMarketingPlanScore (Finding 1 — honest composite, no fabricated legs) · 6 tests
✓
averages onpage_score and aeo_score directly, rank via normalization 0.3ms
✓
drops unmeasurable (none) legs and campaign_replies — never scores them as 0 0.2ms
✓
is null (an honest "—", not 0) when nothing is scorable 0.3ms
✓
current uses observed_value when present, falls back to baseline otherwise; delta only when both are known 0.5ms
✓
counts a shared measurement key ONCE, not once per initiative referencing it 0.2ms
✓
two DIFFERENT keys on the same adapter are two distinct votes, not deduped together 0.5ms
src/reports/lead-search-honesty.vitest.ts
a provider claim is never rendered as a verification · 3 tests
✓
the artifact counts only rows we checked 2.0ms
✓
the chat summary counts only rows we checked 0.4ms
✓
an unchecked batch is told to verify, and told why 0.3ms
found is not saved · 1 test
✓
the artifact reports what actually landed, and accounts for the gap 0.3ms
verify emails from the artifact · 3 tests
✓
offers the verify action on the verified-rate card 0.3ms
✓
scopes the request to THIS batch's list 0.2ms
✓
routes through chat, so the spend still meets a gate 0.6ms
user text inside a button command · 2 tests
✓
no inline event handler is built in this file — the command is data, never script 2.0ms
✓
every command interpolated from data is attribute-escaped 1.6ms
src/routes/cannibalisation-guard.vitest.ts
check-cannibalisation-thresholds · 9 tests
✓
passes on the real tree 39.0ms
✓
fails when the near-duplicate threshold moves in the report only 35.4ms
✓
fails when the cannibalisation threshold moves in the crawler only 39.0ms
✓
fails when the two-token minimum is dropped from the report 35.9ms
✓
fails when the browser tokeniser loses its escaping 35.4ms
✓
fails when the pair findings stop being wired into the report 40.6ms
✓
fails when the markdown rendition would state a threshold the crawler does not use 37.0ms
✓
fails when the markdown rendition retypes a threshold instead of interpolating it 38.8ms
✓
exits 2 — blind, not passing — when the crawler source is missing 34.8ms
src/routes/footer-badges.vitest.ts
bklink shield badge in both footers · 5 tests
✓
the shared light footer carries the shield, linked and sized 1.8ms
✓
puts the light footer in two rows, badge on the bottom one 0.4ms
✓
the homepage footer carries the same shield 24.9ms
✓
keeps the homepage footer to a single row 1.3ms
✓
serves the forensic stamp in /about’s Trust section 1.2ms
CSP covers what the badges actually load · 1 test
✓
allows the badge script and both badge images 1.2ms
shown.io is gone · 3 tests
✓
no longer loads on the homepage or /about 2.0ms
✓
is not left behind in the CSP allowlist 0.3ms
✓
is not named as a vendor on the privacy page it no longer applies to 1.0ms
src/routes/shared-leads.vitest.ts
shared-leads route boundary · 9 tests
✓
requires the authenticated user input before it calls a service 29.4ms
✓
rejects malformed or unknown JSON fields strictly 2.1ms
✓
propagates vector degradation as a curated search response without raw source data 4.1ms
✓
turns source-rights denial into a 403, and unavailable retrieval into a 503 2.0ms
✓
writes a selection with the caller uid as a GraphQL variable, never interpolated 1.2ms
✓
scopes list ownership and the list-item mutation to the caller uid 1.2ms
✓
returns 404 when the requested list is not owned by the tenant 0.8ms
✓
queues identifier actions with tenant context and returns no private identifier payload 2.0ms
✓
requires the injected admin callback and rejects source-rights-prohibited ingestion 1.9ms
src/runtime/job-deferred-tenant.vitest.ts
R5b-G4a-F01 — a queued job keeps its tenant for the work it leaves running · 2 tests
✓
one 'jobs' message: the deferred spend row, written after the job returned, is the job's tenant's 79.3ms
✓
a 'jobs' batch A then B: A's deferred row is A's, and B's rows are B's 23.9ms
settleTenantWindow — the window dies with the tenant scope, and only there · 3 tests
✓
inside a tenant scope: observations handed off once, identity kept for the deferred write 2.5ms
✓
outside a tenant scope (a turn's shared request scope) it flushes, exactly as before 0.8ms
✓
a tenant scope opened outside any request scope is a tenant scope too 0.8ms
§wiring — the background units settle their window instead of flushing it · 4 tests
✓
index.ts async function runAsyncJobInline: settles, never flushes 3.8ms
✓
index.ts async queueInner: settles, never flushes 3.2ms
✓
seo/rank-cron.ts export async function runRankScanTenant: settles, never flushes 0.5ms
✓
seo/onpage-sweep.ts export async function sweepAbandonedOnpageCrawls: settles, never flushes 1.1ms
src/runtime/unbounded-awaits-sweep.vitest.ts
the choke points end inside a limit · 3 tests
✓
reportError with no ctx awaits its send — a collector that never answers no longer holds the caller 53.3ms
✓
googleFetch (ten Google reads go through it) ends inside its limit, and a caller's own signal still wins 192.7ms
✓
a caller signal that never fires does not lift the default: googleFetch still ends inside its limit 151.2ms
the swept files: every fetch carries a signal · 6 tests
✓
no fetch in a swept file is without one 16.9ms
✓
the residue is empty: G5(b) threshold 0 0.5ms
✓
every call that takes no signal has its wait wrapped 11.5ms
✓
every Durable Object call in src carries a bound — the class, not a file list (V12b-cron-data-F02) 139.8ms
✓
the DO-bound scan sees a stub from a helper and an id split from its get (V-lows-F05 mutants) 1.4ms
✓
no helper lets a caller signal REPLACE the default limit (combine, never ??) 56.2ms
src/runtime/version-guard-skips.vitest.ts
check-tag-provenance — every skip states its reason and never reads as OK · 4 tests
✓
skips loudly outside a git repository 58.8ms
✓
skips loudly when there is no origin/main to compare against 261.0ms
✓
ZERO TAGS IS A SKIP, NEVER A PASS — the CI checkout shape 264.0ms
✓
exits 2 when the version walk is too small to trust — stale parser, not bad tags 275.8ms
check-version-forward — the same rule, and a guard that is stricter in CI · 3 tests
✓
skips loudly on a shallow checkout with no HEAD~1 259.4ms
✓
NO exit(0) in the script is silent — every one of them says something first 1.2ms
✓
is stricter in CI than locally, deliberately — and that asymmetry is pinned 0.2ms
the containment this file needed to learn the hard way · 1 test
✓
a fixture git command ignores an inherited GIT_DIR 210.4ms
both are wired into something that runs them · 1 test
✓
appear in package.json 0.8ms
src/tools/free-plan-cap.vitest.ts
the requested count survives validation · 4 tests
✓
carries the number the user asked for 2.4ms
✓
defaults to 25 when the user named no number 0.3ms
✓
migrates a legacy `limit` rather than dropping it 0.4ms
✓
clamps an over-large ask to the fetch ceiling 0.4ms
the free plan caps DELIVERY, on the number the user actually asked for · 5 tests
✓
caps a free user at 10 however many they requested 0.5ms
✓
does not inflate a free user who asked for fewer than the cap 0.2ms
✓
gives a paid user the number they asked for 0.3ms
✓
the cap is visible: a free user asking for 50 is demonstrably narrowed 0.3ms
✓
the fetch floor is identical on both plans — the cap costs nothing to lift 0.4ms
src/tools/geo-schema.vitest.ts
both tools are on the schema contract · 3 tests
✓
seo_geo_research is schematised and dispatch-enforced 2.3ms
✓
seo_geo_research declares topic — the field this epic exists to add 0.2ms
✓
seo_geo_research rejects an off-schema field instead of ignoring it 0.9ms
the deleted alias chains can no longer fire · 2 tests
✓
seo_geo_research rejects the old keyword/query spellings 0.3ms
✓
requires the field the dispatch actually needs 0.3ms
rag_readiness is RETIRED — the requirement moved, it did not vanish · 2 tests
✓
is gone from every advertising surface, so it cannot creep back one at a time 0.5ms
✓
aeo_page_check still declares topic — THE requirement this epic existed for 0.3ms
model-facing copy · 2 tests
✓
separates topic research from brand measurement 0.2ms
✓
names no vendor and no USD price 0.9ms
src/ui/degraded-banner.vitest.ts
the signal travels on a channel that survives the outage · 2 tests
✓
rides /api/version — public, unauthenticated, and NO database 2.5ms
✓
the endpoint READS cached health, it does not probe per request 0.8ms
absent means healthy — a bug here must not invent an outage · 2 tests
✓
the server omits the field entirely unless degraded past the threshold 0.5ms
✓
a failed poll does not raise the bar 0.3ms
the bar itself · 4 tests
✓
says NOTHING IS LOST — the sentence that actually matters 0.5ms
✓
offers no button, because there is nothing the user can do 0.4ms
✓
clears itself when the dependency recovers 0.4ms
✓
is amber and wraps — impaired, not broken, and readable on a phone 0.6ms
the deploy banner no longer kills the poll · 1 test
✓
stopPolling is gone from showBanner 6.3ms
src/seo/aeo-sample.vitest.ts
counting the run the way the estimator prices it · 4 tests
✓
is silent before the picker resolves engines and prompts 1.8ms
✓
multiplies engines by prompts 0.8ms
✓
counts two models of one engine as two calls, because they are two calls 0.3ms
✓
drops exact duplicates and blanks rather than inflating the sample 0.2ms
what it says, and what it refuses to say · 5 tests
✓
says nothing about a run big enough to read 0.3ms
✓
warns about the TREND, never that the check is wrong 0.5ms
✓
pluralises, because "1 answers" reads as a bug and undermines the sentence 0.2ms
✓
fires right up to the threshold and stops exactly at it 0.3ms
✓
stays silent on a null sample rather than inventing a zero 0.5ms
src/seo/brand-answer-position.vitest.ts
brandAnswerPosition · 9 tests
✓
ranks by first mention, not by mention count 1.9ms
✓
reports #1 when we are named before every rival 0.4ms
✓
returns null when no rival was named — never a flattering #1 0.2ms
✓
returns null when we are absent — never a default last place 0.2ms
✓
returns null on an empty answer rather than 0 0.2ms
✓
matches a rival by bare name when the answer never writes the domain 0.2ms
✓
falls back to the domain when the brand name itself is absent 0.2ms
✓
is word-bounded, so a rival inside a longer word does not count 0.3ms
✓
is repeatable — the shared regexes carry no lastIndex between calls 0.6ms
src/seo/brief-kit-decision.vitest.ts
decisionFor — zero survivors · 4 tests
✓
MIXED: leads with what was ruled out, and does not say STOP 2.3ms
✓
NOTHING TESTABLE: still stops, and still says why 0.5ms
✓
ALL RULED OUT: stops, and points outside the frame rather than at a next pull 0.2ms
✓
the ruled-out count is DERIVED, never a fourth number to keep in step 0.4ms
decisionFor — the survivor paths are untouched · 2 tests
✓
one survivor still names the act-first instruction 0.2ms
✓
onNone still receives the honest sentence for policy briefs 0.3ms
decisionFor — the mixed line agrees with its own counts · 3 tests
✓
uses singular agreement for exactly one ruled-out cause 0.4ms
✓
uses plural agreement for more than one 0.3ms
✓
writes "the other one" rather than "the other 1" 0.5ms
src/seo/brief-word-count.vitest.ts
the content brief is told the article length · 5 tests
✓
seo_write_content forwards word_count when it auto-generates the brief 2.1ms
✓
the brief prompt renders the supplied number instead of asking the model to pick 0.4ms
✓
falls back to the model choosing when no word_count was supplied 0.4ms
✓
clamps to the same 400-3000 range the writer uses, so the two cannot disagree 0.5ms
✓
word_count is DECLARED on seo_content_brief, or the model can never pass it 0.4ms
the length target is stated as a requirement, not just a slot · 4 tests
✓
emits a LENGTH REQUIREMENT line naming the number when one was supplied 0.3ms
✓
forbids substituting an estimate, in as many words 0.3ms
✓
emits NOTHING when no target was supplied 0.4ms
✓
places the rule BEFORE the output template, not inside it 0.6ms
src/seo/deep-scan-scan-only.vitest.ts
the scan stored links and the valuation could not read them · 4 tests
✓
the dispatch says the valuation failed — never "connect Analytics", never "scan first" 27.0ms
✓
the reply states what the scan stored and why there is no valuation, and never asks for the scan again 5.3ms
✓
the chip values what is on file — and that chip text routes to the valuation, not to a scan 19.1ms
✓
a paid scan left unvalued is reported, not only told to the user 0.9ms
the valuation threw · 1 test
✓
reads as a failed valuation with the stored counts, and the cause reaches the report 0.7ms
the scan found nothing · 1 test
✓
says so once, offers no re-scan, and files no issue — nothing failed 0.7ms
a repeat scan that found nothing new · 1 test
✓
says nothing new turned up and what is on file 0.3ms
the audit corpus shape (P1-01a repro, canned at the dispatcher seam) · 1 test
✓
renders the scan, not "No backlinks on file" 0.3ms
the valued scan is unchanged — it is a value report with scan facts riding along · 1 test
✓
renders the two-lens report and offers the value chips plus the connect chip 2.5ms
src/seo/entity-plumbing.vitest.ts
a clean entity reading is an ANSWER · 2 tests
✓
rules out every testable cause when the brand resolves and is anchored 2.5ms
✓
does not report a clean reading as untestable 0.9ms
the findings it exists to produce · 4 tests
✓
names an unresolved brand — the engines have nothing to cite 0.4ms
✓
names a missing structured anchor — resolved to Google, invisible to the rest 0.3ms
✓
names a namesake collision, and puts it FIRST — content cannot fix the graph 0.3ms
✓
compares rivals only when a rival set was actually read 0.3ms
what it refuses to claim · 3 tests
✓
never marks sameAs as checked — nothing reads the schema or the profiles 0.8ms
✓
says NEVER LOOKED, not "nothing found", when no entity audit exists 0.4ms
✓
carries a headline and a complete one-pager 0.6ms
src/seo/full-audit-synthesis.vitest.ts
full_seo_audit runs no provider calls (spec FR-001) · 6 tests
✓
never dispatches the two sub-audits it used to nest 2.0ms
✓
reads the six sources the spec names, not two 0.5ms
✓
takes no balance gate — nothing is spent, so nothing is reserved 0.2ms
✓
degrades to guidance rather than an error when nothing has been measured (FR-051) 0.4ms
✓
demotes findings from a stale source instead of dropping them (FR-003) 0.3ms
✓
names each absent source as a CONSEQUENCE, never as a table name 0.4ms
the crawl summary is captured, not discarded (spec FR-030) · 3 tests
✓
parses site-level checks from the poll we already pay for 0.3ms
✓
only reads them from the FINISHED poll — a partial crawl has partial metrics 0.2ms
✓
a missing probe stays null, never false — an unknown must not read as a failure 0.5ms
src/seo/gsc-page-moves.vitest.ts
comparePagePeriods · 3 tests
✓
joins by page, absent-in-one-window counts as zero there, losers ranked by the fall 2.5ms
✓
site-wide direction as a rounded percentage 0.4ms
✓
a first window with no clicks has no percentage, not a fake 0 0.3ms
thin windows claim no direction (live 2026-09-15: 9 → 7 clicks read as -22%) · 1 test
✓
is marked thin, yields no evidence point, and the note states the numbers without a percentage 0.6ms
gscPointFromMoves · 1 test
✓
is a Google-traffic point whose delta is a percent, tagged as such 1.0ms
pageMovesNote · 2 tests
✓
names the move, the windows and the pages that carried it, as paths 0.3ms
✓
says so when nothing fell 0.3ms
wiring · 2 tests
✓
the diagnose dispatch gathers the moves for a search/movement question and hands them to the brief 2.0ms
✓
the presenter and the card both render the losers table 3.2ms
src/seo/onpage-directives.vitest.ts
classifyOnPageIssue · 6 tests
✓
calls broken-by-construction issues Corrective — no traffic data needed 2.1ms
✓
does NOT promote a numerous hygiene issue to Corrective — FR-031 0.5ms
✓
escalates a canonical oddity ONLY when Search Console confirms pages are missing 0.2ms
✓
files structural signals as Advisory 0.3ms
✓
never returns anything outside the vocabulary, including for unknown codes 1.0ms
✓
an unknown code degrades to Suggestive, never to Corrective 0.2ms
stakeGap — the report says what it cannot rank by · 2 tests
✓
raises the gap while no per-page performance is connected 0.3ms
✓
goes silent once the data exists — a resolved gap is not a finding 0.2ms
ONPAGE_EMPTY_COPY · 1 test
✓
gives every directive a real sentence — an empty group must state its absence (FR-030) 0.7ms
src/seo/prompt-library-exits.vitest.ts
the engine picker shows and offers only what the guardrail would ship · 3 tests
✓
a model prompt naming a supplier or claiming "free" is withheld; a buyer's budget and the tenant's own records are not 128.1ms
✓
a library of nothing the guardrail would ship is no picker: one sentence and the way to rebuild it 33.3ms
✓
control: a clean library is offered whole and nothing is counted 13.3ms
the Keywords & AI Prompts view lists only what it may show · 1 test
✓
library rows are withheld exactly as in the picker; the tenant's Search Console rows are listed as they are 4.8ms
a model's prompts handed to a run are withheld before the quote unless the person typed them · 3 tests
✓
the vendor-naming prompt is never priced, staged or run; the clean one and the buyer's budget are; the reply says so once 51.6ms
✓
a prompt the person typed is theirs (#621): priced and staged as typed, nothing withheld 22.1ms
✓
a call left with nothing to measure is refused: nothing priced or run, the model reads why, the reply says so 29.4ms
a plan item's prompts are narrowed the same way before it is priced · 2 tests
✓
the vendor-naming prompt leaves the staged call, and the reply says so 11.6ms
✓
a plan item with nothing left to measure does not run: marked blocked, one sentence, a way on 7.9ms
src/seo/rank-scan-optin.vitest.ts
who the Sunday fan-out scans · 4 tests
✓
a tenant with tracked keywords but no opt-in is not due; one who opted in is 5.1ms
✓
the pre-ruling ask is honoured by a frozen read: seo_rank_track rows before the cutover, or a confirmed resume 8.1ms
✓
a failed opt-in read scans nobody and the run says so (fails closed) 3.5ms
✓
a message for a tenant who is not opted in is dropped at delivery: no balance check, no SERP call 3.5ms
every way of switching it on makes the tenant due · 3 tests
✓
seo_rank_track: tracking keywords research already saved quotes a card, and only the confirm chip opts in 444.0ms
✓
keyword research saves its keywords, enrols no one, and offers the switch as a chip priced in tokens 159.4ms
✓
the scan list shows a research-only tenant as off (not running) with a turn-on chip that reaches the same gate 2.0ms
stopping withdraws it · 2 tests
✓
stop_scheduled_scan clears the opt-in, for an opted-in tenant and for a pre-ruling one 249.1ms
✓
a never-opted-in tenant who says stop is told it was already off, and nothing changes 119.7ms
src/seo/rank-snapshot-attribution.vitest.ts
rank_snapshots is scoped by property · 3 tests
✓
every read of rank_snapshots filters on site 2.3ms
✓
the writer stamps the property it measured against 0.3ms
✓
the writer records NULL, never an empty string, when no site is resolved 0.2ms
no retroactive attribution · 3 tests
✓
the migration adds the column WITHOUT backfilling it 0.5ms
✓
the column is nullable, so unattributed history stays visibly unattributed 0.2ms
✓
no reader treats a NULL site as matching the current property 0.4ms
one site resolver, not five · 3 tests
✓
tenantSiteHost is exported from settings and is the shared predicate 0.4ms
✓
returns empty string for an unset site — callers must decline, not widen 0.2ms
✓
tool-dispatch no longer keeps its own private copy 3.9ms
src/seo/redirect-fix-add-only.vitest.ts
cloudflare_publish_dns_aid · 3 tests
✓
leaves a tenant's own record at a DNS-AID name exactly as it is, and says so 33.1ms
✓
a record nqzai already published is reported as present and not rewritten 2.6ms
✓
reads every name before writing any, so a failed read publishes nothing 1.3ms
cloudflare_fix_redirect · 4 tests
✓
a failed read of the existing rules changes nothing — it used to replace them all 1.1ms
✓
appends one rule through the add-a-rule endpoint; the zone's own rules are not rewritten 1.2ms
✓
a zone with no redirect rules gets its entry point CREATED, which cannot replace anything 1.3ms
✓
a rule already matching the host is left alone, and the reply says what is there 1.0ms
vercel_fix_redirect · 2 tests
✓
a host that already redirects somewhere else keeps its target 1.0ms
✓
a host with no redirect gets one 1.3ms
src/seo/rivals-note.vitest.ts
the note only speaks when the scan has run · 2 tests
✓
is omitted when nothing has been scanned 1.6ms
✓
and it dates the measurement 0.3ms
when someone DOES outrank us, it names them · 2 tests
✓
lists the domains and how many keywords each takes 0.3ms
✓
and forbids calling the picture unknown 0.3ms
when NOBODY outranks us, it forbids the sentence that was actually wrong · 5 tests
✓
states the measured negative rather than staying silent 0.2ms
✓
forbids claiming a competitor took positions 0.2ms
✓
forbids offering to BUY the answer it already has 0.3ms
✓
and says where the evidence actually points 0.2ms
✓
reports the unknown-position pairs rather than hiding them 0.5ms
src/seo/serp-latency.vitest.ts
the SERP client waits for a slow provider · 2 tests
✓
a search answered at 16 s succeeds through the real path 35.8ms
✓
a search answered at 29 s still succeeds; the default wait is at least 30 s 14.0ms
the wait fits the caller · 3 tests
✓
a caller deadline cuts the wait: it ends 3 s before the deadline, and the call is a recorded timeout 3.2ms
✓
with less than 15 s left, nothing is sent and nothing is recorded 2.3ms
✓
a cron may wait 45 s 1.6ms
searches in flight are capped below the shared key limit · 2 tests
✓
a burst of 10 never has more than 4 in flight, and every one completes 6.1ms
✓
a queued search that cannot start in time is not sent, and gives its place back 3.0ms
a search that times out reads the same to the user, and names no vendor · 2 tests
✓
web search says it timed out 2.0ms
✓
the SEO tools say the data source took too long, with no vendor in it 2.6ms
scripts/lib/fixlog-conflict.vitest.mjs
resolveFixlogInRebase — the step merge-pr.mjs runs · 6 tests
✓
two sessions appending: both entries kept, main first, and the rebase completes 316.1ms
✓
same-day entries: the folded `date:` line is restored to BOTH 248.7ms
✓
an EDIT conflict in one entry is refused, not turned into that entry twice 264.3ms
✓
entries that END alike are refused, not resolved with ours missing its tail 248.8ms
✓
a diff3-style conflict is refused rather than pasting the base into ours 207.4ms
✓
returns false and writes nothing when the fixlog is not the conflicted file 8.3ms
merge-pr.mjs is wired to it · 2 tests
✓
treats the fixlog as auto-resolvable and runs the checked step, not the bare resolver 0.4ms
✓
declares AUTO_RESOLVED before the top-level call that uses it (the WORKFLOW trap) 0.3ms
src/admin/gsc-coverage.vitest.ts
gsc-coverage · 5 tests
✓
classifies indexed vs not-indexed from verdict/coverageState 2.1ms
✓
aggregates counts and groups not-indexed by reason, most first 1.2ms
✓
builds a fix prompt with a hint per reason 0.5ms
✓
all-indexed → no-fixes prompt 0.3ms
✓
unknown reason falls back to a generic hint 0.2ms
resolveSitemapTotal · 3 tests
✓
prefers total_urls_known (the real sitemap+seed union) over the smaller pre-merge seed length 0.2ms
✓
falls back to seed length only when total_urls_known is genuinely absent (degenerate empty case) 0.3ms
✓
does not silently regress if total_urls_known is ever smaller than the seed (still trusts the real union) 0.2ms
src/admin/gsc-scan-free.vitest.ts
probeIndexedFree — no paid path exists · 4 tests
✓
returns a real verdict when Google answers 2.2ms
✓
reports unresolved — NOT not_indexed — when Google gives no usable verdict 0.4ms
✓
reports quota_blocked without spending, when the daily budget is gone 0.6ms
✓
reports quota_blocked rather than falling back when there is no Google connection at all 0.4ms
GSC-only scan — pauses on quota, never skips unprobed URLs, never pays · 4 tests
✓
completes a full free scan without ever calling the paid provider 28.1ms
✓
pauses when quota runs out mid-scan and parks the cursor at the unprobed URL 1.5ms
✓
resumes a paused scan from its cursor instead of restarting and re-spending a day of quota 4.6ms
✓
leaves the paid free-first path untouched when gsc_only is not requested 113.1ms
indexer.vitest.ts
Core
8 /8
35ms · 3 suites
PASS
src/admin/indexer.vitest.ts
cleanSubmitUrls · 2 tests
✓
drops non-http, trims, and de-dupes (case/trailing-slash insensitive) 2.5ms
provider selection · 2 tests
✓
defaults to omega and falls back on an unknown provider 0.4ms
✓
reports configured only when the key is present 0.4ms
submitUrlsForIndexing · 4 tests
✓
returns not-configured cleanly (no fetch) when the key is missing 1.3ms
✓
rejects an empty/invalid batch before calling the provider 0.4ms
✓
posts pipe-delimited urls + clamped dripfeed and reports success on "done" 27.1ms
✓
surfaces the provider error verbatim on rejection 0.8ms
src/admin/judge-model-authored-alert.vitest.ts
the model-authored judge alert · 6 tests
✓
exists in the daily digest rather than as a new cron 1.7ms
✓
derives its population from PRESENTED_TOOLS, never a hand-kept list 0.5ms
✓
fires below 0.5 and not at or above it 0.2ms
✓
routes to Sentry LOGS, not Issues — it is a counter, not a fault 0.4ms
✓
carries the fields needed to act, not just a count 0.4ms
✓
splits a tool:leg operation so a leg row is attributed to its tool 0.2ms
the population it actually covers today · 2 tests
✓
seo_backlinks has LEFT the alert, because it now has a presenter 0.8ms
✓
still covers the tools that remain model-authored 0.4ms
src/admin/rca-judge-source.vitest.ts
RCA evidence source (h) — low judge scores · 5 tests
✓
is collected, tenant-tagged and capped like every other observation list 2.2ms
✓
carries the fields needed to cross-reference and to discount internal traffic 1.0ms
✓
selects on the documented ceiling rather than a bare literal 0.2ms
✓
is named in the prompt, with the count of sources updated to match 0.4ms
✓
tells the analyst to treat it as a lead and cross-reference it, not to believe it 0.5ms
judge verdicts can be traced to the turn they judged · 3 tests
✓
captures the turn id synchronously, before the judge detaches 0.5ms
✓
passes it at BOTH judge write sites — single and ensemble — with the session beside it 0.6ms
✓
raises the reasoning cap off the 200-char literal that cut verdicts mid-word 0.6ms
src/admin/readiness-register.vitest.ts
overlaySeed · 3 tests
✓
a register figure replaces the seed figure and the recon value moves into context, labelled 2.7ms
✓
a sub the register does not speak for is untouched; an id the catalogue does not know is ignored 0.5ms
✓
context without a measure keeps the recon measure 0.5ms
the page with a published register · 5 tests
✓
a fresh P_code figure that misses its bound FAILS on facts 39.9ms
✓
a production figure on an unratified map stays unmeasurable, and keeps its value for display 3.2ms
✓
a publish older than the 7-day register window stops counting 2.8ms
✓
lists the register's findings; a proposed severity is never read as rated 5.5ms
✓
carries the audit progress, population summary and dimensions, and says the register is fresh 2.9ms
src/admin/telemetry-tables-exact-overlay.vitest.ts
computeModelAndProviderTables — exact overlay end to end · 3 tests
✓
replaces a sample-derived (approximate) total with the exact grouped total 3.4ms
✓
without exactApiGroups, behaves exactly as before (existing callers/tests unaffected) 0.4ms
✓
still excludes provider="quality" — the exact fetch filters it at the query level too 0.3ms
overlayExactApiUsage · 5 tests
✓
keeps actor and recent_runs from the sample — an aggregate cannot supply either 0.9ms
✓
recomputes the provider-level total as the SUM of its (now-exact) actor rows, not the old sample sum 0.2ms
✓
adds a synthetic entry for an exact group entirely absent from the sample, with actor null and no recent runs 0.4ms
✓
leaves a sample-derived group untouched if no exact data was fetched for it 0.3ms
✓
keeps providers sorted by cost descending after the overlay changes the ranking 0.2ms
src/admin/tenant-economics.vitest.ts
foldTenantEconomics · 8 tests
✓
sums model and provider cost separately and together 2.0ms
✓
prices revenue from what was BOUGHT, not from usage — a trial is cost with zero revenue 0.3ms
✓
reads top-ups as a magnitude — they are stored as a negative credit 0.3ms
✓
leaves coverage null when cost is zero — that is not infinite margin 0.2ms
✓
buckets rows with no user_id as unattributed rather than dropping them 1.0ms
✓
sorts most expensive first — the page answers "who is costing us money" 0.7ms
✓
computes coverage as revenue over cost 0.3ms
✓
coerces string numerics from Hasura instead of concatenating them 0.3ms
src/billing/free-tier-caps.vitest.ts
free-tier cap constants · 3 tests
✓
every cap is a positive integer — a 0 cap would be a wall, not a taste 2.0ms
✓
the AEO free tier still runs a real engine, not an empty set 0.9ms
✓
backlink prospects are capped BELOW the hard 12-domain ceiling, or the cap does nothing 0.3ms
paid tools carry a cost estimate (the gate feeds off it) · 1 test
✓
share_of_model and backlink_outreach_search are priced, so the gate can quote them 0.2ms
cap provenance — the plan table is the whole free-tier policy · 4 tests
✓
declares BOTH of seo_serp_spider's billed dimensions, not just the crawl 0.2ms
✓
lets the paid tier through to the full exact-verify pass 0.1ms
✓
never inflates a request that is already under the cap 0.2ms
✓
keeps every copy-only cap constant equal to the entitlement it quotes to the user 0.3ms
src/billing/plan-budget.vitest.ts
checkAgainstApprovedPlan · 6 tests
✓
allows an approved tool inside budget 2.2ms
✓
halts a tool the user never approved — the "model wants a 4th tool" case 0.5ms
✓
halts when an approved tool would breach the approved total 0.2ms
✓
never tells the user to approve again — a halt must not read like a second gate 0.5ms
✓
fails OPEN with no plan — ordinary single-tool turns must not be blocked 0.2ms
✓
allows spend exactly AT the approved ceiling 0.2ms
planBudgetEnforced gate · 2 tests
✓
defaults to observe-only — a misfiring rule must not block real work 0.4ms
✓
enforces only on an explicit on value 0.3ms
src/billing/plan-runtime.vitest.ts
plan-runtime records without changing the answer · 4 tests
✓
returns exactly what the pure resolver returns 2.9ms
✓
records a trim, and stays silent when nothing was trimmed 0.4ms
✓
does not record a same-count substitution — there is no shortfall to offer 0.3ms
✓
records a multi-engine request narrowed to one 0.5ms
takeCapEvents isolates runs · 1 test
✓
clears, so a second run in the same turn starts clean 1.0ms
cron trims are recorded but attributed to the cron · 1 test
✓
namespaces the cron so it can never be mistaken for a tool 0.3ms
ledger encoding · 1 test
✓
round-trips into a compact marker the admin panel can parse 0.2ms
defaultDepthFor resolves the plan ceiling for a number nobody asked for · 1 test
✓
returns the plan depth and records NO cap event 0.7ms
src/billing/stripe-dispute.vitest.ts
charge.dispute.created · 4 tests
✓
reverses the disputed share as a POSITIVE row, pages a human, and tells the tenant 35.2ms
✓
reverses proportionally on a partial dispute 3.7ms
✓
does NOT double-debit when a refund already reversed the same charge 6.7ms
✓
ignores a sibling product's dispute without touching the ledger or paging 1.1ms
charge.dispute.closed · 3 tests
✓
restores the disputed share as a NEGATIVE row when won, keyed by dispute id, and tells the tenant 15.3ms
✓
writes nothing on a redelivered win 1.2ms
✓
changes nothing when lost — the reversal already happened at open 0.4ms
the refund path tells the tenant too · 1 test
✓
sends the balance-reversed notice after a refund reversal 2.0ms
src/campaigns/backlink-lookup-error-per-call.vitest.ts
backlink_outreach_search: a lookup failure is reported to the request that had it · 3 tests
✓
controls: alone, a provider block reads as a failure and an empty harvest as zero prospects 65.0ms
✓
a harvest that starts during the failing call's error report does not erase that failure 6.7ms
✓
an empty, successful harvest does not read a failure that belongs to another request 15.7ms
apifyDomainContacts: the failure travels with the result · 3 tests
✓
a provider block returns ok:false with the reason and no contacts 3.2ms
✓
a missing key is a failure, not an empty success 1.5ms
✓
an empty harvest is ok:true with zero contacts, and carries no error 1.3ms
no module-level binding holds one call's result · 2 tests
✓
every module-level let/var in src/ is a classified isolate cache or boot hook 148.6ms
✓
no module exports a zero-argument "last error / last result" accessor 74.6ms
src/campaigns/contact-page-scope.vitest.ts
list_contacts answers describe themselves · 5 tests
✓
every exit goes through the page wrapper 2.7ms
✓
states the denominator in prose on EVERY answer, not only when truncated 0.7ms
✓
puts the facts BEFORE the rows they describe 0.5ms
✓
marks an unscoped result as unscoped — for BOTH audiences, separately 0.8ms
✓
carries the verification arithmetic rather than leaving it to be inferred 0.2ms
the schema tells the model what the payload means · 3 tests
✓
requires the list filter when the user names a list 0.2ms
✓
says this is a page and that shown is not total 0.3ms
✓
points at the computed verification block instead of the raw column 0.2ms
src/campaigns/draft-count.vitest.ts
the schema can say how many · 4 tests
✓
accepts a limit at all — this is the whole defect 1.7ms
✓
bounds it to the batch ceiling, so limit can never promise more than the tool delivers 0.3ms
✓
tells the model to pass it when the user names a number 0.4ms
✓
still refuses unknown properties, so a stray arg cannot ride along 0.2ms
the answer says WHICH ceiling applied · 4 tests
✓
restates the user's number when they capped it 4.8ms
✓
reports OUR ceiling when the user set none — this case said nothing at all before 0.3ms
✓
stays quiet when the ask was fully satisfied 0.4ms
✓
does not call the user's own remainder a deferral 0.3ms
src/campaigns/sequence-audience.vitest.ts
P4-06-F02: an ask that names the sequence goes to create_sequence, not the enrol picker · 2 tests
✓
the live probe wording (unquoted name, "day 3") is fully specified 2.6ms
✓
a bare ask, or "named after"/"for my list", still takes the picker flow 0.9ms
P4-06-F02: the audience is chosen explicitly, never defaulted · 3 tests
✓
the list picker leads with the zero-enrolment answer and offers no "all" option 1.5ms
✓
the pre-spend card states the token quote and the real count, and asks 1.2ms
✓
the enrol chip round-trips with its count, and the other chips parse to no enrolment 1.5ms
P4-06-F02: the wiring — nothing is generated or enrolled before the audience is chosen · 3 tests
✓
the writing-style answer spends nothing and enrols nobody 0.6ms
✓
enrolment happens only on the enrol chip and never exceeds its count 0.5ms
✓
the list picker is built from sequenceListPickerOptions 0.3ms
src/chat/answer-options-exits.vitest.ts
agent loop: the options in the model's prose · 5 tests
✓
the probe: the bullet the guardrail rewrote is no chip; the untouched bullets are 160.3ms
✓
a price and a "free" claim rewritten in place are no chips either 36.3ms
✓
the response contract's bold options: neither channel offers the rewritten one 33.1ms
✓
control: a list nothing rewrote is offered whole, and nothing is counted 14.4ms
✓
control: a reply the guardrail blocked offers no options at all 45.7ms
shortcut: the onboarding scan lists the searches a model suggested · 1 test
✓
the rewritten search is no chip; the others are 48.4ms
the wiring · 2 tests
✓
the exit scan records every message line it rewrites, before the rewrite replaces the original 0.7ms
✓
finishChatReply picks the options from the reply as finally rewritten, then the chip guard reads them 1.1ms
src/chat/chip-price-honesty.vitest.ts
every route chip states the ceiling when there is one · 3 tests
✓
NO chip advertises a number below what the gate will demand 1.9ms
✓
the two that measured wrong now carry both ends 0.5ms
✓
a tool with no ceiling above its typical still shows ONE number 0.2ms
costRange is ONE rule with two renderings · 4 tests
✓
compact is for chips, full prose is for the card 0.4ms
✓
collapses when there is no range, in both renderings 0.2ms
✓
a maxTokens BELOW tokens is not a range 0.1ms
✓
the gate message reads it too, so the two surfaces cannot drift 1.4ms
no surface is left formatting a bare typical · 1 test
✓
nothing renders TOOL_COST_ESTIMATE[...].tokens through fmtTokens directly 24.9ms
src/chat/history-persists.vitest.ts
the write is AWAITED, not deferred · 4 tests
✓
no ctx.waitUntil on the history write 1.5ms
✓
the promise is returned so the caller can await it 0.4ms
✓
the same-isolate fast path is kept 0.2ms
✓
the caller still awaits it 5.1ms
a lost write can no longer be silent · 4 tests
✓
saveChatHistory reports instead of swallowing 0.8ms
✓
the reporter is INJECTED, not imported 0.4ms
✓
index wires the reporter and names the consequence 5.5ms
✓
reporting still cannot break the response 0.4ms
src/chat/history-trim.vitest.ts
trimPriorTurns · 8 tests
✓
leaves the last KEEP_FULL messages untouched whatever their size 2.1ms
✓
still stubs an old rendered report — R6 is not undone 0.5ms
✓
gives an old USER message far more room than an assistant one at the same position 0.3ms
✓
preserves a typical ask verbatim, with no truncation marker 0.3ms
✓
marks a cut user message without claiming it was shown to the user 0.4ms
✓
bounds total preserved user text by the budget, newest first 0.4ms
✓
never leaves a user turn worse off than an assistant turn 0.8ms
✓
is a pure function — inputs are not mutated 0.2ms
src/chat/person-words-cards.vitest.ts
typed: the whole text, verbatim, in the person's own turns · 4 tests
✓
an instruction the person typed is theirs, and only its text inside the quotes 6.3ms
✓
reworded, re-cased, typed only in part, or in nobody's turn: not theirs 0.8ms
✓
rank tracking: only the keyword the person typed, never the one the model added beside it 0.7ms
✓
an audience panel: its name and each prompt the person typed; a keyword panel's search terms stay records 0.4ms
edited: a draft subject the person changed in Drafts · 4 tests
✓
only the stamped row's subject is theirs; the model's subject on the next row is not 0.5ms
✓
the flag must be exactly true: a truthy string or a flag on the wrong row exempts nothing 0.4ms
✓
typed: the subject the person typed is theirs on ITS row only 0.6ms
✓
a record span still looks exactly as #618 returned it (no basis field) 0.4ms
src/chat/placeholder-leak.vitest.ts
formatter placeholders · 5 tests
✓
create_sequence names the step count and never a [list-name] 6.7ms
✓
seo_content_ideas points at the user's own top idea 0.4ms
✓
find_competitors names the competitor it just surfaced 0.3ms
✓
the empty branches instruct in plain words, not brackets 0.3ms
✓
no user-facing template in tool-format.ts ships a bracketed placeholder 2.7ms
list_sequences enrolment counts · 3 tests
✓
renders the counts the handler actually returns 0.5ms
✓
distinguishes zero active from zero enrolled 0.4ms
✓
the dispatch reads the fields handleListSequences returns 1.4ms
src/chat/rejected-tool-no-fabrication.vitest.ts
the condition is structural, not a guess about the prose · 4 tests
✓
fires only when a tool was REJECTED and NOT ONE ran 1.6ms
✓
reads the rejection ledger the validator already writes 0.3ms
✓
does not fire on an approval card — a question is not an answer 0.2ms
✓
does not fire on an empty response 0.2ms
it DISCLOSES rather than blocks · 3 tests
✓
appends to the answer instead of replacing it 0.3ms
✓
tells the user what the text IS, and what to do 0.3ms
✓
records the stand-down so it is countable, not just cosmetic 0.3ms
the metadata that caught this stays wired · 1 test
✓
hidden_failure and tool_call_count are still on the judge row 5.8ms
src/chat/shown-final-reply.vitest.ts
a card whose only rendering sat inside a withheld card was never shown · 2 tests
✓
M1 (agent loop): the send card quoted inside an instruction the guardrail withholds is not marked shown, and a typed confirm sends nothing 281.6ms
✓
M1c control: the same quote inside an instruction that ships whole DID show the send card, and its typed confirm sends 62.1ms
the history of a turn is the reply the person received · 6 tests
✓
agent loop, M1: the next model call and the restored transcript hold the sentence, not the instruction card quoting the send card 55.5ms
✓
agent loop, a send card whose subject says "free": the next model call holds the sentence, not the altered card 32.4ms
✓
shortcut, a typed confirm of a withheld send card: the history holds the sentence it answered with, not the raw card 36.2ms
✓
agent loop, a reply rewritten because it promised and delivered nothing: the history holds what the person read 23.8ms
✓
the wiring: at both exits nothing writes to the reply after shown-ness is judged 5.1ms
✓
control: a card shown whole keeps its own text in history, so a typed approval of it still reads it 18.4ms
src/chat/silent-turn-text.vitest.ts
resolveSilentTurnText · 8 tests
✓
relays the tool error when every tool call errored (unchanged behavior) 1.7ms
✓
defaults to "Done." for an ordinary silent turn 0.5ms
✓
recovers a drafting ask that dead-ended on list_contacts 0.9ms
✓
does NOT use the DRAFTING recovery copy when the ask was not a drafting request 5.6ms
✓
renders the successful tool result instead of swallowing it as "Done." 0.3ms
✓
still says "Done." when there is no tool result to render 0.3ms
✓
does NOT recover when the last tool was not a read-only lookup 0.3ms
✓
an errored drafting turn still relays the error, not the recovery copy 0.2ms
src/connectors/google-fetch.vitest.ts
googleFetch — Composio routing · 5 tests
✓
routes a GSC search-analytics query to the GSC connection, verbatim 27.3ms
✓
routes a GA4 runReport to the GA4 connection 0.8ms
✓
returns 501 for Tag Manager (no Composio toolkit) without calling the proxy 0.8ms
✓
reports the connections only when composio_active is true 0.4ms
✓
native mode (flag off) passes through to fetch unchanged, plus a time limit when the caller set none 2.1ms
googleFetch — a proxy timeout is a counter, not a fault · 3 tests
✓
answers 504 with a named code and does not throw 1.4ms
✓
a non-timeout transport failure still answers 502 — that path is unchanged 0.9ms
✓
the source routes TimeoutError to the counter before the Issue reporter 0.8ms
src/drip/foreign-reference.vitest.ts
processDripCron: a reference to another tenant's row is never followed · 6 tests
✓
an enrolment pointing at another tenant's CONTACT sends nothing to that contact and is cancelled 7.1ms
✓
an enrolment pointing at another tenant's SEQUENCE never mails that tenant's step text 1.7ms
✓
an enrolment filed under another tenant's CAMPAIGN is cancelled, not sent under that campaign 1.1ms
✓
another tenant's send rows neither eat this tenant's daily cap nor cancel its contact as bounced 22.2ms
✓
control: the tenant's OWN hard bounce on its own contact still cancels the enrolment 1.2ms
✓
control: an enrolment whose references are all its own tenant's sends exactly as before 1.3ms
handleEnrollSequence enrols only the caller's own contacts · 2 tests
✓
drops another tenant's contact id from the request body before writing (admin-secret path) 27.2ms
✓
refuses with a sentence when none of the ids are the caller's 1.2ms
src/email/dns-fix-add-only.vitest.ts
SPF: the fix adds one record and leaves every other TXT record alone · 4 tests
✓
an apex whose only TXT record is a verification token keeps it, and gains exactly one SPF record 44.2ms
✓
an SPF record already in the zone is never joined by a second one, and is not edited 3.9ms
✓
reads the ZONE, not public DNS: an SPF record public DNS has not caught up with is still respected 14.0ms
✓
a zone it cannot read is not written to 4.5ms
DMARC: the same rule at _dmarc · 2 tests
✓
a stray TXT record at _dmarc survives, and one DMARC record is added 9.0ms
✓
an existing DMARC record is neither duplicated nor weakened 2.4ms
the confirm card shows exactly what will change, and the chip applies only that · 2 tests
✓
names the record it adds and the record it keeps, stages only those fixes, and writes nothing until confirmed 24.3ms
✓
offers no Confirm when there is nothing it would change — it says why instead 5.3ms
src/email/gmail-send.vitest.ts
Gmail send transport · 4 tests
✓
posts to the Gmail API with a bearer token and a base64url-encoded RFC2822 message 38.6ms
✓
strips header-injection attempts from subject/to/reply-to 1.3ms
✓
classifies a 403 dailyLimitExceeded distinctly from a generic failure 0.9ms
✓
classifies a 401/invalid_grant as a reconnect prompt, not a generic failure 0.6ms
Gmail daily send cap · 4 tests
✓
fails open when CHAT_HISTORY is unbound (matches every other rate limit in this codebase) 0.4ms
✓
blocks once the default cap is reached and reports the correct limit 1.0ms
✓
resets in a new day bucket 0.4ms
✓
fails CLOSED when KV throws, and says the limiter is unavailable — not that the limit was hit (audit K4) 1.6ms
src/email/product-update-copy.vitest.ts
product announcement — scope · 2 tests
✓
makes no cost, pricing or token claim 2.5ms
✓
does not claim anything got faster or cheaper without a measurement behind it 0.4ms
product announcement — the promises it makes · 6 tests
✓
leads with the ask-why capability and shows real prompts 0.5ms
✓
says the report still exists — users came for the artifact 0.3ms
✓
describes verification the way it actually behaves 0.3ms
✓
greets by name when there is one, and never with an email address 0.3ms
✓
carries a working dashboard CTA 0.2ms
✓
is registered so the admin console can list and preview it 0.4ms
src/guard-proofs/check-schema-producers.vitest.ts
check-schema-producers — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (producers/consumers match schema; legacy names only in the shim)) · 8 tests
✓
the unmutated sandbox exits 0 1230.7ms
✓
SP-1: exits 1 naming the violation — the skills producer builds the legacy `query` for search_leads instead of the schema field `topic` 1222.4ms
✓
SP-2: exits 1 naming the violation — the campaign dispatcher reads the legacy `limit` on the search_leads path, outside migrateLegacyArgs() 1246.7ms
✓
SP-3: exits 1 naming the violation — the campaign dispatcher reads a search_leads argument the schema does not declare (always undefined) 1227.6ms
✓
SP-4: exits 1 naming the violation — a shortcut hands search_leads the raw sentence as the legacy `query` — the specs/011 entry-point defect 1242.7ms
✓
SP-5: exits 1 naming the violation — the write_article shortcut passes a named domain as `site`, which seo_write_content does not declare (found live 2026-10-30) 1246.6ms
✓
SP-6: exits 1 naming the violation — a direct executeTool call inside the SEO dispatcher adds an undeclared rag_readiness argument 1248.3ms
✓
every mutant was restored: the sandbox exits 0 again 1251.9ms
src/leads/closest-offer.vitest.ts
P4-06-F08: the chip is recognised, and nothing else is · 2 tests
✓
accepts the chip verbatim and the ways a person retypes it 2.1ms
✓
rejects questions and other asks 0.4ms
P4-06-F08: the continuation is the confirmed search, with only the fit check lifted · 3 tests
✓
lifts the fit check and never switches paid sources on 1.0ms
✓
is offered exactly when the result carries the chip 1.9ms
✓
the offer is session-scoped, single-use and lives no longer than the card it rides on 0.7ms
P4-06-F08: the wiring — the chip runs the search, no second card · 3 tests
✓
is redeemed before any intent handler or the low-score bail-out 0.3ms
✓
runs search_leads with the recorded arguments and quotes nothing 0.4ms
✓
the confirmed run records the offer under its own quote 0.4ms
icp-cache.vitest.ts
Core
8 /8
21ms · 2 suites
PASS
src/leads/icp-cache.vitest.ts
one extraction per brief · 6 tests
✓
the second call for the same brief reads the stored profile and skips the model 14.5ms
✓
a changed brief misses by construction 1.4ms
✓
whitespace around the brief does not defeat the cache 0.8ms
✓
a thin brief never reaches the model or the store 0.5ms
✓
an empty extraction is not pinned — it could be an outage 1.4ms
✓
a malformed stored row reads as no cache 0.4ms
the row is tenant data · 2 tests
✓
is a declared setting and is erased with the account 0.3ms
✓
both producers go through the cache — the scan turn and define_icp 2.0ms
src/leads/local-business-locality.vitest.ts
local_business: postal_code and locality can coexist · 5 tests
✓
accepts both and keeps locality — the regression: this used to be silently deleted 3.5ms
✓
still accepts postal_code alone (paired with country_code) 0.6ms
✓
still accepts locality alone 0.6ms
✓
still requires country_code alongside a bare postal_code 0.5ms
✓
still requires at least one of postal_code/locality 0.4ms
resolveSearchLeadsNote: a bare zip discloses instead of silently broadening · 3 tests
✓
discloses when postal_code was the only geography given 0.5ms
✓
says nothing about it when locality was also supplied 0.3ms
✓
outranks the free-tier cap note — even a delivered, capped batch matched the wrong geography 0.2ms
src/leads/one-paid-rung.vitest.ts
the paid leg of leadSearch is DropLeads and nothing else · 4 tests
✓
no retired rung remains in search.ts 3.4ms
✓
the paid leg calls the DropLeads rung, declares dropped filters, and reports a missing token as a fault 0.4ms
✓
the Product Hunt job is gone from every surface 5.3ms
✓
kept on purpose: the backlink harvester, the role-inbox rule, verifyEmail and the Apollo path 0.3ms
the cost protocol sees the rung · 4 tests
✓
the price is classified, reported, and quoted 1.4ms
✓
the paid quote is delivered x the enrich price — a miss is free, so that IS the ceiling 0.4ms
✓
the enrich row is billed on the charge the broker made, with the fallbacks in order 0.5ms
✓
the admin cost roll-up files provider=dropleads under the lead search 0.4ms
src/leads/platform-profile-site.vitest.ts
the URLs that actually caused it · 2 tests
✓
the exact Facebook album URL from the incident 1.7ms
✓
the LinkedIn case from the same sweep 0.4ms
subdomain-aware, never substring · 4 tests
✓
a platform subdomain still counts 0.3ms
✓
a REAL business whose domain merely contains the word is scanned normally 0.4ms
✓
an ordinary business site is untouched 0.3ms
✓
bare domains and malformed input do not throw 0.3ms
what is deliberately NOT listed · 1 test
✓
publishing platforms where the page genuinely IS the product presence 0.3ms
the guard is wired into the scan, before anything is saved · 1 test
✓
returns PLATFORM_PROFILE and never reaches saveSiteOnly 0.9ms
src/leads/profile-shadowing.vitest.ts
a name-only profile · 4 tests
✓
does not shadow a rich brief 2.8ms
✓
still respects the character cap when the brief wins 0.5ms
✓
keeps the name when the brief says LESS — never downgrade 0.2ms
✓
keeps the name when there is no brief at all 0.3ms
a real profile still wins — the preference is intact · 2 tests
✓
prefers the structured profile over an equally rich brief 0.7ms
✓
prefers the profile even when a rambling brief is longer 0.3ms
no profile at all · 2 tests
✓
falls back to the brief, unchanged behaviour 0.4ms
✓
returns empty rather than throwing when both are missing 0.2ms
src/leads/scan-nothing-learned.vitest.ts
a page that declares nothing · 5 tests
✓
is below the substance floor — the premise of every case below 1.9ms
✓
never calls the model 26.4ms
✓
writes no product brief 1.2ms
✓
still saves the site — the domain resolved and site-scoped tools need a subject 0.7ms
✓
says what happened, and flags the source as thin 0.9ms
any one real signal keeps the normal path · 3 tests
✓
a declared brand is enough — the model still runs 1.9ms
✓
the user's own description is enough, even on an empty page 0.7ms
✓
real page copy is enough 0.6ms
src/llm/jev-adoptions.vitest.ts
audience_fit: Jev decides, the writer only writes · 3 tests
✓
a fit verdict never reaches the writer 3.5ms
✓
a mismatch verdict hands the sentence to the writer, whose own verdict stands 0.8ms
✓
a Jev failure, or the flag off, is the old path 1.6ms
page scores: five levels → 0–100 · 4 tests
✓
maps the score position onto the scale the findings read, using the legend size 0.6ms
✓
every axis is a five-level score question, levels concrete and ordered low → high 3.4ms
✓
jevPageScores throws when any axis comes back unscored — a half-scored page is not a scorecard 26.4ms
✓
the notes sentence names the weakest axis 0.5ms
wiring · 1 test
✓
both scorecards try Jev first and keep the writer as the fallback; the rollout names all four contexts 1.7ms
src/llm/router-reasoning-default.vitest.ts
callOpenRouterFull disables reasoning unless asked · 6 tests
✓
sends reasoning:{enabled:false} for a caller that passes NOTHING 3.9ms
✓
sends it for a prose caller with a ceiling and no failOnTruncation 0.6ms
✓
still sends it for a failOnTruncation caller — unchanged from v2.496.1 0.6ms
✓
LETS A CALLER OPT BACK IN with reasoning:{enabled:true} 0.4ms
✓
still honours an explicit effort level 0.5ms
✓
an opted-in caller is NOT translated to effort:minimal on a mandatory-reasoning model 0.6ms
the agent loop is OUTSIDE this default, on purpose · 2 tests
✓
callOpenRouterTools sends NO reasoning key when the caller sets none 1.3ms
✓
callOpenRouterTools still forwards a reasoning option it is given 0.4ms
src/llm/router-reasoning-models.vitest.ts
reasoning is disabled in the form each endpoint accepts · 6 tests
✓
sends effort:minimal to gpt-5-mini, which rejects enabled:false outright 4.0ms
✓
does NOT downgrade a gpt-5 sibling that accepts enabled:false 0.6ms
✓
still sends enabled:false to models that accept it 0.6ms
✓
translates a CALLER-supplied enabled:false too — same choice, spelled for the endpoint 0.4ms
✓
leaves a caller reasoning that is not "off" alone 0.5ms
✓
keeps the copy chain on its first model instead of demoting the draft 0.8ms
a model that refuses enabled:false is retried, not dropped · 2 tests
✓
retries the SAME model with effort:minimal on the 400 that says so 2.4ms
✓
does NOT retry an unrelated 400 — that one is a real failover 1.4ms
src/llm/router-tools-reasoning.vitest.ts
callOpenRouterTools is outside the reasoning default · 3 tests
✓
sends NO reasoning key at all when the caller sets none 3.7ms
✓
forwards a caller-supplied effort verbatim — the live CoT path 1.1ms
✓
does NOT apply the REASONING_MANDATORY rewrite — that helper is scoped to callOpenRouterFull 0.7ms
callOpenRouterTools labels its ledger rows · 2 tests
✓
defaults to chat:v2, so existing callers and existing history keep their meaning 0.7ms
✓
writes a caller-supplied context instead 0.5ms
agent-loop backend preference · 3 tests
✓
sends provider.order StreamLake with fallbacks ON 0.6ms
✓
keeps fallbacks enabled — a hard pin makes one backend outage a failed turn 0.4ms
✓
does NOT pin callOpenRouterFull — single-shot callers were not measured 1.0ms
src/middleware/middleware.vitest.ts
middleware — dispatchToolCallFromText · 8 tests
✓
dispatches a JSON tool call 2.0ms
✓
falls back to an XML tool call 0.7ms
✓
emits structured next actions 0.3ms
✓
bypasses special-tool execution 0.2ms
✓
rejects an unknown tool before execution 0.2ms
✓
returns a top-up before execution 0.2ms
✓
ignores plain text 0.3ms
✓
survives formatter failures on a successful tool run 0.5ms
src/middleware/share-of-model.vitest.ts
registrableCore · 2 tests
✓
returns the SLD, ignoring subdomains 2.2ms
✓
handles two-part TLDs 0.3ms
isOurs — phantom-citation guard · 6 tests
✓
does NOT match a generic brand token inside an unrelated subdomain 0.5ms
✓
still matches our own domain and subdomains of it 0.3ms
✓
matches a distinctive brand token in another registrable domain (real alias hit) 0.3ms
✓
does not match a distinctive token buried in a subdomain of a rival 0.2ms
✓
short (3-4 char) brands match the core label, not arbitrary subdomains 0.3ms
✓
empty/garbage inputs are safe 0.3ms
src/planner/bet-count-channel.vitest.ts
the validator still distinguishes its three outcomes · 4 tests
✓
a below-range count is reported as such 6.4ms
✓
a padded bet is a different message — and it is OUR bug 0.3ms
✓
zero bets on a plan with initiatives is also ours 0.2ms
✓
and a healthy plan still passes 0.4ms
only the below-range case leaves the fault channel · 4 tests
✓
a below-range count goes to Logs as a counter 1.0ms
✓
the other two still reach reportError 0.8ms
✓
the branch is chosen by the MESSAGE, which is the validator's own output 0.7ms
✓
the plan is still built either way — this was never user-facing 0.8ms
src/reports/aeo-rivals-render.vitest.ts
R-D acceptance — durability beats volume in the rendered artifact · 6 tests
✓
the domain three engines agree on outranks the one with equal volume on one engine 1.9ms
✓
names the PAGE, its rank and its shape — a hostname is not actionable 0.6ms
✓
states the ordering rule so the reader can disagree with it 0.2ms
✓
shows what KIND of page wins, excluding our own 0.5ms
✓
groups the work by who has to do it, biggest group first (AEO-009) 0.4ms
✓
the next step is an outreach brief when the market sits on other people pages 0.3ms
R-D — a run stored before source capture says so (trap 14) · 2 tests
✓
falls back to the old chips and explains WHY the detail is missing 0.5ms
✓
a captured run with genuinely no rivals says THAT instead 0.8ms
src/reports/contracts.property.vitest.ts
forensic contracts — totality under adversarial fuzz · 2 tests
✓
no predicate throws across 2000 random hostile results × every contracted type 780.8ms
✓
prose-only types always return no violations regardless of input 7.9ms
forensic contracts — nasty-tenant fixtures · 6 tests
✓
phantom SOV: 80% coverage with zero real citations (the isOurs subdomain collision) 0.3ms
✓
single-competitor thin denominator is still bounded (no crash, no false pass on OOB) 0.2ms
✓
all-error engine legs → empty leaderboard, zero coverage → no false phantom flag 0.2ms
✓
a leg that ERRORED is not a soundness violation — it is a reported absence 0.3ms
✓
campaign with more opens than sends (tracking double-count) is caught 0.2ms
✓
onpage score computed out of [0,100] is caught 0.2ms
src/reports/outbound-report.vitest.ts
generate_emails — draft artifact persists (regression) · 2 tests
✓
returns a real artifact (not null) with the drafts rendered 1.9ms
✓
returns null (plain-text path) for a zero-draft or error result — no empty artifact 0.3ms
search_leads — §17 gold standard · 2 tests
✓
renders a batch-quality bento (verified rate, leads, sources) + a draft-emails action 0.5ms
✓
keeps the contact preview, plain headers, feedback mount 0.4ms
campaign_stats/dashboard — §17 gold standard · 2 tests
✓
renders a performance bento (open/reply/audience/state), no fix buttons (advice in copy) 0.4ms
✓
plain headers + feedback mount 0.2ms
domain_email_readiness_audit — §17 gold standard · 2 tests
✓
renders a deliverability bento (issues/auto-fixable/blacklist) with a one-click fix action 0.4ms
✓
keeps the per-issue drill-down, plain headers, feedback mount 0.3ms
src/reports/playbook-tail.vitest.ts
a playbook answer drops the site-diagnostic tail · 5 tests
✓
the playbook itself is fully rendered 2.6ms
✓
drops the answerProse block 0.4ms
✓
drops the movement block 0.3ms
✓
drops the keywords block 0.2ms
✓
drops the outbound and traffic prose specifically 0.2ms
a BRIEF keeps the tail — its verdicts rest on those readings · 2 tests
✓
still carries the diagnostic prose the verdicts were read from 0.2ms
provenance survives the trim — a shorter answer must not be a less honest one · 1 test
✓
the reading dates and the never-measured list are kept on a playbook 0.6ms
src/reports/render-integrity.vitest.ts
assertReportRenderSound · 7 tests
✓
passes a clean report 2.2ms
✓
flags an empty table body (the blank citation-matrix defect) 1.0ms
✓
flags [object Object] 0.2ms
✓
flags undefined / NaN leaking into a rendered value 0.6ms
✓
does NOT flag the words in legitimate prose 0.2ms
✓
collects multiple distinct defects 0.5ms
✓
is safe on empty/garbage input 0.3ms
aeo_visibility citation matrix — zero test prompts (Sentry NQZAI-5G) · 1 test
✓
renders an explicit empty state instead of an empty tbody 27.4ms
src/runtime/guardrail-user-money.vitest.ts
the two live failures · 2 tests
✓
a liability figure the scan read off the tenant OWN site survives 4.8ms
✓
an ICP band typed an EARLIER turn survives on later turns 2.1ms
what must STILL be redacted — the rule this protects · 3 tests
✓
our own price is not theirs, even inside a rich corpus 0.7ms
✓
a reply mixing both keeps theirs and hides ours 0.5ms
✓
with NO corpus at all, everything is still redacted 0.4ms
matching stays formatting-insensitive, not fuzzy · 2 tests
✓
case and spacing are formatting, not a different figure 0.3ms
✓
a figure the tenant never wrote is NOT rescued by a near miss 0.3ms
the corpus is built from what the turn already holds · 1 test
✓
every user turn, the brief and the profile — and it is never rendered 5.3ms
src/runtime/human-authorisation.vitest.ts
the scope · 5 tests
✓
authorises nothing outside it 3.0ms
✓
authorises its own action, for its own tenant, with the arguments it was opened for 1.1ms
✓
a send authorisation authorises no gate, and no gate authorises a send 0.6ms
✓
cannot be borrowed by a concurrent request in the same isolate 0.9ms
✓
compares values, not key order or object identity 0.3ms
the wiring · 3 tests
✓
is opened in exactly one place: the CONFIRM_GATES loop, around the one replay 82.4ms
✓
is read at exactly the six gates (and the send), each for its own action 165.2ms
✓
every CONFIRM_GATES tool is one of the six (a seventh row would have no reader) 3.7ms
src/runtime/run-marker.vitest.ts
openRunMarker — the timeout side writes the marker · 5 tests
✓
a run aborted by withTimeout writes tool_run status=timeout at the abort, before it settles 3.6ms
✓
the abandoned run settling later never writes a SECOND tool_run row — its outcome goes to tool_run_settled 1.3ms
✓
any other abort is caller_aborted, not timeout 0.3ms
✓
a run that settles first writes exactly one ordinary tool_run row, and a later abort writes nothing 0.5ms
✓
no signal (queue job, nested call path) behaves exactly as before: one row at the settle 0.4ms
the wiring: executeTool writes its marker through openRunMarker, the loop records every timeout · 3 tests
✓
executeTool opens the marker on the caller signal and settles through it (no direct tool_run write in the finally) 0.5ms
✓
executeTool hands its run id to the loop on the signal 0.3ms
✓
the agent loop writes tool_timeout for EVERY timeout, not only TIMEOUT_SETTLE_TOOLS 0.4ms
src/tools/advisory-routing.vitest.ts
the prohibition is gone · 3 tests
✓
no longer declares open questions to be non-plan asks 2.1ms
✓
names the question classes that must reach the planner 0.5ms
✓
the WHY is recorded in the FILE, not spent on every turn 0.4ms
the split is advisory vs imperative, not a keyword list · 2 tests
✓
imperatives keep going straight to their tool 0.3ms
✓
the doubt case prefers the planner, and says why 0.3ms
it does not contradict rule (5) · 2 tests
✓
a single-scope audit routes to a tool the model CAN call 0.3ms
✓
THREE OR MORE dimensions is a brief — the same counting rule the AEO picker uses 0.3ms
the planner is still barred from paid fan-outs · 1 test
✓
neither planner tool may route to a paid fan-out 0.2ms
src/tools/arg-key-shape.vitest.ts
the two turns that died today · 2 tests
✓
generate_emails accepts contactIds as contact_ids 4.0ms
✓
seo_keywords accepts query as its seed topic 0.4ms
a SHAPE transform, not a vocabulary · 4 tests
✓
handles the conventions a model actually emits 1.0ms
✓
needs no list to maintain — it only re-spells onto a DECLARED field 0.3ms
✓
never overwrites a value the model already put in the right field 0.3ms
✓
leaves dispatch metadata alone 0.3ms
what it must NOT do · 2 tests
✓
a bad VALUE is still a rejection — this fixes keys, not contents 0.3ms
✓
search_leads keeps its own query -> topic migration 0.4ms
src/tools/enroll-sequence-identifier.vitest.ts
enroll_in_sequence accepts either identifier · 6 tests
✓
accepts sequence_id — the exact shape that was rejected 4 times 2.7ms
✓
still accepts sequence_name 0.4ms
✓
accepts both together 0.5ms
✓
lets a call with NEITHER identifier through the schema on purpose 0.4ms
✓
still rejects a malformed sequence_id rather than passing it to the DB 0.3ms
✓
still rejects an invented argument — additionalProperties:false is intact 0.3ms
the vocabulary the model is handed matches what the tool accepts · 2 tests
✓
list_sequences returns an id, so the enrol schema must accept one 1.2ms
✓
resolves an id and a name with SEPARATE user-scoped queries, never one _or 0.7ms
src/tools/lead-routing.vitest.ts
list_contacts says what it is NOT for · 3 tests
✓
states it cannot find anyone new 1.5ms
✓
names search_leads as the tool for finding people 0.3ms
✓
tells the model to prefer the paid tool when the ask is to find 0.2ms
search_leads claims the find intent · 2 tests
✓
names the trigger verbs and the NEW/FRESH qualifiers 0.3ms
✓
points away from list_contacts explicitly 0.2ms
a contact-list quality check is verification, not enrichment · 3 tests
✓
verify_contacts claims the quality-check phrasing 0.4ms
✓
enrich_contacts sends the question away rather than absorbing it 0.3ms
✓
each tool names the other as the wrong choice for the other job 0.2ms
src/tools/producer-contract.vitest.ts
skills that call a schematised tool build valid arguments · 3 tests
✓
finds the skill steps to check (a silent zero here would prove nothing) 1.7ms
✓
quick_list_build → search_leads 1.4ms
✓
cold_launch → search_leads 0.4ms
the clarify gate reads the arguments the schema actually produces · 2 tests
✓
asks when the request names nothing to target on 0.9ms
✓
does not interrogate a well-specified request 0.2ms
legacy `query` producers keep working through the migration shim · 3 tests
✓
maps a legacy query onto topic instead of rejecting the call 0.6ms
✓
never lets a legacy query become a provider filter 0.3ms
✓
the chat-shortcut adapter produces the same shape 0.3ms
src/tools/proto-key-binding.vitest.ts
the next-action seal binds every own key, including "__proto__" · 3 tests
✓
a genuine chip with an extra, unsigned top-level "__proto__" is refused 7.2ms
✓
a genuine chip with an extra "__proto__" inside a nested argument is refused 0.9ms
✓
the canonical form keeps an own "__proto__" key, at any depth 1.1ms
validated tool arguments carry only what was validated · 3 tests
✓
a top-level "__proto__" never becomes the prototype of the validated args 1.6ms
✓
a nested "__proto__" never becomes the prototype of a validated object argument 0.4ms
✓
an argument named after an Object.prototype member is not a declared argument 0.5ms
the planner candidate validator and coercer read only declared arguments · 2 tests
✓
"__proto__" is an unknown argument, not a declared one 0.3ms
✓
the coercer drops "__proto__" instead of installing it as a prototype 0.5ms
src/tools/retry-directive.vitest.ts
retryDirective · 7 tests
✓
tells the model to retry from the vocabulary, and not to answer yet 2.8ms
✓
treats an unknown ARGUMENT as a rename, not a bad value 0.8ms
✓
pluralises and de-duplicates when several argument names are wrong 0.3ms
✓
points at `accepted` when lexical matching did find candidates 0.6ms
✓
prefers the vocabulary directive when both are present 0.3ms
✓
names each affected field once 0.2ms
✓
stays silent when there is nothing to retry FROM 0.5ms
the live 2026-08-23 shape produces a directive · 1 test
✓
a real unmatched industry rejects WITH a vocabulary to retry from 3.7ms
src/seo/ai-search-prompt-generator.vitest.ts
singlePromptVerdict · 5 tests
✓
accepts a plain question and strips quotes and spacing 2.4ms
✓
rejects keyword strings, the brand and the host name 0.5ms
✓
rejects a question over the length cap — two needs and a condition is nobody's question 0.4ms
✓
adds the question mark the model dropped 0.4ms
✓
does NOT reject a question that resembles the title — a well-built page is titled for its most common query 0.2ms
generateMostLikelyPrompt · 3 tests
✓
returns the prompt and the cost of the one call 4.2ms
✓
retries an invalid answer once, and the retry is paid for too 2.1ms
✓
nothing usable still reports what it spent 0.5ms
src/seo/dfs-cost.vitest.ts
readCost · 4 tests
✓
reads a reported charge 1.9ms
✓
keeps a genuine zero — free and cached endpoints really do charge nothing 0.4ms
✓
returns null when the field is absent, so the caller falls back to the constant 0.3ms
✓
rejects non-finite and non-numeric values rather than billing NaN 0.3ms
multi-call cost aggregation · 4 tests
✓
sums when every call reported a cost 0.3ms
✓
reports NULL when ANY call went unmeasured — never a partial sum 0.2ms
✓
treats an all-zero run as measured zero, not unmeasured 0.2ms
✓
is zero for a run that made no calls 0.2ms
src/seo/gtm-scope-removal.vitest.ts
dropping the Tag Manager scope · 8 tests
✓
is not requested at consent, and the two that remain are 1.9ms
✓
an absent Tag Manager leaves the DENOMINATOR, never scores 0 against weight 10 0.5ms
✓
and its absence does not make every score provisional either 0.2ms
✓
a connected container with zero tags is still a real 0.6 finding 0.2ms
✓
never tells the user to reconnect Google to regain it — that is what removes it 0.3ms
✓
the god-mode capability no longer promises a check we do not request 0.2ms
✓
the public scope disclosures match what we actually request 1.6ms
✓
the CONNECT CARD does not promise a Tag Manager audit 0.4ms
src/seo/keyword-router-free-rung.vitest.ts
the free rung runs even when spend is denied · 3 tests
✓
resolves volumes with allowPaid:false, and never calls the paid rung 3.5ms
✓
runs BEFORE the paid rung, not after it 0.4ms
✓
leaves the paid rung exactly what Google could not answer 0.9ms
what the free rung refuses to claim · 5 tests
✓
does not resolve a keyword Google returned with no volume 0.6ms
✓
ignores the adjacent ideas Google volunteers for a keyword seed 0.3ms
✓
chunks past Google's 20-seed cap instead of dropping the 21st keyword 1.2ms
✓
a failing free rung still lets the paid rung run 0.4ms
src/seo/keyword-site-attribution.vitest.ts
upsertGscPerformance — the writer records which property the pull came from · 4 tests
✓
writes the normalised host and the raw property onto every behavioural row 4.5ms
✓
normalises a URL-prefix property to the same host as its domain property 0.9ms
✓
never writes behaviour that carries no property 0.3ms
✓
registers the keyword without clobbering its volume/CPC side 1.4ms
fetchSitePerformance — the reader sees one property and no legacy rows · 3 tests
✓
returns only the requested property, not the tenant-wide merge 0.7ms
✓
scopes the query by site and never falls back to tracked_keywords behaviour 0.5ms
✓
returns nothing rather than guessing when no site is given 0.2ms
the volume ladder stays per-keyword, not per-property · 1 test
✓
reads the volume cache WITHOUT a site filter, so a second property costs nothing 0.8ms
src/seo/link-health.vitest.ts
computeLinkHealth · 8 tests
✓
counts dead targets and groups them by the page, not the link 4.0ms
✓
treats a redirect as alive — the link still lands somewhere 0.4ms
✓
excludes rows with no status instead of assuming they are healthy 0.4ms
✓
says "unknown, not healthy" when nothing carried a status 0.3ms
✓
honours broken:true even when the status is missing, without inventing one 0.2ms
✓
lets an explicit status win over a bare broken flag for the same target 0.3ms
✓
never claims first-hand verification — the source rides with the result 0.3ms
✓
handles an empty profile without dividing by zero 0.3ms
src/seo/write-content-length.vitest.ts
the article prompt states its length as a requirement · 3 tests
✓
names a hard floor at 90% of the target instead of a ~approximate hint 27.8ms
✓
scales the floor with the caller-supplied target 1.1ms
✓
tells the model the requirement has a consequence and how to plan for it 1.6ms
the generation ceiling can physically hold the article it demands · 2 tests
✓
leaves the default request at exactly the historic 3500 tokens 1.2ms
✓
raises the ceiling for a long article the caller explicitly asked for 1.2ms
an article that still lands short says so · 3 tests
✓
discloses the shortfall with both numbers 1.3ms
✓
stays quiet when the article met the floor 1.3ms
✓
defers to truncation_note when the draft was cut off 1.6ms
src/leads/shared/chunk-subject-index.vitest.ts
160 · the index exists and covers the join · 4 tests
✓
indexes subject_id 1.8ms
✓
carries chunk_id so the chunk_embedding join stays index-only 0.4ms
✓
is NOT partial on subject_type 0.5ms
✓
is idempotent, because the index was built live before the migration was written 0.2ms
160 · the self-check proves the index is USED, not merely present · 2 tests
✓
collects every plan line, not just the first 0.3ms
✓
fails on a Seq Scan and on the index not being chosen 0.3ms
160 · the reader this was built for still looks up by subject_id · 2 tests
✓
the embed candidate query still anti-joins document_chunk on subject_id 0.3ms
✓
and still joins chunk_embedding by chunk_id, which is why chunk_id is in the index 0.2ms
client/shell-actions.vitest.ts
V12b-edge-F02 — the shell binds without a single inline handler · 5 tests
✓
every one of index.html's controls binds to a known action 369.2ms
✓
each control calls the function its handler named, with the arguments its handler passed 227.7ms
✓
the five handlers that were inline code do what that code did 231.9ms
✓
a control is bound as its on<event> PROPERTY, so code that replaces it still replaces it 108.6ms
✓
a control that arrives AFTER boot is never bound, whatever it names 94.5ms
V12b-edge-F02 — the delegated dispatcher · 2 tests
✓
an error event (no person involved) may only name a display fallback 93.3ms
✓
server HTML may name report actions only — never a main.ts control or a shell control 88.9ms
src/google_analytics_helpers.vitest.ts
google_analytics_helpers · 7 tests
✓
builds the metadata cache key 1.4ms
✓
compatibility cache key ignores input ordering 0.3ms
✓
normalizes join paths 7.6ms
✓
computes metric deltas 0.2ms
✓
attaches row deltas 0.3ms
✓
summarizes merge snapshots without prior 0.3ms
✓
summarizes merge snapshots with prior 0.3ms
mixpanel.vitest.ts
Core
7 /7
44ms · 2 suites
PASS
src/mixpanel.vitest.ts
mixpanel request geo · 4 tests
✓
binds request.cf geo for the async chain and is empty outside it 28.0ms
✓
stamps mp_country_code/$city/$region onto tracked events 5.7ms
✓
events fired outside a request carry no geo (and still send) 1.5ms
✓
people $set carries $country_code/$city and never a real $ip 1.9ms
mixpanel Unicode-safe payload encoding (NQZAI-4A) · 3 tests
✓
setServerMixpanelPeople round-trips a non-Latin1 $name/$email without throwing 1.8ms
✓
captureServerMixpanelEvent round-trips a non-Latin1 error_message (judge/feedback path) 1.8ms
✓
sanity: the original btoa(JSON.stringify(...)) path would have thrown on this input 1.8ms
src/admin/judge-turn-provenance.vitest.ts
the judge-provenance column is actually requested · 4 tests
✓
finds both quality_scores queries — primary and fallback 2.3ms
✓
selection 0 requests turn_id 0.4ms
✓
selection 1 requests turn_id 0.2ms
✓
every field feedback-rca reads off a quality row is in BOTH selections 0.9ms
the write side that was wrongly blamed · 3 tests
✓
captures the turn id SYNCHRONOUSLY, before the detached judge runs 0.4ms
✓
passes it in logApiUsage's turnIdOverride slot, not a meta field 0.3ms
✓
and the SESSION in the 10th slot, captured before the IIFE too (2026-09-24) 0.8ms
src/admin/telemetry-pagination.vitest.ts
drainList · 7 tests
✓
does not query at all when the first page came back short — the only path taken at current volume 3.1ms
✓
keeps paging while pages come back full, and stops on the first short page 0.9ms
✓
advances the offset by a full page each time rather than re-reading page one 1.8ms
✓
stops at the ceiling instead of looping forever on an endlessly-full list 1.1ms
✓
keeps the rows already collected when a later page fails, rather than throwing the lot away 0.7ms
✓
leaves an unknown list untouched rather than guessing a query for it 0.4ms
✓
passes the caller’s window through, so a continuation cannot widen the range 0.4ms
src/admin/telemetry-payload.vitest.ts
trimClientPayload · 7 tests
✓
drops the arrays with no client reader 4.0ms
✓
trims the two arrays the client DOES read to a display window 1.9ms
✓
keeps the NEWEST rows — the arrays arrive created_at desc and both readers show recent items 0.8ms
✓
leaves short arrays alone 0.5ms
✓
declares the window it applied, so the client cannot mistake it for the working set 0.2ms
✓
does not touch the computed aggregates it sits beside 0.5ms
✓
survives a payload missing those keys entirely 0.8ms
src/admin/testomat-freshness.vitest.ts
computeStalenessBreaches · 7 tests
✓
flags a behavior suite (SLA 8d) run 10 days ago, passes one run 3 days ago 2.7ms
✓
uses the newest run in a suite, not the oldest 0.3ms
✓
suite 17 has a tight 2-day SLA (posted daily by the judge cron) 0.3ms
✓
suites 13-16 and 18-24 breach like any other: they have eval rows and ride the weekly rotation (2026-09-15) 1.3ms
✓
a suite that has NEVER run is a breach (age null) 0.3ms
✓
rows without a bracketed suite code are ignored 0.2ms
✓
all-fresh catalog yields no breaches 0.2ms
src/auth/account-export.vitest.ts
handleAccountExport · 4 tests
✓
reads every table scoped by the caller and returns a download 29.5ms
✓
never selects the columns the user role is denied 0.8ms
✓
a table that cannot be read is reported in place, not dropped silently 2.1ms
✓
is rate-limited: over the cap is 429, limiter down is 503 1.1ms
the export never carries a stored credential · 3 tests
✓
replaces every secret field of the sender settings, keeps the rest 0.5ms
✓
leaves every other settings row as it was 0.2ms
✓
a sender row that is not JSON is withheld rather than copied 0.3ms
src/billing/free-tier-aeo.vitest.ts
the free entitlement is affordable on the signup grant · 3 tests
✓
caps 16 prompts to 3 and 4 engines to chatgpt 2.4ms
✓
the capped run clears the affordability gate; the uncapped one never could 0.4ms
✓
and leaves the user enough to do something else afterwards 0.2ms
the picker and the card are capped, not just the dispatch · 4 tests
✓
the quote prices the plan depth, not the raw selection 1.2ms
✓
what gets DISPATCHED is what was priced 0.4ms
✓
the narrowing is DISCLOSED, never silent 1.0ms
✓
a PAID plan is not narrowed 0.9ms
src/billing/run-cap-honesty.vitest.ts
a refusal states the entitlement that bound · 5 tests
✓
names the limit and the tool instead of "your current plan" 1.9ms
✓
says a LIFETIME cap does not reset — the fact that decides what to do next 0.4ms
✓
says WHEN a windowed cap resets, rather than only offering money 0.3ms
✓
still promises a top-up ONLY because the paid plan really has no run cap 0.8ms
✓
degrades to a true sentence when the caller passes no entitlement 0.3ms
the refusal is not printed twice · 2 tests
✓
suppresses the append when the body already IS the offer 5.5ms
✓
still appends for a tool that DELIVERED something and had the rest trimmed 0.4ms
src/billing/silent-handlers-g5c.vitest.ts
R1 — a swallowed KV failure on the auth / money path is reported, the default is unchanged · 2 tests
✓
createPushTicket: a failed ticket write still answers null, and reaches reportSwallowed 5.6ms
✓
hasCostPending: an unreadable cost-gate record still reads as "no card pending", and is reported 1.0ms
R1 — a swallowed promise on the money path is reported · 1 test
✓
sendManualTopupReceipt: a failed receipt send after a credit resolves, and is reported 1.5ms
R2 — an auth failure that ends in an error page is reported · 1 test
✓
maybeHandleAdminGa4OAuthCallback: a failed token exchange still redirects with status=error, and reaches reportError 22.7ms
R3 — a swallowed ledger write is reported · 1 test
✓
runPerfDriftCron: a rejected logApiUsage on a drift row is reported, the cron still returns its drifts 2.4ms
R1 — a stored webhook key that can verify nothing is reported; a garbled signature is not · 2 tests
✓
verifySendGrid: an unimportable stored key still answers false, and reaches onKeyError 4.0ms
✓
verifySendGrid: a caller-supplied signature that is not base64 is refused WITHOUT a report 5.0ms
src/campaigns/draft-grounding.vitest.ts
generate_emails is told what it does NOT know · 5 tests
✓
states that a company name is not knowledge of the company 1.7ms
✓
names the only recipient facts that exist, so "invent nothing" is actionable 0.3ms
✓
closes the specific extrapolations that were observed 0.5ms
✓
offers the honest fallback instead of only prohibiting 0.3ms
✓
grounds claims about OUR product in the sender context too 0.4ms
both drafting prompts carry a grounding rule · 2 tests
✓
the backlink path still has the one it always had 0.2ms
✓
neither prompt block is empty — the slices still find their anchors 0.3ms
src/campaigns/generate-emails-zero.vitest.ts
generate_emails zero outcomes are distinguishable · 4 tests
✓
no contacts resolved → a targeting problem, not a drafting one 1.7ms
✓
contacts resolved but the writer produced nothing → OUR failure, must not read as empty success 0.3ms
✓
drafts produced but none saved → the existing dropped-contacts warning, not a writer failure 0.2ms
✓
partial save is still a success with a shortfall, not a zero 0.2ms
zero-draft message · 3 tests
✓
states the drafting step failed and explicitly clears the list 0.5ms
✓
never tells the user to add or fix contacts 0.3ms
✓
reads correctly for a single contact 0.3ms
src/campaigns/tenant-reference-dispatch.vitest.ts
list_sent_emails (probe d2) · 2 tests
✓
never renders another tenant's contact or campaign through the caller's own send row 10.4ms
✓
a campaign-name filter matches only the caller's own campaigns 1.0ms
launch_campaign (probe d3) · 3 tests
✓
a campaign whose sequence_id names another tenant's sequence enrols nobody into it 1.1ms
✓
control: the tenant's own sequence launches and enrols the tenant's contact 2.0ms
✓
the skill preflight does not price a launch off another tenant's sequence 0.8ms
list membership reads · 2 tests
✓
listMemberContactIds returns only the caller's own contacts, whatever the membership rows name 0.8ms
✓
apifyListCache projects only the caller's own contacts through the list 0.7ms
src/chat/brief-without-site.vitest.ts
briefStatusText: brief with a site · 2 tests
✓
still tells the model not to re-ask — the original behaviour is untouched 1.8ms
✓
gates that instruction on a site actually being known 0.3ms
briefStatusText: brief WITHOUT a site · 4 tests
✓
says the site is missing rather than implying everything is set up 0.2ms
✓
tells the model to proceed with outbound instead of asking for a domain 0.3ms
✓
still allows the ask when a site-scoped tool is the actual request 0.2ms
✓
forbids it as a precondition 0.2ms
the premise that made this reachable · 1 test
✓
the chat shortcut writes a brief without touching __site_url__ 0.8ms
src/chat/call-legs.vitest.ts
promptLegs classifies a wire prompt by leg · 4 tests
✓
first system is the system prompt, later systems are context, last user is the message 2.2ms
✓
tool results and this turn's own tool-call message are counted where they belong 0.6ms
✓
never throws on odd content 0.8ms
✓
the datapoint order is fixed and documented 0.6ms
every agent-loop call site names its reason · 3 tests
✓
first / first_cot / tool_round on the main call, and the three follow-ups 0.7ms
✓
the router writes the reason to the ledger row and the legs to the metric 1.7ms
src/chat/competitor-pick.vitest.ts
isCompetitorGapAsk · 2 tests
✓
recognises the shapes the gap tools answer 2.6ms
✓
leaves everything else alone 0.6ms
competitorPickBackstop · 3 tests
✓
the live [8.2.1] turn: no tool, own site named, four+ saved → four keyword chips 1.3ms
✓
a backlink ask gets the backlink chips 0.3ms
✓
stands down when a tool ran, chips exist, fewer than two are saved, or a rival is named 0.3ms
the chips are the tools' own strings · 2 tests
✓
matches seo/tool-dispatch.ts verbatim 1.9ms
✓
is wired at the end of runChatV2 on no-tool turns 4.4ms
src/chat/diagnose-question-bound.vitest.ts
the bound itself · 4 tests
✓
matches the maxLength the schema actually declares 4.5ms
✓
truncates over-long input and leaves short input untouched 1.3ms
✓
never returns a non-string, whatever it is handed 0.5ms
✓
the real 710-character message that broke it now fits 0.4ms
BOTH producers use the shared bound — neither carries its own literal · 3 tests
✓
the answer-shape shortcut bounds the message 1.0ms
✓
the misroute redirect bounds the message 0.4ms
✓
no producer bounds the QUESTION by its own literal 1.4ms
src/chat/empty-tenant-route.vitest.ts
D1 — the menu shown to an empty tenant · 4 tests
✓
does NOT offer the synthesis chip when nothing has been measured 1.6ms
✓
still offers the two audits that CAN run — the menu is narrowed, not emptied 0.4ms
✓
offers it again the moment there is something to read 0.7ms
✓
does not mutate the shared array — a filtered menu must not shrink the real one 0.2ms
D2 — a deliberate stop is not a use of the allowance · 3 tests
✓
recognises the empty-tenant synthesis return as BLOCKED 0.3ms
✓
still treats a real delivery as a use of the allowance 0.2ms
✓
the refund condition covers blocked runs, not just errors 4.4ms
src/chat/jev-judge.vitest.ts
the shadow verdict · 4 tests
✓
asks a five-band score and one failure mode from the product's own taxonomy 3.5ms
✓
maps the band position onto the judge's 0–1 scale and keeps the taxonomy honest 1.6ms
✓
decides nothing: not rolled out or failed → null → no columns 1.8ms
✓
rides beside the real verdict on both judge paths, conversation turns only 4.8ms
the shadow call is metered to the turn it judged · 3 tests
✓
with a meter: exactly one quality row, op judge_shadow, turn and session passed, no verdict keys 1.7ms
✓
no meter → no row (the verdict is unchanged); Jev failing → no row, and null 1.0ms
✓
the op is a literal on one line, so check-quality-ops can see it; index.ts passes the meter 4.0ms
src/chat/judge-in-loop.vitest.ts
latestLowJudgeVerdict · 2 tests
✓
reads ONE recent low verdict on THIS tenant + session, bounded by score and age 3.7ms
✓
no row, no session, or a failed read all prime nothing 0.6ms
priorVerdictLine · 1 test
✓
states the score and reasoning as ground truth and forbids the repeat 0.5ms
primedTurnsSummary · 1 test
✓
splits judged rows by the ledger mark and averages each side 0.6ms
the loop is wired (source pins) · 3 tests
✓
the v2 handler reads the verdict before composing and passes it into runChatV2 0.8ms
✓
the judged turn is marked in the ledger and on the payload 0.7ms
✓
the digest names today AND the window on the no-renderer line, and reports the loop 0.4ms
src/chat/judge-internal.vitest.ts
the predicate: an account the set names by email is recognised only WITH the email · 4 tests
✓
listed by id: recognised with or without an email 1.9ms
✓
listed by email: recognised from the email, including gmail dot and +tag variants 0.4ms
✓
listed by email, asked by id alone: NOT recognised — the shape of the defect this fixes 0.2ms
✓
(neg) a customer is never ours, with or without an email 0.3ms
the judge samples with the request's own answer · 3 tests
✓
handleChatV2 computes it once, from the email the route passes 0.8ms
✓
both chat-path judge calls pass it, and the sampling site prefers it 1.0ms
✓
(neg) no caller asserts membership: `internal` only ever carries the predicate's answer 2.1ms
src/chat/search-insight.vitest.ts
the two readers agree · 4 tests
✓
a caution produces both a block and an insight, carrying the same sentence 1.9ms
✓
a rationale does the same, and folds whyNow into the body 0.4ms
✓
a rationale WINS over a concern, in both readers 0.2ms
✓
both return nothing when the model said nothing 0.5ms
the subtraction is exact · 3 tests
✓
the block appears verbatim in the formatted message 5.9ms
✓
removing it leaves the rest of the message intact 0.7ms
✓
a message with no note is unchanged by the subtraction 0.3ms
src/chat/shortfall-balance-consistency.vitest.ts
the exact event · 2 tests
✓
the message that fired NQZAI-93 still reads as a contradiction 2.5ms
✓
the same sentence built from the TURN balance does not 0.5ms
one balance per turn, for everything the user reads · 4 tests
✓
runChatV2 pins the turn balance exactly once 2.8ms
✓
the shortfall message prefers it over its own read 0.2ms
✓
but the DECISION still uses the freshest read 0.3ms
✓
falls back to its own read outside a chat turn 0.2ms
the guard itself is untouched · 1 test
✓
tolerance was not widened to make the symptom go away 0.8ms
src/chat/stage5-movement.vitest.ts
a fresh measurement answers the question instead of re-buying it · 5 tests
✓
the snapshot path exists and runs BEFORE the prompt library is built 1.8ms
✓
is bounded to a week — past that, re-measuring is the honest default 0.3ms
✓
an explicit ask for a fresh run skips it entirely 0.9ms
✓
says plainly that nothing was spent, and offers the paid path 0.2ms
✓
reuses the dashboard TL;DR rather than writing a second narration 0.2ms
what the cached answer actually says · 2 tests
✓
leads with movement, which is the whole point of stage 5 0.5ms
✓
still states the sample honestly — a cached number is not a better number 0.3ms
src/chat/starter-chips.vitest.ts
the home-screen starter chips are intents, not prompts · 3 tests
✓
the outbound starter routes to define_icp without the model 5.4ms
✓
the scan starter scans the saved site or asks for one, without the model 1.0ms
✓
the other starters still reach the model — they are open-ended 50.3ms
"Find these leads" carries the ICP's own arguments · 3 tests
✓
is a next_action with the executable arguments, optional axes dropped when silent 1.6ms
✓
does not render on a thin brief or a brief with no buyer 0.2ms
✓
the plain-text twin is gone from the formatter chips 1.0ms
a chip-dispatched tool is quoted from its own arguments · 1 test
✓
next_action_exec passes the arguments to the estimator instead of the catalogue ceiling 0.4ms
src/commerce/merchandising.vitest.ts
computeCoPurchase · 4 tests
✓
counts a pair once per order and gates below MIN_PAIR_ORDERS 2.8ms
✓
too few multi-item orders → insufficient with an honest note, no fabricated pairs 0.9ms
✓
excluded (cancelled/test) orders contribute nothing 0.3ms
rankPromotable · 3 tests
✓
ranks by margin per day — throughput beats rate 0.5ms
✓
no recorded cost → unrankable, never guessed into the ranking 0.4ms
✓
window floor prevents division blowups 0.2ms
src/dashboard/panel-text-guard.vitest.ts
GET /api/dashboard: the "how AI describes you" card · 3 tests
✓
the sentiment model's summary reads as the guardrail leaves it; a theme it would alter is dropped 8.3ms
✓
a key in the summary withholds the card rather than half-showing it 0.9ms
✓
CONTROL: a clean sentiment ships exactly as stored 0.7ms
GET /api/dashboard: a failed engine's error (network-visible, not rendered) · 2 tests
✓
the completeness block carries the module's own sentence, not the provider's words 1.1ms
✓
CONTROL: an engine's plain reason passes as it is 0.7ms
GET /api/dashboard: the pillar cards' advice line · 1 test
✓
a model's advice reads as the guardrail leaves it 1.2ms
the rule itself · 1 test
✓
an instruction recited whole is withheld, not replaced by the guardrail's own sentence 0.5ms
src/db/migration-188-order.vitest.ts
188 alone · 1 test
✓
applies from the before state, verifies itself, and a re-run changes nothing 470.8ms
187 first, then 188 · 3 tests
✓
keeps 187's three columns and replaces only the CHECK 212.4ms
✓
--clear then puts back exactly 187's post-state, columns included 435.4ms
✓
a failed create restores the permission exactly as read, and a re-run resumes 408.0ms
188 first, then 187 · 1 test
✓
after 187 adds its columns on top of 188, a 188 re-run is a no-op and --clear keeps the columns 405.0ms
drift is still a STOP, before anything is written · 2 tests
✓
a partial 187 (one of its three columns) is refused 98.9ms
✓
an unknown column elsewhere is refused 100.2ms
src/db/migration-190.vitest.ts
the two shapes · 2 tests
✓
BEFORE is exactly migration 188's AFTER for the user role's contacts INSERT 5.3ms
✓
AFTER is BEFORE minus the three verification columns, with the same check and preset 2.3ms
190_apply.sh against the stand-in · 5 tests
✓
applies from the before shape, verifies itself, and a re-run changes nothing 409.1ms
✓
--dry-run reports and writes nothing 98.0ms
✓
--clear puts the before shape back 373.8ms
✓
a failed create restores the permission exactly as read, and a re-run resumes 371.3ms
✓
a drifted permission (an extra column) is a STOP before anything is written 95.7ms
src/email/link-guard.vitest.ts
stripUnapprovedLinks · 7 tests
✓
removes the exact hallucinated booking link from the incident 2.1ms
✓
keeps a link we actually supplied 0.3ms
✓
keeps the tenant product URL and drops an invented one in the same body 0.3ms
✓
strips every URL when nothing is approved 0.3ms
✓
tidies the dangling punctuation the removed link left behind 0.2ms
✓
leaves a link-free body untouched 0.3ms
✓
is not fooled by trailing punctuation on an approved link 0.3ms
src/email/recipient.vitest.ts
extractRecipientAddress · 5 tests
✓
finds the address in the prompts that mis-targeted 2.2ms
✓
returns '' for the send-my-drafts phrasings that must keep falling back 0.6ms
✓
lowercases so the refusal echoes a canonical address 0.2ms
✓
takes the first address when several are named 0.2ms
✓
handles plus-addressing and dotted local parts 0.2ms
adHocRecipientRefusal · 2 tests
✓
names the address and states nothing was queued 0.4ms
✓
never implies emails were sent 0.3ms
src/email/send-ceiling-parity.vitest.ts
send paths share one hourly ceiling · 7 tests
✓
campaign tool (the original) calls checkSendRateLimit 1.8ms
✓
REST bulk send (handleEmailSend) calls checkSendRateLimit 0.3ms
✓
single draft send (handleSendSingleEmail) calls checkSendRateLimit 0.2ms
✓
REST bulk send sizes the ceiling from effectiveSendLimits, not a local constant 0.3ms
✓
single draft send sizes the ceiling from effectiveSendLimits, not a local constant 0.2ms
✓
the single-send path bills platform_send 0.2ms
✓
the single-send path opens a billing window so the fee lands on this user 0.4ms
src/email/tenant-reference-scope.vitest.ts
open pixel (probe d4) · 2 tests
✓
an open on tenant A's send does not advance tenant B's contact the send row names 6.3ms
✓
control: an open on a send to the tenant's own contact advances it 1.3ms
bounce recorder (probe d5) · 2 tests
✓
a hard bounce on tenant A's send does not stop tenant B's enrolment 2.3ms
✓
control: a hard bounce on a send to the tenant's own contact stops the tenant's own enrolment 1.5ms
draft writer (probe d8) · 3 tests
✓
drops another tenant's contact id, keeping positions aligned 1.7ms
✓
files nothing under another tenant's campaign 1.3ms
✓
control: the tenant's own campaign is kept 0.6ms
src/guard-proofs/check-audit-freeze.vitest.ts
check-audit-freeze — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (no tool added during the audit)) · 7 tests
✓
the unmutated sandbox exits 0 88.4ms
✓
AF-1: exits 1 naming the violation — a new LLM-exposed tool is registered during the freeze (the real defect) 84.5ms
✓
AF-2: exits 1 naming the violation — an executable tool is renamed in its dispatcher (a rename counts as an addition) 85.5ms
✓
AF-3: exits 1 naming the violation — the frozen baseline is edited to admit a name without an owner exception entry 86.1ms
✓
AF-4: exits 1 naming the violation — a tool whose name carries a digit is added on BOTH sides during the freeze 86.6ms
✓
AF-5: exits 1 naming the violation — a name is slipped in as a "baseline correction" with no evidence it existed at the baseline commit 80.8ms
✓
every mutant was restored: the sandbox exits 0 again 83.5ms
src/guard-proofs/check-keyword-attribution.vitest.ts
check-keyword-attribution — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (behaviour per property; volume per keyword)) · 7 tests
✓
the unmutated sandbox exits 0 390.1ms
✓
KA-1: exits 1 naming the violation — the planner reads position/impressions off the tenant-wide tracked_keywords registry (the 2026-08-02 merge) 378.1ms
✓
KA-2: exits 1 naming the violation — the volume cache read is filtered by site, so every extra property re-buys volume already paid for 387.6ms
✓
KA-3: exits 1 naming the violation — the keyword-vs-prompt read of keyword_site_performance drops its site filter (all properties merged) 387.8ms
✓
KA-4: exits 1 naming the violation — fetchSitePerformance's requirePositive branch (an interpolated where-clause) loses its site filter 384.5ms
✓
KA-5: exits 2 naming the violation — a table rename leaves the guard matching zero keyword_site_performance reads — it must say it is blind, not OK 378.6ms
✓
every mutant was restored: the sandbox exits 0 again 380.7ms
src/guard-proofs/check-preflight-gates.vitest.ts
check-preflight-gates — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (tool intelligence layer, five rulings)) · 7 tests
✓
the unmutated sandbox exits 0 76.4ms
✓
PG-1: exits 1 naming the violation — a new cost gate is added that never runs preflightForGate 83.3ms
✓
PG-2: exits 1 naming the violation — ENRICH_MAX_PER_CALL raised to 50 — enrich_contacts can now reach the gate its exemption says it never reaches 71.8ms
✓
PG-3: exits 1 naming the violation — the gate's chips are no longer re-applied after the capability payload is assigned over the response 82.1ms
✓
PG-4: exits 1 naming the violation — an exemption marker names send_emails, which has an assessor — a claim that has expired 81.0ms
✓
PG-5: exits 1 naming the violation — the send confirm stops reading the outcome slot — a warning shown there can never be scored 72.9ms
✓
every mutant was restored: the sandbox exits 0 again 68.8ms
src/guard-proofs/check-provider-registry.vitest.ts
check-provider-registry — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (provider truth; closed rulings) + CLAUDE.md §11) · 7 tests
✓
the unmutated sandbox exits 0 646.0ms
✓
PR-1: exits 1 naming the violation — an API_COST key is added that no capability and no retirement classifies 651.5ms
✓
PR-2: exits 1 naming the violation — a live call site is pointed back at the retired SearchApi SERP key (a migration that did not finish) 646.7ms
✓
PR-3: exits 1 naming the violation — backlink_outreach_search is quoted against the retired supplier again (the recorded incident) 656.2ms
✓
PR-4: exits 1 naming the violation — the SERP client is pointed back at the retired SERP ledger key (2026-10-31, DECISIONS #125) 643.3ms
✓
PR-5: exits 1 naming the violation — the SERP client calls the retired SERP endpoint again, under any ledger name 640.8ms
✓
every mutant was restored: the sandbox exits 0 again 647.0ms
src/guard-proofs/check-report-families.vitest.ts
check-report-families — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (one family, one renderer; §7 provider scale)) · 7 tests
✓
the unmutated sandbox exits 0 445.7ms
✓
RF-1: exits 1 naming the violation — seo_backlinks gets its own case block again — the 2026-08-12 two-shape family 454.6ms
✓
RF-2: exits 1 naming the violation — seo_backlink_deep_scan, mid-group, is split into its own renderer 437.2ms
✓
RF-3: exits 1 naming the violation — the backlink summary emits Math.round(rank / 10) as domain_authority again — the 2026-08-12 line 469.3ms
✓
RF-4: exits 1 naming the violation — the SERP competitors' authority is the provider's domain_rank, unrescaled (found live 2026-10-30) 439.4ms
✓
RF-5: exits 1 naming the violation — a report renderer bands a row's provider rank as authority inside a template literal 717.6ms
✓
every mutant was restored: the sandbox exits 0 again 722.0ms
src/guard-proofs/check-tenant-scoping.vitest.ts
check-tenant-scoping — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (user_id on every data-plane query)) · 7 tests
✓
the unmutated sandbox exits 0 152.2ms
✓
TS-1: exits 1 naming the violation — the pre-fix P1-06-F08 recipient lookup is re-added to the inbound handler: selects user_id, filters on nothing 142.7ms
✓
TS-2: exits 1 naming the violation — the contacts-by-id read in the lists route loses its user_id filter 143.2ms
✓
TS-3: exits 1 naming the violation — the contacts upsert targets the GLOBAL email key again — a second tenant's save overwrites the first's row (migration 005's bug) 139.3ms
✓
TS-4: exits 1 naming the violation — a new migration adds a unique index on contacts(email) alone 140.7ms
✓
TS-5: exits 1 naming the violation — a new migration drops the per-tenant key every upsert targets 142.5ms
✓
every mutant was restored: the sandbox exits 0 again 142.0ms
src/guard-proofs/check-tool-registry.vitest.ts
check-tool-registry — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (own money in real currency; audit freeze definition)) · 7 tests
✓
the unmutated sandbox exits 0 48.4ms
✓
TR-1: exits 1 naming the violation — commerce_profitability (tenant revenue) is dropped from TENANT_CURRENCY_TOOLS 46.1ms
✓
TR-2: exits 1 naming the violation — a new executable planner tool is added with no V2_TOOLS entry — the model cannot reach it 42.2ms
✓
TR-3: exits 1 naming the violation — show_marketing_plan keeps its V2_TOOLS entry but loses its executor — "tool not found" at runtime 44.2ms
✓
TR-4: exits 1 naming the violation — a new executable tool whose name carries a digit is added with no V2_TOOLS entry 43.3ms
✓
TR-5: exits 1 naming the violation — a digit-named tool is exposed to the model with no executor behind it 45.5ms
✓
every mutant was restored: the sandbox exits 0 again 43.8ms
src/leads/brief-derivation-gate.vitest.ts
saveProductBrief derivation gate · 7 tests
✓
agrees with isSubstantiveBrief about the two fixtures 2.6ms
✓
derives NOTHING from the one-line brief the incident produced 3.6ms
✓
still saves the brief and the site — a name is real information 0.5ms
✓
still populates onboarding keywords — those read the SITE, not the brief 1.5ms
✓
derives normally from a real brief 2.0ms
✓
honours an explicit allowDerived:false even on a substantive brief 1.4ms
✓
defaults to deriving when no option is passed — the Product panel is unaffected 1.6ms
src/leads/compact-context-budget.vitest.ts
a line that does not fit no longer ends the brief · 2 tests
✓
the lines AFTER an overflowing one still reach the brief — including the capability line 3.6ms
✓
a scalar that cannot fit is skipped whole, and the lines after it still come 0.9ms
breadth before depth · 3 tests
✓
every list gets its first item before any list gets a second 0.5ms
✓
extra room is shared round-robin in priority order, not handed to the first long list 1.0ms
✓
a profile that fits whole is rendered whole — no marker, nothing reordered 0.9ms
never a mid-line cut, never over the cap · 2 tests
✓
a cut list is cut between whole items and says so with "…" 1.9ms
✓
holds the cap and the priority order at every budget 22.7ms
src/leads/corpus-coverage.vitest.ts
corpus coverage vs a dropped filter · 7 tests
✓
reaches the user when the corpus returned nothing and nothing outranks it 1.7ms
✓
does NOT claim the filter was ignored 0.6ms
✓
still says nothing about industry or company size as UNAPPLIED filters 0.4ms
✓
yields to a more specific explanation rather than stacking on it 0.2ms
✓
does not promise results the user cannot see 0.4ms
✓
reads as a sentence when appended after a full stop 0.5ms
✓
stays silent once results were actually delivered 0.7ms
src/leads/lead-count-honesty.vitest.ts
the requested count is honoured on delivery · 2 tests
✓
the people-search branch slices to meta.limit, like the gmaps branch 1.8ms
✓
the gmaps branch still slices too 0.3ms
one run reports one set of numbers · 1 test
✓
the poll path forwards saved instead of dropping it 0.5ms
a green tick means we checked it · 3 tests
✓
the API sends verified_source so the client can tell a claim from a verdict 0.3ms
✓
the list UI ticks only an api-sourced valid, never a provider claim 0.3ms
✓
a provider claim still renders, just not as a verdict 0.3ms
outbound verification is strict · 1 test
✓
every verifyEmail call that stamps verified_source api is strict 0.5ms
src/middleware/next-action-chips.vitest.ts
search_leads chips · 5 tests
✓
offers drafting when leads were actually saved 3.3ms
✓
does NOT point at existing contacts when the search found nothing 0.4ms
✓
offers nothing at all on a zero-result turn rather than something backward-pointing 0.2ms
✓
still offers review once there is something to review 0.4ms
✓
drops drafting when ids are absent even though leads were found 0.3ms
campaign_stats chips · 2 tests
✓
resolves the campaign id from the flat sibling, not by walking the name 0.3ms
✓
regression: walking into the name yields nothing 0.4ms
src/middleware/tool_adapter.vitest.ts
tool_adapter — extractToolCallFromText · 7 tests
✓
extracts a JSON tool call 1.5ms
✓
extracts the first valid JSON tool call 0.3ms
✓
trims the JSON tool name 0.2ms
✓
extracts an XML tool call 0.5ms
✓
extracts a longcat tool call without a closing tag 0.2ms
✓
rejects an unsafe tool name 0.1ms
✓
ignores plain text 0.2ms
src/reports/article-market-currency.vitest.ts
a saved article keeps its market prices · 7 tests
✓
the tenant's price stays as written (real seo_write_content HTML) 38.1ms
✓
a supplier named in the article is still replaced 25.1ms
✓
a "free" claim in the article is still rewritten 1.3ms
✓
a recited instruction in the article is still removed 1.5ms
✓
a key in the article still blocks the whole artifact 0.8ms
✓
every other report keeps the currency rule 2.4ms
✓
the article tools are exactly the document writers 0.7ms
src/reports/offpage-report.vitest.ts
seo_offpage_audit — §17 gold standard · 7 tests
✓
renders a signal bento with fix-prompt cards, grouped by directive 2.2ms
✓
has plain section headers (no "Cluster N"), a feedback mount, and no fabricated sparklines 0.7ms
✓
healthy authority renders green cards with no fix buttons 0.6ms
✓
classifies anchor risk as Fix, authority as Understand — never the other way round 0.9ms
✓
does not repeat one referring domain ten times in a "top links" table 0.6ms
✓
rounds an estimated traffic figure — no thousandths of a visit 0.5ms
✓
never calls a wide, shallow link profile "solid" 0.7ms
src/routes/campaign-stats-coverage.vitest.ts
coverageForCampaignStats · 7 tests
✓
empty audience → names the missing-audience reason, not "underperformed" 2.2ms
✓
has audience but not launched → explains the 0s are pre-launch 0.6ms
✓
launched but nothing sent → points at cadence/window, not recipient behavior 0.4ms
✓
live with replies → grounds insight in the actual rates 0.4ms
✓
a structural zero gets a structural next step, never a copy rewrite 0.7ms
✓
never reports sending activity for a campaign that has sent nothing 0.3ms
✓
opens but no replies → advises body/CTA, not subject success 0.3ms
src/routes/csp-report.vitest.ts
summariseCspReport · 3 tests
✓
keeps origins and paths, drops query strings (legacy shape) 2.1ms
✓
reads the Reporting API array shape 1.2ms
handleCspReport · 3 tests
✓
always answers 204, logs one structured line, and dedupes repeats 26.8ms
✓
answers 204 to malformed and oversized bodies without logging 1.3ms
✓
caps logging per minute 9.9ms
policies point at the endpoint · 1 test
✓
public pages send report-uri 0.3ms
src/routes/meta-budget.vitest.ts
public page meta budgets · 7 tests
✓
every serve* export either renders or is a declared machine format 433.1ms
✓
every page has a non-empty title and description 39.0ms
✓
no title exceeds 60 characters 32.6ms
✓
no description exceeds 160 characters 34.9ms
✓
every robots directive is the shared constant, never a hand-written copy 35.6ms
✓
no page leaks a robots directive into its visible text 36.5ms
✓
no page ships another page's title — a copied template that was never retitled 33.8ms
src/runtime/cron-checkin-honesty.vitest.ts
cron check-ins report what the run did · 7 tests
✓
reads its inputs (a matrix that finds nothing is green for the wrong reason) 2.5ms
✓
every registered monitor is exercised by a wrangler cron 1.1ms
✓
the dispatcher never rejects, whatever fails 0.3ms
✓
FAILURE: when every read fails, no monitored job checks in ok 0.9ms
✓
FAILURE: every job whose check-in is an error has a Sentry event from the dispatcher catch 0.5ms
✓
CONTROL: when every read succeeds with nothing to do, every monitored job checks in ok 0.5ms
✓
CONTROL: the coverage refresh resolved because it did its work, not because it gave up 0.3ms
src/runtime/guardrail-error-class.vitest.ts
a provider error echoed into a reply carries no code and no class in parentheses · 7 tests
✓
the two R2-01 strings, through the backlink formatter and the outbound rewrite 9.7ms
✓
every class the provider classifier can write, after every code shape the rewrite knows 3.3ms
✓
a model quoting the code after the rewrite — "a temporary error (quota)" — loses the class too 0.3ms
✓
a snake_case class aside is never English, so it drops wherever it lands 2.0ms
✓
our own prose is untouched: "(a temporary error)" we wrote, and an English word in parentheses 0.4ms
✓
the class list is the classifier's: provider-failure.ts ProviderErrorClass, read from source 0.4ms
✓
no class aside survives in any of the 28 formatter echo sites fed a classified SERP error 5.0ms
src/runtime/refund-sites-guard.vitest.ts
a refund decision consults the shared yield rule · 3 tests
✓
passes on the current tree 51.4ms
✓
catches a refund site that stops consulting the yield rule 113.2ms
✓
catches a stage-state decision that ignores BLOCKED 117.3ms
what it deliberately does NOT assert · 2 tests
✓
a relay is not a decision — copying a verdict does not have to re-consult the rule 109.8ms
✓
but a NEW decision outside any window is caught 107.8ms
it refuses to certify a file it no longer understands · 2 tests
✓
fails when the refund matcher stops matching, rather than reporting zero sites as OK 89.1ms
✓
is wired into the gate 0.3ms
src/runtime/request-scope.vitest.ts
two requests interleaved in one isolate · 3 tests
✓
each reads back its own identity after the other wrote between its awaits 4.8ms
✓
work a request leaves running (waitUntil, background writes) keeps that request's context 0.7ms
✓
a new request starts clean, never with the previous request's leftovers 0.5ms
the view is transparent · 2 tests
✓
outside any request it is the one module object it always was 0.4ms
✓
in, keys, spread and delete resolve against the current request 1.0ms
what keeps it safe · 2 tests
✓
every initial value is a primitive or null, so no two requests share a nested object 0.3ms
✓
every Worker entry point enters a request scope first: fetch, scheduled, queue, email 6.5ms
src/runtime/tool-call-limit.vitest.ts
checkToolCallLimit · 3 tests
✓
counts up to the cap, then refuses 2.5ms
✓
scopes per user and per tool — one user cannot spend another's allowance 0.5ms
✓
is inactive when KV is unbound 0.2ms
refundToolCallLimit · 2 tests
✓
gives back exactly one allowance 0.6ms
✓
never drives the counter below zero 0.5ms
peekToolCallLimit · 1 test
✓
reads without incrementing 0.4ms
checkToolCallLimit when KV throws · 1 test
✓
refuses, and says the limiter is unavailable rather than that the cap was hit 1.3ms
src/seo/keyword-rivals.vitest.ts
fetchKeywordRivals · 7 tests
✓
scopes to ONE of the tenant's properties 3.1ms
✓
normalises the site, so a stored URL or sc-domain: property still matches 0.5ms
✓
orders rivals by real SERP position, not by whatever the DB returned 0.4ms
✓
keys case-insensitively so the panel join cannot miss on casing drift 1.0ms
✓
collapses the time series to the latest observation per rival 0.5ms
✓
returns an empty map for a tenant with no site rather than querying 0.3ms
✓
degrades to no-rivals on a failed read, and reports it 0.7ms
src/seo/provider-authority.vitest.ts
the provider never rescales its internal rank into an authority score · 4 tests
✓
does not divide rank by ten anywhere 1.9ms
✓
passes the rank through under a name that says what it is 0.4ms
✓
leaves site authority NULL rather than filling it from the rank 0.3ms
✓
reads the free rating service for the off-page audit 0.4ms
an unmeasured authority is dropped from the off-page score, not scored as zero · 3 tests
✓
gates the authority component on the value being measured 0.3ms
✓
rescales the remaining components so a data gap is not a penalty 0.3ms
✓
applies penalties AFTER the rescale, so they are not inflated with it 0.5ms
src/leads/shared/email-pattern.vitest.ts
email pattern inference · 7 tests
✓
recognises each of the seven measured shapes 3.0ms
✓
reproduces the two domains measured on the real corpus 1.3ms
✓
returns null rather than a weak pattern — the common, correct outcome 0.4ms
✓
excludes role accounts from BOTH numerator and denominator 0.3ms
✓
refuses names that cannot support a first/last pattern 0.3ms
✓
is deterministic on ties so re-running does not rewrite rows 0.3ms
✓
builds a candidate from a stored recipe, and refuses an unknown one 0.3ms
ingest.vitest.ts
Core
7 /7
19ms · 1 suite
PASS
src/leads/shared/ingest.vitest.ts
shared-leads ingest contracts · 7 tests
✓
admits policy-approved US rows and normalizes them 13.5ms
✓
blocks disabled/disallowed sources before payload admission 1.0ms
✓
rejects rows whose country contradicts their own batch, and invalid timestamps 0.5ms
✓
admits a non-US row when the SOURCE is scoped to that country 2.2ms
✓
still refuses a country the source is NOT scoped for 0.2ms
✓
defaults a row with no country to its batch country, rather than to US 0.6ms
✓
hashes canonical content deterministically and has a known SHA-256 output 0.8ms
scripts/lib/probe-outcome.vitest.mjs
isUnproductiveCode · 6 tests
✓
treats no response at all as unproductive 1.9ms
✓
treats 4xx deferrals as unproductive — the defect this file exists for 0.4ms
✓
treats definitive answers as productive, whether valid or invalid 0.5ms
✓
accepts numbers and strings identically 0.2ms
✓
matches migration 122 SQL exactly across every code that can reach the column 0.7ms
✓
normalizeCode keeps the empty string out of provider_code entirely 0.3ms
src/admin/gsc-staleness.vitest.ts
isCoverageStale · 6 tests
✓
is stale when there is no cached timestamp at all (first load ever) 1.8ms
✓
is stale when the cached timestamp is unparseable 0.3ms
✓
is NOT stale within the 24h window — reproduces the exact live bug value would be false either way, this asserts the window is honored 0.3ms
✓
IS stale past the 24h window — this is the live production case: cache sat at 2026-07-19 while today is 2026-08-16, ~28 days old 0.2ms
✓
flips exactly at the boundary 0.2ms
✓
respects a custom staleMs override 0.3ms
src/admin/gsc-window.vitest.ts
adminGscWindow · 4 tests
✓
covers exactly N dates — the old UTC window covered N + 1 ("28d" was 2026-08-26 → 2026-09-23) 16.4ms
✓
ends on TODAY IN PACIFIC TIME — at 03:29 UTC it is still yesterday in California 0.4ms
✓
is unaffected by the DST change inside the window (dates, not hours) 0.4ms
✓
clamps nonsense to one day rather than an empty or inverted window 0.4ms
date helpers · 2 tests
✓
addDays crosses month and year ends 0.3ms
✓
dateInZone renders the calendar date in the zone, not in UTC 0.5ms
src/admin/issues-are-faults-only.vitest.ts
the admin panel does not report itself to the system it is reading · 3 tests
✓
every Sentry-API read failure goes to Logs, not Issues 2.5ms
✓
they stay VISIBLE — suppressed is not the same as silenced 0.3ms
✓
real faults elsewhere in this file still use reportError 0.2ms
an expected boot state is not filed at all · 3 tests
✓
the no-session 401 is MARKED, not merely named 0.7ms
✓
the reporter skips it, and only it 0.3ms
✓
the tile still degrades honestly for the user 0.2ms
src/admin/provision-verified.vitest.ts
it calls the real function, not a copy · 2 tests
✓
delegates to ensureVerifiedUserProvisioning 1.9ms
✓
does NOT re-implement the grant or the email 0.5ms
the verification gate survives · 3 tests
✓
passes the user REAL emailVerified, never a hardcoded true 0.2ms
✓
refuses an unknown user or one with no email 0.3ms
✓
the gate it relies on still checks app-verification independently 0.3ms
safe to run twice · 1 test
✓
the grant and the welcome are both idempotent upstream 0.3ms
src/admin/signup-digest.vitest.ts
signupDigestLines · 6 tests
✓
counts real signups only, the silent ones, and the flagged ones; flagged lines first 3.6ms
✓
the 09-15 defect is detected structurally: a confirm card ran 3 tools and the reply showed 1 0.5ms
✓
names the tools with counts, the not-ok runs, the low judge scores, spend, purchases and audits 0.5ms
✓
[fail-first] "spent" is what the signup was charged: failover attempts and redelivery repeats stay out (V10-money2 sweep) 0.7ms
✓
renders as a section with the three counts 0.5ms
✓
is wired into the daily judge report 0.6ms
src/admin/user-verified.vitest.ts
user-verified · 6 tests
✓
treats a __app_email_verified__ row with a JSON instruction as verified 1.9ms
✓
builds the app-verified id set, ignoring empty-instruction rows 0.5ms
✓
is verified when the app flag is set even though Nhost emailVerified is false (the bug) 0.2ms
✓
is verified when Nhost emailVerified is true even without the app flag 0.2ms
✓
is unverified only when neither source says so 0.3ms
✓
card and list agree for the same inputs (no drift) 0.2ms
src/auth/account-export-vendor.vitest.ts
the account export: no supplier and no cost of nqzai's, every row of the tenant's · 6 tests
✓
selects no column that carries nqzai's cost or a supplier's identity 2.4ms
✓
exports snapshots with their summary; seo_snapshots data only through its per-type allow-list (export-snapshot.vitest.ts) 1.5ms
✓
a supplier's name as provenance is relabelled to the operation that wrote it; the row and its data stay 25.5ms
✓
CONTROL: the tenant's own data shows as it is — their contacts, their market metrics, their own search words 2.2ms
✓
nothing in the file names the model router, the connect bridge or a provider cost 1.0ms
✓
a table that could not be read says so, without the database client's own error text 3.0ms
src/auth/export-snapshot.vitest.ts
seo_snapshots in the export: the tenant's figures stay, our suppliers and costs go · 6 tests
✓
the tenant's own Analytics snapshot exports whole, revenue and pages included 30.1ms
✓
an audit of their own site keeps its findings and loses the supplier behind them 1.5ms
✓
an AI-visibility run keeps its measurement and loses the cost, the raw errors and the model slugs 1.3ms
✓
a wholly-own snapshot keeps every figure, and a raw engine error nested anywhere in it still goes 0.9ms
✓
a snapshot kind the allow-list does not name exports its summary and no data 1.5ms
✓
CONTROL: every row stays, with its summary columns 0.8ms
src/auth/resend-after-failed-send.vitest.ts
V12-edge-F02: a resend after a FAILED sign-up mail sends, inside the same window · 4 tests
✓
the provider refuses the sign-up mail; Resend 1 s later delivers a real mail 14.7ms
✓
if the resend fails too, the person reads a plain-words refusal, never "sent" 2.5ms
✓
control: after a SUCCESSFUL send, a second send under the key still dedupes (no second mail) 2.4ms
✓
control: a send still in flight (queued) holds the key against a concurrent duplicate 0.7ms
the sweep: every reader of a transactional dedupe key ignores failed rows · 2 tests
✓
a failed holder under any caller key is released and the send goes out, not faked 1.2ms
✓
the welcome pre-check (ExistingSignupWelcome) does not count a failed welcome as sent 0.9ms
src/auth/signup-server-events.vitest.ts
captureSignupAttribution + ensureVerifiedUserProvisioning — server-side signup events · 6 tests
✓
captures at signup, fires GA4 MP and the DataFast goal exactly once at grant time 31.7ms
✓
fires correctly even when the grant is triggered by a DIFFERENT request than signup (the actual bug) 5.3ms
✓
does not fire twice — a second grant after the bonus is already granted is a no-op 1.1ms
✓
skips silently when the secrets are unset 1.7ms
✓
skips silently when neither cookie was present at signup 1.4ms
✓
never throws when GA4/DataFast fetches fail — signup provisioning must not depend on either 9.8ms
src/auth/verify-provisioning.vitest.ts
the verify endpoint provisions · 2 tests
✓
calls ensureVerifiedUserProvisioning after writing the verified flag 1.9ms
✓
a provisioning failure cannot break a SUCCESSFUL verification 0.3ms
calling it from BOTH paths stays safe · 3 tests
✓
the grant checks for an existing row before inserting 0.2ms
✓
the welcome email is deduped per user 0.3ms
✓
the bootstrap path is untouched — it simply finds the work done 0.3ms
the grant is still gated on actually being verified · 1 test
✓
an unverified user provisions nothing 0.3ms
src/billing/per-tool-llm.vitest.ts
per-tool LLM term · 6 tests
✓
is declared on the tools that have a measured sample, and nowhere else 2.4ms
✓
is folded into costOfCall, which is what makes it reach BOTH surfaces 1.1ms
✓
comes from the TABLE even for tools that have a dynamic estimator 0.4ms
✓
NO TOOL CROSSES THE GATE because of its LLM term — the claim, proved not asserted 0.9ms
✓
search_leads does not double-count its floor, and no longer carries a hand-typed guess 0.3ms
✓
a tool with no measured sample is left alone, not estimated 0.2ms
src/billing/stripe-foreign-session.vitest.ts
a paid session that is not ours · 6 tests
✓
is classified before any money moves 1.9ms
✓
does not decide ownership from metadata a sibling product also sets 0.5ms
✓
sends a foreign session to LOGS, never to the Issues stream 0.2ms
✓
does not go silent on a foreign session 0.3ms
✓
still pages when a session IS ours and cannot be credited 0.3ms
✓
the error a human reads carries what reconciliation needs 0.3ms
src/chat/finalising-step.vitest.ts
the closing step · 6 tests
✓
carries the finalising flag so settle completes it instead of staling it 4.3ms
✓
survives the guardrail scan with its label intact — the flag keys off that label 0.6ms
✓
never flags an ordinary step 0.5ms
✓
names the work rather than the wait — no fake-progress copy 0.5ms
✓
is user-facing copy: no vendor name, no USD figure (CLAUDE.md §4) 0.3ms
✓
keeps ordinary phase projection unchanged — group, elapsed and details still ride 1.2ms
src/chat/find-ask.vitest.ts
the shape of a find-new-people ask · 5 tests
✓
a find verb with a count or a place 3.5ms
✓
owned-inventory wording is never a find ask 0.5ms
✓
the platform's own artefacts are not people 0.3ms
✓
a bare find with no count and no place stays with the intent router 0.3ms
✓
only fires when list_contacts was chosen alone 0.3ms
the loop redirects at the chokepoint, before the cost gate · 1 test
✓
rewrites the call to search_leads with arguments from the same builder the lead chip uses 0.8ms
src/chat/frame-fields-guard-exits.vitest.ts
agent loop: the evidence list carries only hosts the guardrail would show · 1 test
✓
a supplier's host the answer named never reaches the list, though the message was rewritten 215.6ms
agent loop: the cost card's advisory line and chip meet the guardrail · 1 test
✓
the audience-fit assessor's own words never reach the card 38.0ms
GET /api/plan/html: the plan panel reads the guardrail's copy · 1 test
✓
the plan's model-written text never reaches the panel raw; the rest of the plan does 12.3ms
GET /api/chat/quality: the browser gets the score, never the judge's words · 1 test
✓
the reasoning stays on the row 3.5ms
a database failure names no vendor (DECISIONS #55) · 2 tests
✓
GET /api/sequences: the error the panel shows does not name the database 10.9ms
✓
nhostGraphQL itself: both failures open with the neutral prefix 3.1ms
src/chat/picker-turns-not-failures.vitest.ts
arming a picker marks the turn · 3 tests
✓
setPendingPicker records it — the one call every picker makes 2.5ms
✓
and it is recorded BEFORE the KV write, which can be skipped 0.4ms
✓
the flag resets per request 0.4ms
and a picker turn is not judged as a failed answer · 3 tests
✓
isGateTurn includes pickerArmed alongside the three typed fields 1.1ms
✓
the three original terms survive — this is an addition, not a swap 0.6ms
✓
a gate turn that PRODUCED something is still judged 0.2ms
src/chat/write-article-args.vitest.ts
write_article shortcut → seo_write_content arguments · 6 tests
✓
seo_write_content is enforced at dispatch (so an undeclared field is a rejection, not a no-op) 1.8ms
✓
"write a 700-word article about pricing pages for acme.com" validates — including when a domain is named 1.8ms
✓
"write a blog post about programmatic SEO on nqz.ai" validates — including when a domain is named 0.5ms
✓
"draft me an article on cold email deliverability" validates — including when a domain is named 0.2ms
✓
carries the parsed keyword and word count, and no site 0.4ms
✓
the shortcut in src/index.ts passes writeArticleArgs(message) — the wiring, not just the function 4.4ms
src/commerce/commerce-availability.vitest.ts
one switch, every surface · 3 tests
✓
the UI banner is present exactly when the module is under review 2.0ms
✓
the model is told not to offer store features while it is under review 0.7ms
✓
the banner copy and the chat copy say the same thing 0.7ms
the tool result is a soft outcome, not an error · 3 tests
✓
carries a message rather than an error 0.3ms
✓
names the tool that was asked for, so the turn can be traced 0.2ms
✓
does not blame the store platform or promise a date 0.4ms
sync.vitest.ts
Core
6 /6
4ms · 2 suites
PASS
src/commerce/sync.vitest.ts
(top level) · 1 test
✓
order queries request no customer-identifying fields 2.0ms
sync GraphQL documents are structurally balanced · 5 tests
✓
BULK_PRODUCTS_QUERY 0.6ms
✓
RECON_PRODUCTS_QUERY 0.4ms
✓
PRODUCT_REFETCH_QUERY 0.2ms
✓
RECON_ORDERS_QUERY 0.2ms
src/db/nhost-error-attribution.vitest.ts
every Nhost failure knows which query it was · 6 tests
✓
names the operation for the real query shapes this repo sends 2.0ms
✓
degrades to "anonymous" rather than throwing on an unnamed query 0.3ms
✓
the HTTP failure carries it 0.3ms
✓
the GraphQL-errors failure carries it too 0.3ms
✓
the MESSAGE is unchanged, so one outage stays one issue 0.4ms
✓
reportError promotes it to a tag 0.3ms
src/email/domain-readiness.vitest.ts
parseDkimSelectorResult · 6 tests
✓
finds a standard v=DKIM1 record 2.2ms
✓
finds a record with no v= tag — RFC 6376 makes it optional, p= alone still counts 0.4ms
✓
treats an empty p= as a REVOKED key, not a missing one — a different, intentional state 0.2ms
✓
reports not-found on an empty TXT set (the common case — selector unused) 0.2ms
✓
does not mistake an unrelated TXT record for a DKIM key 0.3ms
✓
has a real selector list to probe, not an emptied one 0.3ms
src/email/gmail-one-at-a-time.vitest.ts
gmail-send disabled — feature flag · 1 test
✓
isGmailSendEnabled() is false (scope removed from verification) 1.2ms
gmail-send disabled — resolvesToGmail never resolves to Gmail · 2 tests
✓
is false even when the caller explicitly asks for channel:gmail 0.6ms
✓
is false even when a Gmail identity is connected and no SMTP is configured 0.2ms
gmail-send disabled — sendEmail never hits the Gmail API · 2 tests
✓
with channel:gmail but no SMTP: no Gmail network call, returns a BYOK-required error 1.1ms
✓
automated/drip send (disallowGmail) with a stale Gmail connection makes no Gmail call 0.4ms
SMTP provider resolution still works · 1 test
✓
getConfiguredSmtpProvider returns null when no __smtp__ row exists 0.3ms
src/email/send-failure-reason.vitest.ts
humanizeSendFailure · 6 tests
✓
the live [2.4.2] body: provider JSON becomes a sentence with no vendor voice 2.0ms
✓
known shapes map; unknown shapes keep the message minus URLs and asides 3.5ms
✓
never says "it will be retried" 0.6ms
✓
drops an internal code prefix but keeps its sentence 2.1ms
✓
reads a per-message refusal one level down, never shows the JSON 1.0ms
✓
is the reason the send path records 1.2ms
src/guard-proofs/check-graphql-seams.vitest.ts
check-graphql-seams — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (fail closed on auth)) · 6 tests
✓
the unmutated sandbox exits 0 162.3ms
✓
GS-1: exits 1 naming the violation — a new tenant read calls the dual seam with no token, so it runs as admin past RLS 114.5ms
✓
GS-2: exits 1 naming the violation — the list-membership write drops its userToken (silent admin default) 112.8ms
✓
GS-3: exits 1 naming the violation — the draft-edit write drops its userToken from a call whose vars object has four keys 133.3ms
✓
GS-4: exits 1 naming the violation — a multi-line tenant read with a trailing comma and no token (formatter style) 114.2ms
✓
every mutant was restored: the sandbox exits 0 again 155.7ms
src/guard-proofs/check-product-invariants.vitest.ts
check-product-invariants — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (tokens not USD · no vendor names · in-chat delivery · BACKGROUND_TOOLS)) · 6 tests
✓
the unmutated sandbox exits 0 99.4ms
✓
PI-1: exits 1 naming the violation — seo_keyword_metrics' LLM-visible description quotes $0.49 instead of ~2.45M tokens — the model parrots it 89.5ms
✓
PI-2: exits 1 naming the violation — the in-progress lead search copy names the scraping vendor 89.6ms
✓
PI-3: exits 1 naming the violation — the in-progress lead search promises an email instead of delivering in this chat 90.6ms
✓
PI-4: exits 1 naming the violation — search_leads is added to BACKGROUND_TOOLS — the removed email handoff comes back 86.9ms
✓
every mutant was restored: the sandbox exits 0 again 93.7ms
src/guard-proofs/check-standing-instructions.vitest.ts
check-standing-instructions — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (this document's own citations are checked)) · 6 tests
✓
the unmutated sandbox exits 0 49.8ms
✓
SI-1: exits 1 naming the violation — a row cites a guard by a name that does not exist (a rename the doc never followed) 46.4ms
✓
SI-2: exits 1 naming the violation — a cited guard is dropped from npm run check, so the row reads as protected and nothing runs it 46.8ms
✓
SI-3: exits 1 naming the violation — a CLAUDE.md "Guarded by" sentence names a guard that does not exist 46.3ms
✓
SI-4: exits 1 naming the violation — a row cites a guard whose name carries a digit and which does not exist (P0-05-KP1) 46.9ms
✓
every mutant was restored: the sandbox exits 0 again 46.0ms
src/leads/async-spend-visibility.vitest.ts
the async spend reaches the window it happened in · 2 tests
✓
the Apify leads_scrape charge is accrued, not only ledgered 1.7ms
✓
accrueApiCost is actually imported 0.3ms
the user is told what the background half cost · 3 tests
✓
the completion push carries a total 0.3ms
✓
both completion shapes render it — artifact and plain bubble 0.4ms
✓
states it in tokens, never currency 0.4ms
a failed turn still accounts for what it spent · 1 test
✓
the error branch emits a cumulative footer 0.4ms
lead-fit.vitest.ts
Core
6 /6
16ms · 1 suite
PASS
src/leads/lead-fit.vitest.ts
lead fit · 6 tests
✓
weights sum to one and every axis has five concrete levels 3.2ms
✓
one score question per axis, over the axis levels 1.0ms
✓
the composite is code arithmetic: all top levels = 100, all bottom = 0, weights visible in between 0.4ms
✓
the why-line names each axis and its level; empty when there is no breakdown 0.3ms
✓
returns null — the model's score stands — when the flag is off or there is no brief 0.4ms
✓
research runs the fit beside the generative call, every writeback persists the breakdown, the card shows why 11.4ms
list-name.vitest.ts
Core
6 /6
5ms · 4 suites
PASS
src/leads/list-name.vitest.ts
matching ignores case, because users do · 2 tests
✓
uses _ilike, not _eq or _in 2.6ms
✓
matches any of several names 1.0ms
it does NOT guess between near-miss names · 2 tests
✓
leaves separators alone — two lists differing by separator are two lists 0.3ms
✓
escapes LIKE wildcards so a literal name matches only itself 0.2ms
tenant scoping is structural, not remembered · 1 test
✓
always emits user_id — the parameter is required, so a caller cannot omit it 0.2ms
no usable name is NOT "match everything" · 1 test
✓
returns null for empty, blank and whitespace-only input 0.3ms
src/leads/role-inbox.vitest.ts
role inboxes on a role-constrained people search · 6 tests
✓
drops the shared mailbox when a department was asked for 2.2ms
✓
drops it when only a seniority was asked for 0.3ms
✓
KEEPS it when no role was requested — then it is a weak but honest lead 0.3ms
✓
returns nothing rather than a role inbox when that is all the domain has 0.3ms
✓
treats a missing flag as "not a role inbox" rather than guessing from the title 0.3ms
✓
does not mutate the caller’s array 0.9ms
src/llm/no-window-llm-spend.vitest.ts
an LLM call with no requesting user is written under the platform, never dropped · 6 tests
✓
callOpenRouterFull in an entry scope with no window → one platform row, unattributed:no_window 42.6ms
✓
callOpenRouter (the string wrapper the product rescan uses) → the same platform row 1.7ms
✓
jevEvaluate in an entry scope with no window → one platform row (the same guard, swept) 3.7ms
✓
control: inside a tenant window the row is the tenant's, with no unattributed marker 5.1ms
✓
a detached call is still the caller's business: non-billable writes nothing, billable writes its own identity 4.2ms
✓
outside any request scope there is no env to write with — nothing is written, as trackApiCall 5.4ms
src/middleware/function_registry.vitest.ts
FunctionRegistry · 6 tests
✓
lists only public tools 1.4ms
✓
invokes with valid args 0.4ms
✓
rejects a missing required arg 0.3ms
✓
rejects an unknown property 0.2ms
✓
rejects a non-public function 0.2ms
✓
lists all registered functions 0.2ms
src/outbound-run/cost-estimate.vitest.ts
cost estimate ordering — low <= expected <= high, always · 2 tests
✓
holds at the default daily target 1.8ms
✓
scales linearly with daily target 0.4ms
7-day high estimate at the default 10 leads/day, pinned to a real computed value · 2 tests
✓
is in the low single-digit millions, not the doc's original uncomputed claim 0.4ms
✓
the default budget covers the full 7-day high estimate with margin, derived not hardcoded 0.2ms
run cost aggregates correctly from per-day · 2 tests
✓
run total equals per-day * days 0.2ms
✓
per-lead is per-day / daily target 0.2ms
src/planner/outcome-cron-honesty.vitest.ts
runPlanOutcomeCron resolves only when it did its work · 6 tests
✓
control: a healthy run with nothing due resolves 3.6ms
✓
every read and write failing rejects (it used to resolve, and check in ok) 2.3ms
✓
one failed step rejects, after the other steps still ran 2.2ms
✓
control: one initiative failing is reported and the run still resolves 0.8ms
✓
every initiative failing rejects 0.6ms
✓
the message carries no counts or ids, so failed runs group into one issue 0.7ms
src/reports/construction-escaping.vitest.ts
report HTML is escaped where it is built, not only where it is mounted · 6 tests
✓
element text: a provider rate reaching campaign_stats prose is inert 28.9ms
✓
value-param helper: a crawled category label reaching statCard is inert 1.2ms
✓
a provider number reaching report prose cannot become markup 1.0ms
✓
attribute value: a share figure cannot close title="…" and add a handler 1.0ms
✓
shell title: the artifact title is data and is escaped when the placeholder is filled 4.4ms
✓
honest content is unchanged: an ordinary title and plain values render byte-for-byte 0.4ms
src/reports/rag-score-conformity.vitest.ts
aeo_page_check — the composite carries the attribution too · 6 tests
✓
lifts score_breakdown to the top level so every reader finds it 1.8ms
✓
the composite artifact renders the same breakdown section 13.6ms
✓
the composite artifact names the biggest loss, not just a finding count 0.5ms
✓
the chat formatter reads the NESTED rag leg instead of rendering zeros 4.5ms
✓
the TL;DR states the score rather than falling through to the generic lead 0.8ms
✓
still renders when the rag leg errored — a failed leg is not a blank report 0.4ms
src/reports/resolve-report-href.vitest.ts
resolveReportHref · 6 tests
✓
joins a site-relative path onto the report domain 2.0ms
✓
strips protocol/trailing slash from the base before joining 0.3ms
✓
leaves absolute URLs untouched (base ignored) 0.2ms
✓
prefixes https:// on a bare host 0.2ms
✓
never emits the malformed triple-slash when base is missing 0.4ms
✓
returns empty string for empty input 0.3ms
src/routes/about-structure.vitest.ts
/about 8-part structure · 6 tests
✓
opens with the value-prop sentence 25.7ms
✓
carries every required H2 in order 1.6ms
✓
puts the key facts in a crawlable <dl> with the core rows 1.2ms
✓
names the founder with profile links 1.2ms
✓
mirrors every visible FAQ question into FAQPage JSON-LD 1.3ms
✓
leaves no draft placeholders and names no backend vendor 0.8ms
src/routes/capability-groups.vitest.ts
capability grouping · 6 tests
✓
renders EVERY section exactly once — none lost, none duplicated 4.7ms
✓
keeps every capability — the card count is preserved end to end 0.9ms
✓
has no section falling through to "More" 0.5ms
✓
still loses nothing when a section is unknown to the group list 1.1ms
✓
preserves the section anchors the rest of the site links to 0.7ms
✓
puts the decision-shaped sections together, which is the line pricing mostly draws 0.4ms
src/routes/capability-links.vitest.ts
capability page blog links · 2 tests
✓
never emits a blog URL carrying a known id-only prefix 35.3ms
✓
emits no obviously malformed blog slug 7.4ms
CTAs point at routes that exist · 3 tests
✓
capabilities links no route that does not exist 6.2ms
✓
seo-questions-answered links no route that does not exist 2.3ms
✓
ai-visibility-answered links no route that does not exist 1.8ms
the HTML sitemap is reachable · 1 test
✓
is linked from the shared footer 0.3ms
src/routes/me-internal-flag.vitest.ts
the identity payload carries an internal flag · 6 tests
✓
is true for an account listed in SCORE_EXCLUDE_USERS 30.6ms
✓
matches case-insensitively — the list is lower-cased, the account is not 1.4ms
✓
is true when only the USER ID matches, with no email overlap 1.4ms
✓
is FALSE for a real customer — the flag has to be able to say no 1.3ms
✓
is present on every 200, never conditionally omitted 1.7ms
✓
an unauthenticated call still 401s — the new field did not widen the gate 0.6ms
src/routes/open-tracking.vitest.ts
machine-open suppression · 6 tests
✓
suppresses an explicit prefetch/preview fetch 25.9ms
✓
suppresses unambiguous security gateways and scripted clients 2.0ms
✓
does NOT suppress mail proxies that also carry genuine human opens 0.6ms
✓
does not suppress an ordinary browser fetch 0.2ms
✓
treats a missing request or empty UA as human — never invent a suppression 0.3ms
✓
the time window is long enough to exclude delivery-time proxying, short enough to keep real opens 0.3ms
src/routes/public-links.vitest.ts
the public page list · 3 tests
✓
covers every sitemap page that is not deliberately excluded 2.1ms
✓
links only to pages in the sitemap, each once 0.5ms
✓
an exclusion that is no longer a sitemap page is stale 0.2ms
where it renders · 3 tests
✓
the homepage links every listed page — the cheapest path for crawlers that read little else 28.0ms
✓
the /site-map page lists every listed page 2.0ms
✓
labels are escaped 0.2ms
src/routes/website-health-check.vitest.ts
serveWebsiteHealthCheck SEO metadata · 1 test
✓
renders all required SEO, Open Graph, and Twitter metadata 30.1ms
duplicate/cannibalisation thresholds are not forked · 1 test
✓
the served page carries the escaped tokeniser and both thresholds 1.9ms
website health check rate limiting · 2 tests
✓
limits to 2 usage per IP per day and blocks the 3rd 1.9ms
✓
handleWebsiteHealthApi returns 429 when IP exceeds 2 checks 2.9ms
runWebsiteHealth AEO and DEO signals · 1 test
✓
extracts schema, social cards, tables, pricing, policy, and cta signals 15.3ms
a short read is refused, not scored · 1 test
✓
the page carries the expectation and the retry 2.6ms
src/runtime/api-ratelimit.vitest.ts
checkApiRateLimit · 6 tests
✓
allows and counts a normal request under both keys 2.8ms
✓
refuses the user once their hourly ceiling is reached, naming the scope 0.5ms
✓
refuses an IP once its ceiling is reached even for a fresh user 0.3ms
✓
the per-IP ceiling is looser than the per-user one (an office is one IP) 0.2ms
✓
fails OPEN when KV throws 1.2ms
✓
is inactive when KV is unbound 0.2ms
src/runtime/cron-arm-order-guard.vitest.ts
check-cron-arm-order · 6 tests
✓
passes on the current tree 64.3ms
✓
MUTANT (the pre-fix shape): an unbudgeted, unmonitored job ahead of the monitored sweep fails 136.7ms
✓
MUTANT: a job called without its budget fails 133.4ms
✓
MUTANT: an arm whose budgets sum past the ceiling fails 121.4ms
✓
MUTANT: the sweep moved back to LAST on the hourly arm (monitored and budgeted) fails 146.5ms
✓
MUTANT: a budget named for a different job than the one it wraps fails 131.4ms
src/runtime/eval-escape-not-forgeable.vitest.ts
eval escapes are not forgeable from a request · 6 tests
✓
never reads X-Smoke-Bypass from request headers 2.2ms
✓
never reads X-Approval-Mode from request headers 0.5ms
✓
never reads X-CoT-Override from request headers 0.4ms
✓
never sets the escape headers on an outgoing/synthetic request either 0.5ms
✓
gates the balance skip on the injected argument, not the request 0.4ms
✓
keeps the balance gate wired to that flag 0.3ms
src/runtime/preflight-warned.vitest.ts
the slot is ONE-SHOT · 3 tests
✓
a second read returns nothing — one warning can produce at most one outcome 2.0ms
✓
stores the TOOL, not a bare flag, so a confirm can only be credited to its own warning 0.3ms
it can never break the turn it measures · 3 tests
✓
no KV bound → silent no-op, never a throw 0.8ms
✓
a KV that throws is swallowed on both sides 0.4ms
✓
does not delete when there was nothing to read 0.2ms
src/runtime/public-tool-budget-bounded.vitest.ts
the daily-budget object call ends inside a bound · 6 tests
✓
the bound is a few seconds: one compare-and-add on one storage row, on the public request path 2.3ms
✓
reserve against an object that never answers is REFUSED as unavailable at the bound, and the refusal is reported 4.3ms
✓
reserve does not end BEFORE the bound: a slow object is not a missing one 3.5ms
✓
settle against an object that never answers returns at the bound and leaves the reservation counted (reported) 1.1ms
✓
a peek against an object that never answers reads null at the bound 0.7ms
✓
source pin: the only object call goes through withTimeout (a signal alone would not bound a DO wait) 1.1ms
src/runtime/substitute-spend.vitest.ts
blocksSubstituteSpend — a cap binds the turn, not one tool name · 6 tests
✓
blocks a DIFFERENT paid tool after a cap refusal 1.7ms
✓
never blocks a FREE tool — the turn must still be able to explain itself 0.3ms
✓
does not block the capped tool itself — its own cap check owns that message 0.2ms
✓
does nothing when no cap has bitten 0.2ms
✓
blocks after ANY of several caps, not only the most recent 0.3ms
✓
replays the live incident end to end 0.2ms
src/ui/server-error-not-data.vitest.ts
the seam, not 41 call sites · 3 tests
✓
throws on a 5xx so the catch blocks that already exist finally fire 1.5ms
✓
only for API calls, and only for 5xx 0.4ms
✓
the error carries its status, so a caller can tell what happened 0.2ms
the outage channel must not throw · 1 test
✓
the version poll uses _nativeFetch and so bypasses this entirely 0.2ms
the failure this prevents, stated as the thing a user would see · 2 tests
✓
contacts still renders an ERROR path, not just an empty state 0.8ms
✓
the assignment that turned a failure into an empty list is still the fallback 2.6ms
src/seo/aeo-grounding.vitest.ts
AEO engines answer from retrieval, not memory · 6 tests
✓
chatgpt is grounded with the web plugin 1.8ms
✓
claude is grounded with the web plugin 0.3ms
✓
gemini is grounded with the web plugin 0.2ms
✓
perplexity is NOT double-grounded — sonar already retrieves 0.4ms
✓
EVERY engine in the map is a deliberate choice, grounded or native 0.4ms
✓
an unknown engine yields no model id rather than a plausible-looking one 0.3ms
src/seo/ai-visibility-answers-library.vitest.ts
AI Visibility Answers is registered and reachable · 6 tests
✓
exists in the prompt library, which is also the public capability catalog 4.2ms
✓
every published prompt routes to EXACTLY ONE brief 31.1ms
✓
no two published prompts land on the SAME brief 4.2ms
✓
every prompt is priced at the diagnostic floor with NO provider term 5.5ms
✓
every item carries a label and a description a browser can act on 2.0ms
✓
does not duplicate a prompt already published in another section 0.7ms
src/seo/competitor-store-single-source.vitest.ts
the competitors snapshot read is gone and stays gone · 3 tests
✓
no module reads audit_type "competitors" — it has no writer 1.8ms
✓
sov.ts resolveCompetitorSet no longer touches seo_snapshots at all 0.3ms
✓
sov.ts dropped the now-orphaned nhostAdminGraphQL import 0.2ms
the competitor prompt class is wired to the live store · 3 tests
✓
aeo.ts builds "alternatives to" prompts from the saved competitor set 0.4ms
✓
the alternatives prompt reads the saved set in its OWN block 0.4ms
✓
still tags those prompts as `competitor` so the library can report provenance 0.2ms
src/seo/content-ideas-filter.vitest.ts
content-ideas-filter · 6 tests
✓
drops brand-navigational self-references despite spacing differences 1.9ms
✓
keeps genuine topic questions that merely share a common word 0.3ms
✓
does not gate on very short brand tokens (<4 collapsed chars) 0.2ms
✓
still drops JS-wall / anti-bot interstitial noise 0.6ms
✓
cleanContentIdeas partitions and counts both drop classes 0.9ms
✓
empty brand skips the navigational rule 0.8ms
src/seo/content-ideas-sitemap-probe.vitest.ts
seo_content_ideas sitemap probe · 4 tests
✓
probes the candidates in parallel, not one 5s wait after another 1.6ms
✓
catches each candidate independently, so one throw cannot skip the rest 0.4ms
✓
still lets the first candidate that yields topics win 0.2ms
✓
keeps all three candidates — the fix must not have quietly dropped one 0.4ms
probe semantics — a throwing first candidate must not mask the rest · 2 tests
✓
reaches sitemap_index.xml when sitemap.xml throws 0.9ms
✓
the OLD shared-catch form stopped at the first throw — the regression this locks out 0.3ms
src/seo/friendly-seo-error.vitest.ts
friendlySeoError names the subsystem that actually failed · 4 tests
✓
attributes an exhausted model chain to the writing model, not the SEO provider 2.1ms
✓
still attributes a provider timeout to the SEO provider 0.6ms
✓
keeps the non-timeout model failure distinct from the timeout one 0.3ms
✓
leaves an unrecognised error untouched for the raw path 0.7ms
the corrected message keeps its Sentry classification · 2 tests
✓
a model TIMEOUT stays an expected outcome, exactly as before 1.1ms
✓
a model UNAVAILABLE is still not suppressed 2.6ms
src/seo/geo-cold-start.vitest.ts
the new-account entry states the whole path, not one step of it · 3 tests
✓
names what happens after the domain is given 1.9ms
✓
says WHY the scan matters, in the user's terms 0.4ms
✓
offers a chip rather than ending on a bare instruction 0.2ms
every prompt origin is explainable to the user · 3 tests
✓
labels all five origins 0.6ms
✓
distinguishes a MEASURED origin from a GUESSED one 0.8ms
✓
never uses wording that implies a guess was measured 0.4ms
src/seo/keyword-input.vitest.ts
isEchoedEmptyKeyword · 3 tests
✓
catches the echoed-empty shapes that reached a paid lookup 2.1ms
✓
leaves genuine keywords alone, including quoted ones 0.5ms
✓
reports a genuinely empty string as NOT echoed — the plain guard owns that case 0.2ms
normalizeKeywordInput · 3 tests
✓
collapses both empty and echoed-empty to '' so one guard covers both 0.3ms
✓
passes a real keyword through, trimmed 0.2ms
✓
coerces non-string arguments the model can emit 0.2ms
src/seo/seo-fail-channel.vitest.ts
seoFail routes by what the message SAYS, not by how it travelled · 4 tests
✓
consults the same predicate the returned-{error} path uses 4.9ms
✓
an expected outcome is counted on Logs, not filed as an Issue 5.0ms
✓
reportError is reachable only on the NOT-expected branch 2.9ms
✓
the NQZAI-96 body classifies as an outcome, and a real crash does not 4.8ms
a resumed crawl keeps the rendering mode it was started with · 2 tests
✓
seo_onpage_results passes renderJs from the stored marker 3.9ms
✓
the marker type declares renderJs, so a future reader cannot silently drop it again 2.9ms
src/seo/serpdex-degrade-surface.vitest.ts
a recovered serpdex degradation is a log, not an Issue · 4 tests
✓
reports it on the Logs surface at warn level 1.5ms
✓
does NOT raise it as an Error Issue 0.4ms
✓
keeps the diagnostic context that made the Issue useful 0.3ms
✓
still names the fallback that ran, so the log says what happened next 0.2ms
why an EXPECTED_OUTCOME pattern would NOT have worked here · 2 tests
✓
the degraded string is not on the soft-failure path, so the matcher never sees it 3.2ms
✓
the matcher DOES already cover the read_url 403 pair from the same sweep 2.0ms
src/seo/write-content-budget.vitest.ts
seo_write_content fits its generation inside its tool budget · 6 tests
✓
derives the remaining time from the declared tool budget, not a constant 2.1ms
✓
leaves the cron/inbound path on its historic budget 0.5ms
✓
never lets the derived deadline EXCEED the historic 240s 0.3ms
✓
refuses to start a generation that cannot finish, instead of guaranteeing a timeout 0.3ms
✓
the reserve leaves room for the work that happens AFTER the generation returns 0.2ms
✓
the arithmetic actually closes: reserve + minimum generation < the tool budget 0.4ms
src/leads/shared/branch-telemetry.vitest.ts
every corpus search records the branch it took · 6 tests
✓
emits on EVERY search, not only when a stage degrades 2.0ms
✓
classifies all four branches the way the SQL function does 0.5ms
✓
records the ARGUMENT that chose the branch, so a zero traces to its turn 0.3ms
✓
records the OUTCOME, not just the path — the half the deadline eats 0.2ms
✓
cannot break the search it counts 0.2ms
✓
is a Sentry LOG, never an Issue — a counter is not a fault 0.4ms
src/leads/shared/corpus-gate.vitest.ts
the corpus is the only database the shared-leads path talks to · 2 tests
✓
no retired shared_leads_* root field survives anywhere in src 9.4ms
✓
every corpus root field the path needs is actually wired 1.2ms
one gate, and its refusal still reaches the caller as a refusal · 4 tests
✓
the Worker no longer computes its own rights verdict 0.7ms
✓
a database-side rejection is mapped back to the route's 403 contract 0.7ms
✓
an unreadable policy is NOT reported as a rights refusal 0.5ms
✓
the policy is still fetched — it is not only a gate 0.3ms
src/leads/shared/reachability-ranking.vitest.ts
isReachable · 3 tests
✓
is true only for an active email on a non-consumer domain 2.0ms
✓
is false when the flag is absent — never assume reachable 0.3ms
✓
ignores a reachable flag on a non-email identifier 0.2ms
rankCatalogCandidates · 3 tests
✓
puts a reachable candidate above an unreachable one with a BETTER score 0.3ms
✓
still ranks by score within the same reachability class 0.8ms
✓
is deterministic on a tie 7.3ms
src/leads/shared/region-branch.vitest.ts
the region filter branches on AXIS, not on existence (migration 155) · 6 tests
✓
reads the migration that actually shipped the fix 1.7ms
✓
does not choose the branch with a bare EXISTS over person.locality 0.5ms
✓
probes BOTH organization axes and compares them 0.3ms
✓
keeps the caps that make the comparison meaningful 0.4ms
✓
still requires the person half to be able to FILL the request 0.2ms
✓
carries a self-verification that plants the failing condition rather than counting rows 0.3ms
client/answer-options.vitest.ts
answerOptionChips · 3 tests
✓
renders the server's options and never reads options out of the message 2.4ms
✓
skips what another chip already shows, and keeps to what is left of the budget 0.5ms
✓
none under a report or a cost card, and nothing that is not a short string 0.5ms
client/main.ts renders them · 2 tests
✓
no list-item pattern reads options out of a reply anywhere in the app 1.3ms
✓
the chat reply's option chips are exactly answerOptionChips(data, …) 0.4ms
client/chip-renderer-parity.vitest.ts
chip renderer parity · 5 tests
✓
both renderers branch on __topup__ 1.9ms
✓
both renderers branch on __execute: 0.5ms
✓
both renderers branch on __panel: 0.4ms
✓
both renderers branch on __populate__: 0.4ms
✓
the label normaliser strips every prefix the renderers know 0.3ms
src/admin/gsc-query-jev.vitest.ts
state and questions · 1 test
✓
every question names its own query by KEY — never `queries[i]` 3.3ms
judgeQueries · 4 tests
✓
is null when the flag is off — the classifier then runs on its rules alone 0.8ms
✓
batches, reads every answer back onto ITS query, and bills the platform 27.3ms
✓
a failed batch leaves its queries UNJUDGED — never guessed — and is counted 1.3ms
✓
dedupes and skips empty strings before spending a call 0.9ms
src/admin/gsc-quota-pool.vitest.ts
reserveGscInspectQuota · 5 tests
✓
60 concurrent single reservations all succeed on a handful of writes — none reads as exhausted 2204.0ms
✓
a block request is ONE read-modify-write, counted in the shared state 1.2ms
✓
at the daily cap, a partial grant still says exhausted 0.5ms
✓
a counter that cannot be written is guard_error — NOT exhausted 1102.5ms
✓
a stale day in KV starts the count fresh 0.5ms
src/admin/gsc-site-pick.vitest.ts
pickAdminSite · 5 tests
✓
ignores a non-nqz requested site (the connector default) and picks nqz.ai 2.1ms
✓
honors a requested site only when it is itself an nqz.ai property 0.4ms
✓
prefers the sc-domain nqz property over url variants 0.2ms
✓
falls back to any nqz.ai host variant not in the preferred list 0.2ms
✓
returns null-ish only when the connector truly has no nqz.ai property 0.2ms
src/admin/perf-drift.vitest.ts
computePerfDrift · 5 tests
✓
flags a tool whose recent p95 is >1.5× its baseline 2.8ms
✓
a stable tool (recent ≈ baseline) is not flagged 0.4ms
✓
a tool that got FASTER is not flagged 0.2ms
✓
too few samples in either window → skipped (noise guard) 0.2ms
✓
ignores non-finite / negative durations without crashing 0.3ms
src/admin/readiness-register-published.vitest.ts
the published audit register · 5 tests
✓
ships no address and no UUID: a user or session id never belongs in the register 13.7ms
✓
speaks only for pre-registered subs, and every scored figure is a register figure with a real timestamp 1.9ms
✓
lists every finding once; a severity is rated only by a dated owner ratification, and equals the proposal it ratified 23.3ms
✓
reports the audit it came from consistently 1.0ms
✓
scores with no engine invariant violation 5.6ms
src/admin/score-readiness.vitest.ts
8. scripts/audit/score-readiness.mjs, spawned (the no-import and erasable rules, for real) · 5 tests
✓
--fixture: exit 0, stdout deep-equals scoreFixture(fixture) 203.5ms
✓
--seed --now: the same gate states as the Worker computes at that instant 193.8ms
✓
an empty fixture file exits 2 (blind), and says so on stderr 32.3ms
✓
a fixture with 0 subs exits 2 33.5ms
✓
a fixture that supplies a RULE exits 2 and never scores it (forensic audit P0-10 D3) 196.2ms
src/admin/users-query.vitest.ts
AdminUsers query · 5 tests
✓
does not select users_aggregate — Hasura has no aggregate root for the auth users table 1.8ms
✓
still selects the token_usage aggregate, which DOES exist 0.3ms
✓
uses # for comments, never // — a JS comment inside a GraphQL document is a syntax error 0.2ms
✓
still selects every field the handler reads, so the hoist did not drop one 0.4ms
✓
declares both variables it uses 0.3ms
src/auth/resend-verification-throttle.vitest.ts
per-address cooldown · 3 tests
✓
a resend to the same address inside the cooldown is refused, and nothing is sent for it 7.0ms
✓
the KV key carries a hash of the address, never the address 0.8ms
✓
a KV error REFUSES the resend rather than sending without a bound 1.5ms
per-IP limit · 1 test
✓
reuses the signup limiter: an IP that has spent its signup allowance cannot resend either 0.6ms
the dedupe key dedupes · 1 test
✓
two sends to one address inside the window carry the SAME key, with no per-call token in it 0.7ms
src/billing/balance-cache.vitest.ts
balance cache invalidation on spend · 5 tests
✓
invalidateBalanceCache deletes the cached balance 3.0ms
✓
logTokenUsage drops the stale cached balance so the next read recomputes 191.9ms
✓
logApiUsage drops the stale cached balance 121.8ms
✓
tokensRemaining noCache bypasses a stale cache and reads the ledger fresh 1.2ms
✓
tokensRemaining (cached) still serves the cache when present and not bypassed 1.3ms
src/billing/population-db-form.vitest.ts
the DB form of P_real reproduces the ratified map (V12-data-F01) · 4 tests
✓
premise: the fixture holds the 10 session-classed ids V12 measured, and 313 real ones 2.5ms
✓
none of the 10 session-classed accounts has a row admitted on any ledger 49.8ms
✓
exhaustive: an id's rows are admitted iff classifyPopulation says it is real (323 of 323 agree) 19.2ms
✓
the resolution is ids only and says when it could not complete 15.7ms
the audit scripts resolve the same ids with the same document (LR30 / LR31) · 1 test
✓
sessionClassedIds (scripts/lib/population-lists.mjs) returns exactly the 10 session-classed accounts 53.5ms
src/billing/reservation-accumulates.vitest.ts
a fan-out cannot spend the same balance twice · 3 tests
✓
refuses the leg that the balance can no longer cover 39.4ms
✓
accumulates across legs that all fit 0.5ms
✓
pins the baseline at the FIRST gate, not the last 0.4ms
the NQZAI-92 arithmetic, replayed · 2 tests
✓
the spend the alarm reported is real and is three legs, not one 0.2ms
✓
three reservations cover it; one does not 0.5ms
src/campaigns/tool-dispatch.vitest.ts
statusTagFromName · 3 tests
✓
maps bare status names 2.0ms
✓
normalises case, "list"/"contacts" suffixes, and spaces/hyphens 0.6ms
✓
rejects real list names and junk 0.3ms
statusTagWhere · 2 tests
✓
treats NULL lead_status as 'new' (UI default) 0.8ms
✓
matches other tags exactly 0.3ms
src/chat/confirm-sections.vitest.ts
firstProseLine · 1 test
✓
skips table rows, rules, notes and next-moves, strips bold and bullets, bounds the length 2.3ms
toolLabelFor · 1 test
✓
prefers the cost table label, falls back to the name in words 0.3ms
composeConfirmPreface · 2 tests
✓
markdown: one bold line per tool, report note where one was saved, blank line before the reply 0.3ms
✓
html: the same lines as paragraphs, escaped 0.2ms
the cost_confirm handler keeps every executed tool · 1 test
✓
collects each run and prefixes the reply with the earlier ones 0.8ms
src/chat/guard-vacuity.vitest.ts
every guard fails loudly when the thing it reads is empty · 5 tests
✓
runs the whole guard set, and reports what it could not cover 46410.1ms
✓
the WALKERS fail loudly too, when the tree they walk has no content left 25459.4ms
✓
the not-sandboxable list states a reason for every entry 1.3ms
✓
covers the whole guard set, not a list someone maintains by hand 1.0ms
✓
NO TEST SPAWNS A GUARD WITH ITS STDERR INHERITED — a fixture failure must not read as a real one 56.1ms
src/chat/resend-anyway-wiring.vitest.ts
Resend anyway: a staged card, shown whole, its confirm bound to it · 5 tests
✓
the chip shows a card over exactly the person's own held sends — saying they may arrive twice — and moves nothing 137.2ms
✓
the click on that card puts exactly its two rows back in Drafts — unsent — and a second click runs nothing 46.1ms
✓
typed words never release, not even the chip's exact text: the card is shown again 20.1ms
✓
a chip from a card this conversation did not show, or an earlier card, runs nothing 34.6ms
✓
"No, leave them held" spends the card: its chip then runs nothing 17.2ms
src/chat/response-contract.vitest.ts
response contract registry · 5 tests
✓
every intent applies only known invariants and declares path/cost/role 21.5ms
✓
no duplicate intents 0.4ms
✓
paid/expensive intents that answer require the approval gate 0.7ms
✓
expensive heavy tasks require reasoning-before-handoff (except pure gate turns) 0.5ms
✓
lookup helpers resolve 0.4ms
src/chat/shortcut-domain.vitest.ts
shortcut paths never drop a domain the user named · 5 tests
✓
full_seo_audit extracts it, and carries it through the approval turn 2.3ms
✓
serpdex extracts it — its own catalog prompt names a competitor domain 0.6ms
✓
the on-page DEPTH turn reads the request, not the chip 0.8ms
✓
the SEO route picker carries the domain into whichever audit it selects 0.6ms
✓
every domain-scoped SEO shortcut passes a site — guards the shape, not today instances 1.0ms
src/chat/tables-only.vitest.ts
isTablesOnly · 3 tests
✓
the [1.5.1] reply — tables and captions, no sentence 1.9ms
✓
one real sentence anywhere means it is not tables-only 0.3ms
✓
empty is not tables-only (that is the silent-turn path) 0.2ms
diagnoseAnswerText · 2 tests
✓
mirrors the presenter: bold headline, then the answer 0.4ms
✓
is applied on the agent path after the loop 4.6ms
src/chat/topup-intent.vitest.ts
top-up intent → deterministic route · 2 tests
✓
catches the phrasing the broken button used to send 2.1ms
✓
catches the ways a person actually asks 0.9ms
questions ABOUT spend still reach the model · 2 tests
✓
does not hijack a usage or cost question 0.3ms
✓
does not fire on unrelated messages that merely mention tokens 0.3ms
chip contract · 1 test
✓
the top-up chip carries the __topup__ prefix the client routes on 0.2ms
src/chat/uplift-wiring.vitest.ts
the offer becomes a chip, for every tool · 3 tests
✓
leads with the top-up chip on tools that have no upsell code of their own 3.5ms
✓
keeps the tool's own next steps behind the offer 0.9ms
✓
changes nothing when the run was not capped 0.4ms
the offer is appended to the result, never substituted for it · 2 tests
✓
keeps the whole tool output and adds the offer after it 4.8ms
✓
never quotes a dollar figure 0.3ms
pricing.vitest.ts
Core
5 /5
4ms · 1 suite
PASS
src/commerce/pricing.vitest.ts
computePriceScenario · 5 tests
✓
price rise: margin math + break-even fall boundary 2.3ms
✓
price cut: break-even rise boundary 0.4ms
✓
scenario at or below cost → no break-even, negative margin stated 0.3ms
✓
missing cost → labelled 50%-of-current-price assumption, never silent 0.2ms
✓
invalid inputs rejected 0.2ms
src/connectors/composio-proxy-failure.vitest.ts
composioProxy: successful:false is a failure, not empty data · 5 tests
✓
reports a failed execution as non-2xx even though the HTTP status was 200 26.7ms
✓
carries the upstream reason so it is not just a bare number 0.8ms
✓
prefers a real upstream status over the generic 502 0.8ms
✓
leaves a genuine success completely alone 1.2ms
✓
is additive — an envelope with no `successful` field behaves exactly as before 0.7ms
src/connectors/google-proxy-hosts.vitest.ts
composio proxy endpoint — which Google hosts survive path-only · 5 tests
✓
GSC URL Inspection goes ABSOLUTE — Sentry NQZAI-7M 1.7ms
✓
an unknown Google endpoint defaults to ABSOLUTE, not to a guess about routing 0.4ms
✓
GSC Search Analytics stays path-only — /webmasters/v3 is served by the base host 0.2ms
✓
GA4 Data API stays path-only — it IS the ga4 base host 0.2ms
✓
GA4 ADMIN API goes absolute — a different host on the same route 0.2ms
sequences.vitest.ts
Core
5 /5
29ms · 1 suite
PASS
src/drip/sequences.vitest.ts
handleCreateSequence delay_days coercion · 5 tests
✓
accepts numeric-string delay_days 25.8ms
✓
accepts synonym keys (delay / days / wait_days) 0.6ms
✓
defaults a missing delay: first step 0, later steps 3 0.6ms
✓
still rejects garbage delay values 0.6ms
✓
still rejects steps missing subject/body 0.8ms
src/email/domain-readiness-prompts.vitest.ts
buildDnsFixPrompt — provider-aware routing · 3 tests
✓
names the detected provider and its dashboard path 1.9ms
✓
route53 and godaddy get their own paths 0.3ms
✓
unknown or null provider → neutral phrasing 0.2ms
buildDnsFixPrompt with a derived fix · 2 tests
✓
leads with the concrete change and asks only to apply and verify 0.6ms
✓
recommendedDmarcRecord upgrades in place and keeps the tenant's tags 0.4ms
src/email/silent-handlers-send-cron.vitest.ts
class 1 — a swallowed I/O failure on a send/cron path is reported, the default is kept · 3 tests
✓
consumePendingSend: a KV read failure still refuses the send, and is reported 3.3ms
✓
resolveComposioGscSites: a proxy failure still yields no sites, and is reported 1.8ms
✓
sweepAbandonedOnpageCrawls (cron): an unreadable marker and a failed delete are reported, the sweep goes on 4.3ms
class 2 — a pure helper with no env takes the reporter from its caller · 2 tests
✓
verifySvix: a stored secret that is not base64 still refuses, and tells onSecretError 25.5ms
✓
auditDomainEmailReadiness: DoH lookups that fail on both resolvers are reported, not only scored low 6.5ms
src/email/transactional-fallback.vitest.ts
transactional fallback chain · 3 tests
✓
falls back to Cloudflare when Mailtrap declines, and marks it sent via cloudflare 5.2ms
✓
accumulates BOTH providers errors in last_error when all fail 1.1ms
✓
does not include the dead XSMTP provider in the chain 0.9ms
Cloudflare branch forwards List-Unsubscribe, HTTPS only · 2 tests
✓
#25 an https pair reaches EMAIL.send as headers 0.8ms
✓
#26 an http (dev) pair is withheld, and the send still goes out 0.9ms
src/guard-proofs/check-block-invariant.vitest.ts
check-block-invariant — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (guard the wiring: invariant)) · 5 tests
✓
the unmutated sandbox exits 0 38.1ms
✓
BI-1: exits 1 naming the violation — records() no longer returns null for empty rows — a header-only table is constructible 39.5ms
✓
BI-2: exits 1 naming the violation — a second hand-rolled records-block literal bypasses records() 37.0ms
✓
BI-3: exits 1 naming the violation — the client renders a rowless block it was handed (trusts the producer) 39.5ms
✓
every mutant was restored: the sandbox exits 0 again 36.1ms
src/guard-proofs/check-confirm-surface.vitest.ts
check-confirm-surface — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (HITL rendered; failed send ends the turn)) · 5 tests
✓
the unmutated sandbox exits 0 51.4ms
✓
CS-1: exits 1 naming the violation — the agent-loop confirmation halt relays result.message instead of rendering it 67.1ms
✓
CS-2: exits 1 naming the violation — a failed send_emails no longer halts the turn — the rejection goes back to the model 60.6ms
✓
CS-3: exits 1 naming the violation — the DNS-fix gate returns needs_confirmation with no message of its own 50.6ms
✓
every mutant was restored: the sandbox exits 0 again 51.5ms
src/guard-proofs/check-draft-sendable.vitest.ts
check-draft-sendable — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (send claims its row; never resend an unconfirmed outcome)) · 5 tests
✓
the unmutated sandbox exits 0 47.4ms
✓
DS-1: exits 1 naming the violation — the "send my drafts" fallback filters on status = draft only, so failed drafts are unsendable forever 48.8ms
✓
DS-2: exits 1 naming the violation — a claimed "sending" row (outcome unknown) is put back into the sendable set and would be mailed again 44.3ms
✓
DS-3: exits 1 naming the violation — the Sent list stops excluding failed rows, so a failure is listed as a delivery 45.4ms
✓
every mutant was restored: the sandbox exits 0 again 43.9ms
src/guard-proofs/check-guard-integrity.vitest.ts
check-guard-integrity — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (staleness floor; mutation-test marker)) · 5 tests
✓
the unmutated sandbox exits 0 49.0ms
✓
GI-1: exits 1 naming the violation — a counting guard (check-set-bounds) loses its assertPopulation floor and can pass on zero 47.3ms
✓
GI-2: exits 1 naming the violation — a proven guard loses its MUTATION-TESTED marker, pushing the unproven count over the ceiling 49.7ms
✓
GI-3: exits 1 naming the violation — a guard is unwired from npm run check, so it reads as coverage and runs never 45.9ms
✓
every mutant was restored: the sandbox exits 0 again 45.4ms
src/guard-proofs/check-preflight-coverage.vitest.ts
check-preflight-coverage — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (refine-before-spend · cost axis · literal registration)) · 5 tests
✓
the unmutated sandbox exits 0 41.4ms
✓
PV-1: exits 1 naming the violation — a new outward-acting tool is declared external with no assessor and no written exemption 35.3ms
✓
PV-2: exits 1 naming the violation — a new spend-varying tool (cost decided by an argument) arrives with no decision recorded 42.2ms
✓
PV-3: exits 1 naming the violation — send_emails' assessor registered through a loop — live at runtime, invisible to every grep 36.5ms
✓
every mutant was restored: the sandbox exits 0 again 39.9ms
src/guard-proofs/check-schema-tools.vitest.ts
check-schema-tools — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (schema single source; extractors deleted)) · 5 tests
✓
the unmutated sandbox exits 0 43.5ms
✓
ST-1: exits 1 naming the violation — a deleted prose extractor (extractPersona) is defined again in src/leads/search.ts 42.9ms
✓
ST-2: exits 1 naming the violation — search_leads, which has a schema, gets a hand-written v2tool() definition instead 43.1ms
✓
ST-3: exits 1 naming the violation — the schema-to-provider mapper (src/leads/args.ts) grows a prose regex 44.4ms
✓
every mutant was restored: the sandbox exits 0 again 40.6ms
src/guard-proofs/check-test-spend-ceiling.vitest.ts
check-test-spend-ceiling — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (n=1; test tenants capped 8/tool/day)) · 5 tests
✓
the unmutated sandbox exits 0 37.2ms
✓
TC-1: exits 1 naming the violation — the per-tool daily cap for test tenants is quietly raised from 8 to 50 (the real 2026-07-26 edit) 36.4ms
✓
TC-2: exits 1 naming the violation — the sampling harness repeats one stage 90 times (repeat runs are not testing) 37.9ms
✓
TC-3: exits 1 naming the violation — the harness spends by default: the --execute flag defaults to true 38.4ms
✓
every mutant was restored: the sandbox exits 0 again 35.4ms
src/leads/poor-fit-note.vitest.ts
a poor-fit batch announces itself in the note, not in a column · 5 tests
✓
poorFit is a branch of the note chain, not just a result field 1.7ms
✓
states how many of how many, so the user can check the claim 0.3ms
✓
delivers rather than withholds — they asked for these and they get them 0.4ms
✓
offers BOTH repairs, matching the pre-spend card 0.3ms
✓
only fires on a real sample — three scored leads, majority under 40 0.2ms
src/leads/product-brief-read.vitest.ts
getProductBriefStatus — absence and failure are different facts · 5 tests
✓
a tenant with no brief reads as absent, NOT as a failure 2.6ms
✓
a THROWN read is reported as a failure, not as an empty tenant 0.6ms
✓
a failed read is never silent — it reaches Sentry 0.4ms
✓
returns the brief text when one is on file 0.6ms
✓
getProductBrief keeps its old shape for the 10 callers that only want the text 0.4ms
src/leads/search-query.vitest.ts
normalizeLeadQuery · 5 tests
✓
returns '' for the shapes that crashed extractPersona 1.9ms
✓
treats whitespace-only as absent — ' '.toLowerCase() would not throw, but it is not a query 0.3ms
✓
coerces non-string args the LLM can emit rather than passing them through 0.3ms
✓
preserves a real query verbatim, trimming only the edges 0.3ms
✓
keeps inner casing and punctuation — downstream persona extraction lowercases its own copy 0.2ms
src/llm/jev-keyed-state.vitest.ts
jevKey / jevKeyed · 1 test
✓
zero-pads, keeps order, and builds the same keys the questions name 2.7ms
each builder names items of its own state, by key · 3 tests
✓
prompt fit: all 24 questions resolve to their own prompt — including the tail where the array drifted 3.1ms
✓
keyword themes: each question resolves to its own group of keywords 0.8ms
✓
content verify: every claim question names ITS claim and ITS excerpt; every section question its section 0.9ms
prompt fit at the wire (fetch mocked — a module mock would bypass the internal call) · 1 test
✓
sends a keyed object, reads the answers back in prompt order, and scores prompts past the cap as fit 25.5ms
src/planner/adoption-context.vitest.ts
adaptPlannerAdoption (ADAPTER over the adoption module) · 5 tests
✓
derives readiness from the module rows — blocked wins when a prerequisite is false 3.3ms
✓
joins the planner recommendation history onto families 0.6ms
✓
collects suppressed actions from dismissed + not_run rows only 0.4ms
✓
reuses the adoption module profile summary verbatim 0.4ms
✓
summary lines carry history + missing prerequisites 0.4ms
src/reports/article-copy.vitest.ts
the article artifact offers a copy button · 5 tests
✓
renders one, labelled for the article rather than a prompt 1.5ms
✓
copies the markdown source, title included 0.5ms
✓
is not the rendered HTML 0.4ms
✓
is wired for a re-opened artifact, not only for chat 0.4ms
✓
renders nothing when there is no article to copy 0.5ms
src/reports/godmode-truncation.vitest.ts
buildGodModeInsights — truncated analysis · 5 tests
✓
renders every recommendation and no disclosure when the model finished 2.8ms
✓
drops the cut-off final recommendation instead of rendering half a sentence 0.5ms
✓
discloses that the list is incomplete 0.3ms
✓
never claims truncation when the model produced nothing and the fallback rendered 0.4ms
✓
keeps a lone truncated recommendation rather than emptying the section 0.3ms
src/reports/guardrail-scan.vitest.ts
publishReportChip — guardrail scan · 5 tests
✓
redacts a vendor name embedded in report HTML before saving 20.9ms
✓
redacts a USD figure for a non-tenant-currency tool 1.3ms
✓
does NOT redact USD for a tenant-currency tool (the user's own revenue) 0.6ms
✓
BLOCKs and replaces the artifact on a secret leak, and reports it loudly 0.9ms
✓
leaves clean HTML untouched 0.6ms
src/reports/sov-render.vitest.ts
composite render probe · 1 test
✓
composite shape renders SOV without undefined leakage 3.1ms
aeo_visibility — prompt transparency + next steps (feedback 2026-07-16) · 4 tests
✓
surfaces the exact prompts sent (methodology transparency) 0.6ms
✓
renders a Recommended next steps section with Copy-Fix-Prompt buttons 0.5ms
✓
§17: signal-overview bento (every dimension), plain headers, feedback mount 0.5ms
✓
empty-signal run still yields at least one concrete next step 0.6ms
src/routes/backlink-checker.vitest.ts
/backlink-checker title and description · 3 tests
✓
leads the title with the free checker phrase and stays short enough to display 29.2ms
✓
keeps the meta description within 160 characters and states the free-account terms 2.0ms
✓
never promises an unlimited scan — the scan is metered in tokens 1.9ms
/backlink-checker free-account section · 2 tests
✓
states the grant in tokens with a USD equivalent derived from the retail rate 2.4ms
✓
is linked from the "how to check backlinks free" list and comes before the definition 1.7ms
src/routes/contacts-self-assert.vitest.ts
storeContactsInNhost on the user token · 2 tests
✓
the user-role insert carries no verification column; the claim lands through the server, marked as a claim 7.4ms
✓
a re-sourced address keeps its real verdict: the claim never overwrites one 1.2ms
POST /api/contacts/import keeps only the CSV columns · 1 test
✓
a body row asserting an API verdict is stored with no verdict at all 28.7ms
PATCH /api/contacts/campaign (V1-data-F02) · 2 tests
✓
another tenant's campaign id is refused in a sentence and nothing is written 1.5ms
✓
control: the caller's own campaign is assigned, and null clears it 1.8ms
src/runtime/cron-slot-dedupe.vitest.ts
one scheduled slot → one check-in and one run per monitored job · 5 tests
✓
DUPLICATE: a second delivery of a slot that completed sends no check-in and runs no job 39.5ms
✓
TAKEOVER: a re-delivery after the first invocation died mid-job runs only what was left, on the dead check-in 25.3ms
✓
ALIVE: a delivery that arrives while the first is still inside a job does not start that job again 30.2ms
✓
LATE: a delivery 902 s late (10-26 11:00) runs every job, and every margin covers the measured lateness plus its arm offset 40.3ms
✓
A REAL MISS STAYS LOUD: margins stay inside their interval, and another slot is never suppressed or back-filled 14.1ms
src/runtime/guardrail-market-currency.vitest.ts
scanOutbound({ marketCurrency }) · 5 tests
✓
lifts the currency check alone 4.6ms
✓
still reads a supplier, a "free" claim, a key and an internal tool name 1.3ms
✓
every other caller keeps the rules it had: the default still rewrites the price, allowCurrency still lifts "free" too 0.7ms
✓
only the AI-visibility prompt call sites pass it, anywhere in src/ 66.4ms
✓
the article call sites pass it for ARTICLE_TEXT_TOOLS only: the saved article and the document card 119.7ms
src/runtime/live-stage.vitest.ts
stageSequence (every stage reaches a terminal state) · 5 tests
✓
completes the previous stage before starting the next 2.7ms
✓
closes out the LAST stage on done() — the exact gap the incident exposed 0.5ms
✓
done() is a no-op when no stage is active 1.4ms
✓
supports closing the last stage as failed 0.3ms
✓
is a no-op entirely when reqCtx.progress is null (outside interactive chat turns) 0.4ms
src/runtime/push-channel.vitest.ts
pushToUser — guardrail scan on event.title · 5 tests
✓
redacts a vendor name in the title 31.8ms
✓
leaves a clean, user-derived title untouched 1.2ms
✓
BLOCKs and replaces the title on a secret leak, never sends the raw value 1.4ms
✓
does not redact USD for a tenant-currency tool 0.7ms
✓
passes through events with no title unchanged (job_failed has none) 1.7ms
src/runtime/request-boundary.vitest.ts
an escaped rejection is answered and reported · 3 tests
✓
fetchInner's shape: `return respond(<stalled asset read>)` skips its own catch, and the boundary answers 101.0ms
✓
a handler that answers is passed through untouched, and nothing is reported 1.9ms
✓
a report that itself fails still answers with the failure shape — the boundary never rethrows 4.3ms
index.ts is wired through the boundary (index.ts cannot be imported under node; pinned by source) · 2 tests
✓
the fetch entry settles fetchInner — and withVoiceWidget — inside settleRequest, answering with answerUncaught 0.6ms
✓
fetchInner's own catch answers through the same function, so the two exits cannot drift 1.9ms
src/runtime/staged-args-schema.vitest.ts
staged confirm args use only schema-declared keys · 3 tests
✓
finds the staging call sites (a floor, so a parser that finds nothing cannot pass) 2.3ms
✓
every stage names a schematised tool and is fully readable 0.4ms
✓
every staged key is a declared property of that tool's schema 0.3ms
stagedKeysOf reads what a spread can contribute, and refuses what it cannot read · 2 tests
✓
collects plain, shorthand and conditionally spread keys, but not keys inside a value 0.4ms
✓
a spread of a variable and a computed key are unreadable, never silently empty 0.9ms
src/tools/add-contacts-surface.vitest.ts
add_contacts surface · 5 tests
✓
is schematised, requires contacts[], and tells the model not to substitute a search 2.8ms
✓
list_contacts points at it, so a model reading either schema knows where saving lives 0.3ms
✓
is classified as a tenant write, and is dispatched through the ONE contact writer with source manual 1.8ms
✓
presents the saved rows as a table whose lead states added vs already there 0.9ms
✓
returns nothing to present when nothing was saved, so the error text is what the user reads 0.2ms
src/tools/list-sent-emails-surface.vitest.ts
list_sent_emails surface · 5 tests
✓
is schematised, bounded, a read, in the campaigns family, and preloaded by "sent emails" 3.7ms
✓
campaign_stats and list_campaigns point at it, so the aggregate tools know where the log lives 0.3ms
✓
is dispatched as a tenant-scoped read of emails_sent, newest first, with a count aggregate 2.0ms
✓
presents one row per email with sent/opened/replied/bounced times and an honest page lead 0.7ms
✓
the formatter says "nothing sent" plainly and names the outcome per row 4.5ms
src/seo/backlink-ceilings.vitest.ts
backlink tools reserve their computed cost, not the catalogue ceiling · 5 tests
✓
deep_scan: the ten-row rehearsal is affordable to a plan that can run it 1.9ms
✓
deep_scan: a one-page plan never reserves more than a one-page run can cost 0.4ms
✓
gap: reserves the two-leg computation, matching the measured run 0.2ms
✓
both call sites assert isCeiling — the wiring, not just the arithmetic 0.6ms
✓
every inline computed estimate handed to the gate asserts it 0.6ms
src/seo/honest-stop-brief.vitest.ts
the honest stop hands back the research it already charged for · 5 tests
✓
returns the brief when one was generated 1.9ms
✓
does not tell the user to supply a brief it is already handing them 0.5ms
✓
keeps the original advice when there is genuinely no brief to return 0.4ms
✓
still reads as transient in both shapes, because it is 0.6ms
✓
names no backend vendor in either shape (CLAUDE.md §4) 0.4ms
src/seo/offpage-reads-backlink-cache.vitest.ts
off-page audit reads the backlink cache seo_backlinks writes (P4-06-F07) · 5 tests
✓
an audit after seo_backlinks buys no second backlinks pull 5.9ms
✓
a second audit inside the window buys neither paid leg again 0.9ms
✓
the ranked-keywords leg shares the key seo_competitor_gap writes 0.6ms
✓
a Common Crawl fallback answer is not cached under the paid backlinks key 25.4ms
✓
withSeoRouteCache (geo research topic SERP) writes the key seoRoute reads, and reads the key it writes 1.1ms
src/seo/onpage-coverage-note.vitest.ts
the on-page report footer · 5 tests
✓
does not claim coverage for the live case — a tenant who never connected Google 2.4ms
✓
claims coverage ONLY when coverage was actually read 0.3ms
✓
a thrown/absent read still asks for the connection rather than claiming one 0.3ms
✓
never tells a CONNECTED tenant to connect Google 0.4ms
✓
an unrecognised reason still refuses to claim coverage 0.2ms
src/seo/seo-answers-library.vitest.ts
SEO Answers is registered and reachable · 5 tests
✓
exists in the prompt library, which is also the public capability catalog 4.1ms
✓
every published prompt routes to EXACTLY ONE brief 30.3ms
✓
no two prompts land on the same brief 5.0ms
✓
is priced at the diagnostic floor with NO provider term 1.7ms
✓
does not duplicate a question already listed elsewhere 17.6ms
src/seo/serp-spider-poll.vitest.ts
seo_serp_spider inline poll · 5 tests
✓
declares a bounded inline poll rather than using the full deadline 2.0ms
✓
is a small fraction of the tool budget — the user learns quickly, not eventually 0.4ms
✓
the unbounded deadline it replaced really was near-budget 0.3ms
✓
leaves seo_onpage_audit on the full deadline, because its poll works 0.4ms
✓
still falls through to the durable two-turn contract 0.5ms
src/seo/treg-call-url.vitest.ts
the SERP fallback addresses the routed endpoint through the call route · 3 tests
✓
POSTs to https://treg.to/call/treg.google.serp.organic 38.8ms
✓
carries the team token, the org when one is set, and keeps the routing headers 4.1ms
✓
uses the same base and route as the working Keyword Planner client 3.5ms
one helper builds every treg address in these clients · 2 tests
✓
tregCallUrl and tregHeaders 0.7ms
✓
neither client writes a treg URL or token header of its own 1.1ms
src/seo/write-content-record.vitest.ts
seo_write_content keeps its durable record, or says it did not · 5 tests
✓
control: a tenant with a site URL gets the article AND the row, with no note and no alarm 17.3ms
✓
no site URL: the article is still delivered, the user is told it was not saved, and we hear about it 5.6ms
✓
insert failure: the article is still delivered, the user is told, and the failure reaches Sentry 1.1ms
✓
an insert that returns no id is a failure too, not a quiet success 0.8ms
✓
the note is copy a user can read: no vendor, no currency, no "free" 1.1ms
src/leads/shared/corpus-filter-honesty.vitest.ts
a row with no person cannot satisfy a filter on job title · 3 tests
✓
drops the organization row that has nobody in it 1.8ms
✓
does NOT drop organizations when no title was asked for 0.3ms
the filter names we send must be the ones the RPC reads · 2 tests
✓
translates employeeMin/employeeMax into the keys migration 136 actually parses 1.2ms
✓
leaves every other filter name exactly as it was 1.8ms
client/usage-footer-frame.vitest.ts
the usage footer, drawn by its own code from the frame the browser now receives · 4 tests
✓
the environment is real and the block was found (a file that cannot run must not report a pass) 12.0ms
✓
a turn that paid a provider: LLM and provider tokens and the total, and no dollar figure anywhere 43.6ms
✓
a model-only turn, and the zero-cost `usage` some shortcuts send, still draw their line 10.9ms
✓
CONTROL: a turn that spent nothing draws no footer 3.6ms
src/dashboard-set-site.vitest.ts
SEO section · 3 tests
✓
no site and nothing tracked → the website field, not "keywords for my site" 2.5ms
✓
site set, nothing tracked → the keyword command, as before 0.4ms
✓
keywords tracked → not empty, no field 0.3ms
AI visibility section with no site (the button the new user clicked) · 1 test
✓
is the website field; its chat command stays only as an old-client fallback 37.9ms
scripts/lib/ingest-errors.vitest.mjs
ingest error classification · 4 tests
✓
treats a manifest_sha256 collision as already-ingested, not as a failure 1.8ms
✓
does NOT swallow a different uniqueness violation that means real data loss 0.3ms
✓
does not fire on unrelated failures 0.4ms
✓
exports the constraint name so the script and the test cannot drift apart 0.2ms
src/admin/geo-scorecard-bulk.vitest.ts
handleAdminGeoScorecardBulk · 4 tests
✓
rejects requests without a valid admin secret 28.0ms
✓
calls runGeoScorecard directly for each URL — no rate limiter applied 3.3ms
✓
rejects more than the per-request URL cap 0.8ms
✓
rejects an empty urls array 0.6ms
src/admin/gsc-clicks-total.vitest.ts
getAdminGscClicksTotal · 2 tests
✓
returns the property total Search Console reports — not the 0 the missing field produced 32.3ms
✓
is null — never a zero — when Search Console refuses 1.0ms
firstIncompleteDate · 2 tests
✓
reads the key the REST API actually sends (camelCase, per the discovery document) 0.4ms
✓
still accepts the prose spelling, and is null when Google sends neither 0.3ms
src/admin/release-ledger-window.vitest.ts
the 30-day window is the filter, not the 60 newest rows · 2 tests
✓
asks for the window by date, with a ceiling well above the measured volume 3.8ms
✓
says so when the ceiling binds, instead of reporting a truncated count as the whole 0.6ms
the change-failure rate carries what it can see · 2 tests
✓
every metrics object names its basis 0.9ms
✓
the digest line never prints the rate without the caveat 0.7ms
src/admin/session-key.vitest.ts
no control characters in the join · 4 tests
✓
no file on the join contains a NUL byte 1.9ms
✓
and no other non-printable control character 6.2ms
✓
the key is built by ONE named helper, not three inline templates 0.8ms
✓
the separator is visible and cannot occur inside an id 0.5ms
src/admin/telemetry-sentry-issues.vitest.ts
fetchSentryIssues — F2 window scaling · 4 tests
✓
scales statsPeriod to the requested days, not a fixed 14d 3.2ms
✓
caps statsPeriod at Sentry's 90d ceiling for a wider window 0.6ms
✓
requests the raised ceiling, not the old hardcoded 10 0.6ms
✓
defaults to 14d when no days argument is given (back-compat for other callers) 0.4ms
src/admin/telemetry-trim-placement.vitest.ts
buildAdminTelemetryData / trimClientPayload placement · 4 tests
✓
buildAdminTelemetryData returns the FULL quality_scores array, untrimmed 20.8ms
✓
the RCA analyst's own read pattern (filter quality_scores for ensemble rows) sees ALL matches, not a 500-row slice 7.5ms
✓
the HTTP handler (the only actual browser-facing caller) DOES trim, to 500 34.1ms
✓
trimClientPayload itself is unchanged — still trims when called directly 0.5ms
signup.vitest.ts
Core
4 /4
27ms · 1 suite
PASS
src/auth/signup.vitest.ts
auth signup helpers · 4 tests
✓
prefers CF-Connecting-IP for signup requests 26.5ms
✓
normalizes gmail aliases before signup validation 0.3ms
✓
keeps the auth credential email intact (no dot/plus stripping) 0.2ms
✓
never lets an email pass as a display name 0.4ms
src/billing/legacy-margin.vitest.ts
legacy billing margin · 4 tests
✓
retail is $2.00 per million platform tokens 1.5ms
✓
every CALLED model whose INPUT rate alone meets retail is an ACCEPTED loss-maker 0.8ms
✓
the accepted list is not padded with models that actually make money 0.6ms
✓
free models are not counted as loss-makers — they have their own floor 0.3ms
src/billing/peek-tokens-no-usd.vitest.ts
peekTokens: the footer's numbers, all of them tokens · 4 tests
✓
a turn that paid a provider reports that spend in tokens and carries no dollar figure 5.1ms
✓
a field added to the accumulator does not reach a reply by default 0.9ms
✓
CONTROL: a turn that spent nothing still reports nothing 0.3ms
✓
the server keeps the dollar figure for the one reader that needs it, under its own name 1.0ms
src/billing/quote-on-run-row.vitest.ts
the quote of record · 4 tests
✓
is a request-context field, reset per request 2.1ms
✓
is set by the approval plan, by the agent gate for ungated tools, and by the confirm replay 1.5ms
✓
lands on the tool_run ledger row as quoted_tokens 0.6ms
✓
is what the calibration ratchet judges an args-priced tool by, once enough runs carry it 0.3ms
src/billing/signup-bonus.vitest.ts
the signup bonus is defined exactly once · 4 tests
✓
has ONE definition across src/** 62.1ms
✓
is 1,000,000 — what the public pricing pages promise 0.5ms
✓
the waitlist 5,000,000 is gone, not merely unused 0.2ms
✓
a free-tier lead search fits inside it 0.4ms
src/billing/token-math.vitest.ts
apiCostToTokens — provider cost → token conversion · 3 tests
✓
uses the canonical cost basis 1.7ms
✓
converts a per-unit provider cost to whole tokens 0.4ms
✓
rounds to whole tokens and handles zero 0.2ms
fmtTokens — human-readable token counts · 1 test
✓
formats thousands and millions, raw below 1K 0.3ms
src/campaigns/resume-snapshot.vitest.ts
the resume card covers exactly who it would resume, and says who it left out · 4 tests
✓
replied, bounced, unsubscribed and superseded enrolments are not resumed — and the card says so 234.8ms
✓
whatever changed after the card was shown is named and offered a new card, never resumed by the old one 48.3ms
✓
a resume card that covers no snapshot (staged before cards did) resumes nothing and shows the card 13.3ms
✓
typed text keeps the most-recently-shown rule, and still resumes only the card's contacts 28.6ms
src/campaigns/send-recovery.vitest.ts
the turn still offers a way forward · 4 tests
✓
offers drafting when there is nothing to send 3.7ms
✓
offers the drafts panel when the ids were wrong 0.3ms
✓
never offers a confirm chip on a failed send — there is nothing to confirm 0.3ms
✓
states the failure rather than describing a send 4.6ms
src/campaigns/sequence-intent.vitest.ts
isFullySpecifiedSequenceAsk · 3 tests
✓
a named or spaced ask is the tool's, not the picker flow's 2.2ms
✓
a bare ask still goes through the pickers 0.9ms
✓
is consulted by the state machine gate 4.4ms
create_sequence tells the model what delay_days means · 1 test
✓
names the PREVIOUS step and gives the 1/3/5 example ([6.2.1] 2026-09-15: 0/1/3) 0.8ms
src/chat/backlink-value-two-lenses.vitest.ts
seo_backlink_value: two lenses · 4 tests
✓
leads with both readings, each named, and the table carries earned beside cost to buy 20.0ms
✓
the live case: visits but no revenue on the property → says so for the earned reading, keeps the cost reading 0.7ms
✓
no Analytics → the earned reading is "not measured" with the fix, never a number 0.6ms
✓
the report hero leads with the earned reading too 2.5ms
src/chat/connector-chip-labels.vitest.ts
hand-wired connector chips name the connector (spec §5.4) · 4 tests
✓
the email readiness audit on a Cloudflare-hosted, unconnected zone offers Connect Cloudflare 3.9ms
✓
every email-deliverability branch that points at Cloudflare says so 1.6ms
✓
Slack and Vercel failures name their own connector 0.8ms
✓
the two tools whose whole point is the panel keep "Open Connectors" 0.4ms
src/chat/feedback.vitest.ts
chat feedback · 4 tests
✓
normalizeFeedbackOptions dedupes + trims 1.4ms
✓
normalizeFeedbackOptions falls back on bad input 0.3ms
✓
buildFeedbackSummary aggregates totals, leaderboard, and mismatches 1.0ms
✓
judge_human_agreement is null when no row has both a vote and a judge score 0.2ms
src/chat/frame-fields-article-currency.vitest.ts
the document card of an article · 4 tests
✓
keeps the prices in its title, preview and Copy text (real buildArtifactCard) 3.5ms
✓
still replaces a supplier, rewrites "free" and withholds a key 0.9ms
✓
every other tool's card, and the other parts of an article turn, keep the currency rule 0.9ms
✓
the exit hands it the turn's tool 4.6ms
src/chat/judge-fixtures.vitest.ts
judge-fail fixture pipeline — oracle cross-check · 4 tests
✓
non-forensic failures are ignored (no write) 2.6ms
✓
CONFIRMED: judge forensic-fail AND contracts also flag → clean regression fixture 25.4ms
✓
CONTRACT_GAP: judge forensic-fail but contracts PASS → the judge caught what code missed 1.0ms
✓
captured fixtures are enumerable newest-first for triage 1.0ms
src/chat/narration-degrade.vitest.ts
a failed narration does not throw away the tool results · 4 tests
✓
degrades instead of rethrowing when tools already ran 2.2ms
✓
still throws when NOTHING ran, because there is nothing to degrade to 0.5ms
✓
tells the user the summary is machine-rendered 0.6ms
✓
is distinguishable from an ordinary silent turn in telemetry 0.3ms
src/chat/pair-completion.vitest.ts
pair completion — two nouns are two calls · 4 tests
✓
supplies the half the model skipped, in either direction 2.0ms
✓
does nothing when both ran, or when neither ran 0.3ms
✓
needs BOTH nouns in the message — one listing alone is a complete answer 0.3ms
✓
is not fooled by unrelated tools having run 0.2ms
src/chat/silent-turn-diagnosis.vitest.ts
a diagnosis outranks whatever ran last · 4 tests
✓
returns the diagnosis, not the incidental closing tool 2.0ms
✓
falls back to the last tool when no diagnosis ran 6.0ms
✓
ignores a diagnose result that errored or said nothing 0.4ms
✓
does not shadow a genuine tool error 0.2ms
src/chat/skill-approval-gate.vitest.ts
the gate exists at all · 2 tests
✓
search_leads is always-confirm, so a skill step naming it must never self-execute 1.8ms
✓
the threshold used by the halt is the same one the chat gate uses 0.5ms
runSkill halts on a step that needs approval · 2 tests
✓
does not call executeTool for an always-confirm step 1.4ms
✓
still runs a step that costs nothing 6.4ms
src/chat/turn-failure.vitest.ts
reportChatTurnFailure · 3 tests
✓
a streaming-turn throw is a Sentry ISSUE (exception event) carrying the turn context 34.8ms
✓
emits Mixpanel error_occurred for the user even when the scope has no user 7.0ms
✓
keeps exactly one feature:chat.v2:fail log line (dashboards count it) — no derived duplicate 4.4ms
both /api/chat catches call it · 1 test
✓
the streaming catch and its non-streaming twin 5.2ms
src/commerce/revenue-reconciliation.vitest.ts
buildRevenueReconciliation · 4 tests
✓
aligned verdict within 10%, comparable figure includes tax+shipping 5.1ms
✓
GA4 far below store = ga4_undercount (measurement gap, per the google_merge lesson) 0.7ms
✓
refunds and non-storefront channels appear as quantified explanation factors 0.6ms
✓
degrades gracefully when GA4 errors: store numbers still returned 0.7ms
src/commerce/shopify-client.vitest.ts
parseGid · 2 tests
✓
extracts numeric ids from admin gids 1.9ms
✓
returns null for junk 0.4ms
parseInventoryLevelId · 2 tests
✓
decodes location + inventory item from the InventoryLevel gid (the read_locations dodge) 0.7ms
✓
degrades to nulls on unexpected shapes 0.4ms
core.vitest.ts
Core
4 /4
3ms · 1 suite
PASS
src/connectors/core.vitest.ts
Apollo partner connector · 4 tests
✓
is flagged as a partner with a CTA and default link 1.8ms
✓
resolveSignupUrl falls back to the committed default 0.4ms
✓
env.APOLLO_PARTNER_URL overrides the default (rotatable link) 0.2ms
✓
non-partner connectors have no signup link 0.3ms
src/connectors/gmail-oauth-state.vitest.ts
gmail: the connect state is bound to the browser that started it · 4 tests
✓
a normal flow still connects 38.2ms
✓
completed in a browser without A's cookie, it saves nothing and never redeems the code 6.2ms
✓
a replayed state is refused 6.3ms
✓
a 30-day-old state of the Shopify shape (NaN timestamp) is refused 2.5ms
mark-sent.vitest.ts
Core
4 /4
36ms · 2 suites
PASS
src/drip/mark-sent.vitest.ts
SentDrip records the send · 3 tests
✓
never passes null for channel 2.5ms
✓
omits the field entirely on the platform transport, and names it on Gmail 0.7ms
✓
the mutation no longer declares a $channel variable it cannot fill 0.4ms
the class, not just the instance · 1 test
✓
no _set anywhere writes a literal null into emails_sent.channel 31.8ms
src/email/dictated-draft.vitest.ts
dictated email — transcribed, not generated · 4 tests
✓
parses the [2.1.2] request exactly: subject, body, values 3.2ms
✓
fills placeholders from the user first, then the contact, and leaves the rest visible 0.9ms
✓
needs BOTH a subject and a body — a subject alone is a brief for the generator 0.4ms
✓
accepts unquoted and curly-quoted forms 0.6ms
src/email/render-sanitize.vitest.ts
normalizeBodyToHtml — the model's HTML is allow-listed, not trusted · 4 tests
✓
drops script, handlers, javascript: links and unlisted elements from a block-HTML body 6.5ms
✓
an inline anchor in a plain-text body keeps its link only when the scheme is allowed 1.6ms
✓
entity-encoded schemes and style beacons are refused 1.1ms
✓
an honest generated body is byte-identical 1.1ms
src/guard-proofs/check-connector-degrade.vitest.ts
check-connector-degrade — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (refuse or disclose)) · 4 tests
✓
the unmutated sandbox exits 0 149.5ms
✓
CD-1: exits 1 naming the violation — a new tool reads the Google token and returns an empty result in silence when it is missing 142.1ms
✓
CD-2: exits 1 naming the violation — lead search drops its "Apollo is not connected" disclosure and returns [] silently 150.2ms
✓
every mutant was restored: the sandbox exits 0 again 145.0ms
src/guard-proofs/check-cost-keys.vitest.ts
check-cost-keys — G8(c) mutation proof (cited V-litescrape F01 (not a STANDING_INSTRUCTIONS citation)) · 4 tests
✓
the unmutated sandbox exits 0 51.6ms
✓
CK-1: exits 1 naming the violation — the SERP call site bills an operation that has no price 48.8ms
✓
CK-2: exits 1 naming the violation — the fallback bills an operation that has no price when no charge is reported 51.7ms
✓
every mutant was restored: the sandbox exits 0 again 47.0ms
src/guard-proofs/check-live-path-render.vitest.ts
check-live-path-render — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (guard the wiring) + CLAUDE.md) · 4 tests
✓
the unmutated sandbox exits 0 72.0ms
✓
LP-1: exits 1 naming the violation — the agent loop hands the model the raw result again — the exact line that shipped the defect 89.4ms
✓
LP-2: exits 1 naming the violation — the SSE response stops attaching the blocks the server built (built and unreachable) 80.9ms
✓
every mutant was restored: the sandbox exits 0 again 64.8ms
src/guard-proofs/check-model-pricing.vitest.ts
check-model-pricing — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (×10 margin on actual cost)) · 4 tests
✓
the unmutated sandbox exits 0 194.9ms
✓
MP-1: exits 1 naming the violation — a model the code calls (perplexity/sonar) loses its LLM_COST_PER_M entry 188.6ms
✓
MP-2: exits 1 naming the violation — openai/gpt-5.6-luna set back to its pre-audit 1.00/6.00 — an unaccepted loss-maker 188.9ms
✓
every mutant was restored: the sandbox exits 0 again 190.6ms
src/guard-proofs/check-plan-coverage.vitest.ts
check-plan-coverage — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (chips, not prose — uplift→chip)) · 4 tests
✓
the unmutated sandbox exits 0 101.5ms
✓
PC-1: exits 1 naming the violation — getNextStepSuggestions stops turning result.uplift into a chip — the offer is in the payload and never shown 104.7ms
✓
PC-2: exits 1 naming the violation — executeTool stops attaching an uplift to a capped run — every depth cap becomes a silent dead end 118.5ms
✓
every mutant was restored: the sandbox exits 0 again 101.7ms
src/guard-proofs/check-presenter-coverage.vitest.ts
check-presenter-coverage — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (guard the wiring — presenter coverage)) · 4 tests
✓
the unmutated sandbox exits 0 43.5ms
✓
PR-1: exits 1 naming the violation — list_contacts' presenter is renamed away — a migrated tool left with no deterministic records 42.1ms
✓
PR-2: exits 1 naming the violation — a new record-producing tool lands in formatToolResult with a markdown table and no presenter 45.2ms
✓
every mutant was restored: the sandbox exits 0 again 43.9ms
src/guard-proofs/check-prompt-attribution.vitest.ts
check-prompt-attribution — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (every LLM call identifiable in the ledger)) · 4 tests
✓
the unmutated sandbox exits 0 147.1ms
✓
PA-1: exits 1 naming the violation — the audience-fit LLM call loses its context — anonymous in the ledger 146.2ms
✓
PA-2: exits 1 naming the violation — the audience-fit call reuses another file's label (icp_extract) — the original 'lead_find' shape 146.8ms
✓
every mutant was restored: the sandbox exits 0 again 142.1ms
src/guard-proofs/check-run-attribution.vitest.ts
check-run-attribution — G8(c) mutation proof (cited V-litescrape F01 (not a STANDING_INSTRUCTIONS citation)) · 4 tests
✓
the unmutated sandbox exits 0 300.3ms
✓
RA-1: exits 1 naming the violation — the SERP call site bills under a provider with no cost-reporting class 299.2ms
✓
RA-2: exits 1 naming the violation — the fallback call site bills under a provider with no cost-reporting class 293.9ms
✓
every mutant was restored: the sandbox exits 0 again 294.9ms
src/guard-proofs/check-set-bounds.vitest.ts
check-set-bounds — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (list/filter ⇒ count)) · 4 tests
✓
the unmutated sandbox exits 0 38.6ms
✓
SB-1: exits 1 naming the violation — enroll_in_sequence (arms real sends) keeps list_name and loses its limit 39.5ms
✓
SB-2: exits 1 naming the violation — verify_contacts (bills per contact) loses its limit 38.4ms
✓
every mutant was restored: the sandbox exits 0 again 36.9ms
src/guard-proofs/check-truncation-gate.vitest.ts
check-truncation-gate — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (parsed ⇒ failOnTruncation; prose ⇒ disclose; never persist a repair)) · 4 tests
✓
the unmutated sandbox exits 0 140.8ms
✓
TG-1: exits 1 naming the violation — the product-profile scan (parsed, repaired, persisted) drops failOnTruncation 138.6ms
✓
TG-2: exits 1 naming the violation — the feedback-RCA prose site stops reading LLMResult.truncated — its disclosure can never fire 133.5ms
✓
every mutant was restored: the sandbox exits 0 again 132.2ms
src/guard-proofs/check-version-forward.vitest.ts
check-version-forward — G8(c) mutation proof (cited docs/STANDING_INSTRUCTIONS.md (version bump; allocate against main) + CLAUDE.md §5) · 4 tests
✓
the unmutated sandbox exits 0 65.3ms
✓
VF-1: exits 1 naming the violation — a branch that ships code carries a version BEHIND main (a number main already deployed) 65.8ms
✓
VF-2: exits 1 naming the violation — a commit on main ships code without moving the version 60.0ms
✓
every mutant was restored: the sandbox exits 0 again 0.5ms
src/leads/list-attach.vitest.ts
upsertContactList survives the DO-NOTHING null · 3 tests
✓
returns the id on first creation 2.3ms
✓
falls back to SELECT when the list already exists — the incident case 0.6ms
✓
returns null only when the list genuinely does not exist either way 0.5ms
the full save attaches memberships on a SECOND save into the same list · 1 test
✓
replays the incident: existing list, 3 contacts, memberships must be written 3.5ms
src/leads/verify-changes.vitest.ts
verifyChangeRows · 4 tests
✓
keeps only the addresses whose verdict actually moved 2.3ms
✓
NEVER reports a move to unverified 0.3ms
✓
drops rows missing either side of the comparison 0.3ms
✓
is empty for an empty or absent result set 0.5ms
src/lifecycle/lifecycle-audience.vitest.ts
lifecycle audience · 4 tests
✓
AUDIENCE: suppressed and deleted users cost zero per-user reads; the rest are still evaluated 94.1ms
✓
TERMINAL BLOCK: a user the gate refuses is marked, so the next run does not summarise them again 22.4ms
✓
TERMINAL BLOCK: an unreadable consent state is transient — no marker, retried next hour 19.1ms
✓
LOOP BUDGET: the pass stops at its budget, says so, and the next run resumes after the last user reached 17.2ms
src/planner/initiative-tenant-scope.vitest.ts
updateInitiativeStatus tenant scope · 4 tests
✓
refuses to transition an initiative owned by someone else 2.4ms
✓
allows the real owner 0.6ms
✓
carries user_id into the mutation predicate, not just the read check 0.7ms
✓
selects user_id in the read so ownership is checkable at all 0.4ms
src/routes/app-shell-csp.vitest.ts
P1-13a-F07 — the app shell carries an enforced Content-Security-Policy · 4 tests
✓
/app: enforced CSP with a per-response nonce on every <script>, and no 'unsafe-inline' for script 109.0ms
✓
/dashboard: enforced CSP with a per-response nonce on every <script>, and no 'unsafe-inline' for script 50.8ms
✓
the nonce is fresh per response (a cached or replayed nonce is a known one) 5.9ms
✓
the report-only companion covers the directives whose third-party inventory is not provable offline 2.5ms
src/routes/markdown-negotiation.vitest.ts
requestWantsMarkdown · 2 tests
✓
detects an Accept header requesting text/markdown 26.2ms
✓
is false for a normal browser Accept header 0.5ms
maybeServeMarkdown · 2 tests
✓
passes through untouched when the client did not ask for markdown 1.7ms
✓
renders a <summary> as a heading, distinct from its answer paragraph 5.9ms
src/routes/p1b-leftovers.vitest.ts
green used as TEXT meets WCAG AA (--green-ink) · 2 tests
✓
light: --green-ink on --paper and --surface 2.2ms
✓
dark: --green-ink on --paper and --surface 0.5ms
public marketing templates · 2 tests
✓
declare no font-size under 12px 8.1ms
✓
do not set text colour with the 3.4:1 --green-700 7.7ms
src/routes/seo-generative-report-batch1.vitest.ts
/content-optimization-ai-tools title and answer block · 2 tests
✓
matches the query wording and stays inside the SERP budget 28.0ms
✓
leads the content with a direct answer that names the picks 2.0ms
llms.txt homepage facts · 2 tests
✓
states the brand variants so "nqz" and "nqz.ai" resolve to nqzai 0.7ms
✓
states the signup grant in tokens with a derived USD equivalent 1.2ms
src/runtime/async-jobs.vitest.ts
async-jobs tier declaration · 2 tests
✓
enrich_contacts runs INLINE, never backgrounded (renders the card + gets judged) 1.8ms
✓
still backgrounds the genuine long report tools 0.3ms
isBackgroundAckMessage · 2 tests
✓
matches the real background-ack copy 0.3ms
✓
does NOT match ordinary answers or empty input 0.3ms
src/runtime/cors-origin.vitest.ts
per-request CORS origin (K5) · 4 tests
✓
two interleaved requests each read their own origin after awaiting 5.2ms
✓
outside any request scope the origin is the wildcard 0.4ms
✓
resolves wildcard for public paths and an allowlisted origin for the data plane 23.6ms
✓
index.ts reads the scoped origin, never a module variable 6.6ms
src/runtime/cron-refire-idempotency.vitest.ts
a re-fired cron cannot double-send · 4 tests
✓
drip writes its emails_sent row before it sends 2.2ms
✓
a transactional send checks its dedupe key and writes its row before any provider call 0.8ms
✓
the lifecycle sends all carry a dedupe key 0.5ms
✓
noRetry() stays uncalled on purpose 4.9ms
src/runtime/cron-trace-liveness.vitest.ts
the arm trace judges a previous invocation by whether it can still be alive · 4 tests
✓
CONCURRENT: a previous invocation that started 8 s ago and has no end yet is NOT filed (188a0505…) 8.3ms
✓
SAME-KEY: an arm that finished is not filed because its end landed inside KV's one-write-per-second window (5e102d4a…) 3.0ms
✓
KILL: an invocation with no end, older than the platform wall clock, is filed exactly once — naming its job 12.1ms
✓
RE-FIRE: the platform's re-fire of a killed slot (same scheduledTime) does not erase the kill 3.5ms
src/runtime/kv-entry-backstop.vitest.ts
boundEntryKv · 2 tests
✓
a hung verb rejects at the backstop; a healthy one gets every argument; other bindings are untouched 9.2ms
✓
a site with its own bound times out at ITS bound over a wrapped namespace, not the backstop 1.3ms
WIRING: the scheduled and queue entries hand down bounded KV · 2 tests
✓
scheduledInner: a KV read over a dead store settles 4.9ms
✓
queueInner: a KV read over a dead store settles 4.2ms
map-limit.vitest.ts
Core
4 /4
40ms · 1 suite
PASS
src/runtime/map-limit.vitest.ts
mapLimit · 4 tests
✓
never runs more than `limit` at once 7.0ms
✓
preserves input order regardless of completion order 31.1ms
✓
handles an empty list and a limit above the item count 0.8ms
✓
runs every item — the batch is bounded, not truncated 0.5ms
src/runtime/vendor-parity.vitest.ts
the eval vendor check is derived, not retyped · 4 tests
✓
parses every name the product declares 9.2ms
✓
detects the escaped names, which a raw parse silently misses 0.6ms
✓
does NOT flag the tenant's own mail provider in an SPF fix 0.3ms
✓
honours the product's own allow-list 0.5ms
src/runtime/zero-action-probe.vitest.ts
zero-action probe: expected refusals are not non-answers · 4 tests
✓
skips the exact NQZAI-6R payload — the balance gate refusing 2.3ms
✓
skips other economic gates and prerequisite asks 2.3ms
✓
does NOT skip a real non-answer — the case the probe exists to catch 2.3ms
✓
does NOT skip an EMPTY reply 0.4ms
src/ui/bug-report-wiring.vitest.ts
bug reporter — every global it reads is actually written · 1 test
✓
has no read-only window.__GLOBAL__ in the report payload 6.3ms
bug reporter — the capture cannot silently stop working · 3 tests
✓
normalises modern colour functions in onclone 0.5ms
✓
captures the viewport, not the whole scroll height 0.3ms
✓
never blocks the report on the screenshot 0.4ms
effects.vitest.ts
Core
4 /4
6ms · 2 suites
PASS
test/replay/effects.vitest.ts
pinTurn: what a turn DID · 2 tests
✓
counts every non-telemetry write and every provider request, and nothing else 2.8ms
✓
a turn with no final frame pins nulls, never a guess 0.9ms
diffConversation: a moved field is reported by name · 2 tests
✓
equal conversations diff to nothing 0.4ms
✓
a second send, a moved route, a changed chip, a lost turn and a harness error each show 0.6ms
src/seo/aeo-gap-ceiling.vitest.ts
aeo_gap generation ceiling · 3 tests
✓
asks for 900 tokens, not the 400 that truncated ~88% of real generations 1.5ms
✓
does NOT pass a reasoning option — it inherits the router default deliberately 0.4ms
✓
still routes on the seo chain at the same temperature 0.3ms
the truncation disclosure the ceiling exists to stop firing · 1 test
✓
still discloses when a gap analysis is cut off 0.3ms
src/seo/aeo-model-cited-egress.vitest.ts
seoGeoResearch — the pages an answer engine cited (P0-02c-F04 pair 1) · 1 test
✓
never connects to a cited internal host, a cited page that redirects inward, or the tenant sitemap’s inward redirect 46.8ms
the other AEO page reads go through the same choke point (sweep of aeo.ts) · 3 tests
✓
checkContentQuality: neither the audited page’s redirect nor its outbound links reach an internal host 6.2ms
✓
seoAeoCheck: the page, llms.txt and robots.txt reads re-check every redirect 4.9ms
✓
seoGenerateLlmsTxt: a sitemap or robots.txt that redirects inward is never followed 1.8ms
src/seo/backlink-gap-snapshot-shape.vitest.ts
the gap reads the shape the database actually stores · 4 tests
✓
finds our referring domains under backlink_profile, not at the top level 3.3ms
✓
produces a MEASURED gap from a real snapshot — not no_baseline 1.4ms
✓
still reads a FLAT snapshot, so older rows are not orphaned 0.5ms
✓
the dispatcher actually performs the nested read 1.9ms
src/seo/content-brief-reasoning.vitest.ts
seo_content_brief disables hidden reasoning · 3 tests
✓
passes reasoning:{enabled:false} on the brief generation call 1.5ms
✓
keeps the 600-token ceiling — the budget was never the problem 0.3ms
✓
still routes on the seo chain at the same temperature 0.3ms
the brief feeds a second paid call, which is why an empty one is not a local failure · 1 test
✓
seo_write_content still auto-runs the brief and injects it as briefContext 0.4ms
src/seo/cron-fair-ordering.vitest.ts
rank cron: least-recently-scanned goes first · 4 tests
✓
sorts the due tenants before any of them is handed to the queue 2.0ms
✓
reads the last scan per user in ONE query, not per user 1.2ms
✓
a never-scanned tenant sorts ahead of every scanned one 7.6ms
✓
falls back to the old order rather than skipping the run when the read fails 0.4ms
src/seo/geo-scorecard-fabrication-check.vitest.ts
geo_scorecard — Unverified NQZAI feature claims (self-audit only) · 4 tests
✓
flags a fabricated named module attributed to nqzai 43.7ms
✓
does not flag a real, allowlisted nqzai capability 5.9ms
✓
does not flag a third-party term like Knowledge Graph mentioned alongside nqzai 4.9ms
✓
does not run this check at all for a third-party URL 4.5ms
src/seo/geo-scorecard-self-fetch.vitest.ts
geo_scorecard self-zone fetch (SELF service binding) · 4 tests
✓
fetches an nqz.ai URL through env.SELF, never the public edge 43.9ms
✓
falls back to a plain fetch for an nqz.ai URL when SELF is not bound (e.g. local wrangler dev) 8.4ms
✓
routes an nqz.ai/blog/* URL through BLOG_WORKER, not SELF 5.1ms
✓
does not route a third-party URL through SELF 2.5ms
src/seo/google-merge-totals.vitest.ts
the merged report states its totals once, each named for its population · 4 tests
✓
sums the joined rows and reads the all-channel figure from attribution 16.1ms
✓
falls back to the channel rows when attribution carries no total 0.5ms
✓
an attribution leg that failed yields NULL for the all-channel figure — never a zero that reads as no traffic 0.4ms
✓
the totals sit at the head of the payload, before the rows 1.0ms
src/seo/index-coverage.vitest.ts
computeIndexCoverage · 4 tests
✓
buckets indexed vs not-indexed from ValueSERP probes (free tier) 33.1ms
✓
caps the free tier at 50 URLs 11.3ms
✓
paid tier lifts the cap 8.7ms
✓
enriches the not-indexed subset with a reason when GSC access is provided 1.4ms
src/seo/keyword-rung-degrade.vitest.ts
the ladder falls through when its last rung fails · 2 tests
✓
fromApify catches instead of propagating 1.9ms
✓
degrades to an EMPTY map, so an unresolved keyword carries no volume rather than zero 0.5ms
the provider gives up before the tool budget does · 2 tests
✓
bounds the keyword-volume call below the 30s tool wall-clock 0.4ms
✓
leaves the client default alone — this is a per-call ceiling, not a global one 0.3ms
src/seo/prompt-fit.vitest.ts
prompt fit · 4 tests
✓
one noul per prompt, naming the brief and the prompt by KEY (never position), with the false cases spelled out 2.7ms
✓
returns null — every prompt ticked — when the flag is off or the brief is empty 0.6ms
✓
the threshold and the cap are the ones the client and the server share 2.2ms
✓
the picker carries prompt_fit and the selector unticks off-brief prompts without dropping them 8.4ms
src/seo/query-helpers.vitest.ts
pickGscPropertyForHost · 4 tests
✓
resolves the property matching the audited host, not the default 2.0ms
✓
matches URL-form properties too 0.3ms
✓
returns null when the host has no verified property (caller falls back to site_url) 0.5ms
✓
extractGoogleSiteHost handles sc-domain + url forms 0.3ms
src/seo/sov-weekly-confirm-replay.vitest.ts
weekly AI-visibility opt-in: the confirm replays what turn 1 staged · 4 tests
✓
executeTool validates sov_trend before dispatch, so a staged key the schema lacks is fatal 2.2ms
✓
a chosen day survives the confirm and reaches the weekly config the cron reads 27.6ms
✓
engines and a frozen panel survive the confirm too 2.8ms
✓
control: with no day at all the opt-in confirms and keeps the default day 2.0ms
src/leads/shared/ingestion-service.vitest.ts
shared lead ingestion service · 4 tests
✓
persists an approved batch using parameterized values and a transactional outbox 16.6ms
✓
rejects unauthorized, disallowed, and invalid batches before any client call 1.6ms
✓
uses the curated ingest mutation as the only database boundary and exposes an exact outbox command when atomic outbox is unavailable 2.0ms
✓
writes invalid verification, tombstone, and identifier suppression as one idempotent command 0.7ms
src/multitenant.vitest.ts
multitenant scoping · 3 tests
✓
assertUserScope fails closed on missing userId 1.4ms
✓
blocks cross-tenant reads 0.3ms
✓
blocks cross-tenant deletes 0.2ms
src/observability-cron-monitor.vitest.ts
cron monitors track the schedule the worker actually runs · 3 tests
✓
reads both sides (a test that finds nothing is green for the wrong reason) 1.8ms
✓
every monitored schedule matches a worker cron, shifted by the measured day-of-week offset 1.4ms
✓
the check-in payload carries monitor_config, so the schedule is upserted from code 0.3ms
src/admin/adoption-email.vitest.ts
finalizeAdoptionBody · 3 tests
✓
appends a styled CTA button, not a bare URL 1.9ms
✓
strips a raw link the model wrote anyway despite the instruction not to 0.5ms
✓
keeps the greeting and body as separate paragraphs (blank-line preserved) 0.2ms
src/admin/feedback-fixlog.vitest.ts
feedback fixlog · 3 tests
✓
every entry is well-formed 40.2ms
✓
entries are in chronological order (append-at-bottom discipline) 1.4ms
✓
prompt section carries every entry and the verification instruction 64.2ms
src/admin/feedback-rca-kv-bounded.vitest.ts
feedback RCA over a KV that never answers · 3 tests
✓
AUTHORIZED-TOKEN READ: an unreadable store rejects resolution and the status route answers 503 126.1ms
✓
APP-TOKEN CACHE: a hung read is a miss, a hung write is a lost write; the minted token is returned 149.6ms
✓
REPORT PERSIST: a hung write settles at the bound and is filed as a lost write 46.6ms
src/admin/feedback-rca-reasoning.vitest.ts
feedback_rca opts back into reasoning · 3 tests
✓
passes reasoning:{enabled:true} explicitly 1.7ms
✓
keeps the large ceiling that was sized to hold the reasoning 0.5ms
✓
the prompt still contains the derive-before-answering instruction the opt-in rests on 0.3ms
src/admin/ga4-oauth-start.vitest.ts
handleAdminGa4OAuthStart — admin secret required before any OAuth state exists · 3 tests
✓
no secret → 401, and no consent URL (no state was minted) 27.4ms
✓
a wrong secret → 401 0.8ms
✓
the admin secret → 200 with a Google consent URL carrying a state (the SPA path still works) 4.3ms
src/admin/gsc-click-accounting.vitest.ts
buildClickAccounting · 3 tests
✓
attributes the gap to anonymized queries when the named count is exact 2.2ms
✓
refuses to call the gap "anonymized" when the row cap cut rows that still had clicks 0.6ms
✓
an uncapped result is exact whatever its last row holds 0.2ms
src/admin/reddit-draft-metered-once.vitest.ts
the Reddit draft's router fallback is metered exactly once · 3 tests
✓
one model call → one ledger row: the caller's api_usage line, keyed by the generation id; no token_usage row 40.9ms
✓
a failed attempt before the success is not in the caller's line, so the floor still records it (once) 11.4ms
✓
source pin: the fallback declares it meters itself, and its line carries the generation id as the event key 1.5ms
src/billing/balance-cache-kv-bounded.vitest.ts
ledger writers over a KV that never answers · 3 tests
✓
invalidateBalanceCache settles at the bound, not later and not never 5.1ms
✓
WIRING: logApiUsage writes its ledger row and settles 47.1ms
✓
tokensRemaining returns the ledger answer when the cache write never answers 2.5ms
src/campaigns/backlink-discovery-diagnosis.vitest.ts
backlink outreach discovery: the first real failure is the diagnosis · 3 tests
✓
a timeout followed by searches that were never sent fails as the timeout 9.4ms
✓
only the real failure is reported; a refusal to start is not a call 1.5ms
✓
when nothing could be sent at all, the run says so rather than "no candidate sites" 1.6ms
src/chat/agent-context-lines.vitest.ts
agent ground-truth context lines · 2 tests
✓
the saved competitor set is injected by name and joined into the brief status text 2.3ms
✓
the admin judge accepts caller-supplied stored context and puts it before the prompt 0.9ms
a spend stand-down turn carries a structural marker to the client (2026-09-15) · 1 test
✓
runChatV2 returns spendBlocked and the v2 payload surfaces spend_blocked 0.5ms
src/chat/feedback-upsert-scope.vitest.ts
createChatFeedbackRecord · 3 tests
✓
cannot overwrite another tenant's row that holds the same message id, and says so 4.9ms
✓
control: refreshes the caller's own row for the same message 0.8ms
✓
control: inserts a new message's row 0.4ms
src/chat/present-aeo-page-check.vitest.ts
aeo_page_check presenter · 3 tests
✓
three scores with one name each, six predictors, and what cost points 4.5ms
✓
no target query → coverage is "not measured", never 0% 0.6ms
✓
an errored or scoreless result presents nothing 0.2ms
src/chat/sent-log-reply.vitest.ts
the send log reply: a paragraph break, never an escaped newline · 2 tests
✓
the formatter breaks the line before its table, so the table is a table 9.3ms
✓
agent loop, the model silent after the tool: the reply is the count line, the rows are the block, and nothing reads "\n" 203.2ms
no formatter writes an escaped newline into what it returns · 1 test
✓
src/chat/tool-format.ts has none 2.7ms
digest.vitest.ts
Core
3 /3
18ms · 2 suites
PASS
src/commerce/digest.vitest.ts
isoWeek · 1 test
✓
stable ISO-8601 week ids across year boundaries 1.9ms
commerce_weekly_digest template · 2 tests
✓
renders revenue delta, margin+coverage, and attention items in the store currency 14.6ms
✓
no prior-week revenue → no fabricated delta; clean stores get no attention section 0.5ms
composio.vitest.ts
Core
3 /3
47ms · 1 suite
PASS
src/connectors/composio.vitest.ts
composioFetch — 429 retry · 3 tests
✓
retries a 429 with backoff and succeeds once the rate limit clears 39.4ms
✓
gives up after exhausting retries if still rate-limited 4.8ms
✓
does not retry a non-429 error — fails on the first attempt 1.8ms
src/dashboard/vitals-input.vitest.ts
vitals counts (K2) · 3 tests
✓
reads "running" from enrollment status, never from the sequence row 2.2ms
✓
counts running SEQUENCES, not active enrollments 2.4ms
✓
a failed read is reported, not passed off as a real zero 1.4ms
src/drip/suppression-reimport.vitest.ts
processDripCron reads suppression by address, not by contact row · 3 tests
✓
an enrolment on a re-imported address that unsubscribed is ended, and nothing is sent or logged 31.9ms
✓
control: the same address in ANOTHER tenant's book is still mailed by that tenant's sequence 3.3ms
✓
control: a re-imported address with no suppression history is mailed 5.5ms
src/guard-proofs/check-tag-provenance.vitest.ts
check-tag-provenance — G8(c) mutation proof (cited CLAUDE.md §5 (guarded by check-tag-provenance.mjs)) · 3 tests
✓
the unmutated sandbox exits 0 353.2ms
✓
TP-1..3: exits 1 naming the violation — one tag off main (squash orphan), one naming a version main never allocated, one a commit late on main 353.4ms
✓
every mutant was restored: the sandbox exits 0 again 0.3ms
src/lifecycle/lifecycle-cursor-preempt.vitest.ts
lifecycle resume cursor vs the job budget · 3 tests
✓
the loop stops strictly before the job budget, measured from the job start, with a reserve 4.3ms
✓
CLEAN EXIT: a slow-but-bounded database — the job finishes inside its budget and leaves a cursor 75.2ms
✓
PRE-EMPTED: when one user outlasts the reserve, the cursor written as the loop advanced survives 8.0ms
reminders.vitest.ts
Core
3 /3
6ms · 1 suite
PASS
src/lifecycle/reminders.vitest.ts
touchUserActivity presence write · 3 tests
✓
first activity writes a user_presence upsert with geo 4.2ms
✓
activity within the 10-min window skips the DB write 0.9ms
✓
activity past the window writes again 0.5ms
src/middleware/token_hook.vitest.ts
token_hook · 3 tests
✓
parses model usage payload 1.4ms
✓
merges usage accumulators 0.3ms
✓
suggests a cheaper model on large completions 0.2ms
src/reports/merge-report.vitest.ts
seo_google_merge — §17 gold standard · 3 tests
✓
aggregates opportunities into a findings bento with fix prompts 2.1ms
✓
restores the REAL daily-sales trend (regression from the fabricated-sparkline sweep) 0.5ms
✓
has a feedback mount and no "Cluster N" section headers 0.4ms
titles.vitest.ts
Core
3 /3
2ms · 1 suite
PASS
src/reports/titles.vitest.ts
report titles · 3 tests
✓
every report-class tool has a human title (no snake_case, no bare tool name) 1.4ms
✓
appends the site and prefers an article title for written content 0.4ms
✓
humanizes unmapped tools instead of leaking snake_case 0.2ms
health.vitest.ts
Core
3 /3
3ms · 1 suite
PASS
src/routes/health.vitest.ts
healthVerdict · 3 tests
✓
is 200 ok while the infra cron reports healthy 2.1ms
✓
is 503 degraded once the cron has seen the database down, and says since when 0.4ms
✓
reports null checked_at when the cron has never written (unknown is not down) 0.3ms
src/routes/nap-consistency-checker.vitest.ts
nap-consistency-checker demo normalizers stay in sync with src/seo/nap.ts · 3 tests
✓
normAddress: demo transcription matches the real function on every known pair 28.5ms
✓
normPhone: demo transcription matches the real function on every known pair 1.5ms
✓
still reports a genuine conflict as a conflict, not a false match 1.9ms
src/routes/p0-audit-copy.vitest.ts
/capabilities card labels carry no second copy of the price · 1 test
✓
has no embedded token figure in the AI visibility audit and TAP labels 35.4ms
/ai-search-optimization quotes one cost for the full multi-engine run · 1 test
✓
every "M tokens" figure on the page agrees, and the retired 13M is gone 3.5ms
/ai-search-prompt-generator storage and limit copy matches the code · 1 test
✓
no "store your data" claim; discloses the six-hour cache and both limits 1.4ms
src/routes/p1-hardening.vitest.ts
public page security headers · 1 test
✓
sends Referrer-Policy and Permissions-Policy alongside the existing four 2.0ms
muted text token meets WCAG AA (4.5:1) on its own backgrounds · 2 tests
✓
light theme: --ink-3 on --paper and --surface 0.7ms
✓
dark theme: --ink-3 on --paper, --surface and --surface-2 0.4ms
src/routes/seo-generative-report-batch2.vitest.ts
/about title · 2 tests
✓
does not repeat the brand and stays inside the SERP budget 26.8ms
✓
leaves /privacy and /terms on the default title 1.9ms
/domain-reputation-checker answer block · 1 test
✓
opens the content with a direct answer that names all four layers 2.7ms
src/runtime/async-jobs-guardrail.vitest.ts
completeAsyncJob — guardrail scan on summarizeResult() · 3 tests
✓
redacts a vendor name in result.message before it reaches the completion email 8.6ms
✓
leaves ordinary result.message untouched 3.8ms
✓
BLOCKs a secret embedded in the result before it reaches the completion email 1.2ms
src/runtime/cron-hourly-arm.vitest.ts
the hourly arm · 3 tests
✓
ORDER: the sweep has checked in (in_progress and ok) before the lifecycle job makes its first read 21.5ms
✓
BUDGET: a lifecycle job that never answers cannot hold the arm; it is filed, and every later job still runs 26.8ms
✓
WITNESS: an invocation the platform killed (a trace row with no end) is filed by the next one 73.8ms
src/runtime/git-config-tripwire.vitest.ts
git-config tripwire · 3 tests
✓
sees an identity written by a fixture — the 2026-09-21 incident 9.1ms
✓
ignores branch.* — a parallel session's `push -u` is not a test leak 6.4ms
✓
reports a removal too, and an absent file as a state rather than a crash 7.8ms
src/runtime/kv-bounded.vitest.ts
boundedKv · 3 tests
✓
a get that never answers rejects with KvTimeoutError at the bound 6.1ms
✓
many timeouts at one site are reported once; a healthy answer is passed through untouched 3.1ms
✓
WIRING: the lifecycle cron settles over a KV that never answers — and says it did no work 34.2ms
src/runtime/send-rate-limit.vitest.ts
checkSendRateLimit · 3 tests
✓
allows under the ceiling and refuses over it, naming the reason 2.8ms
✓
fails CLOSED when KV throws, and the refusal says the limiter is unavailable — not that the limit was hit 1.8ms
✓
is inactive when KV is unbound (local dev, tests) 0.4ms
src/runtime/tenant-figures-on-scan-turn.vitest.ts
the tenant's own figures survive the rail when the brief is in the owned text · 3 tests
✓
without the brief the prices are rewritten; with it they stand 6.0ms
✓
nqzai's own price is still never a dollar figure, brief or no brief 0.4ms
✓
every path that produces a brief owns it before the reply is scanned 5.4ms
src/ui/draft-delete-client.vitest.ts
deleteDraft · 3 tests
✓
removes the draft when the server deleted it 2.8ms
✓
keeps the draft, and says why, when the server answers 4xx 1.0ms
✓
keeps the draft when the fetch wrapper throws on a 5xx 0.7ms
src/seo/backlink-gap-readiness.vitest.ts
backlinkBaselineNote — only claims what it can still know before spending · 3 tests
✓
warns when no site is set — the one case the user can fix before paying 2.6ms
✓
stays SILENT when a site is set, instead of predicting a number it is about to measure 0.3ms
✓
never tells the user to run an off-page audit to fix the gap basis 0.4ms
src/seo/common-crawl-fallback.vitest.ts
Common Crawl fallback · 3 tests
✓
reports a not-yet-indexed site as NOT INDEXED, not as an outage 27.8ms
✓
still reports a REAL outage as an outage 1.1ms
✓
parses a live-shaped success response 1.1ms
src/seo/content-brief-grounding.vitest.ts
seo_content_brief tenant grounding · 3 tests
✓
reads the product brief and site from settings inside the case 1.9ms
✓
the prompt carries the TENANT CONTEXT block with the grounding instruction 0.4ms
✓
an absent brief is disclosed on the result, never silently written for the keyword alone 0.2ms
src/seo/diagnose-headline-producers.vitest.ts
diagnose: the headline consults every brief producer · 3 tests
✓
has exactly one headline-selection expression to reason about 1.6ms
✓
consults the traffic-incident brief, which is built outside the dgAnswer chain 0.4ms
✓
every dg* brief is reachable from the headline: either in the chain or named explicitly 2.3ms
src/seo/diagnose-payload-parity.vitest.ts
both diagnose return paths carry the same briefs · 3 tests
✓
finds exactly the two payload lists 2.4ms
✓
neither list is missing a brief the other has 1.0ms
✓
includes the newest brief, so the guard is demonstrably live 1.1ms
src/seo/geo-scorecard-reasoning.vitest.ts
geo_scorecard LLM call — reasoning disabled (2026-08-29) · 3 tests
✓
sends reasoning:{enabled:false} to the provider 38.2ms
✓
asks for a ceiling that only has to cover the visible JSON 4.4ms
✓
still scores all 7 LLM-backed findings from the reasoning-free answer 3.3ms
src/seo/index-classify.vitest.ts
isRowIndexed — the one canonical classifier · 3 tests
✓
treats a PASS verdict as indexed regardless of coverage_state 1.9ms
✓
reads real GSC coverageState values correctly 0.6ms
✓
is safe on empty / null rows 0.3ms
src/seo/leg-timeout.vitest.ts
withLegTimeout · 3 tests
✓
returns the real result when the promise settles before the timeout 2.3ms
✓
degrades to an {error} object — never rejects — when the leg is slower than its budget 2.4ms
✓
does not let a slow leg block a fast sibling — Promise.all resolves with mixed results 0.9ms
src/seo/serp-crawl.vitest.ts
crawlViaValueSerp — page-1 resilience (NQZAI-64) · 3 tests
✓
falls back to a count-only query when the broad num=10 page-1 times out 30.5ms
✓
DEGRADES (never throws) when both the broad and count-only queries fail 3.3ms
✓
normal path: page 1 enumerates + carries the count 3.4ms
src/seo/settings-updated-at.vitest.ts
settings writes move updated_at (P4-06-F03) · 3 tests
✓
upsertSettings — the writer behind the scan toggles, the product brief and competitors 3.2ms
✓
the weekly rank-scan claim stamps when it was taken 0.5ms
✓
SWEEP: every upsert on templates_user_id_name_key in src/ updates updated_at too 74.3ms
src/admin/analytics-funnel.vitest.ts
analytics golden-path funnels · 2 tests
✓
every stage op is a registry tool or a known non-tool operation 4.4ms
✓
covers all four product sections 1.0ms
src/admin/gsc-disconnect.vitest.ts
handleAdminGscDisconnect · 2 tests
✓
rejects without the admin secret 26.1ms
✓
deletes the token, meta, and coverage cache KV entries, leaving the deep scan state untouched 2.7ms
src/admin/gsc-no-fallback.vitest.ts
getAdminGscClicksTotal — no tenant-connector fallback · 2 tests
✓
returns null when there is no admin-kv token, without ever querying tenant connections 2.3ms
✓
still resolves clicks normally when a real admin-kv token exists (not a total removal of the read path) 30.9ms
src/admin/infra-health-kv-bounded.vitest.ts
probeInfraHealth over a KV that never answers · 2 tests
✓
a hung READ of the stored state cannot hold the probe past its budget 5.6ms
✓
a hung WRITE of the new state cannot hold it either, and the bound is the shared 5 s one 2.8ms
src/admin/mixpanel-activity.vitest.ts
fetchMixpanelUserActivity — fallback fail-soft · 2 tests
✓
returns the primary (empty) result instead of throwing when the unfiltered fallback times out 44.5ms
✓
still returns fallback results when the fallback succeeds 3.2ms
src/admin/mixpanel-adoption.vitest.ts
computeFunnels · 2 tests
✓
counts sequential first-touch survivors, not mere co-occurrence 3.7ms
✓
handles empty data without dividing by zero 0.7ms
src/auth/signup-verify-mirror.vitest.ts
verifySignupEmailToken mirrors the verdict into Nhost · 2 tests
✓
writes __app_email_verified__ AND updateUser(emailVerified: true) for the same user 3.5ms
✓
a failed mirror write does not turn a successful verification into a failure 2.0ms
src/billing/geo-research-card.vitest.ts
P4-06-F05 — the free geo-research card quotes the run the free plan can make · 2 tests
✓
the estimator narrows a free plan to its engine set (holds on every tree) 2.0ms
✓
the agent card for a FREE tenant prices one engine, not four 2.8ms
src/billing/orchestration-floor.vitest.ts
the orchestration floor tracks the measured agent turn · 2 tests
✓
is one full-prompt call after the 2026-09-17 loop fixes, not the old two 1.8ms
✓
asking still costs less than the smallest thing worth asking about 0.3ms
src/chat/lead-no-fit-chips.vitest.ts
search_leads: the relevance gate refused a delivery · 2 tests
✓
offers the closest matches anyway, first 3.3ms
✓
does not open with "No contacts found for that query" over a refusal 4.7ms
src/chat/onboarding-ask-chips.vitest.ts
the first-turn website ask carries chips · 2 tests
✓
attaches the populate chip and the skip chip when no brief, no URL, no tool and no gate 2.2ms
✓
the populate chip prefills the composer; the skip chip is wording the onboarding gate already reads as a skip 2.0ms
src/chat/present-backlink-gap.vitest.ts
seo_backlink_gap renders the prospects the tool actually returns · 2 tests
✓
emits one records block with a row per prospect 3.9ms
✓
an empty gap presents nothing — the formatter says so in words 0.3ms
src/chat/shortcut-dispatch-coverage.vitest.ts
every shortcut rule is dispatched in tryChatShortcut · 2 tests
✓
reads the real rule set (a floor, so an empty list cannot pass) 2.2ms
✓
each one has a handler by id, or is a CONFIRM_GATES confirm/cancel intent 27.4ms
src/email/byok-required.vitest.ts
sendEmail — no platform fallback · 2 tests
✓
fails with a clear message when the user has no configured sending provider 2.0ms
✓
never calls fetch when there is no configured provider (no silent platform-credential send) 0.3ms
src/email/inbound-failure.vitest.ts
handleInboundEmail — a throw is recorded, then re-raised · 2 tests
✓
a reply whose attribution read throws leaves a Sentry Issue and an inbound_email/failed row 27.3ms
✓
a bounce (null sender) is recorded as kind=bounce with the heuristic that fired 0.8ms
src/email/send-command-framing.vitest.ts
sendCmd refuses a command carrying CR or LF, with the address gate open · 2 tests
✓
a smuggled RCPT TO in from_email never reaches the wire as its own command 35.1ms
✓
a smuggled command in the recipient is refused the same way 2.2ms
src/llm/jev-positional-guard.vitest.ts
no Jev builder addresses a list by position · 2 tests
✓
scans the real set — never an empty or partial one 2.7ms
✓
finds no `name[${…}]` path in any of them 21.5ms
src/reports/commerce-report.vitest.ts
commerce_profitability — §17 gold standard · 2 tests
✓
overview: cost-coverage-first bento + missing-cost action + plain headers + feedback 29.5ms
✓
products focus: best/worst-margin bento (worst-first when losing money) + plain headers 1.2ms
src/reports/content-quality-report.vitest.ts
seo_content_quality — §17 gold standard · 2 tests
✓
turns failing E-E-A-T categories into fix-prompt findings cards (healthy categories excluded) 2.7ms
✓
has a feedback mount, honest score, and no "Cluster N" headers 0.8ms
src/reports/metric-stamps.vitest.ts
entity_audit renderer — health_score stamp (cross-surface with the dashboard entity card) · 2 tests
✓
stamps health_score with a machine-readable value and stays render-sound 30.0ms
✓
all stamps share one epoch and the consistency check passes 0.7ms
src/reports/page-check-topic-wiring.vitest.ts
the composite forwards what the sub-tool needs · 2 tests
✓
aeo_page_check passes `topic` to rag_readiness 3.7ms
✓
aeo_page_check declares `topic` so the model can set it 86.9ms
src/reports/usage-inline.vitest.ts
get_usage_breakdown — inline chat chart, not a report surface · 2 tests
✓
is flagged inline (no artifact panel) 1.8ms
✓
renders a donut + plan bar + breakdown, but NOT a full report shell 0.9ms
src/routes/ai-agent-guardrails.vitest.ts
/ai-agent-guardrails copilot answers · 2 tests
✓
has an h2 for every search, each followed by a paragraph, above the first original section 26.8ms
✓
invents no permissions claim and leaves no placeholder 1.0ms
src/routes/geo-scorecard-xss.vitest.ts
public GEO scorecard: crawled strings render as text, crawled URLs are scheme-checked · 2 tests
✓
no injected handler or script URL survives into the rendered results 388.2ms
✓
the finding text still reads correctly — a literal "<h1>" is shown, not parsed 114.0ms
src/routes/keyword-landing-runtime.vitest.ts
keyword landing runtime · 2 tests
✓
emits a parseable inline form script with an escaped website regex 28.4ms
✓
classifies the supported website inputs without accepting malformed URL-like input 2.0ms
src/runtime/cron-coverage-budget.vitest.ts
refreshCorpusCoverage budget · 2 tests
✓
covers the slowest measured run with at least a minute to spare 2.2ms
✓
still leaves the 07:00 arm under the ceiling, and every other job on it ≥ 7× its worst measured run 0.9ms
src/runtime/request-context.vitest.ts
startTokenTracking clears per-turn ownership state · 2 tests
✓
a claimed site from a previous request does not reach the next one (K6) 3.7ms
✓
the described product is cleared the same way 0.3ms
src/tools/graphql-callsite-coverage.vitest.ts
the mutation-name guard can see a generic call site · 2 tests
✓
the extractor tolerates a generic between the name and the paren 2.1ms
✓
the optional generic cannot leap a statement boundary into the query literal 0.4ms
src/seo/domain-validity.vitest.ts
isValidDomain · 2 tests
✓
rejects the red-team probe and other garbage 2.9ms
✓
accepts real domains (post-normalization) 0.5ms
src/seo/onpage-results-seed-status.vitest.ts
seo_onpage_results carries the seed status the crawl was started with · 2 tests
✓
passes the stored seedStatus to the crawl fetch, so the crawler-refused verdict can fire 13.2ms
✓
a marker written before seedStatus existed still reads as unknown (0), never as a guess 0.5ms
src/seo/seo-route-rival-provider.vitest.ts
an open-web SERP call keeps its rivals under the provider that answered · 2 tests
✓
seoRoute hands the capture the provider seoRouteSerp returned 4.3ms
✓
the stored rival rows carry that provider 2.6ms
src/admin/gsc-handler-tally.vitest.ts
handleAdminGsc — every panel counts the same population · 1 test
✓
classifies ALL fetched queries, ships the display slice, and says where the headline clicks are 48.9ms
src/billing/ledger-writers.vitest.ts
every token_usage / api_usage writer is accounted for · 1 test
✓
names every insert site, and every credit or reversal writer inserts with a derived id 120.8ms
src/billing/stripe-checkout-params.vitest.ts
createTopUpCheckout · 1 test
✓
tags the session, the PaymentIntent and the card statement as nqzai, and still owns itself by success_url 28.8ms
src/reports/export-css-coverage.vitest.ts
report export CSS coverage · 1 test
✓
every report-* class used in html.ts report bodies is defined in REPORT_EXPORT_CSS 4.1ms
src/routes/ai-backlink-outreach-tool.vitest.ts
backlink outreach page: the token quote · 1 test
✓
every worst-case figure on the page is the gate's own maxTokens 28.1ms
src/routes/ai-keyword-research-and-finder-tool-copilot.vitest.ts
/ai-keyword-research-and-finder-tool Copilot search answers · 1 test
✓
has an h2 + direct answer per search, above the first original section 28.1ms
src/routes/ai-lead-sourcing-cost-comparison-copilot.vitest.ts
/ai-lead-sourcing-cost-comparison Copilot search answers · 1 test
✓
has an h2 + direct answer per search, above the first original section 27.6ms
src/routes/ai-marketing-planner-compliance.vitest.ts
/ai-marketing-planner lead-generation compliance answers · 1 test
✓
has an h2 + direct answer per search, above the first original section 29.2ms
src/routes/ai-search-optimization-copilot.vitest.ts
/ai-search-optimization agency-evaluation answers · 1 test
✓
has an h2 + paragraph per search, above the first original section 30.0ms
src/routes/ai-search-prompt-generator-copilot.vitest.ts
/ai-search-prompt-generator search-phrase answers · 1 test
✓
has an h2 + paragraph per search, above the first original h2 27.8ms
src/routes/ai-seo-agent-copilot.vitest.ts
/ai-seo-agent Copilot search answers · 1 test
✓
has an h2 + direct answer per search, above the first original section 27.5ms
src/routes/b2b-leads-database-copilot.vitest.ts
/b2b-leads-database Copilot search answers · 1 test
✓
has an h2 + direct answer per search, above the first original section 28.3ms
src/routes/content-optimization-ai-tools-refresh.vitest.ts
/content-optimization-ai-tools content-refresh answers · 1 test
✓
has an h2 + direct answer per search, above the first original explainer section 28.7ms
src/routes/indexnow-key.vitest.ts
IndexNow key files · 1 test
✓
serves both keys as bare text, and nothing else 26.6ms
src/routes/pillar-conversion-hero.vitest.ts
pillar conversion hero · 1 test
✓
emits a parseable handoff script without exposing submitted values in a URL 16.7ms
src/runtime/rate-limited-marker.vitest.ts
rate_limited reaches the v2 payload · 1 test
✓
is tracked off the executed result, returned by runChatV2, and spread onto the payload 2.3ms
src/seo/providers-path-encoding.vitest.ts
apifyRunSync encodes the provider-returned ids it puts in a path · 1 test
✓
runId and datasetId are encoded segments, never raw 33.1ms
src/seo/serp-notify.vitest.ts
publishSerpdexArtifactAndNotify — live chat confirmation · 1 test
✓
emits a job_completed push carrying the report chip 3.6ms