AI 资讯
The Cheap Way to Add AI Review to CI: Small Local Models Plus Prompt Caching
I wired an AI code reviewer into CI, felt clever, and then looked at the bill after a busy week of PRs. Every push, every commit, sending full diffs to a big frontier model. It added up faster than I expected, and most of what it was reviewing was formatting changes and README edits that did not need a genius reading them. So I rebuilt it as two tiers, and the cost dropped hard without losing the catches that mattered. The idea is simple. Do not send everything to the expensive model. Use a cheap model as a bouncer that decides what is even worth escalating, and reserve the big model (with caching turned on) for the files that could actually hurt you. Tier one: a cheap triage pass The first tier looks at the diff and answers one question: is anything here risky enough to justify a real review? That is a classification task, and classification does not need a frontier model. I run this tier on a small local model. On my own machine that is Ollama with qwen2.5-coder, but in CI it can be a self-hosted small model or the cheapest cloud tier your provider offers. The job is triage, not judgment. The triage prompt is deliberately narrow. I do not ask it to review. I ask it to route: You are a triage filter for code review. For the diff below, output JSON only: { "risk": "low" | "high", "reason": " <one short phrase > " } Mark "high" if the diff touches: auth, access control, money/token math, cryptography, SQL or shell string building, deserialization, file paths, network calls, or anything that changes who can do what. Mark "low" for formatting, comments, docs, tests, renames, and config bumps. DIFF: <diff here > A small model is perfectly good at "does this touch auth or money." When it says low, CI posts a one-line "no high-risk changes detected" and stops. No expensive call. In practice that shortcuts the majority of PRs, because most PRs really are docs, tests, and plumbing. Tier two: the big model, but only on the risky files, with caching When tier one says high, t
AI 资讯
One folder shape for every course: a lifecycle monorepo convention
TL;DR I merged several training courses into one monorepo and gave every course the same numbered folder shape : 00-planning → 04-post-training . A _TEMPLATE/ you copy to start the next one, an _ARCHIVED/ you park old stuff in, and a CLAUDE.md that makes the convention machine-readable. The trick that makes it stick: templates use <angle-bracket-slots> , and "done" is a grep that returns nothing. I had course material scattered across repos — planning notes here, marketing copy there, facilitator run-sheets in a third place. Every new course started from a blank page, and I re-invented the folder layout each time. So I collapsed everything into one monorepo with a single rule: every course has the identical shape. The lifecycle, as folders The insight isn't "use folders" — it's that a course has a lifecycle , and numbered folders make that lifecycle the primary axis instead of file type. Plan it, sell it, teach it, run it, follow up. Five stages, always in order: Folder Stage What lives here 00-planning/ Prepare Syllabus (source of truth), specs 01-marketing/ Sell Positioning master + channel assets 02-content/ Teach Modules, one file each 03-delivery/ Run Run-sheet, pre-flight checklist, fallback plan 04-post-training/ Follow up Feedback form, follow-up email, post-mortem The numeric prefix isn't decoration. It forces sort order to match the actual workflow, so the folder listing reads like the process itself. Same reason migration files are timestamped — order is information. <course>/ 00-planning/ -> derives everything below 01-marketing/ 02-content/ 03-delivery/ 04-post-training/ --. post-mortem findings | ^------------------' feed back into 00..03 That loop at the end matters: the post-mortem doesn't sit in a graveyard folder. Its findings flow back into the syllabus, the run-sheet, the marketing. The structure runs the same feedback loop it's supposed to teach. _TEMPLATE/ : a course starts as a copy Starting a new course is one line: cp -r _TEMPLATE my-new-cou
AI 资讯
Unlocking Digital Identities with Open-Source SSI SDK
why-we-open-sour-c1f013bf.webp alt: Building Digital Identity Tools - Why We Open-Sourced Our SSI SDK relative: false Self-Sovereign Identity (SSI) is a framework that allows individuals and organizations to control their own digital identities and share verified credentials without relying on a central authority. This paradigm shift empowers users with greater privacy and control over their personal data, while also providing robust mechanisms for verifying the authenticity of credentials. What is Self-Sovereign Identity (SSI)? SSI is built around the concept of decentralized identifiers (DIDs) and verifiable credentials. DIDs are unique identifiers that are controlled by the entity they represent, enabling them to manage their own identity data. Verifiable credentials are digital assertions that can be issued by one party and verified by another, ensuring the authenticity and integrity of the information shared. Why did we open-source the SSI SDK? Open-sourcing the SSI SDK was a strategic decision driven by several factors. First, fostering innovation within the community is crucial for advancing the field of digital identity. By making our SDK available to everyone, we encourage collaboration and experimentation, leading to new ideas and improvements. Second, promoting transparency is essential for building trust in digital identity systems. Open-source projects allow others to inspect the codebase, understand how it works, and identify potential vulnerabilities. This transparency helps build confidence in the security and reliability of the SDK. Finally, enabling a broader community to contribute to and benefit from secure digital identity solutions aligns with our mission to democratize access to these technologies. By lowering the barriers to entry, we hope to empower more developers and organizations to adopt and improve upon our work. What are the key features of the SSI SDK? The SSI SDK provides a comprehensive set of tools for building digital identity app
AI 资讯
Link Manual Test Cases to Playwright and Robot Specs
Most teams already keep Playwright or Robot Framework specs next to the product. Manual cases often live somewhere else — a spreadsheet, a cloud TMS, or a wiki page nobody updates after the first release. That is why automation coverage is usually a quarterly guess: the catalog and the specs never share an id. Put both in the same Git repo , give every manual case a stable id, and linking becomes a text match. Any IDE agent can do that if the cases are files it can already see — no custom AI product inside a test tool. One repo, two layers of the same suite Manual cases are YAML files under .gitoza-lite/test/cases/ (VS Code / Cursor extension) or .gitoza/test/cases/ (Desktop app). The filename without .yaml is the case id . Automated tests live wherever your team already puts them — tests/ , e2e/ , robot/ — in the same repository. Traceability is a shared id: put that case id on the automation side as a tag (or name), and on the YAML side as automated: true plus a params pointer. A PR can change the case, the Playwright spec, and the link in one review. Step 1 — Draft manual cases in the IDE Open the repo in Cursor or VS Code. Point the agent at a few existing case files so it learns your title style, tags, and step length. Then feed it a user story, a ticket, or a screenshot. Ask for several cases at once, not one shallow step. A useful prompt looks like: Read .gitoza-lite/test/cases/shopflow/auth/ for format. From ticket SHOP-184, draft three YAML cases (happy path, invalid password, locked account). Filename = case id. Use tags auth and smoke where it fits. Save the files under the suite folder. Then open the Gitoza Lite Test Repository tab to browse, edit, and — when you are ready — run them as a manual suite with Pass / Fail / Skip. The extension does not ship its own model. It keeps cases as plain YAML so whatever assistant you already use can read and write them. A minimal case: --- title : Login with valid credentials priority : high tags : [ smoke , auth ]
AI 资讯
Preorders for Samsung’s new Z Fold and Flip 8 come with up to $350 in gift cards
Samsung's newest foldables are here. At Galaxy Unpacked, the company announced the Galaxy Z Flip 8, Galaxy Z Fold 8, and Galaxy Z Fold 8 Ultra. All three devices will be available on August 7th, but you can preorder them now starting at $1,199.99, $1,899.99, and $2,099.99, respectively. You probably noticed that Samsung's foldable lineup […]
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 资讯
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
AI 资讯
The Friction Is A Feature, Not A Bug: Teaching and Mentoring in the Age of AI
Those who have been following me for a while will know that teaching and mentoring are a Big Deal™️ to me. Before I got into tech I was a teacher, and still consider myself a teacher at heart. Being a teacher and mentor was never separate in my eyes from being a good programmer and engineer; on the contrary, teaching was a tool that helped me become better at my craft at every stage of the journey. But in the last few years, and accelerating in the last few months, the landscape for teaching and learning has been changing at a scary pace. The advent of LLMs and "AI" coding assistants has drastically shifted how we acquire engineering skills in ways that we are definitely not prepared for. All of that has prompted many thoughts and conversations, and I hope to distill some of them in this blog post. In true Talmudic fashion, this post doesn't contain too many answers and will hopefully leave you with more questions than you started with. But asking the questions is how we start these conversations, and these conversations need to be happening if we are to do right by the coming generation of programmers and engineers. Don't Spoon-Feed Me As a student, whether in Yeshiva when I used to spend hours each day poring over dense Talmudic legal debates and esoteric Chassidic philosophy or later while learning Rails and React at the Flatiron bootcamp, I quickly realized an uncomfortable truth about skill acquisition. My best, most profound learning never happened when a lesson went smoothly; it happened when I was painfully stuck, banging my head against a cryptic error message or wrestling with a concept that just wouldn't click (usually at 2 AM, fueled by cold coffee and sheer stubbornness). When you strip away that struggle, you get rid of the growth. And when you get rid of the growth, the learning just doesn't happen. Even if you memorize just enough to pass the test, "easy come easy go." Without that cognitive friction, the knowledge evaporates the moment you close you
开发者
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 资讯
#02 – Encapsulation & Abstraction in Python
Welcome to Day 2! Today we focus on two core pillars of Object-Oriented Programming: Encapsulation: Hiding internal state and requiring all interaction to go through performing validation or controlled methods. Abstraction: Hiding complex implementation details and exposing only a clean, simplified interface to the user. 1. Access Modifiers: Public, Protected, & Private 🛡️ Python does not have strict enforcement keywords like public or private found in Java or C++. Instead, it uses naming conventions and name mangling to communicate intent and protect internal data. ┌─────────────────────────────────────────────────────────────────────────────┐ │ ACCESS MODIFIERS IN PYTHON │ ├──────────────┬───────────────┬──────────────────────────────────────────────┤ │ Level │ Syntax │ Scope / Intended Access │ ├──────────────┼───────────────┼──────────────────────────────────────────────┤ │ Public │ self.name │ Accessible anywhere (inside & outside class) │ │ Protected │ self._balance │ Internal & subclasses only (Convention) │ │ Private │ self.__pin │ Class internal only (Triggers Name Mangling) │ └──────────────┴───────────────┴──────────────────────────────────────────────┘ Public ( self.name ): Fully accessible from anywhere. Protected ( self._balance ): Single leading underscore. Signals to developers: "This is internal—do not mutate or access outside this class or its subclasses." Private ( self.__pin ): Double leading underscore. Triggers name mangling ( _ClassName__attribute ), making it hard to accidentally access or override outside the class. 💻 Code Example: Access Modifiers & Name Mangling class SecureVault : def __init__ ( self , owner : str , balance : float , pin_code : str ): self . owner = owner # Public self . _balance = balance # Protected (convention) self . __pin = pin_code # Private (name mangled) def verify_pin ( self , pin : str ) -> bool : return self . __pin == pin vault = SecureVault ( " Alice " , 50000.0 , " 9876 " ) # Public access works as expected
AI 资讯
Surround sound speaker channel numbers explained: Bigger isn't always better
Here's what to pay attention to when building a home theater system.
AI 资讯
If you pay a hacker’s ransom, chances are that they’ll come back for more
The long-held understanding among security researchers and network defenders is that it's impossible to negotiate in good faith with an extortion racket because there's no incentive for the other side to actually walk away.
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
产品设计
Vizhi
Mission control for Codex CLI on a Logitech MX keypad Discussion | Link
AI 资讯
Philips’ new smart toothbrush shows you where you didn’t properly brush
The latest addition to Philips' Sonicare line of smart electric toothbrushes could take the guesswork out of your brushing routine. The Next-Generation DiamondClean 9900 Prestige uses a third-generation AI model to provide real-time feedback on how you're brushing through a glowing ring on its base, while a touchscreen highlights areas of your mouth that may […]
AI 资讯
Microsoft is bringing original Xbox games to PC
Microsoft is expanding its Xbox backward compatibility efforts today by bringing original Xbox games to PC. An early preview release will see four classic Xbox games available on PC today, as part of a bigger effort to bring more Xbox console games to PC in the future. The first four games are Blinx: The Time […]
AI 资讯
AMD commits up to $5 billion to Anthropic
AMD says it's going to invest up to $5 billion in Anthropic, while helping to expand the AI company's computing power, according to an announcement on Wednesday. As part of the new partnership, Anthropic will deploy up to 2 gigawatts of AMD's Instinct MI450 AI GPUs using the chipmaker's new Helios rack-scale system, as reported […]
AI 资讯
SwiftScale Software
QA agent that tests apps the way you'd explain them Discussion | Link
科技前沿
What happens when you try to chop a photon in half?
A mirror that moves mid-photon could release a shower of new photons.
开源项目
GitHub Increased Instant Navigation from 4% to 22% by Rethinking Client Side Architecture
GitHub redesigned GitHub Issues navigation using a client-side architecture that combines caching, predictive prefetching, and service workers to reduce perceived latency. The approach uses IndexedDB, in-memory caching, and background synchronization to serve data faster. GitHub reported instant navigation improvements from 4% to 22%, with latency reductions across multiple navigation By Leela Kumili