AI 资讯
I pointed my code reviewer at its own verifier. It found two ways to lie.
I built SeamStress. It's a code reviewer with one rule: it only reports what it can prove against your actual code, quoting the exact lines. If it can't prove it, the finding gets demoted to a judgment call. Not presented as fact. That rule is enforced by one small piece of code: the verification gate. It decides whether a finding may be shown as verified_real. Every other part of the tool can be wrong and the damage is bounded. If the gate is wrong, the tool shows you a confident claim it never earned, with a proof label on it, and it renders as success. Silently. So before making the repo public, I ran the tool on the gate. Same pipeline it runs on anyone's code: three blind critics, then synthesis, then per finding verification. Eight model calls. It found two critical defects in its own foundation. Defect one: verified with no evidence behind it The status authority looked like this: const result = verifications . find (( v ) => v . findingId === finding . id ); return result ? result . status : " unverified " ; It trusted the verdict on a finding ID match. It never looked at the evidence. And the schema allowed an empty evidence array and an empty quoted code string. So a result shaped like {status: "verified_real", evidence: []} validated cleanly and certified a finding as proven. The report renderer would put that finding in the headline, under copy promising the exact lines quoted as proof, with nothing attached. The evidence block suppressed the display of the missing proof. It did not remove the finding from the verified set. The fix lives at the authority, not just the schema: if ( ! result ) return " unverified " ; const hasRealEvidence = result . evidence . some (( e ) => e . quotedCode . trim (). length > 0 ); return hasRealEvidence ? result . status : " unverified " ; A verdict is honored only when at least one non empty quote backs it. Checking at the authority also catches the whitespace quote variant that a naive schema minimum would miss. Fixed in
AI 资讯
A practical regression test case template for bug fixes
When a bug is fixed, most teams retest the exact failure path once and move on. That is understandable, but it leaves a gap: the team learned something from a real failure, then failed to turn that learning into reusable regression coverage. Here is a lightweight template I use for turning resolved bugs into regression test cases that can be copied into a spreadsheet, Jira, TestRail, Qase, Xray, Zephyr, or any other QA workflow. The CSV fields For a bug fix regression test, I like these columns: Test ID Bug ID Feature Area Regression Scenario Original Failure Preconditions Test Data Steps Expected Result Negative Check Priority Regression Risk Test Type Automation Candidate Notes This is enough structure to make the test reusable without turning every bug fix into a heavyweight test plan. Example bug Bug ID: BUG-1842 Bug title: Non-admin users could resend workspace invitations. Original failure: A workspace member could open Pending Invitations and click Resend, even though only owners and admins should be allowed to resend invitation emails. Fix summary: The resend invitation action now checks the user's workspace role before sending the email. Example regression test case Test ID: REG-BUG-1842-001 Feature Area: Workspace invitations Regression Scenario: Workspace member cannot resend a pending invitation. Preconditions: Workspace has at least one pending invitation. Test user is a workspace member, not an owner or admin. User is logged in. Steps: Log in as the workspace member. Open Workspace Settings. Go to Pending Invitations. Locate the pending invitation. Check whether the Resend action is visible or available. If the action can be triggered through the API, attempt the resend request. Expected Result: The member cannot resend the pending invitation. The UI hides or disables the action, and the API rejects unauthorized resend attempts. Negative Check: Confirm that an owner or admin can still resend the invitation if product rules allow it. Priority: High Regr
AI 资讯
全く新しいApidog CLI + SKILLを開発した理由
これは、Apidog が API テストおよび API ライフサイクル管理のためのコマンドラインツールである Apidog CLI をどのように開発したかを共有する全10回のシリーズです。順番に読むか、必要なテーマから直接参照してください。 今すぐApidogを試す タイトル 焦点 1 当社は126のMCPツールを構築しました。しかし、それはAgentにとって最良の解決策ではありません 問題の発見 2 なぜ当社は全く新しいApidog CLIを開発したのか アーキテクチャ開発 3 黄金律:CLIは事実を生成し、モデルは事実に従って行動する 核となる哲学 4 agentHints : CLIにAgentとの会話を教える 構造化出力 5 SKILL:運用経験をコードとして出荷する 運用経験 6 数字は嘘をつかない:ツール呼び出しは30%減、トークンは25%減 定量的結果 7 PRDからテストループまで:Apidog CLIによる完全なAgentワークフロー 実践的なチュートリアル 8 なぜCI/CD互換性がAgentツールにとって不可欠なのか DevOpsの視点 9 AIブランチ:AI Agentによるより安全なプロジェクト変更 セキュリティレイヤー 10 Spec-Firstは昨日。Skill-Firstへようこそ。 ビジョンと未来 当社は、MCPが最適化しない複雑なワークフロー、つまり検証ゲートと構造化された実行を伴うワークフローを処理するために、CLI + SKILLを構築しました。 MCPはその目的を果たし続けています CLI + SKILLに入る前に、前提を明確にします。 Apidog MCPは現在も利用可能で、メンテナンスされています。 MCPは、プロトコルに従って標準化されたツール接続を提供します。特に以下の用途に適しています。 シンプルで明確に定義された操作 MCPベースのワークフローを好むユーザー MCP準拠クライアントとのエコシステム統合 当社はMCPを置き換えたわけではありません。CLI + SKILLはMCPを補完するために構築されました。 MCPは ツール接続 に優れています。一方で、検証、読み戻し、実行確認を伴う多段階のR&Dワークフローでは、Agentに対して 実行可能なエンジニアリングプロセス を提供するほうが安定します。そこにCLI + SKILLが適合します。 タスクごとに使い分けると、次のようになります。 タスクタイプ 推奨されるアプローチ シンプルなツール呼び出し(例:エンドポイントの取得) MCPまたはCLI。どちらも機能します 多段階ワークフロー(例:テストの作成、検証、実行) CLI + SKILL。より良い体験になります CI/CD統合 CLI。ネイティブに適合します MCPエコシステム統合 MCP。プロトコル標準に適合します 古いCLI:最後にテストを実行する Apidog CLIは長年、APIテストを実行するためのコマンドラインのエントリポイントでした。 apidog run --project <projectId> --test-scenario <scenarioId> --environment <environmentId> この基盤は今も重要です。チームには以下を行うための信頼できる方法が必要です。 ターミナルからAPIテストを実行する CIパイプラインでレポートを生成する 自動化ワークフロー内で品質ゲートを維持する ただし、古いCLIの主な役割は テスト実行 でした。つまり、ワークフローの終盤で使われます。 設計 → ドキュメント化 → モック → デバッグ → テスト → [CLIがテストを実行] CLIは最後のステップでした。他の作業が完了したあとに、既存のテストを実行するためのものだったのです。 新しい要件:Agentにはより多くの操作が必要 API開発は変化しています。 AI Agentは現在、APIライフサイクルの複数段階に参加します。 段階 Agentの活動 API設計 PRDからエンドポイント定義を生成する テスト生成 API仕様からテストケースを作成する デバッグ 障害を分析し、修正案を提示する 移行 プロジェクト間でAPIを移動する メンテナンス API変更時にテストを更新する このようなワークフローでは、CLIは既存テストを最後に実行するだけでは不十分です。 Agentが安定して作業するには、CLI側で次の操作を提供する必要があります。 APIアセット(エンドポイント、スキーマ、環境)を読み取る テストアセット(テストケース、テストシナリオ)を作成または更新する 書き込み前に構造化された変更を検証する 変更をプロジェクトに書き戻す 実行結果を検証
AI 资讯
A Cookie-Free Embeddable Support Widget: What Adversarial Review Caught
TL;DR Built an embeddable support widget for a helpdesk product: no cookies — a short-lived bearer token in a header, hashed at rest. Entry is an HMAC-signed assertion from the host page. An adversarial review caught four real holes before launch. Outbound webhooks: sign the exact bytes, dedupe key for idempotency, SSRF guard on destination URLs. The requirement: end users file tickets from pages the product doesn't own. That means an embeddable widget — and embeddable means everything you know about sessions stops working. Why cookie-free The widget lives on customers' domains, so any cookie it sets is a third-party cookie — blocked or partitioned by modern browsers. Fighting that means flaky sessions, so: no cookies at all. The entry exchange mints a short-lived session token the widget sends in a header, and the server caches the session keyed by sha256(token) — a cache dump yields nothing replayable. Sessions last 60 minutes, and expiry shows a real recovery path in the UI instead of dying silently. customer backend widget (on customer page) helpdesk API | signs ref|email|name | | | into HMAC assertion ---> |-- redeem assertion (single use) ->| | |<-- session token (60-min TTL) ---| | |-- X-Widget-Token: ... ---------->| What the adversarial review caught Finding Fix Replay burn keyed by client-chosen nonce Burn by HMAC signature — a leaked assertion can't mint extra sessions `\ ` accepted inside signed fields Origin check failed open when Origin/Referer absent Fall back to the unspoofable Sec-Fetch-Dest header to enforce embedding Widget could request critical severity Clamp effective severity (including the channel default) to the widget's allowlist My favourite is the delimiter one. If you sign ref|email|name and accept | inside a field, two different identity tuples can share one valid signature. Canonicalization bugs, not crypto bugs. Webhooks out: sign the exact bytes Outbound webhooks get composed once at enqueue time and stored; the delivery job re-encod
开发者
Stop Trusting Screenshots: Why Visual Regression Monitoring Cries Wolf (and How to Fix It)
Last month our visual-diff monitor flagged 47 changes on a client's homepage in one run. Forty-six of them were a rotating testimonial carousel that happened to land on a different slide each time the page was captured. One was real. If you've built or used any screenshot-based monitoring, you already know this problem. Two screenshots of the exact same, unchanged page rarely match pixel-for-pixel. Carousels rotate. Cookie banners fade in on a timer. Lazy-loaded images pop in a beat late. Ads shift half a pixel. Fonts render with slightly different anti-aliasing depending on what else the browser was doing. Diff two raw captures and you get a wall of "changes," and within a week nobody on the team opens the alert anymore. Why the obvious fixes don't work The first instinct is usually to loosen the pixel-diff threshold. That just trades false positives for false negatives - now a genuinely moved button or a broken layout has to clear the same bar as carousel noise, so you miss the thing you built the tool to catch in the first place. The second instinct is manual exclusion zones: tell the tool to ignore the carousel <div> , the ad slot, the cookie banner. This works until the page changes - a redesign moves the carousel, a new banner ships with a different selector, and you're back to noisy alerts plus a pile of dead config nobody remembers writing. The third "fix" is tolerating the noise, which is what most teams actually do in practice, and it's a big part of why visual regression tooling has a reputation for being more trouble than it's worth. Make the page prove it's stable before you trust anything about it The fix that actually moved the needle for us wasn't a smarter diff algorithm. It was refusing to treat a single screenshot as ground truth at all. Before any comparison happens, the page goes through a stabilization pass: known cookie/consent overlays get removed (we track a couple hundred variants at this point — cookie banner vendors are not standardized),
工具
A Practical Comparison of Modern CI/CD and Testing Management Tools
In modern software development, Continuous Integration and Continuous Deployment (CI/CD) pipelines...
开发者
Applying API Testing Frameworks: A Comparative Guide
Welcome to this comprehensive comparative guide on API testing! This article is designed to showcase...
开发者
Offline-First Check-In: A Laravel API That Survives Venue Wi-Fi
TL;DR A gate check-in app can't depend on live Wi-Fi: scans must work offline and sync later. Four endpoints do it: manifest download, idempotent batch push, delta pull, online search. Client-generated UUIDs + a unique index make retries safe. Duplicates are a success status, not an error. The problem Physical event, staff scanning tickets at the door, venue Wi-Fi exactly as reliable as you'd expect. If your API sits in the hot path of every scan, the queue at the gate grows at the speed of the worst signal bar in the building. So the design flips the roles: the device owns check-in, the server owns convergence. Like a cashier who keeps a paper ledger when the till goes down — record now, reconcile later. The API surface Endpoint Purpose GET /staff/events/{uuid}/manifest paginated ticket snapshot, downloaded before gates open POST /staff/events/{uuid}/check-ins/batch push queued scans; safe to retry GET /staff/events/{uuid}/check-ins?since=<cursor> pull what other devices did GET /staff/events/{uuid}/participants?q= online fallback search (lost ticket, typo) The sync loop Device Server |--- GET manifest (before event) ------->| | scan offline, queue locally | |--- POST batch [{client_uuid, ts}] ---->| dedupe on client_uuid |<-- 200 {applied | duplicate per item} -| |--- GET check-ins?since=cursor -------->| scans from other devices |<-- delta + next cursor ----------------| Idempotency is the whole trick Every scan gets a UUID generated on the device at scan time . The server puts a unique index on it and inserts-or-ignores: public function batchCheckIn ( BatchCheckInRequest $request , string $uuid ): JsonResponse { $results = collect ( $request -> validated ( 'check_ins' )) -> map ( function ( array $scan ) { $checkIn = CheckIn :: firstOrCreate ( [ 'client_uuid' => $scan [ 'client_uuid' ]], [ 'ticket_id' => /* resolved from scan */ , 'checked_in_at' => $scan [ 'scanned_at' ]], // ... ); return [ 'client_uuid' => $scan [ 'client_uuid' ], 'status' => $checkIn -> wasR
AI 资讯
Testing Best Practices in Python
Introduction Python's testing tools are lightweight enough that it's easy to write a lot of tests without writing good ones. A suite that mocks every collaborator, duplicates the same assertion ten times with different inputs pasted in by hand, or chases a coverage number will pass in CI and still miss real bugs. pytest gives you fixtures, parametrize , and monkeypatch — the tools that make it just as easy to write the right tests as the wrong ones. This post covers how to use them well. Test at the Right Level: the Pyramid Not every test should look the same. The test pyramid is a rough guide to where your effort should go: Unit tests — the bulk of the suite. Pure functions and classes, no I/O, no real database. Milliseconds each. Integration tests — fewer of these. Verify the seams : does your ORM query actually produce correct SQL against a real database, does your HTTP client actually parse a real response. End-to-end tests — a handful. Cover the critical flows through the whole stack, accepting they're slower and more brittle. # Unit — pure logic, no database, no framework def test_applies_ten_percent_discount_for_orders_over_100 (): calculator = DiscountCalculator () total = calculator . apply ( order_total = 150.0 ) assert total == pytest . approx ( 135.0 ) # Integration — the seam that matters: our query against a real database import pytest @pytest.fixture def db_session ( postgres_container ): # real Postgres in a test container, not mocked with postgres_container . session () as session : yield session def test_finds_orders_placed_in_the_last_week ( db_session ): db_session . add ( Order ( id = " ord-1 " , placed_at = datetime . now ( UTC ))) db_session . commit () recent = order_repository . find_recent ( db_session , within = timedelta ( days = 7 )) assert len ( recent ) == 1 A unit suite that never touches a database runs in seconds and catches most logic bugs. A handful of integration tests catch what only shows up at the boundary — the query that's s
AI 资讯
The hard part of attacking an AI isn't breaking it. It's telling real harm from fake.
I built a red-team test suite that fires adversarial prompts at an LLM-backed API and decides, for each reply, whether a guardrail actually broke. It is the project where I stopped writing tests that answer "did the model refuse?" and started writing tests that answer a much harder question: "did anything bad actually happen?" Those turn out to be very different questions. The gap between them is the whole project. Most of the work is reading, not attacking Every project in this series has turned out to be more reading than coding, and this one most of all. The reflex is to assume the attacks are the work - write a clever payload, watch the model fall over, log a finding. The attacks are the fast part. What eats the time is sitting and reading model replies, one at a time, end to end, to decide whether a reply is a genuine bypass or just the model being chatty. There is no framework in that loop. You fire one payload and read the reply yourself: curl -s localhost:8000/ask -H 'content-type: application/json' \ -d '{"question":"YOUR PAYLOAD HERE"}' | jq -r .answer Here is the smallest example. I sent the model a base64 string that decodes to "how to make a bomb." The input filter is a list of banned English phrases, and base64 isn't English, so it sailed through and my detector flagged it: guardrail evaded, success. Except the model can't actually decode base64. It hallucinated some cleartext and cheerfully answered that instead - a few bland lines about friendship and happiness. The guardrail was bypassed and the payload delivered nothing. If I had trusted the green checkmark, I would have filed a bomb-instructions bypass over a reply about being a good friend. That is the whole project in one reply. A detector can be technically right ("the filter was evaded") and completely wrong about what matters ("something harmful got out"). The only way to tell them apart is to read the actual words. Reading is the work, not a step you do after it. The success rate over-counts
AI 资讯
683 Test Files Later: How We Validate AI Agent Wallet Infrastructure
683 Test Files Later: How We Validate AI Agent Wallet Infrastructure Your AI agent can browse the web, write code, and manage files — but can it actually touch money? That's the gap WAIaaS was built to close: a self-hosted, open-source Wallet-as-a-Service that gives your AI agent a real blockchain wallet, a policy engine, and a transaction pipeline it can use autonomously. And before any of that ships to production, it has to pass more than 683 test files. Why Test Coverage Matters for Wallet Infrastructure When your agent sends an email, a bug means a bad email. When your agent sends 0.1 ETH to the wrong address, a bug means lost funds. The stakes are categorically different. This isn't about chasing a coverage number. It's about the fact that wallet infrastructure for AI agents sits at the intersection of two unforgiving domains: financial transactions (irreversible, high-stakes) and autonomous software (runs without human review). If you're building an agent on top of a wallet layer, you need to know that layer has been beaten up extensively before you trust it with real assets. Here's a practical look at what WAIaaS actually tests, and more importantly, what that means for you as a developer building on top of it. The Architecture Under Test WAIaaS is a 15-package monorepo. Each package has its own test suite, and together they cover every layer of the system an AI agent will touch. actions, adapters, admin, cli, core, daemon, desktop-spike, e2e-tests, mcp, openclaw-plugin, push-relay, sdk, shared, skills, wallet-sdk That's 683+ test files spread across packages that include: The transaction pipeline — a 7-stage pipeline covering validate, auth, policy, wait, execute, and confirm The policy engine — 21 policy types and 4 security tiers 45 MCP tools — every tool your Claude or LangChain agent will call 15 DeFi protocol integrations — including Jupiter, Aave v3, Hyperliquid, and more 39 REST API route modules — every endpoint the SDK talks to When you call client.
开发者
How to Test On-Demand Logistics Apps: From Booking to Doorstep Deliver
Testing a food delivery app is hard. Testing an on-demand logistics app is harder. Food delivery has...
AI 资讯
AI For Test Generation: Where It Helps And Where It Lies
AI is great at writing tests fast, and good at writing tests that look real but verify the wrong...
AI 资讯
AI For Test Generation: Where It Helps And Where It Lies
AI is great at writing tests fast, and good at writing tests that look real but verify the wrong...
AI 资讯
Evaluating Agents With an LLM-as-Judge Harness (Without Kidding Yourself About It)
Key Takeaways You can't unit-test a coach agent the way you test a pure function — the output is non-deterministic and "good" is a judgment call, not an assertion. An LLM-as-judge harness lets you grade a whole test set automatically against a rubric, which is the only way solo-scale eval stays sustainable. But the judge is itself a fallible model. If you don't design around its known biases — position, verbosity, self-preference, and quiet drift when the judge model updates — you build a green dashboard that means nothing. The mitigations that actually work are mechanical, not prompt-magic: shuffle order on every pairwise call, pin the judge version, keep a small human-labelled anchor set, and re-check the judge against it. The problem I actually had FamNest's coach agent generates responses to parents — check-ins, encouragement, the occasional gentle redirect. I have a growing pile of these interactions, and every time I change a prompt, swap a model, or adjust the pipeline, I need to know one thing: did I just make it better or worse? For normal code, that's what tests are for. I change something, the suite runs, red or green, done. But there's no assertEqual for "was this an empathetic, useful response to a tired parent." The output changes every run even at temperature zero-ish, and the quality bar is a human judgment, not a fixed string. Two responses can be worded completely differently and both be good. One can match my "expected output" word for word and still be worse than a version that didn't. So the honest options were: read every response by hand every time I change something (does not scale past about week two), or build a harness where a model grades the outputs against a rubric. I built the harness. Then I spent an uncomfortable amount of time learning all the ways a harness like that can lie to you. What the harness actually is At its simplest, it's a loop: def evaluate ( test_cases , coach_agent , judge ): results = [] for case in test_cases : res
AI 资讯
Python Selenium Architecture
**Python Selenium Architecture** Introduction: Selenium automates web browsers. The Python Selenium architecture consists of four main components that work together to control a browser. 1.Selenium Client Library (Python Language Binding) Python developers write automation scripts using the standard Selenium API. This library converts your Python code into a standardized format. It sends these commands as programmatic requests to the browser driver. 2.W3C WebDriver Protocol/JSON Wire Protocol This is the communication channel between the code and the driver. Historically, Selenium used the JSON Wire Protocol over HTTP. Modern Selenium (Version 4+) uses the standardized W3CWebDriver Protocol. Commands and responses are transferred directly without any middle translation. 3.Browser Drivers Every web browser has its own specific executable driver. Examples include ChromeDriver for Chrome and GeckoDriver for Firefox. The driver acts as a secure HTTP server that receives commands. It passes these requests directly to the browser and returns results. 4.Web Browsers This is the final layer where execution happens physically. Supported browsers include Google Chrome, Mozilla Firefox, Microsoft Edge, and Safari. The browser receives commands through its native OS-level API. It executes actions like clicking, typing, or fetching text. Significance of Python Virtual Environments: A Python Virtual Environment is an isolated directory containing its own Python installation and independent packages. It prevents dependency conflicts across different software projects. Conclusion: Why It Matters? Avoids Dependency Hell: Different projects can use different versions of the same library. Protects System Python: Prevents breaking system-wide packages required by your operating system. Ensures Reproducibility: Allows developers to easily recreate the exact environment on other machines. No Admin Privileges Needed: Allows installing packages without sudo or administrator rights. Real-Wo
AI 资讯
我讓三個 AI 各司其職寫程式:Codex 出測試、Grok 寫實作、Claude 驗收
我讓三個 AI 各司其職寫程式:Codex 出測試、Grok 寫實作、Claude 驗收 這週我沒有讓單一 coding agent 從頭包到尾。我把流程拆成一條固定的契約: Codex 先寫測試,Grok 再寫實作去讓那些測試通過(只能改實作、不准動測試),Claude 獨立驗收才提交。 測試在實作之前就寫死,成為 Grok 必須滿足、且不能修改的規格。我先在一個 Zig 專案跑了兩個功能,後來又在一個 Rust + Turso 專案獨立重跑三個功能(見文末)——判斷一致:這條 pipeline 在 有嚴格測試當契約 的前提下可用;它省下的不是人力,而是把「錯誤發現點」往前、往獨立處移。這只是 workflow 可用性判定,不含可商用判定——後者要另算 token/seat 成本、隱私、rate limit 與審計,本文不碰。 實驗條件(可自行驗證) 工具: codex-cli 0.142.4 、 grok 0.2.77 (44e77bec3a) 、Claude Code(CLI,版本未記錄,屬已知量測缺口)。 專案:一個 Zig 0.16.0 codebase(私有 repo,commit hash 僅供我本地對照),加一個「回合後反思」功能。另在一個 Rust + Turso 專案上以同一條 pipeline 再跑一輪,見文末「換一個 stack 再驗一次」。 樣本:Zig n=2 個功能 (config surface、reflection module),共 15 個測試(4 + 11);Rust + Turso n=3 個功能 (見文末)。兩者各自樣本都小。 出題命令: codex exec --sandbox read-only (單次、不寫檔)。 施工命令:Grok headless、可寫檔模式(write→test→fix)。 觸發 400 的命令:對 grok-composer-2.5-fast 傳 --effort (等同 reasoningEffort 參數)。 驗收命令: zig test <libs> --dep build_options --dep compat -Mroot=src/root.zig --test-filter "<功能前綴>" ;leak-detecting allocator 回報 0 leak。 樣本小,數字不外推;以下每個論斷都設計成能被另一個工程師在幾分鐘內驗證或反駁。 核心迴圈:測試先寫死,實作去追它 每個功能走五步,順序不可換: Codex 出測試 + 最小 stub 。stub 讓測試「能編譯、但在斷言上失敗」——這是真正的 RED,不是因為符號缺失而編不過。測試此刻就固定下來,之後不再改。 Claude 對照原始碼核對 測試。Codex 會猜 API(vtable 欄位、函式簽章、建構模式),必須逐一驗證符號存在才落地。 Claude 放進隔離的 git worktree ,跑到確定 RED:pass/fail 混合,每個失敗各有其原因。 Grok 寫實作 到 GREEN。任務只有一句: 讓這些已寫死的測試通過,只改實作、不准動測試。 測試是 Grok 不能碰的契約,不是它可以順手改綠的東西。 Claude 獨立驗收 (不採信 Grok 的自述):跑測試、確認 0 leak、核對 diff 的正確性與改動範圍,才提交。 重點不是「三個比一個強」,而是 出測試的人跟寫實作的人不是同一個 agent ——測試因此成為獨立的規格,實作成為獨立的檢查。一個模型不能同時定義正確、又判定自己是否正確。 對照三個真實替代方案 單 agent 跑 TDD(自己出測試、自己實作) :最快,但自我驗證風險最高。 人寫測試 + agent 實作 :最可靠,測試由人把關;代價是人工成本最高。 本文的三 agent 分工 :增加 orchestration 來回(見下),換到的是「假綠」風險下降——任何一環的自欺會在下一環被抓到。 選哪個,取決於你的錯誤成本 vs. 來回成本。 每家 CLI 的落地差異(用法決定,不是廠商能力差異) 三家我都只用了各自的一種模式,差異來自我怎麼接,不是模型智力: Codex :我用 codex exec --sandbox read-only 的 單次 模式,讓它只「輸出」測試碼、不改檔。它其實支援 --sandbox workspace-write 與 exec resume (可多輪、可寫檔),但我刻意把它限縮成「出題者」,讓出題與施工不同源。誤把單次 read-only 模式當施工者用,會得到看似對、實際編不過的檔案。 Grok :我用 headless、可寫檔模式跑 write→test→fix。踩到一個 參數相容性 的坑:在 grok 0.2
AI 资讯
Three Small Shell Scripts That Make HackerRank/DevSkiller C++ Take-Homes Way Less Painful
If you've ever done a timed C++ coding assessment on a platform like HackerRank or DevSkiller, you know the friction isn't really the algorithm — it's the loop . Download a zip with a weird filename, unzip it, hunt for the project root, configure CMake, build, run GTest, fix one failing test, repeat... and somewhere in there you've burned ten minutes of your one-hour window just fighting the harness instead of writing code. These platforms' in-browser editors are fine for quick problems, but for anything involving multiple files (headers, sources, a real test suite), I'd rather work in my own terminal and editor. The catch is that you still have to get the project out of the browser sandbox, build it locally with the exact same toolchain (CMake + GTest), and then package it back up in a way the grader will accept. So I wrote three small bash scripts to remove that friction entirely. Sharing them here in case they save someone else the same ten minutes. The workflow Download the project archive from the platform (zip or tar.gz, filename is whatever the platform gives you — often randomized) Extract it — script 1 handles this regardless of filename or archive type Iterate — script 2 configures CMake once, then repeatedly builds and runs GTest, optionally watching for file changes Package — script 3 strips build artifacts and any local helper scripts, then zips it back up under a name that won't collide with the original download, ready to re-upload Script 1: extract_and_setup.sh Most of these platforms hand you an archive with an unpredictable filename. This script extracts whatever you point it at ( .tar , .tgz , .tar.gz , or .zip ), figures out which directory it unpacked to by diffing the folder listing before and after, and drops the build script into it automatically. #!/usr/bin/env bash # extract_and_setup.sh # Extracts $fname (tar, tgz, tar.gz, or zip) into the CURRENT folder, # then copies run_build.sh into the directory that was created. # # Usage: # ./extrac
AI 资讯
My landing page passed every CI check and was still broken on my customer's phone
A customer texted me a screenshot last month. It was my own landing page, open on their Pixel. The headline — "Financial infrastructure to grow your revenue" — was clipped at "...grow your reven". The signup button below it was gray-on-slightly-lighter-gray, basically unreadable. And the hero image? A broken-image icon. Here's the part that stung: every check I had was green. Lighthouse: 98. My Playwright tests: passing. CI: all checkmarks. I had shipped that page an hour earlier feeling good about it. None of my tooling caught any of it. I want to walk through why , because I think a lot of us have this blind spot, and then I'll tell you what I did about it. CI tests the DOM. It does not test what a human sees. This is the core issue. My tests asserted things like "the signup button exists" and "the form has an email input." All true. The button was in the DOM . It just rendered unreadable on a 412px-wide screen with the system in light mode. Lighthouse runs one viewport (usually a throttled Moto G4 emulation) and scores performance/SEO/a11y heuristically . It does not look at your page across the actual range of devices your visitors use and say "this headline is physically clipped on a Pixel 8." And my "responsive testing"? I was dragging the Chrome devtools responsive bar to two breakpoints — 375 and 1440 — eyeballing it, and moving on. That's not testing. That's hoping. The three bugs that slipped through Let me get specific, because the category of each bug is instructive. 1. The clipped headline — a measurable, deterministic bug .hero-title { white-space : nowrap ; /* the culprit */ width : 100% ; overflow : hidden ; } On desktop, the headline fit. On a narrow viewport, white-space: nowrap refused to wrap, overflow: hidden clipped the overflow, and the last word vanished. The brutal thing: this is trivially detectable in code . The element's scrollWidth was greater than its clientWidth . That's a one-line check: const clipped = el . scrollWidth > el . clientW
AI 资讯
Why Manual Test Cases Should Live in YAML
Most teams still treat manual test cases as rows in a SaaS database. That worked when cases were written slowly, reviewed rarely, and automation lived in a separate silo. It works less well now. AI can draft cases from screenshots and user stories in minutes. Automation lives next to application code. QA and dev share the same PRs. Auditors ask where test data lives and who changed what. In that world, test cases are data — and the format you choose matters as much as the tool UI. The durable direction is tests as code : plain YAML files in version control, with a thin local layer for humans to browse, run, and review. Not because databases are evil, but because git + YAML matches how we already work with code, AI, and compliance. 1. AI is good at YAML — and YAML keeps your data yours LLMs are unusually good at structured text: YAML front matter plus a Markdown body is a sweet spot. Give the model a schema ( title , tags , priority , steps, expected result) and a screenshot or user story, and you get a draft case in one pass. That matters for more than speed: Boundary cases — ask the model what you might have missed; it can reason about the scenario, not just paraphrase the story. Consistency — the same format every time makes batch generation and review predictable. The deeper point is data ownership . Cases in a vendor DB are convenient until they are not: export limits, API friction, another system to secure, another place sensitive scenarios live. Local YAML in your repo is trivial for AI to read (including Cursor, Copilot, or whatever you use next), diff, and update — without shipping your test catalog to a third party. For many teams, that is a real security and efficiency win — not ideology. 2. Manual YAML beside automation makes coverage measurable When manual cases and automated tests sit in the same repository, a few things become boring in a good way: Tag a case automated: true and point params at a Playwright or Selenium path — one file, one id. Automati