10 interesting stories served every morning and every evening.
In 2024, Apple signed a deal with Taboola to serve ads in its app, notably Apple News. John Gruber, writing in Daring Fireball said at the time:
If you told me that the ads in Apple News have been sold by Taboola for the last few years, I’d have said, “Oh, that makes sense.” Because the ads in Apple News — at least the ones I see1 — already look like chumbox Taboola ads. Even worse, they’re incredibly repetitious.
I use Apple News to keep up on topics that I don’t find in sources I pay for (The Guardian and The New York Times). But there’s no way I’m going to pay the exorbitant price Apple wants for Apple News+ — £13 — because, while you get more publications, you still get ads.
And those ads have gotten worse recently. Many if not most of them look like and probably are scams. Here are a few examples from Apple News today.
Here are three ads that are scammy; the first two were clearly generated by AI, and the third may have been created by AI.
Why are they scams? When I searched domain information for the domains, I found that they were registered very recently.
This recent registration doesn’t necessarily mean they are scams, but they don’t inspire much confidence.
Here’s one example. This ad from Tidenox, whose website says I am retiring, showing a photo of an elderly woman, who says, “For 26 years, Tidenox has been port of your journey in creating earth and comfort at home.” The image of the retiring owner is probably made by AI. (Update: someone on Hacker News pointed out the partly masked Google Gemini logo on the bottom right. I hadn’t spotted that, in part because I don’t use any AI image generation tools.)
These fake “going out of business ads” have been around for a few years, and even the US Better Business Bureau warns about them, as they take peoples’ money then shut down. Does Apple care? Does Taboola care? Does Apple care that Taboola serves ads like this? My guess: no, no, and no.
Note the registration date for the tidenox.com domain. It’s nowhere near 26 years old, and it’s registered in China:
Shame on Apple for creating a honeypot for scam ads in what they consider to be a premium news service. This company cannot be trusted with ads in its products any more.
...
Read the original on kirkville.com »
Think of your database like your home. Your home has a living room, bedroom, bathroom, kitchen, and garage. Each room serves a different purpose. But they’re all under the same roof, connected by hallways and doors. You don’t build a separate restaurant building just because you need to cook. You don’t construct a commercial garage across town just to park your car.
That’s what Postgres is. One home with many rooms. Search, vectors, time-series, queues—all under one roof.
But this is exactly what specialized database vendors don’t want you to hear. Their marketing teams have spent years convincing you to “use the right tool for the right job.” It sounds reasonable. It sounds wise. And it sells a lot of databases.
Let me show you why it’s a trap and why Postgres is the better choice in 99% of cases.
You’ve heard the advice: “Use the right tool for the right job.”
Sounds wise. So you end up with:
Congratulations. You now have seven databases to manage. Seven query languages to learn. Seven backup strategies to maintain. Seven security models to audit. Six sets of credentials to rotate. Seven monitoring dashboards to watch. And seven things that can break at 3 AM.
And when something does break? Good luck spinning up a test environment to debug it.
Here’s a different idea: Just use Postgres.
This isn’t just about simplicity. AI agents have made database sprawl a nightmare.
Think about what agents need to do:
With one database? That’s a single command. Fork it, test it, done.
With seven databases? Now you need to:
* Make sure they’re all at the same point in time
* Spin up seven different services
* Tear down seven services when you’re done
This is virtually impossible without a ton of R&D.
And it’s not just agents. Every time something breaks at 3 AM, you need to spin up a test environment to debug. With six databases, that’s a coordination nightmare. With one database, it’s a single command.
In the AI era, simplicity isn’t just elegant. It’s essential.
The myth: Specialized databases are far superior at their specific tasks.
The reality: Sometimes they’re marginally better at a narrow task. But they also bring unnecessary complexity. It’s like hiring a private chef for every meal. Sounds luxurious, but it adds expense, coordination overhead, and creates problems you didn’t have before.
Here’s the thing: 99% of companies don’t need them. The top 1% have tens of millions of users and a large engineering team to match. You’ve read their blog posts about how amazing Specialized Database X works for them. But that’s their scale, their team, their problems. For everyone else, Postgres is more than enough.
Here’s what most people don’t realize: Postgres extensions use the same or better algorithms as specialized databases (in many cases).
These aren’t watered-down versions. They’re the same/better algorithms, battle-tested, open source, and often developed by the same researchers.
* pgvectorscale: 28x lower latency than Pinecone at 75% less cost
* pg_textsearch: The exact same BM25 ranking that powers Elasticsearch
Beyond the AI/agent problem, database sprawl has compounding costs:
Cognitive load: Your team needs SQL, Redis commands, Elasticsearch Query DSL, MongoDB aggregation, Kafka patterns, and InfluxDB’s non-native SQL workaround. That’s not specialization. That’s fragmentation.
Data consistency: Keeping Elasticsearch in sync with Postgres? You build sync jobs. They fail. Data drifts. You add reconciliation. That fails too. Now you’re maintaining infrastructure instead of building features.
SLA math: Three systems at 99.9% uptime each = 99.7% combined. That’s 26 hours of downtime per year instead of 8.7. Every system multiplies your failure modes.
These extensions aren’t new. They’ve been production-ready for years:
* JSONB: Since 2014 (11 years). As fast as MongoDB, with ACID.
Over 48,000 companies use PostgreSQL, including Netflix, Spotify, Uber, Reddit, Instagram, and Discord.
What this means: Building a RAG app used to require Postgres + Pinecone + Elasticsearch + glue code.
Now? Just Postgres. One database. One query language. One backup. One fork command for your AI agent to spin up a test environment.
Here’s all you need:
Below are working examples for each use case. Skip to what you need.
What you get: The exact same BM25 algorithm that powers Elasticsearch, directly in Postgres.
This is what Elasticsearch requires a separate plugin for. In Postgres, it’s just SQL.
What you get: pgvectorscale uses the DiskANN algorithm (from Microsoft Research), achieving 28x lower p95 latency and 16x higher throughput than Pinecone at 99% recall.
Now every INSERT/UPDATE automatically regenerates embeddings. No sync jobs. No drift. No 3 AM pages.
* Prometheus: Great for metrics, not your application data
What you get: Automatic time partitioning, compression up to 90%, continuous aggregates. Full SQL.
For AI applications, you often need both keyword search and semantic search:
Try that with Elasticsearch + Pinecone. You’d need two API calls, result merging, failure handling, and double latency.
In Postgres: one query, one transaction, one result.
Remember the home analogy? You don’t build a separate restaurant just to cook dinner. You don’t construct a commercial garage across town just to park your car. You use the rooms in your home.
That’s what we’ve shown you here. Search, vectors, time-series, documents, queues, caching—they’re all rooms in the Postgres home. Same algorithms as the specialized databases. Battle-tested for years. Used by Netflix, Uber, Discord, and 48,000 other companies.
So what about that 99%?
For 99% of companies, Postgres handles everything you need. The 1%? That’s when you’re processing petabytes of logs across hundreds of nodes, or you need Kibana’s specific dashboards, or you have exotic requirements that genuinely exceed what Postgres can do.
But here’s the thing: you’ll know when you’re in the 1%. You won’t need a vendor’s marketing team to tell you. You’ll have benchmarked it yourself and hit a real wall.
Until then, don’t scatter your data across seven buildings because someone told you to “use the right tool for the right job.” That advice sells databases. It doesn’t serve you.
Start with Postgres. Stay with Postgres. Add complexity only when you’ve earned the need for it.
In 2026, just use Postgres.
All these extensions are available on Tiger Data. Create a free database in minutes:
No need for specialized databases, just use Postgres.
...
Read the original on www.tigerdata.com »
LinkedIn silently probes for 2,953 Chrome extensions on every page load.
This repository documents every extension LinkedIn checks for and provides tools to identify them.
The complete list of extensions with names and Chrome Web Store links:
Fetches extension names from Chrome Web Store with Extpose fallback for removed/unavailable extensions.
# Fetch all extensions
node fetch_extension_names.js
# Fetch a subset (useful if rate limited)
node fetch_extension_names.js –offset 0 –limit 500
node fetch_extension_names.js -o 500 -l 500
# Show help
node fetch_extension_names.js –help
Test script that processes the first 3 extensions with verbose output.
node test_fetch.js
* ~22% found via Extpose fallback (removed or unavailable on Chrome Web Store)
...
Read the original on github.com »
There have been a lot of complaints about both the competency and the logic behind the latest Epstein archive release by the DoJ: from censoring the names of co-conspirators to censoring pictures of random women in a way that makes individuals look guiltier than they really are, forgetting to redact credentials that made it possible for all of Reddit to log into Epstein’s account and trample over all the evidence, and the complete ineptitude that resulted in most of the latest batch being corrupted thanks to incorrectly converted Quoted-Printable encoding artifacts, it’s safe to say that Pam Bondi’s DoJ did not put its best and brightest on this (admittedly gargantuan) undertaking. But the most damning evidence has all been thoroughly redacted… hasn’t it? Well, maybe not.
I was thinking of writing an article on the mangled quoted-printable encoding the day this latest dump came out in response to all the misinformed musings and conjectures that were littering social media (and my dilly-dallying cost me, as someone beat me to the punch), and spent some time searching through the latest archives looking for some SMTP headers that I could use in the article when I came across a curious artifact: not only were the emails badly transcoded into plain text, but also some binary attachments were actually included in the dumps in their over-the-wire Content-Transfer-Encoding: base64 format, and the unlucky intern that was assigned to the documents in question didn’t realize the significance of what they were looking at and didn’t see the point in censoring seemingly meaningless page after page of hex content!
Just take a look at EFTA00400459, an email from correspondence between (presumably) one of Epstein’s assistants and Epstein lackey/co-conspirator Boris Nikolic and his friend, Sam Jaradeh, inviting them to a ████████ benefit:
Those hex characters go on for 76 pages, and represent the file DBC12 One Page Invite with Reply.pdf encoded as base64 so that it can be included in the email without breaking the SMTP protocol. And converting it back to the original PDF is, theoretically, as easy as copy-and-pasting those 76 pages into a text editor, stripping the leading > bytes, and piping all that into base64 -d > output.pdf… or it would be, if we had the original (badly converted) email and not a partially redacted scan of a printout of said email with some shoddy OCR applied.
If you tried to actually copy that text as digitized by the DoJ from the PDF into a text editor, here’s what you’d see:
You can ignore the EFTA00400459 on the second line; that (or some variant thereof) will be interspersed into the base64 text since it’s stamped at the bottom of every page to identify the piece of evidence it came from. But what else do you notice? Here’s a hint: this is what proper base64 looks like:
Notice how in this sample everything lines up perfectly (when using a monospaced font) at the right margin? And how that’s not the case when we copied-and-pasted from the OCR’d PDF? That’s because it wasn’t a great OCR job: extra characters have been hallucinated into the output, some of them not even legal base64 characters such as the , and [, while other characters have been omitted altogether, giving us content we can’t use:1
> pbpaste \
| string match -rv ‘EFTA’ \
| string trim -c ” >” \
| string join “” \
| base64 -d >/dev/null
base64: invalid input
I tried the easiest alternative I had at hand: I loaded up the PDF in Adobe Acrobat Pro and re-ran an OCR process on the document, but came up with even worse results, with spaces injected in the middle of the base64 content (easily fixable) in addition to other characters being completely misread and butchered — it really didn’t like the cramped monospace text at all. So I thought to do it manually with tesseract, which, while very far from state-of-the-art, can still be useful because it lets you do things like limit its output to a certain subset of characters, constraining the field of valid results and hopefully coercing it into producing better results.
Only one problem: tesseract can’t read PDF input (or not by default, anyway). No problem, I’ll just use imagemagick/ghostscript to convert the PDF into individual PNG images (to avoid further generational loss) and provide those to tesseract, right? But that didn’t quite work out, they seem (?) to try to load and perform the conversion of all 76 separate pages/png files all at once, and then naturally crash on too-large inputs (but only after taking forever and generating the 76 (invalid) output files that you’re forced to subsequently clean up, of course):
> convert -density 300 EFTA00400459.pdf \
-background white -alpha remove \
-alpha off out.png
convert-im6.q16: cache resources exhausted `/tmp/magick-QqXVSOZutVsiRcs7pLwwG2FYQnTsoAmX47′ @ error/cache.c/OpenPixelCache/4119.
convert-im6.q16: cache resources exhausted `out.png’ @ error/cache.c/OpenPixelCache/4119.
convert-im6.q16: No IDATs written into file `out-0.png’ @ error/png.c/MagickPNGErrorHandler/1643.
So we turn to pdftoppm from the poppler-utils package instead, which does indeed handle each page of the source PDF separately and turned out to be up to the task, though incredibly slow:
> pdftoppm -png -r 300 EFTA00400459.pdf out.png
After waiting the requisite amount of time (and then some), I had files out-01.png through out-76.png, and was ready to try them with tesseract:
for n in (printf “%02d\n” (seq 1 76))
tesseract out-$n.png output-$n \
–psm 6 \
-c tessedit_char_whitelist=’>’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= \
-c load_system_dawg=0 \
-c load_freq_dawg=0
end
The above fish-shell command instructs tesseract(1) to assume the input is a single block of text (the –psm 6 argument) and limit itself to decoding only legal base64 characters (and the leading > so we can properly strip it out thereafter). My original attempt included a literal space in the valid char whitelist, but that gave me worse results: the very badly kerned base64 has significant apparent spacing between some adjacent characters (more on this later) and that caused tesseract to both incorrectly inject spaces (bad but fixable) and also possibly affect how it handled the character after the space (worse).
Unfortunately, while tesseract gave me slightly better output than either the original OCR’d DoJ text or the (terrible) Adobe Acrobat Pro OCR results, it too suffered from poor recognition and gave me very inconsistent line lengths… but it also suffered from something that I didn’t really think a heuristic-based, algorithm-driven tool like tesseract would succumb to, as it was more reminiscent of how first-generation LLMs would behave: in a few places, it would only read the first dozen or so characters on a line then leave the rest of the line blank, then pick up (correctly enough) at the start of the next line. Before I saw how generally useless the OCR results were and gave up on tesseract, I figured I’d just manually type out the rest of the line (the aborted lines were easy enough to find, thanks to the monospaced output), and that was when I ran into the real issue that took this from an interesting challenge to being almost mission impossible.
I mentioned earlier the bad kerning, which tricked the OCR tools into injecting spaces where there were supposed to be none, but that was far from being the worst issue plaguing the PDF content. The real problem is that the text is rendered in possibly the worst typeface for the job at hand: Courier New.
If you’re a font enthusiast, I certainly don’t need to say any more — you’re probably already shaking with a mix of PTSD and rage. But for the benefit of everyone else, let’s just say that Courier New is… not a great font. It was a digitization of the venerable (though certainly primitive) Courier fontface, commissioned by IBM in the 1950s. Courier was used (with some tweaks) for IBM typewriters, including the IBM Selectric, and in the 1990s it was “digitized directly from the golf ball of the IBM Selectric” by Monotype, and shipped with Windows 3.1, where it remained the default monospace font on Windows until Consolas shipped with Windows Vista. Among the many issues with Courier New is that it was digitized from the Selectric golf ball “without accounting for the visual weight normally added by the typewriter’s ink ribbon”, which gives its characteristic “thin” look. Microsoft ClearType, which was only enabled by default with Windows Vista, addressed this major shortcoming to some extent, but Courier New has always struggled with general readability… and more importantly, with its poor distinction between characters.
While not as bad as some typewriter-era typefaces that actually reused the same symbol for 1 (one) and l (ell), Courier New came pretty close. Here is a comparison between the two fonts when rendering these two characters, only considerably enlarged:
The combination of the two faults (the anemic weights and the even less distinction between 1 and l as compared to Courier) makes Courier New a terrible choice as a programming font. But as a font used for base64 output you want to OCR? You really couldn’t pick a worse option! To add fuel to the fire, you’re looking at SVG outlines of the fonts, meticulously converted and preserving all the fine details. But in the Epstein PDFs released by the DoJ, we only have low-quality JPEG scans at a fairly small point size. Here’s an actual (losslessly encoded) screenshot of the DoJ text at 100% — I challenge you to tell me which is a 1 and which is an l in the excerpt below:
It’s not that there isn’t any difference between the two, because there is. And sometimes you get a clear gut feeling which is which — I was midway through manually typing out one line of base64 text when I got stuck on identifying a one vs ell… only to realize that, at the same time, I had confidently transcribed one of them earlier that same line without even pausing to think about which it was. Here’s a zoomed-in view of the scanned PDF: you can clearly see all the JPEG DCT artifacts, the color fringing, and the smearing of character shapes, all of which make it hard to properly identify the characters. But at the same time, at least in this particular sample, you can see which of the highlighted characters have a straight serif leading out the top-left (the middle, presumably an ell) and which of those have the slightest of strokes/feet extending from them (the first and last, presumably ones). But whether that’s because that’s how the original glyph appeared or it’s because of how the image was compressed, it’s tough to say:
But that’s getting ahead of myself: at this point, none of the OCR tools had actually given me usable results, even ignoring the very important question of l vs 1. After having been let down by one open source offering (tesseract) and two commercial ones (Adobe Acrobat Pro and, presumably, whatever the DoJ used), I made the very questionable choice of writing a script to use yet another commercial offering, this time Amazon/AWS Textract, to process the PDF. Unfortunately, using it directly via the first-party tooling was (somewhat) of a no-go as it only supports smaller/shorter inputs for direct use; longer PDFs like this one need to be uploaded to S3 and then use the async workflow to start the recognition and poll for completion.
Amazon Textract did possibly the best out of all the tools I tried, but its output still had obvious line length discrepancies — albeit only one to two characters or so off on average. I decided to try again, this time blowing up the input 2x (using nearest neighbor sampling to preserve sharp edges) as a workaround for Textract not having a tunable I could set to configure the DPI the document is processed at, though I worried all inputs could possibly be prescaled to a fixed size prior to processing once more:2
> for n in (printf “%02d\n” (seq 01 76))
convert EFTA00400459-$n.png -scale 200% \
EFTA00400459-$n”_2x”.png; or break
end
> parallel -j 16 ./textract.sh {} ::: EFTA00400459-*_2x.png
These results were notably better, and I’ve included them in an archive, but some of the pages scanned better than others. Textract doesn’t seem to be 100% deterministic from my brief experience with it, and their features page does make vague or unclear mentions to “ML”, though it’s not obvious when and where it kicks in or what it exactly refers to, but that could explain why a couple of the pages (like EFTA00400459-62_2x.txt) are considerably worse than others, even while the source images don’t show a good reason for that divergence.
With the Textract 2x output cleaned up and piped into base64 -i (which ignores garbage data, generating invalid results that can still be usable for forensic analysis), I can get far enough to see that the PDF within the PDF (i.e. the actual PDF attachment originally sent) was at least partially (de)flate-encoded. Unfortunately, PDFs are binary files with different forms of compression applied; you can’t just use something like strings to extract any usable content. qpdf(1) can be (ab)used to decompress a PDF (while leaving it a PDF) via qpdf –qdf –object-streams=disable input.pdf decompressed.pdf, but, predictably, this doesn’t work when your input is garbled and corrupted:
> qpdf –qdf –object-streams=disable recovered.pdf decompressed.pdf
WARNING: recovered.pdf: file is damaged
WARNING: recovered.pdf: can’t find startxref
WARNING: recovered.pdf: Attempting to reconstruct cross-reference table
WARNING: recovered.pdf (object 34 0, offset 52): unknown token while reading object; treating as string
WARNING: recovered.pdf (object 34 0, offset 70): unknown token while reading object; treating as string
WARNING: recovered.pdf (object 34 0, offset 85): unknown token while reading object; treating as string
WARNING: recovered.pdf (object 34 0, offset 90): unexpected >
WARNING: recovered.pdf (object 34 0, offset 92): unknown token while reading object; treating as string
WARNING: recovered.pdf (object 34 0, offset 116): unknown token while reading object; treating as string
WARNING: recovered.pdf (object 34 0, offset 121): unknown token while reading object; treating as string
WARNING: recovered.pdf (object 34 0, offset 121): too many errors; giving up on reading object
WARNING: recovered.pdf (object 34 0, offset 125): expected endobj
WARNING: recovered.pdf (object 41 0, offset 9562): expected endstream
WARNING: recovered.pdf (object 41 0, offset 8010): attempting to recover stream length
WARNING: recovered.pdf (object 41 0, offset 8010): unable to recover stream data; treating stream as empty
WARNING: recovered.pdf (object 41 0, offset 9616): expected endobj
WARNING: recovered.pdf (object 41 0, offset 9616): EOF after endobj
qpdf: recovered.pdf: unable to find trailer dictionary while recovering damaged file
Between the inconsistent OCR results and the problem with the l vs 1, it’s not a very encouraging situation. To me, this is a problem begging for a (traditional, non-LLM) ML solution, specifically leveraging the fact that we know the font in question and, roughly, the compression applied. Alas, I don’t have more time to lend to this challenge at the moment, as there are a number of things I set aside just in order to publish this article.
So here’s the challenge for anyone I can successfully nerdsnipe:
* Can you manage to recreate the original PDF from the Content-Transfer-Encoding: base64 output included in the dump? It can’t be that hard, can it?
* Can you find other attachments included in the latest Epstein dumps that might also be possible to reconstruct? Unfortunately, the contractor that developed the full-text search for the Department of Justice did a pretty crappy job and full-text search is practically broken even accounting for the bad OCR and wrangled quoted-printable decoding (malicious compliance??); nevertheless, searching for Content-Transfer-Encoding and base64 returns a number of results — it’s just that, unfortunately, most are uselessly truncated or only the SMTP headers from Apple Mail curiously extracted.
I have uploaded the original EFTA00400459.pdf from Epstein Dataset 9 as downloaded from the DoJ website to the Internet Archive, as well as the individual pages losslessly encoded to WebP images to save you the time and trouble of converting them yourself. If it’s of any use to anyone, I’ve also uploaded the very-much-invalid Amazon Textract OCR text (from the losslessly 2x’d images), which you can download here.
Oh, and one final hint: when trying to figure out 1 vs l, I was able to do this with 100% accuracy only via trial-and-error, decoding one line of base64 text at-a-time, but this only works for the plain-text portions of the PDF (headers, etc). For example, I started with my best guess for one line that I had to type out myself when trying with tesseract, and then was able to (in this case) deduce which particular 1s or ls were flipped:
> pbpaste
SW5mbzw8L01sbHVzdHJhdG9yIDgxIDAgUj4+L1Jlc29lcmNlczw8L0NvbG9yU3BhY2U8PC9DUzAG
> pbpaste | base64 -d
Info<>/Resoerces<
> # which I was able to correct:
> pbpaste
SW5mbzw8L0lsbHVzdHJhdG9yIDgxIDAgUj4+L1Jlc291cmNlczw8L0NvbG9yU3BhY2U8PC9DUzAG
> pbpaste | base64 -d
Info<>/Resources<
…but good luck getting that to work once you get to the flate-compressed sections of the PDF.
I’ll be posting updates on Twitter @mqudsi, and you can reach out to me on Signal at mqudsi.42 if you have anything sensitive you would like to share. You can join in the discussion on Hacker News or on r/netsec. Leave a comment below if you have any ideas/questions, or if you think I missed something!
...
Read the original on neosmart.net »
Deck, Andrew. “A new bill in New York would require disclaimers on AI-generated news content.” Nieman Journalism Lab. Nieman Foundation for Journalism at Harvard, 5 Feb. 2026. Web. 6 Feb. 2026.
Deck, A. (2026, Feb. 5). A new bill in New York would require disclaimers on AI-generated news content. Nieman Journalism Lab. Retrieved February 6, 2026, from https://www.niemanlab.org/2026/02/a-new-bill-in-new-york-would-require-disclaimers-on-ai-generated-news-content/
Deck, Andrew. “A new bill in New York would require disclaimers on AI-generated news content.” Nieman Journalism Lab. Last modified February 5, 2026. Accessed February 6, 2026. https://www.niemanlab.org/2026/02/a-new-bill-in-new-york-would-require-disclaimers-on-ai-generated-news-content/.
{{cite web
| title = A new bill in New York would require disclaimers on AI-generated news content
| last = Deck
| first = Andrew
| work = [[Nieman Journalism Lab]]
| date = 5 February 2026
| accessdate = 6 February 2026
| ref = {{harvid|Deck|2026}}
...
Read the original on www.niemanlab.org »
Your web browser does not support this video. The Waymo World Model: A New Frontier For Autonomous Driving SimulationThe Waymo Driver has traveled nearly 200 million fully autonomous miles, becoming a vital part of the urban fabric in major U.S. cities and improving road safety. What riders and local communities don’t see is our Driver navigating billions of miles in virtual worlds, mastering complex scenarios long before it encounters them on public roads. Today, we are excited to introduce the Waymo World Model, a frontier generative model that sets a new bar for large-scale, hyper-realistic autonomous driving simulation. Your web browser does not support this video.Simulation of the Waymo Driver evading a vehicle going in the wrong direction. The simulation initially follows a real event, and seamlessly transitions to using camera and lidar images automatically generated by an efficient real-time Waymo World Model.
Simulation is a critical component of Waymo’s AI ecosystem and one of the three key pillars of our approach to demonstrably safe AI. The Waymo World Model, which we detail below, is the component that is responsible for generating hyper-realistic simulated environments.The Waymo World Model is built upon Genie 3—Google DeepMind’s most advanced general-purpose world model that generates photorealistic and interactive 3D environments—and is adapted for the rigors of the driving domain. By leveraging Genie’s immense world knowledge, it can simulate exceedingly rare events—from a tornado to a casual encounter with an elephant—that are almost impossible to capture at scale in reality. The model’s architecture offers high controllability, allowing our engineers to modify simulations with simple language prompts, driving inputs, and scene layouts. Notably, the Waymo World Model generates high-fidelity, multi-sensor outputs that include both camera and lidar data.This combination of broad world knowledge, fine-grained controllability, and multi-modal realism enhances Waymo’s ability to safely scale our service across more places and new driving environments. In the following sections we showcase the Waymo World Model in action, featuring simulations of the Waymo Driver navigating diverse rare edge-case scenarios.Most simulation models in the autonomous driving industry are trained from scratch based on only the on-road data they collect. That approach means the system only learns from limited experience. Genie 3’s strong world knowledge, gained from its pre-training on an extremely large and diverse set of videos, allows us to explore situations that were never directly observed by our fleet.Through our specialized post-training, we are transferring that vast world knowledge from 2D video into 3D lidar outputs unique to Waymo’s hardware suite. While cameras excel at depicting visual details, lidar sensors provide valuable complementary signals like precise depth. The Waymo World Model can generate virtually any scene—from regular, day-to-day driving to rare, long-tail scenarios—across multiple sensor modalities.Your web browser does not support this video.Simulation: Driving on the Golden Gate Bridge, covered in light snow. Waymo’s shadow is visible in the front camera footage.
Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Simulation: Driving on a street with lots of palm trees in a tropical city, strangely covered in snow.
Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Simulation: The leading vehicle driving into the tree branches.
Your web browser does not support this video.Simulation: Driving behind a vehicle with precariously positioned furniture on top.
Your web browser does not support this video.Simulation: A malfunctioned truck facing the wrong way, blocking the road.
Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.In the interactive viewers below, you can immersively view the realistic 4D point clouds generated by the Waymo World Model.Interactive 3D visualization of an encounter with an elephant.
The Waymo World Model offers strong simulation controllability through three main mechanisms: driving action control, scene layout control, and language control.Driving action control allows us to have a responsive simulator that adheres to specific driving inputs. This enables us to simulate “what if” counterfactual events such as whether the Waymo Driver could have safely driven more confidently instead of yielding in a particular situation.Counterfactual driving. We demonstrate simulations both under the original route in a past recorded drive, or a completely new route. While purely reconstructive simulation methods (e.g., 3D Gaussian Splats, or 3DGS) suffer from visual breakdowns due to missing observations when the simulated route is too different from the original driving, the fully learned Waymo World Model maintains good realism and consistency thanks to its strong generative capabilities.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Scene layout control allows for customization of the road layouts, traffic signal states, and the behavior of other road users. This way, we can create custom scenarios via selective placement of other road users, or applying custom mutations to road layouts.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Language control is our most flexible tool that allows us to adjust time-of-day, weather conditions, or even generate an entirely synthetic scene (such as the long-tail scenarios shown previously).Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.During a scenic drive, it is common to record videos of the journey on mobile devices or dashcams, perhaps capturing piled up snow banks or a highway at sunset. The Waymo World Model can convert those kinds of videos, or any taken with a regular camera, into a multimodal simulation—showing how the Waymo Driver would see that exact scene. This process enables the highest degree of realism and factuality, since simulations are derived from actual footage.Your web browser does not support this video.Your web browser does not support this video.Your web browser does not support this video.Some scenes we want to simulate may take longer to play out, for example, negotiating passage in a narrow lane. That’s harder to do because the longer the simulation, the tougher it is to compute and maintain stable quality. However, through a more efficient variant of the Waymo World Model, we can simulate longer scenes with dramatic reduction in compute while maintaining high realism and fidelity to enable large-scale simulations.🚀 Long rollout (4x speed playback) on an efficient variant of the Waymo World ModelYour web browser does not support this video.Navigating around in-lane stopper and fast traffic on the freeway.
Your web browser does not support this video.Your web browser does not support this video.Driving up a steep street and safely navigating around motorcyclists.
Your web browser does not support this video.By simulating the “impossible”, we proactively prepare the Waymo Driver for some of the most rare and complex scenarios. This creates a more rigorous safety benchmark, ensuring the Waymo Driver can navigate long-tail challenges long before it encounters them in the real world.
The Waymo World Model is enabled by the key research, engineering and evaluation contributions from James Gunn, Kanaad Parvate, Lu Liu, Lucas Deecke, Luca Bergamini, Zehao Zhu, Raajay Viswanathan, Jiahao Wang, Sakshum Kulshrestha, Titas Anciukevičius, Luna Yue Huang, Yury Bychenkov, Yijing Bai, Yichen Shen, Stefanos Nikolaidis, Tiancheng Ge, Shih-Yang Su and Vincent Casser.We thank Chulong Chen, Mingxing Tan, Tom Walters, Harish Chandran, David Wong, Jieying Chen, Smitha Shyam, Vincent Vanhoucke and Drago Anguelov for their support in defining the vision for this project, and for their strong leadership and guidance throughout.We would like to additionally thank Jon Pedersen, Michael Dreibelbis, Larry Lansing, Sasho Gabrovski, Alan Kimball, Dave Richardson, Evan Birenbaum, Harrison McKenzie Chapter and Pratyush Chakraborty, Khoa Vo, Todd Hester, Yuliang Zou, Artur Filipowicz, Sophie Wang and Linn Bieske for their invaluable partnership in facilitating and enabling this project.We thank our partners from Google DeepMind: Jack Parker-Holder, Shlomi Fruchter, Philip Ball, Ruiqi Gao, Songyou Peng, Ben Poole, Fei Xia, Allan Zhou, Sean Kirmani, Christos Kaplanis, Matt McGill, Tim Salimans, Ruben Villegas, Xinchen Yan, Emma Wang, Woohyun Han, Shan Han, Rundi Wu, Shuang Li, Philipp Henzler, Yulia Rubanova, and Thomas Kipf for helpful discussions and for sharing invaluable insights for this project.
...
Read the original on waymo.com »
After being interrupted multiple times by an annoying console window that would pop up periodically on my new gaming PC, I managed to track the offending executable down to AMD’s AutoUpdate software.
In my anger, I decided to punish this software by decompiling it to figure out how it worked, and accidentally discovered a trivial Remote Code Execution (RCE) vulnerability in the process.
The first thing I found, is that they store their update URL in the program’s app.config, although its a little odd that they use their “Develpment” URL in production, it uses HTTPS so its perfectly safe.
The real problem starts when you open up this URL in your web browser, and realise that all of the executable download URL’s are using HTTP.
This means that a malicious attacker on your network, or a nation state that has access to your ISP can easily perform a MITM attack and replace the network response with any malicious executable of their choosing.
I was hoping that AMD perhaps had some form of certificate validation to ensure that it could not download & run any unsigned executables, however a quick look into the decompiled code revealed that the AutoUpdate software does no such validation and immediately executes the downloaded file.
After finding this issue, I thought it was worth reporting to AMD since it seemed to be a pretty severe issue.
However it turned out to be considered “out of scope”, resulting in AMD not considering this to be a vulnerability.
If you liked this blog, you can read another of my write-ups here: 1.4 Billion exposed user records via insecure Firebase instances in top Android apps
...
Read the original on mrbruh.com »
I was an early employee at CircleCI. I have used, in anger, nearly every CI system that has ever existed. Jenkins, Travis, CircleCI, Semaphore, Drone, Concourse, Wercker (remember Wercker?), TeamCity, Bamboo, GitLab CI, CodeBuild, and probably a half dozen others I’ve mercifully forgotten. I have mass-tested these systems so that you don’t have to, and I have the scars to show for it, and I am here to tell you: GitHub Actions is not good. It’s not even fine. It has market share because it’s right there in your repo, and that’s about the nicest thing I can say about it.
Buildkite is what CI should feel like. But first, let me tell you what CI should not feel like.
Before I get into it: if you’re a Nix shop, take a look at Garnix. It evaluates your flake, figures out what needs building, and builds it. No YAML. No pipeline configuration. It just looks at your flake.nix and does the right thing. Sometimes the best CI configuration is no CI configuration.
Most shops are not Nix shops. This post is for the rest of you. I’m sorry.
Let me start with the most visceral thing, the thing that will sound like I’m exaggerating but I am not.
Your build fails. You get a red X on your pull request. You click through to see what happened. This is where the ordeal begins.
First you land on the checks summary page, which shows you a list of workflow runs. Maybe one failed. Maybe three failed. You click the one that looks relevant. Now you’re on the workflow run page, which shows you a list of jobs. You click the failed job. Now you’re on the job page, which shows you a list of steps, all collapsed. You click the step that failed. The page hitches. You scroll. There is a pause, a held breath, and then the logs appear, slowly, like a manuscript being revealed one line at a time to a supplicant who has not yet proven worthy.
That’s three or four clicks just to see the error, and every one of them loads a new page with its own loading spinner, and none of them are fast. You are navigating a bureaucracy. You are filling out forms at the DMV of CI.
And then the log viewer itself. I have used every CI system known to man, and the GitHub Actions log viewer is the only one that has crashed my browser. Not once. Repeatedly. Reliably. Open a long build log, try to search for an error, and Chrome will look you in the eye and die. This is the log viewer for the most popular CI system in the world. This is the tool you are expected to use to understand why your build failed. It cannot survive contact with its own output.
With large logs (and if you have a real build system, you have large logs) you often can’t even scroll to the bottom. The page just gives up. The scrollbar is there, technically, but it’s decorative. It’s a suggestion. You drag it down and the page chokes and stutters and eventually you realize you’re not going to get there this way. So you download the raw log artifact and open it in a text editor like it’s 2003 and you’re reading Apache access logs on a shared hosting box. Except it’s 2025 and this is a product made by one of the richest companies on earth.
And when you’re done, when you’ve finally found the error, processed your grief, and want to go back to the pull request that started this whole ordeal, you hit the back button. Does it take you to the PR? No. It takes you to some other page in the GitHub Actions UI. A summary page, maybe. Or a different run. Or a page you don’t recognize. The back button in the GitHub Actions UI is a roulette wheel. You will land somewhere. It will not be where you wanted to go. You will click the back button again. You will land somewhere else. Eventually you give up and type the PR URL from memory or go find it in your browser history, which is now 80% GitHub Actions URLs, a fact that will haunt you when you look at it later.
So the logs have betrayed you, or perhaps they simply could not be made to appear at all. Now begins the second ritual: the debugging.
You push a commit. You wait. A runner picks it up. You watch logs scroll. Something fails. The error looks like someone fed a stack trace through a paper shredder and then set the shredder on fire. You add a run: env step to see what’s going on. You push again. You wait again. A twenty-minute feedback loop for a one-line change. You do this fourteen times. This is your afternoon now. You had plans. You were going to go outside. The afternoon belongs to the CI now. It has always belonged to the CI. You are only now perceiving this truth.
There is something devotional about the experience. You approach the logs. You make your offering of clicks and patience. The page considers your request. Sometimes it grants you the knowledge you seek. Sometimes it takes your browser tab instead, a small sacrifice, consumed, gone. You open a new tab. You try again. This is the ritual. You did not choose it. The work continues.
Every CI system eventually becomes “a bunch of YAML.” I’ve been through the five stages of grief about it and emerged on the other side, diminished but functional. But GitHub Actions YAML is a special breed. It’s YAML with its own expression language bolted on, its own context object model, its own string interpolation rules, and a scattering of gotchas that will slowly hollow you out as a person. Each gotcha leaves a mark. The marks do not fade.
Have you ever tried to conditionally set an environment variable based on which branch you’re on? Have you done the ${{ }} expression dance, misquoted something, and then waited four minutes for a runner to spin up just to discover your string got eaten? Of course you have. We all have. We have all stared at a diff that changes one character in a YAML expression and thought “I went to college for this.”
The expression syntax has the quality of a language that grew in the dark, unsupervised. It began as a convenience. It accreted features. Somewhere along the way it crossed a threshold, and now it exists in a liminal space- too complex to be configuration, too constrained to be a proper language. You learn its grammar not from documentation but from failure, each error message a koan that points toward understanding but does not provide it.
Ah yes, the GitHub Actions Marketplace. The npm of CI. A bazaar of community-maintained actions of varying quality, most of which are shell scripts with a Dockerfile and a dream.
Every time you type uses: some-stranger/cool-action@v2, you’re handing a stranger access to your repo, your secrets, and your build environment. Yes, you can pin to a SHA. Nobody does. And even if you do, you’re still running opaque code you didn’t write and probably haven’t read, in a context where it has access to your GITHUB_TOKEN and whatever else you’ve stuffed in there. Every action you add is another set of house keys you’re handing to someone you’ve never met and hoping for the best.
The Marketplace has the energy of a night market in a city you don’t know, where every stall sells something that claims to solve your problem. Some of them do. Some of them have other intentions. You cannot tell which is which from the outside. You can only install them and see what happens. This is called “dependency management.” We have normalized it. The normalization does not make it safe.
With GitHub Actions, you’re renting Microsoft’s runners. They’re slow, they’re resource-constrained, you can’t customize them in any meaningful way, and you’re at the mercy of GitHub’s capacity planning. Need a beefy machine for a big build? You can pay for a larger runner, at prices that will get you a calendar invite from finance titled “we need to talk,” and you still don’t control the environment.
You know how I know GitHub’s runners are bad? Because there’s an entire cottage industry of companies whose sole product is “GitHub Actions, but the runners don’t suck.” Namespace, Blacksmith, Actuated, Runs-on, BuildJet. There are at least half a dozen startups that exist purely to solve the problem of GitHub Actions being slow. Their pitch is, essentially, “keep your workflows, we’ll just make them not take forever.” The fact that this is a viable business model, that multiple companies can sustain themselves on the premise that the default compute for the world’s most popular CI system is inadequate, tells you everything you need to know.
Now, to be fair, you can bring your own runners to GitHub Actions. Self-hosted runners exist. You can set up your own machines, install Nix, configure your environment exactly how you want it. And this does solve the compute problem. Your builds will be faster. Your caches will be warm. But you’ll still be writing GitHub Actions YAML. You’ll still be fighting the expression syntax and the permissions model and the marketplace and the log viewer that crashes your browser. You’ve upgraded the engine but you’re still driving the car that catches fire when you turn on the radio.
I think the people who originally built GitHub Actions were probably well-intentioned. They probably cared about developer experience. But this is a Microsoft product now, and Microsoft is where ambitious developer tools go to become enterprise SKUs. The original engineers have long since been reorged into other divisions or ground down into product managers. The vision, if there was one, is entombed now. But if you press your ear to the floor during a particularly slow build, you can still hear its heart beating, faintly, beneath the floorboards.
Things that seem small but accumulate. Each one is survivable. Together they form a compelling case for simply walking into the sea. The sea does not have YAML. The sea does not require a GITHUB_TOKEN.
The actions/cache action is an exercise in futility. Cache keys are confusing, cache misses are silent, and cache eviction is opaque. You will spend more time debugging caching than you save by having a cache.
Reusable workflows can’t be nested beyond a certain depth, can’t access the calling workflow’s context cleanly, and live in YAML files that are impossible to test in isolation. At some point you realize you’re writing a distributed system in YAML and you have to sit down and think about the choices that led you here. The thinking changes you. You do not get the old version of yourself back. That person didn’t know what a workflow_call trigger was. That person was happy.
The GITHUB_TOKEN permissions model is a maze. permissions: write-all is a hammer, fine-grained permissions are a puzzle, and the interaction between repository settings, workflow settings, and job-level settings will make you want to lie down on the floor. I once spent an entire day on token permissions. I will never get that day back. It’s gone. I could have learned to paint. I could have called my mother. I could have mass-tested a new CI system. Anything.
Concurrency controls are blunt. Cancel in-progress runs on the same branch? Sure, one line. Anything more nuanced? No. The system does not wish to discuss nuance. The system has other concerns.
Secrets can’t be used in if conditions. This means you can’t do things like if: secrets. DEPLOY_KEY != ‘’ to conditionally run a step based on whether a secret is configured. GitHub doesn’t want secret values leaking into logs via expression evaluation, which is a reasonable security concern. But the practical result is that you can’t write workflows that gracefully degrade when optional secrets aren’t present. Instead you need awkward workarounds like setting a non-secret environment variable that flags whether the real secret exists. It’s one of those decisions that makes perfect sense in a security review and makes you want to scream when you’re actually trying to write a workflow that works in both forks and the main repo.
At some point in every engineer’s CI journey, a temptation presents itself.
“What if I just wrote bash scripts?” the voice whispers. “What if I stopped fighting the CI system and just run:’d a big shell script that does everything? I could run it locally. I could test it. I’d be free.”
I understand the appeal. I have felt it myself, late at night, after the fourth failed workflow run in a row. The desire to burn down the YAML temple and return to the simple honest earth of #!/bin/bash and set -euo pipefail. To cast off the chains of marketplace actions and reusable workflows and just write the damn commands. It feels like liberation. It is not.
Here’s what actually happens. Your bash script works. You feel clever. You tell your coworkers about it. Then the script grows. It acquires conditionals. It acquires functions. It acquires argument parsing. It acquires a second script that it sources. Someone adds error handling. Someone else adds logging. Someone (and this person should be stopped, but never is) adds “just a little bit of parallelism.”
Three months later you have 800 lines of bash that reimplements job parallelism with wait and PID files, has its own retry logic built on a for loop and sleep, and parses its own output to determine success or failure. The script has become self-aware. There’s a race condition in the cleanup trap that only manifests on Linux kernel 6.x, and you are the only person who understands the script, and you are on vacation, and your phone is ringing.
You have not escaped CI. You have built a CI system. It’s just worse than every other CI system, because it’s written in bash, and nobody can follow it, and it has no test framework, and shellcheck is screaming into the void, and the void is also written in bash.
Bash is fine for glue. Bash is fine for “run these four commands in order.” Bash is not a build system. Bash is not a test harness. The fact that it can be coerced into impersonating both is not a recommendation. It’s a warning sign. You are not simplifying. You are moving complexity from a place with guardrails to a place with none. The complexity will not be grateful for its new freedom. The complexity will use its freedom to make your life worse.
There are other ways to live. Buildkite is what CI should feel like. Not joyful, nothing about CI is joyful, but tolerable. A tool that understands its purpose and does not fight you. Let me tell you how the other half lives.
Buildkite’s log viewer is just a web page that shows you logs and doesn’t crash. I realize that’s a low bar. It’s a bar that GitHub Actions trips over and falls face-first into the mud, gets up, slips again, and somehow sets the mud on fire.
The terminal output rendering is excellent. Build logs look like terminal output, because they are terminal output. ANSI colors work. Your test framework’s fancy formatting comes through intact. You’re not squinting at a web UI that has eaten your escape codes and rendered them as mojibake. This sounds minor. It is not minor. You are reading build logs dozens of times a day. The experience of reading them matters in the way that a comfortable chair matters. You only notice how much it matters after you’ve been sitting in a bad one for six hours and your back has filed a formal complaint.
Annotations let your build steps write rich Markdown output (test failure summaries, coverage reports, deploy links,) right into the build page. You don’t have to dig through log output to find the thing you care about. The information comes to you. After years of fighting GitHub Actions’ collapsible log groups and wondering which of the seventeen nested folds contains the actual error message, this feels like stepping out of a cave into sunlight.
And debugging? Buildkite doesn’t make CI debugging fun. Nothing does. Nothing can. It is one of the irreducible sufferings of our craft. But because the agent runs on your infrastructure, you can SSH into the box. You can look at what’s actually happening. You can reproduce the environment locally because you built the environment. You are still mortal, but at least you have tools.
Buildkite has YAML too, but the difference is that Buildkite’s YAML is just describing a pipeline. Steps, commands, plugins. It’s a data structure, not a programming language cosplaying as a config format. When you need actual logic? You write a script. In a real language. That you can run locally. Like a human being with dignity and a will to live.
This is the boundary the bash zealots were actually looking for: not “put everything in bash,” but “put the orchestration in config and the logic in code.” Buildkite respects this boundary. GitHub Actions blurs it until you can no longer tell where configuration ends and programming begins, and then the programming happens in a language that can’t do basic arithmetic without ${{ }} and a prayer.
With Buildkite, the agent is a single binary that runs on your machines. Your cloud, your on-prem boxes, your weird custom hardware. You control the instance types, the caching, the local storage, the network. Run agents on a fleet of massive EC2 instances with NVMe drives and 20 gigs of Docker layer cache. Run them on a Raspberry Pi. It doesn’t care. The fastest CI is the one with a warm cache on a big machine that you control.
You don’t see a cottage industry of “Buildkite, but faster.” You don’t need one. You just run bigger machines.
GitHub Actions will never give you this. GitHub Actions will give you a mass-produced Ubuntu VM with the emotional warmth of a hospital waiting room.
I can hear the objection forming: “But I don’t want to run my own CI infrastructure. I just want to push code and have tests run.”
Fair. Running your own agents is not for everyone. If you’re maintaining a small open source library in your spare time, you shouldn’t have to spin up EC2 instances and manage autoscaling groups. GitHub Actions’ free tier for public repos is genuinely valuable for the OSS ecosystem, and I’m not here to tell a solo maintainer they need to set up Terraform to run their unit tests.
This post is mostly aimed at teams running production systems at businesses, places where you’re already managing infrastructure, where CI time is measured in engineering hours lost per week, where the build that takes 45 minutes is costing you real money in both compute and salary. If that’s you, the overhead of running Buildkite agents pays for itself quickly. If you’re publishing a 200-line npm package on your weekends, the calculus is different and that’s fine.
In Buildkite, pipeline steps are just data. You can generate them.
Your pipeline YAML can contain a step that runs a script, and that script can emit more pipeline steps. Dynamically. At runtime. Based on whatever logic you want: which files changed, what day of the week it is, the phase of the moon, whether the build gods are feeling merciful.
So you write a script that looks at your monorepo, figures out what changed, and uploads exactly the right set of steps for the things that need building and testing. No hardcoded matrix. No if: contains(github.event.pull_request…) spaghetti. Just a program that outputs steps.
GitHub Actions has matrix strategies and if conditions and reusable workflows and all sorts of mechanisms that try to approximate this. They’re all worse. They’re declarative in the worst sense: you’re declaring things in a language that isn’t powerful enough to express what you mean, so you end up building a Rube Goldberg machine out of YAML and regret. The machine grows. You feed it. It does not thank you.
I’ll be honest: Buildkite’s plugin system is structurally pretty similar to the GitHub Actions Marketplace. You’re still pulling in third-party code from a repo. You’re still trusting someone else’s work. I won’t pretend there’s some magic architectural difference that makes this safe.
The real difference is narrower than I’d like: Buildkite plugins tend to be thin shell hooks rather than entire Docker images with their own runtime, so there’s less surface area to hide things in, and you can usually read the whole plugin in a few minutes. More importantly, they run on your infrastructure, so at least the blast radius is something you control. It’s not a solved problem. It’s a smaller problem.
Buildkite has custom emoji. You can put a little :parrot: or :docker: or your team’s custom emoji next to your pipeline steps. This is, objectively, a frivolous feature. It is also one of my favorite things about Buildkite, because it tells you something about the people who built it. They thought about what it feels like to use their product. They knew that CI is a slog and that a small dumb thing like a custom emoji next to your deploy step can make the slog a fraction more bearable.
GitHub Actions would never do this. GitHub Actions is a product designed by a committee that has never once asked “but is it delightful?” and it shows.
Buildkite is built by people who clearly use CI every day and have thought hard about what makes it tolerable. The result is a tool that, if not exactly joyful, at least does not make you want to lie down on the floor. In this industry, that’s high praise.
Yeah. GitHub Actions won by being the default, not by being good. It’s free for public repos, it’s built into the platform everyone already uses, and it’s Good Enough. It’s the Internet Explorer of CI. It ships with the thing. People use it because switching costs are real and life is finite and we’re all just trying to ship code and go home.
If you’re a small team with a simple app and straightforward tests, it’s probably fine. I’m not going to tell you to rip it out.
But if you’re running a real production system, if you have a monorepo, if your builds take more than five minutes, if you care about supply chain security, if you want to actually own your CI: look at Buildkite.
I’ve been doing this for a long time. I’ve watched CI systems come and go. I’ve helped build one. The pattern is always the same: the CI system that wins market share is never the one that’s best at being a CI system. It’s the one that’s easiest to start using.
GitHub Actions is the easiest CI to start using. Buildkite is the best CI to keep using. And in the long run (assuming your CI hasn’t already ground you into a fine paste, assuming the YAML hasn’t hollowed you out entirely, assuming there’s still someone left who remembers what it was like before,) that’s what matters.
If your CI works and you’re happy, great, keep going. But if you’ve got that nagging feeling that it’s fighting you more than helping you: you’re not the problem. The tooling is. There are other ways to live.
...
Read the original on iankduncan.com »
Software is a static list of instructions, which we are constantly changing.
...
Read the original on theprogrammersparadox.blogspot.com »
To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".
10HN is also available as an iOS App
If you visit 10HN only rarely, check out the the best articles from the past week.
If you like 10HN please leave feedback and share
Visit pancik.com for more.