AI 资讯
TRUE Coverage: How We Achieved 90% Faster CI by Measuring What Tests Actually Do
TL;DR: Use per-test coverage data to build a reverse map (file → tests that touch it). Git diff + map lookup = run only relevant tests. 43min → 4min CI time. The Problem Everyone Has Your test suite runs for 45 minutes. You change one file. Should you: Run all 2,000 tests? (Safe but slow) Run tests with matching filenames? (Fast but broken) Manually tag tests? (Gets stale immediately) We tried all three. They all failed. The Insight: Stop Guessing, Start Measuring What if we just measured what each test actually executes? Coverage tools have done this for years: { "src/MyComponent.js" : { "statements" : { "0" : 5 , "1" : 12 , "2" : 0 } } } Key insight: Coverage tools report per test run, not per test file. All we needed: save coverage after each individual test. The Architecture (5 Steps) Step 1: Instrument the Code // Build config (webpack/vite/rollup/etc) export default { plugins : [ process . env . COLLECT_COVERAGE && coveragePlugin ({ include : ' src/**/* ' , exclude : [ ' **/*.test.* ' ] }) ] } Works with: Istanbul (JS), coverage.py (Python), SimpleCov (Ruby), JaCoCo (Java) Step 2: Collect Coverage Per Test // Test framework afterEach hook afterEach ( async () => { const coverage = getCoverageData (); saveCoverage ( `coverage- ${ testName } .json` , coverage ); }); Step 3: Build the Reverse Map const map = {} ; for (const coverageFile of allCoverageFiles()) { const testName = extractTestName(coverageFile); const coverage = JSON.parse(read(coverageFile)); map [ testName ] = [] ; for (const [ sourceFile , data ] of Object.entries(coverage)) { if (wasExecuted(data)) { map [ testName ] .push(sourceFile); } } } Example output: { "tests/user-profile.test.js" : [ "src/components/Profile.jsx" , "src/components/Card.jsx" , "src/utils/formatters.js" ] } The magic: The test told us what it executed. No parsing, no guessing. Step 4: Detect Tests CHANGED = $( git diff origin/main...HEAD --name-only ) TESTS = $( lookupTestsInMap " $CHANGED " ) npm test $TESTS Step 5: Auto-Up
AI 资讯
Fixing a Live Production AI Agent with Docker, Sentry, and Google AI
This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry . Project Overview I recently deployed the Dograh AI voice agent (named Zoya) live on my production website, Mobile One Media , to handle client inquiries for our 4K video production, audio engineering, and app development services. For the first 48 hours, the agent worked flawlessly. However, on day three, it suddenly stopped responding on the live site. Users were experiencing complete hang-ups when trying to navigate the service menu. This wasn't a local testing issue; this was a live production fire that needed immediate debugging and a permanent fix. Bug Fix or Performance Improvement The Problem: Issue: After ~48 hours of continuous uptime, the live Dograh AI widget on mobileonemedia.com began silently failing, resulting in infinite loading states and dropped user sessions. Impact: 100% of new agent interactions were failing, directly blocking potential client leads from contacting our media production services. Root Cause: A Docker container configuration issue combined with a system prompt misalignment. The agent's Docker environment variables were not properly persisting the workflow state, and the system prompt was failing to initialize correctly after container restarts, causing the agent to lose conversational context. Code and Video Demo GitHub Pull Request: https://github.com/dograh-hq/dograh/pull/287 Watch the live agent in action: https://youtu.be/pKUxtq8sKDs?si=r1s2LK7zGIzpd2Ry The Fix Summary: Archived the old, messy agent configuration that was causing the Docker and prompt issues. Built a brand new, clean agent setup from scratch with proper architecture. Rebuilt the Docker container configuration with proper environment variable persistence and volume mounting. Fixed the system prompt initialization sequence to ensure it loads correctly on container startup. Added health check endpoints to monitor agent readiness before accepting user connections. My Improvements
AI 资讯
Catch the dangerous Postgres migration at the CI step
-- looks routine in review, locks your table in production: CREATE INDEX idx_orders_customer ON orders ( customer_id ); ALTER TABLE users ALTER COLUMN email SET NOT NULL ; Both of those statements hold a lock that blocks traffic while they scan or build against the table. On a small table you never notice. On a busy production table it is downtime, and a diff review does not catch it because the SQL looks fine. pg-migration-guard is a free tool that reads the migration and flags these before they reach production: $ pg-migration-guard V42__orders.sql WARN IDX01 CREATE INDEX without CONCURRENTLY [becomes a blocker on a large or busy table] Why: Plain CREATE INDEX takes a lock that blocks all writes until the build finishes. Safe: CREATE INDEX CONCURRENTLY idx ON tbl (col); -- outside a transaction WARN NN01 SET NOT NULL scans the whole table under ACCESS EXCLUSIVE Safe: ADD CONSTRAINT c CHECK (col IS NOT NULL) NOT VALID; VALIDATE CONSTRAINT c; then SET NOT NULL; Summary: 0 blocker, 2 warn, 0 advisory Why migrations bite Whether a Postgres migration is safe has almost nothing to do with intent and everything to do with locks. A migration is dangerous when it holds a strong lock while it scans or rewrites a large table. ACCESS EXCLUSIVE blocks reads and writes; SHARE blocks writes. The change that reads fine in review is the one that quietly takes that lock. Put it in CI The most useful place for this is the pull request, so a risky migration fails the build before anyone merges it. There is a GitHub Action: name : migration-guard on : pull_request : paths : [ " db/migration/**.sql" ] jobs : guard : runs-on : ubuntu-latest steps : - uses : actions/checkout@v4 - uses : actions/setup-python@v5 with : python-version : " 3.x" - uses : technical-turtle/pg-migration-guard@v1 with : path : db/migration fail-on : blocker Each finding shows up as an inline annotation on the diff, so the author sees exactly which line is the problem and what the safe rewrite is. Or run it locall
开发者
WebP vs AVIF vs PNG vs JPEG: A Practical Format Guide for 2026
After spending 2 years building an image compression tool, here's my no-nonsense format guide. ## The Rule | If it's... | Use... | |---|---| | Logo, icon, screenshot | PNG | | Photo, everyday image | WebP | | Smallest possible file | AVIF | | Maximum compatibility | JPEG | ## Why? PNG — Lossless. Keeps text and sharp edges crisp. Supports transparency. But files are large for photos. JPEG — Works literally everywhere since 1992. Good compression for photos. No transparency support. At 80-85% quality, the visual difference from 100% is invisible but the file is half the size. WebP — The sweet spot. 25-35% smaller than JPEG with same quality. Supports both lossy and lossless. Supports transparency. Every modern browser supports it now (97%+ global coverage). For most websites, this is the right answer. AVIF — The next-gen format. 50% smaller than JPEG, 30% smaller than WebP. Supports HDR, 12-bit color, and both lossy/lossless. The catch: not supported on older devices (iOS 15 and below). Use it with a <picture> fallback. ## Real Numbers I ran the same photo through all four formats at comparable quality: JPEG (90%): 842 KB PNG: 3,241 KB WebP (90%): 547 KB AVIF (90%): 382 KB WebP cut the JPEG size by 35%. AVIF cut it by 55%. ## What I Recommend I built CompressFast ( https://compressfast.site ) — a free browser-based image compressor that handles all these formats. No uploads, no servers, everything runs locally.
AI 资讯
Stop Screenshotting Architecture Diagrams: Build Them as Single-File HTML
TL;DR Spent today rebuilding two training diagrams — a layered reference architecture and a workflow swimlane — as single-file HTML instead of exported images. The trick: data in a plain JS array, layout in CSS Grid, connectors in an SVG overlay measured at runtime . Result: diagrams you can step through, click into, and hand over as one file that opens offline. Why not just export a PNG? Because a screenshot is stale by the next sprint, and nobody re-opens the drawing tool to fix it. Approach Editable by a dev Interactive Portable PNG from a drawing tool No (need the source file) No Yes Mermaid in a doc Yes No Needs a renderer Hand-built HTML Yes (it's a data array) Yes One file, opens anywhere The third option costs a few hours once. After that, updating a component is editing one object in an array. Separate the data from the drawing This is the whole design. Nothing about position, colour, or DOM lives in the content: const TIERS = [ { key : ' clients ' , label : ' Clients ' , sub : ' consumers · admins ' }, { key : ' edge ' , label : ' Edge ' , sub : ' TLS · load balancing ' }, // ... ]; const COMPONENTS = [ { id : ' app ' , tier : ' app ' , x : . 34 , label : ' Control Plane ' , tech : ' PHP-FPM ' , role : ' Governance UI and sync orchestration. ' , points : [{ type : ' info ' , text : ' Pushes approved config downstream ' }] }, // ... ]; const LINKS = [[ ' consumers ' , ' edge ' ], [ ' edge ' , ' gateway ' ], /* ... */ ]; tier picks the row. x is a fraction (0..1) across that row , not a pixel. So the layout survives any viewport without me hand-tuning coordinates. Layout: Grid for the boxes, SVG on top for the wires +--------------------------------------------------+ | lane label | [card 1] [card 2] [card 3] | <- CSS Grid row |------------+-------------------------------------| | lane label | [card 4] [card 5] | +--------------------------------------------------+ ^ ^ sticky column SVG overlay (position:absolute; inset:0) draws paths between measured centre
AI 资讯
The browser wars aren’t about search anymore — here are the best alternatives to Chrome and Safari
We’ve compiled an overview of some of the top alternative browsers available today aiming to challenge Chrome and Safari.
科技前沿
Why Samsung Gave Its Next Folding Phone a New Shape
People spend hours watching videos on their smartphones. The wider, shorter, and lighter Galaxy Z Fold8 caters to exactly that.
AI 资讯
Samsung’s Galaxy Watch 9 and Ultra 2 bet big on battery
It's a year of refinement for the Galaxy Watch. With the new Galaxy Watch 9 and Galaxy Watch Ultra 2, which are being announced today, Samsung is more or less taking what people like about its watches and tweaking those elements to be better. The company has been doing this for the past few generations […]
科技前沿
Which New Samsung Foldable Phone Should You Buy? Fold8 Ultra, Fold8, or Flip8?
Samsung’s folding phone family has a new middle child with a fresh form factor, but which of its eighth-gen foldables is right for you?
AI 资讯
I launched to zero signups, then found 5 features nobody could reach
I spent months building an AI agent platform. I launched it on Product Hunt yesterday. Zero signups. The comments were friendly. Three of the four asked for the same thing — not features, not integrations, not a lower price. They wanted to see what the agents did and what they cost . One put it better than my own landing page ever did: they liked that it wasn't "a black box." So I went to make the cost dashboard better. Instead I found out my product had been lying to me for months, and the lies had a pattern. Here's everything, with the code. 1. Every run cost $0.00 The Cost Analytics page reported $0.02 in total across ~100 executions . I'd assumed that meant the platform was cheap to run. It meant the data was being destroyed at write time. cost_cents = int ( ( llm_response . prompt_tokens * 0.5 / 1000 ) + ( llm_response . completion_tokens * 1.5 / 1000 ) ) A typical run on my platform is 56 prompt tokens and 45 completion tokens. That's 0.0843 cents . int() makes it 0 . Not some runs. Essentially every run — because almost every LLM call costs less than one cent. The production numbers: 189 agent runs, 2 with a non-zero cost. 99% of my cost data was zeroes, and the two survivors were just big enough to clear a whole cent. The rates in that formula were correct. I checked them against the providers' pricing pages; the arithmetic is right. The bug is entirely int() on a value that is almost never ≥ 1. A Decimal would have been the textbook fix, but Decimal / float raises TypeError and ~80 call sites do arithmetic on this number, so I widened the column to a float and kept the unit (cents). It's a dashboard estimate, not money — Paddle handles money — so float rounding is irrelevant here. 2. Workflow costs were never recorded at all Truncation at least loses precision. This one lost everything. WorkflowExecution.total_cost_cents and total_tokens_used had no write site anywhere in the codebase . Not a broken write — no write. The columns had been NULL since the feat
AI 资讯
whoimports: who still imports this Python module?
Before you rename, move, or delete a Python module: who still imports this? Grepping hits strings and comments. Importing the package can run side effects. whoimports walks the tree with the AST and prints every matching import / from … import line. Install pip install git+https://github.com/SybilGambleyyu/whoimports.git Usage whoimports src/auth/session.py whoimports auth.session -f json whoimports pkg.util -f md Notes Zero dependencies, Python 3.10+ File paths and dotted module names Understands src/ layouts text / markdown / JSON output Pairs with gitchurn and redactx for safe refactor context. Source: github.com/SybilGambleyyu/whoimports · MIT
AI 资讯
logsnip: cut CI noise, keep the stack traces
Cut the noise. Keep the stack traces. CI logs are mostly package installs. The failure is a few dozen lines buried under thousands of Downloading… lines. Scrolling for the real stack trace is a tax paid on every red build. logsnip is a zero-dependency Python CLI that extracts those failure regions and collapses the rest. Install pip install git+https://github.com/SybilGambleyyu/logsnip.git # or the whole toolkit: curl -fsSL https://raw.githubusercontent.com/SybilGambleyyu/devkit/main/install.sh | bash One-liners # Last failure from a GitHub Actions run gh run view --log-failed | logsnip --last # Headlines only logsnip ci-full.log --summary # Safe to paste into an AI assistant gh run view --log-failed | logsnip --last | redactx What it matches Built-in patterns cover pytest E lines and AssertionError , npm ERR! , rustc error[E…] , TypeScript error TS… , GitHub Actions ##[error] , make failures, and common exit-code messages. Stack frames after a hit are pulled in automatically. Design No network, no config files, no dependencies — pipe-friendly --check exits 1 when error-like lines appear (CI gate) --json for machines; --summary for humans in a hurry Pairs with redactx before anything leaves your machine Source: github.com/SybilGambleyyu/logsnip · MIT
AI 资讯
Your API Retried the Request. Your Customer Got Charged Twice.
A customer clicks the Pay button, the server sends the request to a payment provider, and the charge succeeds. The trouble begins when the response never reaches the browser because the connection drops. The frontend sees a timeout and retries the same request, while the backend treats it as a brand-new payment. One customer action has now created two valid charges. This kind of failure is easy to miss because every part of the system appears to behave correctly on its own. The browser retries because it never received a response, the API processes a valid POST request, and the payment provider accepts the instruction it was given. The defect sits between those systems, where no component has enough context to know that the second request is a repeat. The same pattern can create duplicate orders, emails, subscriptions, shipments, support tickets, or background jobs. The common advice is to retry failed requests, but that advice is incomplete. A retry is safe only when the server can distinguish a repeated business operation from a new one. For payment APIs, that usually means introducing an idempotency key, storing the original result, and protecting the write path against race conditions. The rest of this article walks through that flow using Node.js, Express, and PostgreSQL. The bug starts with a normal-looking endpoint Consider a small Express endpoint that creates a payment by calling an external provider. The code receives the request body, sends the amount and customer data to the provider, and returns the resulting payment object. Nothing about this route looks obviously unsafe during a basic code review, and the happy-path test is likely to pass without trouble. The risk appears only when the request succeeds remotely but the response is lost before the client receives it. `app.post("/payments", async (req, res, next) => { try { const payment = await paymentProvider.charge({ customerId: req.body.customerId, amount: req.body.amount, currency: req.body.currenc
AI 资讯
The Bugs I Didn't Write And The Assumptions That Caused Them
This week I accidentally created my first vibe coded application. You might ask how one does this accidentally, but it's actually easier than you think. Assumptions Made: The first mistake I made was to assume that Claude remembered my setup and how I like to pair program. I have only had one previous project coded with the help of Claude and GHCP and it's a much more basic application than what I was building this week. I assumed, incorrectly, that Claude would 'remember' how I liked to work and go through the project with me as we make decisions and coding blocks together. The other assumption I made was giving a somewhat blanket approval for Claude to just run with things. I thought at some point Claude would stop, check its understanding during development and then continue but I got excited at the idea of using subagents and once I'd selected that option there was no stopping Claude on its rampage through my code! So What's the Project? I've recently started looking at doing more work with AI rather than just prompting Claude or GHCP to help with the day to day. I wanted to actually call an LLM and sift through information which could then be saved in a DB and recalled at a later point. I set myself a four week plan (with the help of Claude) to help solidify my learning with week one being a basic console application in C# that takes some text, sends to an LLM and then extracts certain information, in this case names of people, which is saved into a Postgres database. Sounds simple right? Where things went right This project started off very interesting. I had a conversation with Claude, same as I would with another developer, about the right LLM to use for this project. We went through the positives, negatives and the potential cost benefits and pitfalls of each option. In the end it was narrowed down to two choices, OpenAI or Gemini. Given that I was experimenting quite a bit and I didn't want to accidentally run up costs, I decided to go with Gemini's free t
AI 资讯
SOLID Design Principles: Stop Writing Code That Breaks When You Touch It
Guidelines, not rules. Here's the difference — and why it matters. What is SOLID? SOLID is a set of software design guidelines — not hard rules, but principles that guide how we organize our code. The goal is simple: as your codebase grows and your team scales, things should get easier to change, not harder. SOLID is what makes that possible. Five principles. One goal. Let's walk through each one with real code. S — Single Responsibility Principle A class, function, or method should have one and only one reason to change. The Violation class Bird : def __init__ ( self , name : str , bird_type : str ): self . name = name self . bird_type = bird_type def make_sound ( self ): # two jobs — deciding the type AND making the sound if self . bird_type == " parrot " : print ( " Squawk! " ) elif self . bird_type == " eagle " : print ( " Screech! " ) elif self . bird_type == " owl " : print ( " Hoot! " ) else : print ( " ... " ) make_sound() has two responsibilities — deciding which bird type it is AND making the sound. That's two reasons to change. Add a new bird? Touch make_sound() . Change how sounds work? Touch make_sound() again. Two different reasons, one method. SRP violated. The Fix from abc import ABC , abstractmethod class Bird ( ABC ): def __init__ ( self , name : str ): self . name = name @abstractmethod def make_sound ( self ): pass class Parrot ( Bird ): def make_sound ( self ): print ( " Squawk! " ) class Eagle ( Bird ): def make_sound ( self ): print ( " Screech! " ) class Owl ( Bird ): def make_sound ( self ): print ( " Hoot! " ) # Usage birds = [ Parrot ( " Polly " ), Eagle ( " Sam " ), Owl ( " Oliver " )] for bird in birds : bird . make_sound () Now each class has one responsibility. Parrot.make_sound() only changes if parrots change how they sound. Nothing else touches it. O — Open/Closed Principle A class should be open for extension but closed for modification. SRP and OCP go hand in hand. When you fixed SRP in the Bird example above — you also fixed OCP.
AI 资讯
The 2026 Honda Prelude is a marvel of hybrid technology
When it comes to enthusiast-geared Honda hardware, the Civic Si, Civic Type R, and Acura NSX often come to mind first for their revvy VTEC (Honda's form of variable valve timing) engines and playful chassis dynamics. The Prelude, on the other hand, less so. Instead, the Prelude is a technological study - still aimed at […]
AI 资讯
Late Night Shipping Safi Budget Engine Updates & Render Deployment published
Finished up a solid coding sprint tonight working on Safi-Budget a financial management application built around the 50/30/20 budget framework. I'm currently building and training over at Zone01Kisumu , and getting this build updated and deployed live was the main goal for today's session. What Was Updated Today Localized Currency Logic: Updated the core engine defaults from EUR over to** KES** (Kenyan Shillings) to better support local financial tracking workflows. Auth Flow Refinements:** Ironed out session management and routing logic to ensure clean sign-in and logout behavior across the app. Containerization & Deployment:** Confirmed the Go backend containerizes smoothly with Docker and runs cleanly on Render. Tech Stack Language: Go (Golang) Containerization: Docker Deployment Platform: Render Live Demo & Link You can test out the live deployment here: 👉 Safi Budget Engine Live App
AI 资讯
Build a Crypto Payment Module for SaaS Apps
Most SaaS products do not need a “crypto payment button.” They need a payment module. That distinction matters. A button can redirect a customer to a payment page. A module has to know which user is paying, which workspace should be upgraded, which plan should become active, when access should expire, how failed or expired payments should be handled, how support can inspect payment status, and how finance can export records later. That is where developers can build a serious product. A Crypto Payment Module for SaaS Apps is a reusable layer that lets SaaS builders add crypto payments without building the whole payment lifecycle from scratch. In this article, I will use OxaPay as the example crypto payment infrastructure because its documentation exposes the primitives needed for this kind of module: invoice generation, white-label payments, static addresses, webhooks, payment information, payment history, SDKs for PHP, Python and Laravel, and automation integrations. This is not a “get rich with crypto APIs” article. It is a practical blueprint for developers who want to build something SaaS founders, indie hackers, agencies, and product teams may actually pay for. The core idea A Crypto Payment Module gives SaaS apps a production-ready way to accept crypto payments and translate payment events into SaaS account states. Instead of selling this: I can integrate crypto payments into your app. You sell this: I can give your SaaS a reusable crypto billing module with invoices, payment status tracking, webhook verification, plan activation, grace periods, admin tools, and payment history sync. That is a much stronger offer. A SaaS founder does not only care that a payment happened. They care that the right account is upgraded, the right plan is applied, the right billing period is extended, the right user sees the right status, and the support team can understand what happened when something goes wrong. That is what your module should solve. Why this is a real developer
AI 资讯
How MCP Is Changing Website QA Workflows for Development Teams
Modern development teams use CI/CD pipelines, automated testing, feature flags, and AI-assisted coding to release new functionality multiple times per week. Yet despite all of these improvements, one part of the delivery process often remains surprisingly inefficient: website feedback. Clients still send screenshots through email. Designers leave comments in Slack. QA engineers create tickets manually. Developers spend time figuring out where an issue actually occurred before they can even begin fixing it. As AI becomes increasingly integrated into software development, another technology is beginning to reshape this workflow: the Model Context Protocol (MCP) . Rather than treating website feedback as disconnected conversations, MCP makes it possible for AI systems to understand the context surrounding a reported issue, helping development teams reduce unnecessary back-and-forth and resolve problems faster. Why Website QA Still Creates Bottlenecks Most website review processes haven't changed much over the past decade. Someone spots an issue, takes a screenshot, writes a short description, and sends it to a developer. The developer then has to answer a familiar set of questions. Which page? Which browser? Which screen size? Can you reproduce it? What exactly were you clicking? The actual bug may only take a few minutes to fix, but understanding the issue can consume considerably more time. As websites become increasingly dynamic, reproducing reported problems becomes even more difficult. Personalization, authentication, browser differences, JavaScript frameworks, and responsive layouts all introduce variables that aren't captured in a simple screenshot. Why Context Matters More Than Ever AI coding assistants have dramatically improved developer productivity. However, AI is only as useful as the context it receives. If an assistant only receives a vague message such as: "The button doesn't work." there is very little it can do. Now compare that with a report containi
开发者
I'm speaking at React Day Berlin 2026 — bridging React into a Preact form engine
I'm excited to share that I'll be speaking at React Day Berlin 2026 this December! My talk How I Brought React Into a Preact Form Engine: A Production Bridge Pattern I'll walk through how we integrated React into an existing Preact-based form engine in production — the bridge pattern we used, the trade-offs, and what I'd do differently next time. Duration: up to 20 minutes Dates: December 4 & 7, 2026 Format: remote or in-person (TBD) Join me (free stream access) You can register through my speaker badge and get partial free access to watch the stream: 👉 My React Day Berlin 2026 badge Speaker page: reactday.berlin/#person-sam-abaasi ReactDayBerlin #react #preact #javascript #webdev See you there!