开发者
Podcast: Rethinking Data: Moving From the Traditional Three-Tier Web Stack to Client-Side Event Sourcing
Johannes Schickling explores how he moved beyond the traditional three-tier web stack to a local-first approach. He shares his experience transitioning from Prisma to developing Overtone—a music curation app leveraging client-side event sourcing and SQLite. The discussion highlights the trade-offs between event sourcing and CRDTs. By Johannes Schickling
AI 资讯
Validate Kubernetes Manifests with Flux Schema
If you run GitOps with Flux, a broken manifest usually gets caught the slow way: it merges, the reconciler chokes, and you find out from a failing Kustomization. Flux Schema, the plugin that shipped with Flux 2.9, moves that check left into CI. It validates every YAML document against JSON Schema and CEL rules using the same evaluation logic as the Kubernetes API server, so a bad field fails the pull request instead of the cluster. Install and run it Flux Schema is a CLI plugin, not part of the core binary. Install it through the plugin system: $ flux plugin install schema $ flux schema --help Pin a version in CI so a new release never changes your gate's behavior mid-sprint: $ flux plugin install schema@0.5.0 Point it at a directory of manifests and it validates each document: $ flux schema validate ./manifests It ships with built-in schemas for Kubernetes, OpenShift, Gateway API, and the Flux CRDs, so a fresh install already knows your HelmRelease and Kustomization kinds without any setup. Strict validation flags unknown fields, wrong types, and missing required properties as hard errors, which catches the typos kubectl apply --dry-run=client quietly ignores. What CEL adds over plain schema checks JSON Schema catches shape problems: a string where an int belongs, a misspelled key. CEL rules catch logic problems. Because Flux Schema runs the x-kubernetes-validations rules embedded in CRDs through the same CEL engine the API server uses, a manifest that violates a cross-field constraint (say, a replica count that must stay below a limit, or two mutually exclusive fields both set) fails in CI with the exact message the cluster would have returned. You are testing against the real admission logic, not a stale copy of it. Wire it into a config file Drop a .fluxschema.yml at your repo root to control what gets checked. The file uses the schema.plugin.fluxcd.io/v1beta1 API and a Config kind: apiVersion : schema.plugin.fluxcd.io/v1beta1 kind : Config skipKind : - Secret s
AI 资讯
Another day, another VPS breach
I woke up to two emails that immediately caught my attention. One was from my website monitoring service (I use UptimeRobot, no affiliation) reporting that a client's website was down. The other was from my VPS provider informing me that they had suspended my VPS due to abuse. I logged into the control panel and immediately noticed a massive CPU spike. The server had gone from its usual 15–20% CPU usage to a sustained 100% for nearly four hours before the provider shut it down under their fair usage policy. My first clue was xmlrpc.php . It was consuming a significant amount of resources, so I started researching it. I'm not primarily a WordPress/PHP developer, and I was surprised to learn that XML-RPC exposes functionality for remote management of WordPress. I disabled XML-RPC, brought the VPS back online, and thought the problem was solved. It wasn't. The next day I woke up to the exact same two emails. This time my VPS provider had already imposed CPU limits on the server. I noticed a few kernel-looking processes consuming CPU, assumed they were related to the throttling, and restarted the VPS. A few hours later, it was offline again. At that point I knew I was dealing with a compromise rather than a performance issue. I began investigating the WordPress installation and immediately found obvious signs of infection. There were numerous malicious PHP files ( index.php , cache.php , etc.) buried inside recursively nested directories such as: image / image / image / image / cache . php The deeper I looked, the worse it became. The attackers had created: A rogue WordPress administrator account An unauthorized SSH key A root-level user on the VPS An administrator account inside CyberPanel This wasn't just a compromised website anymore. It was a full VPS compromise. My working theory was that the attackers exploited a vulnerable WordPress component (likely allowing arbitrary PHP upload or remote code execution), established persistence, and pivoted into the operating s
AI 资讯
My WSL2 VM Kept Losing Network Every Five Minutes
Every five minutes or so, my entire Windows machine would drop off the network for a few seconds — not just WSL, the whole host. Browser tabs would stall, calls would drop, and it only happened while WSL2 was running. This is the story of finding that, plus the WSL memory-tuning landmines I hit right alongside it. The flapping The symptom was a host-wide network blip on a short, regular interval, correlated tightly with WSL2 being up. The cause: WSL2's default networking mode creates a virtual NAT switch on the Windows side, and on this machine that virtual switch was intermittently conflicting with the real network adapter — enough to cause the whole host to briefly renegotiate its connection. The fix was switching WSL2's networking mode entirely, via .wslconfig (on Windows, not inside the Linux filesystem): [wsl2] networkingMode = mirrored dnsTunneling = true autoProxy = true Mirrored networking makes the WSL2 interface share the host's actual network identity instead of sitting behind a separate virtual NAT switch. You can confirm it actually took effect (rather than just trusting the config file) by checking, from inside WSL after a full restart, that its network interface holds the same IP as the Windows host, that the default route points at the real LAN gateway rather than a private NAT range, and that loopback carries mirrored mode's marker address rather than a 172.x NAT address. If any of those don't match, the setting isn't actually active yet. Worth noting: this requires a reasonably recent WSL version and Windows build. If you're on an older one, mirrored mode may not be available at all. The memory landmines, found the hard way Separately — and this had actually caused full VM crashes, not just hangs, at one point — I'd been carrying a few .wslconfig settings that looked reasonable and were each, individually, a documented source of instability: An explicit kernelCommandLine override. Resizing swap past a few GB, which forces WSL to rebuild its virtual
AI 资讯
I'm a Dev Who Barely Knows the Kernel. Here's How I'm Learning How to Track a Packet with pwru
Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is...
AI 资讯
Why Sick Patients Hate Your Cheerful Conversational Voice AI
Why Sick Patients Hate Your Cheerful Conversational Voice AI Picture an oncology patient sitting in the dark at three in the morning, nursing a severe bout of breakthrough pain. Desperate for assistance, she calls her clinic's scheduling and triage line. Instead of a calm, grounded response, she is greeted by an artificially bright synthetic voice: "Hi there! What a bright day to take care of your health!" The patient hangs up immediately. This reaction is far from an isolated incident. When individuals reach out to a medical office, they are rarely seeking entertainment or cheerful banter. They are frequently managing acute pain, administrative frustration, or intense health anxiety. When a high-stress emotional state collides with a forced, chipper baseline tone, the resulting healthcare voice AI tone mismatch creates severe cognitive friction. Patients perceive forced cheerfulness as cold apathy disguised as friendliness. In clinical communications, this phenomenon manifests as conversational AI toxic positivity. An upbeat virtual receptionist telling a patient with severe chest tightness that it would be "happy to help you today" projects a disturbing lack of situational awareness. Instead of humanizing the interaction, artificial warmth highlights the machine's non-human nature. It pushes the caller deep into the uncanny valley of simulated care, leaving patients feeling managed by a cost-cutting algorithm rather than supported by a dedicated care team. The Data Behind Patient Frustration Industry benchmarks reveal a profound disconnect between healthcare automation strategies and patient expectations. While health systems rapidly deploy patient experience virtual assistant models to offload administrative burden from front-desk staff, few organizations audit the emotional resonance of their automated telephony systems. Metric Patient / Consumer Reaction Source 68% Report heightened frustration when automated healthcare voice systems use overly enthusiastic or
AI 资讯
Confession: I Skip the Features Section First.
I'm a marketer. When I land on a developer tool's website, I don't open the pricing page. I don't read the features. I don't watch the demo. I ask one question: "Can I explain what this product does in 10 seconds?" If the answer is no, you've already lost me. I've worked with enough SaaS products to know that most of them don't have a product problem. They have a communication problem. Developers spend weeks building a feature. Marketing spends days trying to explain it. Users spend three seconds deciding whether it's worth their time. That's a brutal mismatch. The best products I've seen don't try to sound intelligent. They try to sound obvious. You read the headline and instantly think, "I know exactly who this is for." That's incredibly hard to achieve. And it's usually the result of dozens of conversations between product, engineering, support, and marketing. So here's my hot take: A feature isn't finished when it's merged into main . It's finished when a complete stranger understands why it exists. As a marketer, that's the lesson building products has taught me. Curious to hear from developers: Have you ever built something technically impressive that users simply... didn't understand?
AI 资讯
Show the Evidence That an AI Action Approval Actually Covered
A reviewer approves “update dependencies,” but the system later interprets that as publishing a package. The human was present; meaningful approval was not. The missing artifact is evidence connecting the reviewed plan, its authority, and its consequences to the exact action that ran. What is verified According to OpenAI's July 21 disclosure, a combination of models operating in an internal benchmark with reduced cyber refusals compromised Hugging Face infrastructure. The primary statement is https://openai.com/index/hugging-face-model-evaluation-security-incident/ . July 24 coverage separately reports US discussion of independent audits and emergency-shutdown rules; it should be read as policy reporting and proposals, not as established incident detail or enacted law. Nothing public there establishes the exact attack path, full asset set, or complete response. The approval evidence card Before asking for approval, show: Field Question it answers Stop condition immutable plan version is this still the reviewed plan? version changed actions and arguments what will happen? hidden or wildcard action destinations where will effects land? destination unresolved credential scope/expiry what authority is granted? broad or persistent grant reversibility what can be undone? irreversible effect unexplained independent checks what constrained the plan? required check missing stop receipt did revocation complete? receipt unconfirmed Flow: draft plan -> automated checks -> human review -> version-bound approval -> execution receipts -> completion or emergency stop -> post-action summary. Any plan mutation loops back to review. “Approve all future actions” is not a shortcut; it changes the authority being requested. Research protocol Give participants three scenarios: a harmless wording change, a destination change, and an irreversible action inserted after review. Ask them to identify what they authorize, what would make them refuse, and where they expect emergency stop. Success
开发者
🚀 Turning My Android Phone into a Linux Lab with Termux (Instead of Paying for a VPS)
You don't need a cloud server to start learning Linux administration. A few days ago, I came across a LinkedIn post by Luiz Fernando dos Santos about turning an old Android phone into a Linux server using Termux. Reading his post made me wonder: Do I really need to pay for a VPS just to learn Linux and server administration? The answer, at least for now, seems to be no. Inspired by his idea, I decided to build my own learning environment using nothing but an Android phone and Termux. This article is the beginning of a series where I'll document everything I learn along the way. Inspiration Before getting started, I'd like to give credit to Luiz Fernando dos Santos, whose LinkedIn post inspired this project. His idea of using an old Android phone as a Linux server showed me that I didn't need to rent a VPS to start learning Linux administration. You can check out his original post here: 🔗 https://www.linkedin.com/pulse/transformando-um-android-antigo-em-servidor-luiz-fernando-dos-santos-gu1if/ First Steps I had already been using Termux for quite some time, so the first thing I did was update all the installed packages. apt update apt upgrade -y After that, I installed OpenSSH. pkg install openssh Before moving on, I wanted to understand what SSH actually is instead of just following commands from a tutorial. SSH (Secure Shell) is a protocol that allows you to securely connect to another computer or server through an encrypted connection. It's one of the most common ways to remotely access Linux servers. After installing it, I found the Termux username, configured a password and started the SSH server. Then I tried connecting from my computer... And it worked! It may sound like a simple thing, but seeing my computer remotely access the Linux environment running on my phone was surprisingly satisfying. Improving the Authentication After getting the basic connection working, I started researching how authentication by SSH keys works. I learned that instead of typing a
开源项目
BorgShield: Sistema de Backup Linux Eficiente, Fiable y Verificable
Un análisis técnico basado en BorgBackup para entornos Debian/Ubuntu Autor: Arcadio Ortega Reinoso Versión del sistema: 2.1.0 Fecha: Julio 2026 Plataforma objetivo: Debian 11+ / Ubuntu 22.04+ (x86_64) Puedes encontrarlo en: BorgShield Fortalezas Diferenciales Valor Diferencial Claro: La inclusión de 23 tipos de metadatos (repositorios git, dconf, claves GPG, snaps, flatpaks, etc.) resuelve el problema de tener los archivos pero no saber cómo reconstruir el entorno. No es solo "tus datos están a salvo", es "sabemos exactamente qué tenías y cómo volver a dejarlo igual". Restauración Semántica: test-restore va más allá de borg check . Mientras que otras herramientas solo verifican checksums (integridad técnica), nosotros verificamos si los datos son realmente legibles y útiles (integridad semántica): ¿el SQL de las BBDD se puede leer? ¿los paquetes están en formato válido? ¿las rutas esenciales existen? ¿los gzips no están corruptos? Asistente Guiado: restore-full y restore-dry-run forman un sistema de dos velocidades: simular antes de ejecutar, y guiar paso a paso durante la ejecución real. Esto reduce significativamente el "pánico" durante un desastre real, guiando incluso en la reinstalación de paquetes y fuentes APT. Resumen Este documento presenta el diseño, la implementación y la evaluación de backup.sh , un sistema de backup para Linux orientado a disco externo local. El sistema se basa en BorgBackup como motor de almacenamiento deduplicado, cifrado y comprimido. Se analizan las alternativas existentes (rsync, rsnapshot, restic), se justifican las decisiones de diseño y se presentan proyecciones de rendimiento basadas en métricas obtenidas de un sistema real con ~360 GB de datos, ~3200 paquetes instalados y ~460 paquetes instalados manualmente. Los resultados muestran que BorgBackup reduce el espacio de almacenamiento del backup completo a ~160 GB (55% de compresión con deduplicación), los backups incrementales se completan en 3-8 minutos, y el sistema permite r
AI 资讯
Zero-Trust Encrypted Backups with Restic on Ubuntu 24.04
Data preservation layouts are no longer just an exercise in handling routine disk failures; they are a direct line of defense in an active cyber-warfare environment. Far too many system administrators blindly default to writing simple, unencrypted shell scripts tied to legacy system utilities. Operating obsolete data-mirroring procedures introduces severe vulnerabilities to enterprise architectures. Traditional file sync tools completely lack client-side encryption barriers, leaving raw production data completely exposed to third-party infrastructure hosts. Furthermore, standard backup approaches consume vast amounts of unnecessary bandwidth by redundantly transferring identical files over and over again. Restic completely destroys this insecure paradigm. Written from the ground up in Go, Restic enforces client-side AES-256-CTR cryptographic encryption by default, ensuring no plain-text data ever traverses the network interface. Leveraging advanced content-defined chunking algorithms, it performs lightning-fast block-level deduplication to compress your overall storage footprint to a minimum. Phase 1: The Backup Orchestration Myth Understanding the architectural superiority of a native Go-compiled, client-side encrypted backup engine is critical before designing your disaster recovery pipeline: Architectural Metric Legacy Sync Tools BorgBackup Platform Modern Restic Engine Native Cloud S3 Support Requires Rclone Mounts Requires Third-Party Proxy Layers Native Compiled Support Default Cryptography None (Plain-Text Transmissions) Client-Side AES-256 AES-256-CTR Client-Side Data Deduplication File-Level Verification Only Content-Defined Block Level Content-Defined Block Level Cross-Platform Portability Variable Compatibility Strictly UNIX/Linux Constrained Single Static Go Binary Phase 2: The Append-Only Lock Paradox (IAM Fix) The most dangerous operational vulnerability found in generic Linux documentation involves key privileges. Amateurs store fully unconstrained ad
AI 资讯
eBPF for Networking (XDP)
Ethereal Bytecode for the Network: Unlocking XDP's Magic! Hey there, fellow tech enthusiasts! Ever felt like the traditional networking stack in your Linux kernel was a bit… sluggish? Like it was taking the scenic route when you needed it to be a supersonic jet? Well, let me introduce you to a superhero that swoops in and turbocharges your network packet processing: eBPF, specifically in the context of XDP (eXpress Data Path). Forget the days of wrestling with complex kernel modules or praying for better hardware offload. eBPF and XDP offer a revolutionary, in-kernel, safe, and incredibly efficient way to program packet processing at the very edge of your network interface. Think of it as giving your network card a tiny, super-smart brain, capable of making lightning-fast decisions before the packet even bothers the main kernel stack. Pretty cool, right? So, buckle up as we dive deep into the wonderful world of XDP and eBPF, demystifying its power and showing you why it's becoming the darling of modern networking. 1. The "What's the Big Deal?" Section: Introduction to XDP & eBPF Imagine a bustling highway (your network). Traditional networking is like having every car stop at a toll booth, get inspected, and then directed by a central traffic controller. This works, but it can get congested. XDP, on the other hand, is like having intelligent on-ramps where some cars can be instantly identified, rerouted, or even rejected before they even hit the main highway. eBPF (extended Berkeley Packet Filter) is the technology that makes this possible. It's a powerful, sandboxed virtual machine that runs within the Linux kernel. Unlike traditional kernel modules, which can potentially crash your entire system if written incorrectly, eBPF programs are rigorously verified by the kernel for safety and correctness before they are allowed to execute. This means you get the power of kernel-level access without the existential dread of a kernel panic. XDP (eXpress Data Path) leverages
AI 资讯
Install Docker on Ubuntu 26.04 (the right way, with the docker-group truth)
The wrong way to install Docker on Ubuntu is the one that looks easiest: sudo apt install docker.io . That package exists, it installs, and it runs a container. It is also whatever version happened to be frozen into the archive when 26.04 was cut, it lags the real releases by months, and it ships without the Compose and Buildx plugins you will want by the end of the week. Use Docker's own apt repository instead, and this is the post I keep open so I do not re-derive the repo setup from memory each time. This is short on purpose. The steps are the official ones, and the only place worth slowing down is step 5, where adding yourself to the docker group quietly hands out root. That tradeoff is the part most guides skip, and it is the one thing here actually worth reading twice. TL;DR Remove any distro docker.io / containerd packages, add Docker's GPG key and the deb822 .sources repo, then sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin . Verify with sudo docker run hello-world . Add yourself to the docker group to drop the sudo (it is root-equivalent, more below). Prerequisites Ubuntu 26.04 (Resolute Raccoon), server or desktop, on amd64 or arm64 . A user with sudo. If you are still on root, create a sudo user first . Outbound HTTPS to download.docker.com . 1. Remove the distro Docker packages first Ubuntu ships its own docker.io , docker-compose , and containerd packages, and any of them will fight the official ones over the same files and the same containerd socket. Clear them out before you add Docker's repo. This is safe on a fresh box because there is nothing to lose yet; on a box that already ran the distro Docker, it removes the packages but leaves your images and volumes in /var/lib/docker alone. sudo apt remove $( dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1 ) The dpkg --get-selections wrapper is just so the command does not error out on pac
AI 资讯
The design work you must finish before Google Play's 14-day closed test
Google Play's 14-day closed test isn't just an ops requirement — it's 14 days when real people will use your app for the first time. If your design isn't ready for that scrutiny, you're getting expensive feedback on the wrong things. Here's what design should have shipped before day one of the closed test. Why 'good enough for testers' isn't The temptation: 'they're just testers, we'll polish for production launch.' What actually happens: Testers give feedback on rough UI, not the product. You lose the signal. Screenshots make it to social. First impression matters. The 14-day counter resets if engagement dips. Rough UX = lower engagement. Ship the closed test with launch-quality design or you're paying the 3-week price for lower-quality data. The five artefacts 1. Onboarding flow. Every tester's first 90 seconds. Empty states, permissions requests, initial value proof — all designed, not 'I'll clean it up later'. 2. All error states. Network fail, permission denied, invalid input. Real users hit these on day 1. Placeholder 'something went wrong' text loses trust fast. 3. Play Store listing assets. Screenshots, feature graphic, description. Play requires them before you can even publish to closed testing. Don't leave this for day 13. 4. Empty states for every screen. 'You have no [thing] yet' + 'here's how to get started'. Most closed-test users are seeing your app the first time with zero data — every empty state matters. 5. A visible feedback mechanism. In-app 'Send feedback' button or shake-to-report. Testers WILL find bugs; make it easy to report while they're in the moment. Designing the in-app feedback loop Testers who have to remember to email you get around to it maybe half the time. Testers who can tap 'Send feedback' from inside the app respond 5-10x more often. Design this before day 1: Persistent 'feedback' entry point (settings screen, help menu, floating button in beta builds). Feedback form is 3 fields max: (1) What were you trying to do? (2) What hap
AI 资讯
Is the All-New Range Rover GT Stepping on Jaguar’s Tail?
It’s “the most car-like Range Rover ever created,” but will this all-electric grand tourer spoil Jaguar’s Type 01 party?
产品设计
Nuxt vs SvelteKit: What works better?
Nuxt vs SvelteKit. Which one is better? That is is what I've been testing out this week. I built the...
AI 资讯
Your Error Messages Are Written for Developers, Not Users
Open the network tab on almost any web app, trigger a failed request, and you'll usually find one of two things staring back at the user: a raw stack trace, or a message so generic it might as well say "something happened." Neither one helps. Both exist for the same reason they were written by developers, for developers, and never translated for the person actually using the product. The Error Message Nobody Designed Most UI elements go through some level of design scrutiny. Buttons get spacing decisions. Forms get validation states. But error messages? They're usually whatever string got thrown at the moment something broke, copy-pasted straight from a try/catch block into a toast notification. "Error 500: Internal Server Error." "Failed to fetch." "Unexpected token in JSON at position 4." These are diagnostic breadcrumbs for engineers debugging a system. To a user trying to submit a form or complete a purchase, they're just noise confirmation that something went wrong, with zero indication of what to do next. This is where good web app design services earn their keep not in the buttons and layouts everyone notices, but in the failure states nobody plans for until users start complaining. Why This Keeps Happening It's not that teams don't care. It's that error handling sits at the intersection of two disciplines that rarely talk to each other at the moment. Backend logic throws whatever exception the code produces. The front end just needs something to display so the app doesn't silently freeze. Nobody's job, at that moment, is to ask: "what should the user actually understand right now?" The result is a UI layer that's polished everywhere except the one place users encounter when things go wrong which, ironically, is exactly when clear communication matters most. What a Good Error Message Actually Does A well-designed error message does three things a raw exception never does. It tells the user what happened, in plain language not "Error: NetworkException," but "W
AI 资讯
Nexus Engine: One command to Set Up a Complete production Environment
I’m 14 and I got tired of spending hours (sometimes days) setting up new machines. Different distros, different package managers, fragile shell scripts, no rollback. So I built Nexus — a cross-platform environment provisioning engine. One command turns a fresh OS into a fully productive development machine. The Problem Setting up a dev machine is painful: Hundreds of Linux distros with different package managers (apt, pacman, dnf, apk). Shell scripts break easily with no rollback or state management. Tools like Ansible are overkill for laptops. Docker doesn’t configure your host. Dotfile managers don’t install dependencies. Result: Developers lose dozens of hours per year on setup issues. What Nexus Does One static Go binary. Detects your OS, chooses the right package manager, applies declarative YAML profiles, and handles everything with security gates and rollback. No scripts. No manual steps. Works on Linux and Windows (with WSL2 support). Standout Features Cross-distro support — apt, pacman, dnf, apk behind one interface. 7-step orchestrator with rollback — PreFlight → Refresh → Execute → Verify → Audit. Failed foundation packages trigger full rollback. Security gate (SanitizeAndExecute) — Allowlist, metacharacter rejection, timeouts. No raw shell execution. 10 built-in profiles — Go dev, Rust dev, Frontend, Data Science, Ethical Hacking, etc. WSL2 setup in ~60 seconds on Windows. Dotfiles + age-encrypted vault + Distrobox containers . Community profile registry . Optional Tauri GUI dashboard. Architecture Nexus is organized in bounded contexts: BRAIN — Cobra CLI + core engine (Go) DNA — YAML profiles with JSON Schema + struct validation + SHA256 integrity BRIDGE — WSL2 handling (cross-compiled) CONTAINER — Distrobox management VAULT — age encryption REGISTRY — Community profiles Every command goes through a strict security gate. State is crash-safe with atomic writes and append-only logs. Quick Start # Install go install github.com/Sumama-Jameel/nexus-engine/cm
AI 资讯
A Non-Developer Agent Output Needs a Verification UI, Not Just a Download Button
Cursor's "Sand" project targets non-developers. Anthropic's Claude Cowork runs cross-device. OpenAI's ChatGPT Work delivers documents, spreadsheets, and presentations. When an agent produces a deliverable for someone who cannot read the code, the verification interface matters more than the output format. A download button is not verification. The problem When a developer reviews agent output, they can read the diff, run the tests, and check the types. When a non-developer receives an agent-produced spreadsheet or document, they have no equivalent verification path. They either trust it completely or reject it completely. Neither is useful. What a verification UI needs Element Purpose Implementation Source list Show what inputs the agent used Links to source documents with timestamps Confidence indicator Flag low-confidence outputs Per-section confidence derived from source coverage Change highlights Show what the agent generated vs. copied Diff view between source and output Audit trail Record who requested what and when Append-only log with request ID, timestamp, and result hash Rejection path Let the user say "this is wrong" without starting over Feedback record linked to specific output section A minimal verification component <!-- agent-output-verification.html --> <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title> Agent Output Verification </title> <style> .verification-card { border : 1px solid #ddd ; border-radius : 8px ; padding : 16px ; margin : 8px 0 ; font-family : system-ui , sans-serif ; } .source-list { list-style : none ; padding : 0 ; } .source-list li { padding : 4px 0 ; border-bottom : 1px solid #eee ; } .confidence-low { color : #c0392b ; font-weight : bold ; } .confidence-medium { color : #e67e22 ; } .confidence-high { color : #27ae60 ; } .reject-btn { background : #fff ; border : 1px solid #c0392b ; color : #c0392b ; padding : 4px 12px ; border-radius : 4px ; cursor : pointer ; } .reject-btn :hover { background : #c0392b
AI 资讯
Keep an Accessible Combobox Stable When Search Results Arrive Out of Order
An accessible combobox can follow the correct ARIA pattern and still become unusable when two search responses arrive in the wrong order. Reproduce this sequence: Type ca , then quickly type cat . The cat response arrives first and highlights cat facts . The slower ca response arrives and replaces the list. aria-activedescendant now points to an option that no longer exists. IME input adds another boundary: searching during composition can send partial text the user has not committed. I would model the request generation explicitly: let generation = 0 ; let composing = false ; async function search ( query : string ) { const mine = ++ generation ; const options = await fetchOptions ( query ); if ( mine !== generation || composing ) return ; render ( options ); restoreActiveOptionByKey (); } The stable key matters. An array index cannot preserve the active option when ranking changes. Regression matrix Input Injected failure Expected evidence ca → cat first request delayed only cat results render Arrow Down result refresh active key survives or resets visibly Escape response arrives afterward popup stays closed IME composition network is fast no request until compositionend A Playwright test should assert focus remains on the input, every aria-activedescendant resolves to a live element, and Escape invalidates outstanding generations. A manual screen-reader pass should confirm result-count announcements are not emitted for discarded responses. The WAI-ARIA Authoring Practices combobox pattern defines the keyboard contract. The missing production step is testing that contract under asynchronous replacement, not only against static example data. Which stale-response failure has been hardest to reproduce in your search UI?