10 interesting stories served every morning and every evening.

Microsoft Office 2019 and 2021 for Mac view-only conversion (2026) - Consumer Rights Wiki

consumerrights.wiki

From Consumer Rights Wiki

Microsoft Office 2019 and 2021 for Mac view-only con­ver­sion (2026) is a sched­uled re­mote degra­da­tion of per­pet­u­ally-li­censed Microsoft Office soft­ware for ma­cOS and iOS, set for July 13, 2026 when a li­cense-val­i­da­tion cer­tifi­cate used by the Office apps ex­pires.[1] After Office 2019 for Mac reached end of sup­port in October 2023, Microsoft as­sured cus­tomers their in­stalled apps would continue to func­tion.“[2] The July 13, 2026 con­ver­sion in­stead drops the apps into a Microsoft-defined reduced func­tion­al­ity mode,” in which files can be opened and viewed but not edited or saved.[1][3] By May 30, 2026, the orig­i­nal 2023 end-of-sup­port page had been re-dated and rewrit­ten on Microsoft’s site; the continue to func­tion” clause was re­moved.[4][2]

Microsoft an­nounced gen­eral avail­abil­ity of Office 2019 for Windows and Mac on September 24, 2018. In the launch blog post, Microsoft’s Jared Spataro wrote that Office 2019 is a one-time re­lease and won’t re­ceive fu­ture fea­ture up­dates,” po­si­tion­ing the prod­uct as the on-premises al­ter­na­tive to the Office 365 sub­scrip­tion.[5] Contemporary Microsoft Store pages mar­keted Office Home & Student 2019 as a One-time pur­chase for 1 PC or Mac” at $149.99, with copy that ex­plic­itly con­trasted the per­pet­ual prod­uct against the Office 365 sub­scrip­tion model: One-time pur­chases don’t have an up­grade op­tion, which means if you plan to up­grade to the next ma­jor re­lease, you’ll have to buy it at full price.“[6]

Office 2021 for Mac be­came gen­er­ally avail­able on October 5, 2021 un­der the same one-time-pur­chase model & is sched­uled to reach end of sup­port on October 13, 2026 per the Microsoft Lifecycle Policy.[7]

Office 2019 for Mac reached end of sup­port on October 10, 2023.[3]

Microsoft’s end-of-sup­port page for Office 2019 for Mac, be­fore and af­ter the 2026 edit

Internet Archive snap­shot of the page from June 3, 2023; orig­i­nally pub­lished April 12, 2023.[2]

Internet Archive snap­shot of the page from June 3, 2023; orig­i­nally pub­lished April 12, 2023.[2]

The same Microsoft URL cap­tured on May 30, 2026, re-dated Published: May 15th, 2026.[4]

The same Microsoft URL cap­tured on May 30, 2026, re-dated Published: May 15th, 2026.[4]

The June 3, 2023 snap­shot of Microsoft’s end-of-sup­port page con­tained this pas­sage:

Support for Office 2019 for Mac will end on October 10, 2023. Rest as­sured that all your Office 2019 apps will con­tinue to func­tion—they won’t dis­ap­pear from your Mac, nor will you lose any data. However, you could ex­pose your­self to se­ri­ous and po­ten­tially harm­ful se­cu­rity risks.[2]

Support for Office 2019 for Mac will end on October 10, 2023. Rest as­sured that all your Office 2019 apps will con­tinue to func­tion—they won’t dis­ap­pear from your Mac, nor will you lose any data. However, you could ex­pose your­self to se­ri­ous and po­ten­tially harm­ful se­cu­rity risks.[2]

By May 30, 2026, the same URL car­ried a new pub­li­ca­tion date of May 15th, 2026 and a shorter pas­sage:

Support for Office 2019 for Mac ended on October 10, 2023. Rest as­sured that all your Office 2019 apps won’t lose any data. Your data can be ac­cessed on any sup­ported Microsoft 365 or Office prod­uct. However, you could ex­pose your­self to se­ri­ous and po­ten­tially harm­ful se­cu­rity risks.[4]

Support for Office 2019 for Mac ended on October 10, 2023. Rest as­sured that all your Office 2019 apps won’t lose any data. Your data can be ac­cessed on any sup­ported Microsoft 365 or Office prod­uct. However, you could ex­pose your­self to se­ri­ous and po­ten­tially harm­ful se­cu­rity risks.[4]

The 2023 as­sur­ance that the apps would continue to func­tion” was re­moved; the data-safety clause was kept; a new sen­tence point­ing own­ers to any sup­ported Microsoft 365 or Office prod­uct” was added.[2][4] The 2023 word­ing was resur­faced in May 2026 by JimmyTech, a San Francisco IT con­sul­tancy, which char­ac­ter­ized the July 2026 con­ver­sion as Microsoft breaking that promise.“[8]

Microsoft’s ad­min­is­tra­tor doc­u­men­ta­tion states that Microsoft 365 apps use a dig­i­tal cer­tifi­cate to val­i­date li­cens­ing. The cer­tifi­cate cur­rently in use ex­pires on July 13, 2026. Apps that are up­dated to the min­i­mum re­quired ver­sions al­ready in­clude the re­newed cer­tifi­cate and con­tinue to func­tion nor­mally. Apps on older ver­sions en­ter re­duced func­tion­al­ity mode af­ter the cer­tifi­cate ex­pires.“[1] The min­i­mum re­quired builds are ver­sion 16.83 on ma­cOS and ver­sion 2.93 on iOS, & those builds in turn re­quire ma­cOS 12 (Monterey) or later, or iOS 17.0 or later.[1]

Office 2019 has no fix. The prod­uct line is bounded by a hard build cap be­low the 16.83 thresh­old, and Microsoft’s own sup­port doc­u­men­ta­tion states the is­sue cannot be re­solved by up­dat­ing or re­in­stalling Office 2019 for Mac.“[3][8] Office 2021 for Mac, by con­trast, is still re­ceiv­ing up­dates through its October 13, 2026 re­tire­ment date & can reach 16.83 on sup­ported ma­cOS ver­sions.[7][3] Windows and Android ver­sions of Office are not af­fected by the cer­tifi­cate ex­piry.[1]

After July 13, 2026, af­fected in­stalls of Word, Excel, PowerPoint, Outlook, and OneNote on Mac, iPhone, and iPad will en­ter re­duced func­tion­al­ity mode, in which Microsoft says users can open and view files but can’t edit, save, or ac­cess full fea­tures.“[1] Office 2021 for Mac and Microsoft 365 for Mac users on ma­cOS 12 (Monterey) or later can avoid the con­ver­sion by up­dat­ing to build 16.83.[1] Office 2019 for Mac users have no up­date path.[3]

Microsoft be­gan email­ing af­fected cus­tomers in mid-May 2026 about the up­com­ing change.[8] PiunikaWeb, which pub­lished the ear­li­est press cov­er­age on May 16, 2026, char­ac­ter­ized the user re­sponse as largely neg­a­tive.“[9] The email in­cluded an of­fer of a free Microsoft 365 Personal trial that re­quires a pay­ment method and con­verts to a paid sub­scrip­tion if not can­celled.[3][9]

Microsoft di­rects af­fected users to three op­tions: con­tin­u­ing to use the apps in view-only mode, switch­ing to the free Microsoft 365 web apps, or pay­ing for a Microsoft 365 sub­scrip­tion or a new per­pet­ual Office Home 2024 li­cense.[3][1] Microsoft has is­sued no pub­lic state­ment rec­on­cil­ing the July 2026 con­ver­sion with the 2023 continue to func­tion” as­sur­ance.[2]

AppleInsider’s Amber Neely, in a May 28, 2026 ar­ti­cle, wrote that Microsoft will be ef­fec­tively brick­ing the stand­alone Office 2019 for Mac, iPad, and iPhone users on July 13, 2026.“[10] JimmyTech framed the choice as dis­cre­tionary:

But cer­tifi­cates can get re­newed. The fact that Microsoft is us­ing this ex­pi­ra­tion as a dead­line that re­tires older ver­sions of Office, rather than qui­etly re­new­ing the cer­tifi­cate, is a choice.

But cer­tifi­cates can get re­newed. The fact that Microsoft is us­ing this ex­pi­ra­tion as a dead­line that re­tires older ver­sions of Office, rather than qui­etly re­new­ing the cer­tifi­cate, is a choice.

[8]

TidBITS Talk and PiunikaWeb com­menters dis­cussed mi­grat­ing to LibreOffice, OnlyOffice, and Apple’s Pages.[11][9]

Microsoft

Microsoft 365

Adobe Creative Suite ac­ti­va­tion

↑ 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 Certificate up­date for Microsoft 365 apps on man­aged ma­cOS and iOS de­vices”. Microsoft Learn. Microsoft. 2026 – 05-14. Retrieved 2026 – 05-29.

↑ 2.0 2.1 2.2 2.3 2.4 2.5 End of sup­port for Office 2019 for Mac”. Microsoft Support. Microsoft. Archived from the orig­i­nal on 2023 – 06-03. Retrieved 2026 – 05-30.

↑ 3.0 3.1 3.2 3.3 3.4 3.5 3.6 Update Microsoft 365 or Office on your ma­cOS or iOS de­vice”. Microsoft Support. Microsoft. May 2026. Retrieved 2026 – 05-29.

↑ 4.0 4.1 4.2 4.3 End of sup­port for Office 2019 for Mac”. Microsoft Support. Microsoft. Retrieved 2026 – 05-30.

↑ Spataro, Jared (2018 – 09-24). Office 2019 is now avail­able for Windows and Mac”. Microsoft 365 Blog. Microsoft. Retrieved 2026 – 05-29.

Buy Office Home & Student 2019”. Microsoft Store. Microsoft. Archived from the orig­i­nal on 2020 – 01-05. Retrieved 2026 – 05-29.

↑ 7.0 7.1 Office 2021 - Microsoft Lifecycle”. Microsoft Learn. Microsoft. Retrieved 2026 – 05-29.

↑ 8.0 8.1 8.2 8.3 Obomsawin, Jimmy (2026 – 05-21). Microsoft is dis­abling Office 2019 for Mac on July 13, 2026”. JimmyTech. Retrieved 2026 – 05-29.

↑ 9.0 9.1 9.2 K, Sudhanshu (2026 – 05-16). Using an older Apple de­vice? Microsoft Office is tak­ing away edit­ing fea­tures soon”. PiunikaWeb. Retrieved 2026 – 05-29.

↑ Neely, Amber (2026 – 05-28). Microsoft is killing Office 2019 for Mac and iPhone, and you can’t do much about it”. AppleInsider. Retrieved 2026 – 05-29.

Office 2019 switch­ing to view-only mode, what to do?”. TidBITS Talk. 2026 – 05-16. Retrieved 2026 – 05-29.

reuters.com

www.reuters.com

Please en­able JS and dis­able any ad blocker

Domain Expertise Has Always Been the Real Moat

www.brethorsting.com

The hard part of writ­ing soft­ware has never been the writ­ing. It was build­ing a work­ing model of the do­main in your head first. Before you could ship a pay­roll sys­tem you had to un­der­stand gar­nish­ments and pre-tax de­duc­tions and what hap­pens when some­one’s pay pe­riod strad­dles a rate change. Before you could ship a tran­sit app you had to learn what a GTFS feed is, why a trip and a route aren’t the same thing, and how a bus that’s on time” can still be wrong. The code was a tran­scrip­tion of that un­der­stand­ing. Acquiring the un­der­stand­ing was the job.

Agentic AI sev­ered the link be­tween the two. You can now pro­duce the soft­ware with­out ever build­ing the model, and that breaks an as­sump­tion the whole pro­fes­sion was or­ga­nized around.

The stan­dard take, in­clud­ing my own from last year, is that these tools am­plify se­nior de­vel­op­ers be­cause se­nior de­vel­op­ers have judg­ment. True, but in­com­plete. What I’ve watched hap­pen since is more spe­cific and more in­ter­est­ing: the bind­ing con­straint has moved from can you build it to can you tell whether it’s right.

Think about who can ac­tu­ally use one of these tools well. Picture two peo­ple.

The first is a do­main ex­pert with no real soft­ware back­ground. A lo­gis­tics dis­patcher, a clin­i­cal coder, an ac­tu­ary. They can’t read a stack trace and they could­n’t tell you the dif­fer­ence be­tween a hash map and a list. But they can look at a sched­ule the agent gen­er­ated and know in­stantly that no dri­ver can legally work that shift, or that a claim with those codes would never pay. They know the cor­rect out­puts for a given set of in­puts be­cause they’ve spent ten years liv­ing in those in­puts and out­puts. Hand them an agent and they are star­tlingly ef­fec­tive, be­cause the thing they’re miss­ing, the abil­ity to pro­duce code, is ex­actly the thing the agent sup­plies. What they bring is the thing the agent can’t: the ground truth.

The sec­ond is a strong gen­er­al­ist en­gi­neer who has never worked in the do­main. They can ar­chi­tect any­thing, they know re­li­a­bil­ity and test­ing and how to keep a sys­tem from falling over at 2am. But drop them into clin­i­cal cod­ing and they can­not tell a plau­si­ble-look­ing wrong an­swer from a right one. The agent will hap­pily gen­er­ate a billing rule that com­piles, passes the tests the en­gi­neer thought to write, and is sub­tly, ex­pen­sively in­cor­rect. The en­gi­neer has no or­a­cle. They can ver­ify that the soft­ware is well-built. They can­not ver­ify that it’s cor­rect, be­cause cor­rect­ness here is de­fined en­tirely by a do­main they don’t hold in their head.

Notice which way this cuts. Pre-agent, the en­gi­neer had a path the dis­patcher did­n’t: they could go learn the do­main. Slowly, painfully, by shad­ow­ing ex­perts and read­ing specs and get­ting things wrong in pro­duc­tion, they would build the men­tal model and then they could build the sys­tem. That path was the whole ca­reer lad­der in a lot of fields. The do­main ex­pert had no equiv­a­lent path, be­cause learn­ing to build re­li­able soft­ware is years of work they were never go­ing to do.

Agentic tools col­lapsed one of those paths and not the other. The en­gi­neer’s ad­van­tage, the abil­ity to trans­late a do­main model into work­ing code, is now cheap. The do­main ex­pert’s ad­van­tage, know­ing what right looks like, is not. You can’t prompt your way to it. There’s no skill file that con­tains the tacit knowl­edge of a per­son who has rec­on­ciled a thou­sand pay­rolls.

So the most valu­able per­son in this new world is the one who has both skills be­cause they can ver­ify at both lay­ers. They know the gen­er­ated code is sound and they know the an­swers it pro­duces are true. They can write the test that en­codes a dri­ver can’t ex­ceed eleven hours” be­cause they know the rule, and they can tell that the test it­self is mean­ing­ful be­cause they know what they’re test­ing. The agent does the tran­scrip­tion. They do the judg­ing, twice.

If you’re an ex­pe­ri­enced en­gi­neer bet­ting on where to spend the next few years, this is the bet. The me­chan­i­cal skill you sweated for, turn­ing a clear idea into clean code, has got­ten dra­mat­i­cally less valu­able. The thing that’s still scarce is a deep, ver­i­fied model of some real do­main. Go get one. Pick an in­dus­try, an in­stru­ment, a reg­u­la­tory regime, a phys­i­cal process, and learn it the way you once learned a pro­gram­ming lan­guage or frame­work. That’s the part the agent can’t do for you, and it’s the part that’s now worth the most.

Anthropic surpasses OpenAI to become world’s most valuable AI startup

qazinform.com

13:21, 30 May 2026

Anthropic has be­come the most valu­able ar­ti­fi­cial in­tel­li­gence startup in the world, sur­pass­ing OpenAI in mar­ket val­u­a­tion. Following a new fund­ing round, the val­u­a­tion of the de­vel­oper be­hind the Claude AI as­sis­tant has ap­proached the $1 tril­lion mark, re­ports a Qaz­in­form News Agency cor­re­spon­dent.

Anthropic an­nounced that it had raised $65 bil­lion in a Series H fund­ing round. The largest in­vestors in­cluded Altimeter Capital, Dragoneer, Greenoaks, and Sequoia Capital.

Following the deal, Anthropic of­fi­cially over­took OpenAI in mar­ket val­u­a­tion and be­came the largest AI com­pany among Silicon Valley’s pri­vate star­tups.

The new val­u­a­tion is nearly three times higher than the com­pa­ny’s February val­u­a­tion, when Anthropic was es­ti­mated to be worth around $380 bil­lion. The fund­ing pack­age also in­cluded pre­vi­ously agreed in­vest­ments, in­clud­ing $5 bil­lion from Amazon.

The main dri­ver be­hind Anthropic’s growth is said to be the pop­u­lar­ity of its Claude AI as­sis­tant and the Claude Code ser­vice, which is widely used by soft­ware de­vel­op­ers. The com­pany re­ported that its an­nual rev­enue had grown to $47 bil­lion. Last year, the fig­ure stood at about $10 bil­lion.

At the same time, Anthropic in­tro­duced its new ar­ti­fi­cial in­tel­li­gence model, Claude Opus 4.8, as well as the closed sys­tem Claude Mythos Preview, which of­fers en­hanced cy­ber­se­cu­rity ca­pa­bil­i­ties for cor­po­rate clients.

Anthropic Chief Financial Officer Krishna Rao stated that de­mand for Claude prod­ucts con­tin­ues to grow rapidly around the world.

It is noted that Anthropic’s rise has in­ten­si­fied com­pe­ti­tion in the ar­ti­fi­cial in­tel­li­gence mar­ket. In March, OpenAI was val­ued at $852 bil­lion fol­low­ing a record $122 bil­lion fund­ing round. At the same time, the largest AI com­pa­nies are prepar­ing for pub­lic list­ings. According to CNBC, OpenAI may file for an ini­tial pub­lic of­fer­ing (IPO) within the com­ing weeks. Anthropic is also con­sid­er­ing a pub­lic stock of­fer­ing, al­though the ex­act tim­ing has not yet been dis­closed.

Earlier, Qazinform News Agency re­ported that Kazakhstan ranked among the coun­tries least con­cerned about job losses caused by ar­ti­fi­cial in­tel­li­gence, ac­cord­ing to the lat­est global sur­vey by the Gallup International Association.

OpenRouter Raises $113M Series B | OpenRouter

openrouter.ai

Skip to con­tent

/

pandoc-templates.org

pandoc-templates.org

pan­doc-jour­nal-tem­plates

sachsmc (Michael Sachs)

Journal tem­plates for sev­eral ma­jor jour­nals (incl. JASA, TAS, JBES, JCGS, SBP, Technometrics, Biometrical Journal, Biometrics, Biometrika, Biostatistics, AOAS, AOP, AAP, AOS, SSY, Journal of Statistical Software, Statistics in Medicine, and The R Journal).

GitHub - kristapsdz/openrsync: BSD-licensed implementation of rsync

github.com

Introduction

This sys­tem has been merged into OpenBSD base. If you’d like to con­tribute to openr­sync, please mail your patches to tech@openbsd.org. This repos­i­tory is sim­ply the OpenBSD ver­sion plus some glue for porta­bil­ity.

This is an im­ple­men­ta­tion of rsync with a BSD (ISC) li­cense. It’s com­pat­i­ble with a mod­ern rsync (3.1.3 is used for test­ing, but any sup­port­ing pro­to­col 27 will do), but ac­cepts only a sub­set of rsync’s com­mand-line ar­gu­ments.

Its of­fi­cially-sup­ported op­er­at­ing sys­tem is OpenBSD, but it will com­pile and run on other UNIX sys­tems. See Portability for de­tails.

The canon­i­cal doc­u­men­ta­tion for openr­sync is its man­ual pages. See rsync(5) and rsyncd(5) for pro­to­col de­tails or util­ity doc­u­men­ta­tion in openr­sync(1). If you’d like to write your own rsync im­ple­men­ta­tion, the pro­to­col man­pages should have all the in­for­ma­tion re­quired.

The Architecture and Algorithm sec­tions on this page serve to in­tro­duce de­vel­op­ers to the source code. They are non-canon­i­cal.

Project back­ground

openr­sync is writ­ten as part of the rpki-client(1) pro­ject, an RPKI val­ida­tor for OpenBSD. openr­sync was funded by NetNod, IIS.SE, SUNET and 6connect.

Installation

On an up-to-date UNIX sys­tem, sim­ply down­load and run:

% ./configure % make # make in­stall

This will in­stall the openr­sync util­ity and man­ual pages. It’s ok to have an in­stal­la­tion of rsync at the same time: the two will not col­lide in any way.

If you up­grade your sources and want to re-in­stall, just run the same. If you’d like to unin­stall the sources:

# make unin­stall

If you’d like to in­ter­act with the openr­sync as a server, you can run the fol­low­ing:

% rsync –rsync-path=openrsync src/* dst % openr­sync –rsync-path=openrsync src/* dst

If you’d like openr­sync and rsync to in­ter­act, it’s im­por­tant to use com­mand-line flags avail­able on both. See openr­sync(1) for a list­ing.

Algorithm

For a ro­bust de­scrip­tion of the rsync al­go­rithm, see The rsync al­go­rithm”, by Andrew Tridgell and Paul Mackerras. Andrew Tridgell’s PhD the­sis, Efficient Algorithms for Sorting and Synchronization”, cov­ers the top­ics in more de­tail. This gives a de­scrip­tion suit­able for delv­ing into the source code.

The rsync al­go­rithm has two com­po­nents: the sender and the re­ceiver. The sender man­ages source files; the re­ceiver man­ages the des­ti­na­tion. In the fol­low­ing in­vo­ca­tion, first the sender is host re­mote and the re­ceiver is the lo­cal­host, then the op­po­site.

% openr­sync -lrtp re­mote:foo/​bar ~/baz/xyzzy % openr­sync -lrtp ~/foo/bar re­mote:baz/​xyzzy

The al­go­rithm hinges upon a file list of names and meta­data (e.g., mode, mtime, etc.) shared be­tween com­po­nents. The file list de­scribes all source files of the up­date and is gen­er­ated by the sender. The shar­ing is im­ple­mented in flist.c.

After shar­ing this list, both the re­ceiver and sender in­de­pen­dently sort the en­tries by the file­names’ lex­i­co­graph­i­cal or­der. This al­lows the file list to be sent and re­ceived out of or­der. The or­der­ing pre­serves a di­rec­tory-first or­der, so di­rec­to­ries are processed be­fore their con­tained files. Moreover, once sorted, both sender and re­ceiver may re­fer to file en­tries by their po­si­tion in the sorted ar­ray.

After the re­ceiver reads the list, it it­er­ates through each file in the list, pass­ing in­for­ma­tion to the sender so that the sender may send back in­struc­tions to up­date the file. This is called the block ex­change” and is the maintstay of the rsync al­go­rithm. During the block ex­change, the sender waits to re­ceive a re­quest for up­date or end of se­quence mes­sage; once a re­quest is re­ceived, it scans for new blocks to send to the re­ceiver.

Once the block ex­change is com­plete, the files are all up to date.

The re­ceiver is im­ple­mented in re­ceiver.c; the sender, in sender.c. A great deal of the block ex­change hap­pens in blocks.c.

Block ex­change

The block ex­change se­quence is dif­fer­ent for whether the file is a di­rec­tory, sym­bolic link, or reg­u­lar file.

For sym­bolic links, the in­for­ma­tion re­quired by the re­ceiver is al­ready en­coded in the file list meta­data. The sym­bolic link is up­dated to point to the cor­rect tar­get. No up­date is re­quested from the sender.

For di­rec­to­ries, the di­rec­tory is cre­ated if it does not al­ready ex­ist. No up­date is re­quested from the sender.

Regular files are han­dled as fol­lows. First, the file is checked to see if it’s up to date. This hap­pens if the file size and last mod­i­fi­ca­tion time are the same. If so, no up­date is re­quested from the sender.

Otherwise, the re­ceiver ex­am­ines each file in blocks of a fixed size. See Block sizes for de­tails. (The ter­mi­nal block may be smaller if the file size is not di­vis­i­ble by the block size.) If the file is empty or does not ex­ist, it will have zero blocks. Each block is hashed twice: first, with a fast Adler-32 type 4-byte hash; sec­ond, with a slower MD4 16-byte hash. These hashes are im­ple­mented in hash.c. The re­ceiver sends the file’s block hashes to the sender.

Once ac­cepted, the sender ex­am­ines the cor­re­spond­ing file with the given blocks. For each byte in the source file, the sender com­putes a fast hash given the block size. It then looks for match­ing fast hashes in the sent block in­for­ma­tion. If it finds a match, it then com­putes and checks the slow hash. If no match is found, it con­tin­ues to the next byte. The match­ing (and in­deed all block op­er­a­tion) is im­ple­mented in block.c.

When a match is found, the data prior to the match is first sent as a stream of bytes to the re­ceiver. This is fol­lowed by an iden­ti­fier for the found block, or zero if no more data is forth­com­ing.

The re­ceiver writes the stream of bytes first, then copies the data in the iden­ti­fied block if one has been spec­i­fied. This con­tin­ues un­til the end of file, at which point the file has been fully re­con­sti­tuted.

If the file does not ex­ist on the re­ceiver side–-the ba­sis case–-the en­tire file is sent as a stream of bytes.

Following this, the whole file is hashed us­ing an MD4 hash. These hashes are then com­pared; and on suc­cess, the al­go­rithm con­tin­ues to the next file.

Block sizes

The block size al­go­rithm plays a cru­cial role in the pro­to­col ef­fi­ciency. In gen­eral, the block size is the rounded square root of the to­tal file size. The min­i­mum block size, how­ever, is 700 B. Otherwise, the square root com­pu­ta­tion is sim­ply sqrt(3) fol­lowed by ceil(3)

For rea­sons un­known, the square root re­sult is rounded up to the near­est mul­ti­ple of eight.

Architecture

Each openr­sync ses­sion is di­vided into a run­ning server and client process. The client openr­sync process is ex­e­cuted by the user.

% openr­sync -rlpt host:path/​to/​source dest

The server openr­sync is ex­e­cuted on a re­mote host ei­ther on-de­mand over ssh(1) or as a per­sis­tent net­work dae­mon. If ex­e­cuted over ssh(1), the server openr­sync is dis­tin­guished from a client (user-started) openr­sync by the –server flag.

Once the client or server openr­sync process starts, it ex­am­ines the com­mand-line ar­gu­ments to de­ter­mine whether it’s in re­ceiver or sender mode. (The dae­mon is sent the com­mand-line ar­gu­ments in a pro­to­col-spe­cific way de­scribed in rsyncd(5), but oth­er­wise does the same thing.) The re­ceiver is the des­ti­na­tion for files; the sender is the ori­gin. There is al­ways one re­ceiver and one sender.

The server process is ex­plic­itly in­structed that it is a sender with the –sender com­mand-line flag, oth­er­wise it is a re­ceiver. The client process im­plic­itly de­ter­mines its sta­tus by look­ing at the files passed on the com­mand line for whether they are lo­cal or re­mote.

openr­sync path/​to/​source host:des­ti­na­tion openr­sync host:source path/​to/​des­ti­na­tion

In the first ex­am­ple, the client is the sender: it sends data from it­self to the server. In the sec­ond, the op­po­site is true in that it re­ceives data.

The clien­t’s com­mand-line files may have any of the fol­low­ing host spec­i­fi­ca­tions that de­ter­mine lo­cal­ity.

lo­cal: ../path/to/source ../another

re­mote server: host:path/​to/​source :path/to/another

re­mote dae­mon: rsync://​host/​mod­ule/​path ::another

Host spec­i­fi­ca­tions must be con­sis­tent: sources must all be lo­cal or all be re­mote on the same host. Both may not be re­mote. (Aside: it’s tech­ni­cally pos­si­ble to do this. I’m not sure why the GPL rsync is lim­ited to one or the other.)

If the source or des­ti­na­tion is on a re­mote server, the client then fork(2)s and starts the server openr­sync on the re­mote host over ssh(1). The client and the server sub­se­quently com­mu­ni­cate over sock­et­pair(2) pipes. If on a re­mote dae­mon, the client does not fork, but in­stead con­nects to the stand­alone server with a net­work socket(2).

The server’s com­mand-line, whether passed to an openr­sync spawned on-de­mand over an ssh(1) ses­sion or passed to the dae­mon, dif­fers from the clien­t’s.

openr­sync –server [–sender] . files…

The files given are ei­ther the sin­gle des­ti­na­tion di­rec­tory when in re­ceiver mode, or the list of sources when in sender mode. The stand­alone full-stop is a mys­tery to me.

Locality de­tec­tion and rout­ing to client and server run-times are han­dled in main.c. The client for a server is im­ple­mented in client.c and the server in server.c. The client for a net­work dae­mon is in socket.c. Invocation of the re­mote server openr­sync is man­aged in child.c.

Once the client and server be­gin, they start to ne­go­ti­ate the trans­fer of files over the con­nected socket. The pro­to­col used is spec­i­fied in rsync(5). For dae­mon con­nec­tions, the rsyncd(5) pro­to­col is also used for hand­shak­ing.

The re­ceiver side is man­aged in re­ceiver.c and the sender in sender.c.

The re­ceiver side tech­ni­cally has two func­tions: not only must it up­load block meta­data to the sender, it must also han­dle data writes as they are sent by the sender. The rsync pro­to­col is de­signed so that the sender re­ceives block re­quests and con­tin­u­ously sends data to the re­ceiver.

To ac­com­plish this, the re­ceiver mul­ti­tasks as the up­loader and down­loader. These roles are im­ple­mented in up­loader.c. and down­loader.c, re­spec­tively. The mul­ti­task­ing takes place by a fi­nite state ma­chine dri­ven by data com­ing from the sender and files on disc are they are ready to be check­summed and up­loaded.

The up­loader scans through the list of files and asyn­chro­nously opens files to process blocks. While it waits for the files to open, it re­lin­quishes con­trol to the event loop. When files are avail­able, it hashes and check­sums blocks and up­loads to the sender.

The down­loader waits on data from the sender. When data is ready (and pre­fixed by the file it will up­date), the down­loader asyn­chro­nously opens the ex­ist­ing file to per­form any block copy­ing. When the file is avail­able for read­ing, it then con­tin­ues to read data from the sender and copy from the ex­ist­ing file.

Differences from rsync

The de­sign of rsync in­volves an­other mode run­ning along­side the re­ceiver: the gen­er­a­tor. This is im­ple­mented as an­other process fork(2)ed from the re­ceiver, and com­mu­ni­cat­ing with the re­ceiver and sender.

In openr­sync, the gen­er­a­tor and re­ceiver are one process, and an event loop is used for speedy re­sponses to read and write re­quests.

Security

Besides the usual de­fen­sive pro­gram­ming, openr­sync makes sig­nif­i­cant use of na­tive se­cu­rity fea­tures.

The sys­tem op­er­a­tions avail­able to ex­e­cut­ing code are fore­most lim­ited by OpenBSD’s pledge(2). The pledges given de­pend upon the op­er­at­ing mode. For ex­am­ple, the re­ceiver needs write ac­cess to the disc–-but only when not in dry-run mode (-n). The dae­mon client needs DNS and net­work ac­cess, but only to a point. pledge(2) al­lows avail­able re­sources to be lim­ited over the course of op­er­a­tion.

The sec­ond tool is OpenBSD’s un­veil(2), which lim­its ac­cess to the file-sys­tem. This pro­tects against rogue at­tempts to break out” of the des­ti­na­tion. It’s an at­trac­tive al­ter­na­tive to ch­root(2) be­cause it does­n’t re­quire root per­mis­sions to ex­e­cute.

On the re­ceiver side, the file-sys­tem is un­veil(2)ed at and be­neath the des­ti­na­tion di­rec­tory. After the cre­ation of the des­ti­na­tion di­rec­tory, only tar­gets within that di­rec­tory may be ac­cessed or mod­i­fied.

Lastly, the MD4 hashs are seeded with ar­c4ran­dom(3) in­stead of with time(3). This is only ap­plic­a­ble when run­ning openr­sync in server mode, as the server gen­er­ates the seed.

Portability

Many have asked about porta­bil­ity.

The only of­fi­cially-sup­ported op­er­at­ing sys­tem is OpenBSD, as this has con­sid­er­able se­cu­rity fea­tures. openr­sync does, how­ever, use ocon­fig­ure for com­pi­la­tion on non-OpenBSD sys­tems. This is to en­cour­age port­ing.

It cur­rently is portable across Linux (glibc and musl), FreeBSD, NetBSD, Mac OS X, and OmniOS. This is en­forced by the GitHub CI mech­a­nism, which tests on this sys­tems. Architectures tested for in­clude x86_64, aarch64, and s390x.

The ac­tual work of port­ing is match­ing the se­cu­rity fea­tures pro­vided by OpenBSD’s pledge(2) and un­veil(2). These are crit­i­cal el­e­ments to the func­tion­al­ity of the sys­tem. Without them, your sys­tem ac­cepts ar­bi­trary data from the pub­lic net­work.

This is pos­si­ble (I think?) with FreeBSD’s Capsicum, but Linux’s se­cu­rity fa­cil­i­ties are a mess, and will take an ex­pert hand to prop­erly se­cure.

rsync has spe­cific run­ning modes for the su­per-user. It also pumps ar­bi­trary data from the net­work onto your file-sys­tem. openr­sync is about 10 000 lines of C code: do you trust me not to make mis­takes?

Devlog ⚡ Zig Programming Language

ziglang.org

This page con­tains a cu­rated list of re­cent changes to main branch Zig.

This page con­tains en­tries for the year 2026. Other years are avail­able in the Devlog archive page.

May 30, 2026

ELF Linker Improvements

Author: Matthew Lugg

I’ve spent the past few weeks work­ing on our new ELF linker which de­buted in Zig 0.16.0. At the time of the 0.16.0 re­lease, this linker im­ple­men­ta­tion was in its fairly early stages, and only re­ally sup­ported link­ing Zig-only code with­out any ex­ter­nal li­braries (even libc)—hence why it was (and still is) dis­abled by de­fault (it can be en­abled with -fnew-linker). However, quite a lot of progress has been made since that ini­tial re­lease!

Here’s a nice mile­stone—as of my lat­est PR, the new ELF linker is ca­pa­ble of build­ing the self-hosted Zig com­piler with LLVM and LLD li­braries en­abled, a task which re­quires quite a few fea­tures un­der the hood.

[mlugg@nebula mas­ter]$ # Build the Zig com­piler us­ing the new linker: [mlugg@nebula mas­ter]$ zig build -Dno-lib -Dnew-linker -Denable-llvm [mlugg@nebula mas­ter]$ # Use that com­piler to build some­thing with LLVM and LLD: [mlugg@nebula mas­ter]$ ./zig-out/bin/zig build-exe ~/hello.zig -fllvm -flld [mlugg@nebula mas­ter]$ ./hello Hello, World! [mlugg@nebula mas­ter]$

Of course, an ELF linker is­n’t nec­es­sar­ily the most ex­cit­ing thing in the world, which is why the head­line fea­ture of this new linker is its sup­port for fast in­cre­men­tal com­pi­la­tion. After the re­cent en­hance­ments, it is now pos­si­ble (on x86_64 Linux) to per­form in­cre­men­tal re­builds while link­ing ex­ter­nal li­braries, C sources, etc—with­out any ad­di­tional per­for­mance over­head! Here’s a clip of me try­ing it out on Andrew’s Tetris clone:

Oh, and fast in­cre­men­tal re­builds also work nicely on the Zig com­piler it­self:

[mlugg@nebula mas­ter]$ zig build -Dno-lib -Denable-llvm -fincremental –watch Build Summary: 4/4 steps suc­ceeded in­stall suc­cess └─ in­stall zig suc­cess └─ com­pile exe zig Debug na­tive suc­cess 36s

Build Summary: 4/4 steps suc­ceeded in­stall suc­cess └─ in­stall zig suc­cess └─ com­pile exe zig Debug na­tive suc­cess 244ms

Build Summary: 4/4 steps suc­ceeded in­stall suc­cess └─ in­stall zig suc­cess └─ com­pile exe zig Debug na­tive suc­cess 228ms

Build Summary: 4/4 steps suc­ceeded in­stall suc­cess └─ in­stall zig suc­cess └─ com­pile exe zig Debug na­tive suc­cess 288ms

Build Summary: 4/4 steps suc­ceeded in­stall suc­cess └─ in­stall zig suc­cess └─ com­pile exe zig Debug na­tive suc­cess 283ms

The biggest miss­ing fea­ture of this linker im­ple­men­ta­tion right now is that it still does not yet sup­port gen­er­at­ing DWARF de­bug in­for­ma­tion for Zig code—that’s def­i­nitely my next pri­or­ity. But even with­out that sup­port, it’s amaz­ing just how use­ful in­stant re­builds can be, for ex­am­ple in any sit­u­a­tion where you’re do­ing a lot of print de­bug­ging.

If you’re us­ing the mas­ter branch of Zig and you’re on x86_64 Linux, con­sider try­ing out in­cre­men­tal com­pi­la­tion with the new ELF linker if it pre­vi­ously was­n’t work­ing with your pro­ject! I ex­pect many code­bases to al­ready work great with it, un­lock­ing the abil­ity to re­build your pro­ject in mil­lisec­onds. Of course, if you come across any bugs, please do open an is­sue.

And if you’re cur­rently stick­ing to tagged re­leases of Zig, don’t worry—as Andrew men­tioned in his last de­vlog, Zig 0.17.0 is just around the cor­ner, so it won’t be long be­fore you can try this too!

May 26, 2026

Build System Reworked

Author: Andrew Kelley

Big branch just landed: sep­a­rate the maker process from the con­fig­urer process

This de­vlog en­try is es­sen­tially a pre­view of the up­com­ing re­lease notes, but serves as an ad­vanced no­tice to those who want to help test out the new fea­tures and pro­vide feed­back that will guide the Zig pro­ject mov­ing for­ward.

Before, build.zig files plus the build sys­tem im­ple­men­ta­tion were all com­piled into one bloated process, in Debug mode. After build.zig logic fin­ished con­struct­ing a build graph in mem­ory, the build run­ner” code ex­e­cuted it.

Now, build.zig files are com­piled into a small process (the configurer”) in de­bug mode. After this logic fin­ishes con­struct­ing a build graph in mem­ory, it is se­ri­al­ized to a bi­nary con­fig­u­ra­tion file. The par­ent zig build process is aware of this file and caches it for next time. While wait­ing for all that, it asyn­chro­nously com­piles the build graph ex­e­cu­tion process (the maker”) in re­lease mode. Once the con­fig­u­ra­tion file is avail­able and the maker process is fin­ished com­pil­ing, the maker process is ex­e­cuted, pass­ing it the con­fig­u­ra­tion file. The maker process only needs to be com­piled once per zig ver­sion thanks to the global cache. The maker process then ex­e­cutes the build graph, which is con­tained within the se­ri­al­ized con­fig­u­ra­tion file.

The pri­mary mo­ti­va­tion of this change was to make zig build faster, in three ways:

Only the user’s build.zig logic will be com­piled with each change, rather than the en­tire build sys­tem along with it. This is start­ing to be­come more valu­able now that we have in­tro­duced –watch, –fuzz and –webui. The build sys­tem can grow more fea­tures with­out mak­ing zig build take longer.

Only the user’s build.zig logic will be com­piled with each change, rather than the en­tire build sys­tem along with it. This is start­ing to be­come more valu­able now that we have in­tro­duced –watch, –fuzz and –webui. The build sys­tem can grow more fea­tures with­out mak­ing zig build take longer.

Now the build sys­tem can skip re­run­ning the build.zig logic en­tirely when it knows noth­ing will change, for ex­am­ple if you add -freference-trace to your zig build com­mand line, it now avoids re-run­ning your build.zig logic re­dun­dantly, us­ing the same con­fig­u­ra­tion as last time.

Now the build sys­tem can skip re­run­ning the build.zig logic en­tirely when it knows noth­ing will change, for ex­am­ple if you add -freference-trace to your zig build com­mand line, it now avoids re-run­ning your build.zig logic re­dun­dantly, us­ing the same con­fig­u­ra­tion as last time.

Now the process that ac­tu­ally ex­e­cutes the build graph is com­piled with op­ti­miza­tions en­abled.

Now the process that ac­tu­ally ex­e­cutes the build graph is com­piled with op­ti­miza­tions en­abled.

To demon­strate points 2 and 3, here is the dif­fer­ence be­tween run­ning zig build –help be­fore and af­ter:

Benchmark 1 (34 runs): mas­ter/​zig build -h mea­sure­ment mean ± σ min … max out­liers delta wal­l_­time 150ms ± 5.52ms 145ms … 165ms 4 (12%) 0% peak_rss 84.8MB ± 275KB 84.2MB … 85.1MB 0 ( 0%) 0% cpu_­cy­cles 593M ± 4.01M 588M608M 2 ( 6%) 0% in­struc­tions 995M ± 52.5K 995M995M 0 ( 0%) 0% cache_ref­er­ences 25.8M ± 165K 25.4M … 26.1M 0 ( 0%) 0% cache_misses 651K ± 20.1K 619K697K 0 ( 0%) 0% branch_misses 918K ± 7.44K 906K935K 0 ( 0%) 0% Benchmark 2 (348 runs): branch/​zig build -h mea­sure­ment mean ± σ min … max out­liers delta wal­l_­time 14.3ms ± 744us 13.2ms … 23.3ms 8 ( 2%) ⚡- 90.4% ± 0.4% peak_rss 78.5MB ± 562KB 77.1MB … 81.4MB 7 ( 2%) ⚡- 7.4% ± 0.2% cpu_­cy­cles 24.1M ± 821K 22.8M … 27.1M 3 ( 1%) ⚡- 95.9% ± 0.1% in­struc­tions 43.7M ± 23.8K 43.7M … 43.8M 56 (16%) ⚡- 95.6% ± 0.0% cache_ref­er­ences 1.46M ± 14.6K 1.40M … 1.50M 19 ( 5%) ⚡- 94.3% ± 0.1% cache_misses 142K ± 4.87K 127K157K 2 ( 1%) ⚡- 78.1% ± 0.4% branch_misses 126K ± 1.37K 120K129K 12 ( 3%) ⚡- 86.3% ± 0.1%

It’s dra­matic be­cause be­fore, build.zig logic was be­ing ex­e­cuted with each zig build com­mand, but now, the build sys­tem uses the cached, se­ri­al­ized con­fig­u­ra­tion in­stead.

Aside from per­for­mance, I ex­pect third-party tool­ing such as ZLS to ben­e­fit from con­sum­ing the se­ri­al­ized con­fig­u­ra­tion file rather than main­tain­ing a fork of the build run­ner.

This change­set heav­ily re­works the in­ter­nal mech­a­nism of the zig build sys­tem, how­ever, it is mostly non-break­ing from an API per­spec­tive, with the ex­cep­tions noted in the PR linked above.

For most peo­ple I’m guess­ing this is the main break­ing change they’ll hit:

if (b.args) |args| { run_cmd.ad­dArgs(args); }

⬇️

run_cmd.ad­dPassthru­Args();

This re­moves a ca­pa­bil­ity from build scripts since they can no longer ob­serve those ar­gu­ments. In ex­change, it means that when chang­ing those ar­gu­ments, build scripts no longer must be re­built from source.

If you’re some­one who wants to in­flu­ence the di­rec­tion of Zig, this is a good time to up­grade your pro­jects to the de­vel­op­ment ver­sion and try out these changes. We’ll be re­leas­ing 0.17.0 within a cou­ple weeks from now. However, if you don’t have time, and you find out that 0.17.0 broke your build, don’t worry, there will be plenty of op­por­tu­nity to get fixes in for the 0.17.1 tag as well.

April 08, 2026

Incremental com­pi­la­tion with LLVM

Author: Matthew Lugg

I’ve been spend­ing a bit of time work­ing on per­sonal pro­jects af­ter merg­ing my type res­o­lu­tion changes last month, but I did find the time re­cently to make some im­prove­ments to the LLVM code­gen back­end. This in­volved a few dif­fer­ent en­hance­ments with var­i­ous goals, but one nice user-fac­ing change was that I man­aged to get in­cre­men­tal com­pi­la­tion work­ing with the LLVM back­end.

Sadly this can’t do any­thing to speed up the dreaded LLVM Emit Object: that time is en­tirely down to LLVM. However, what in­cre­men­tal com­pi­la­tion does help with is min­i­miz­ing the time spent in the ac­tual Zig com­piler code, which means that if your code has com­pile er­rors (so LLVM Emit Object” will be skipped), you’ll usu­ally get those er­rors very quickly. (Of course, it does still give you a slight speed-up in suc­cess­ful builds too.)

This sup­port is avail­able in mas­ter branch builds right now, and will be in the 0.16.0 re­lease (which we’ll be tag­ging very soon).

For any­one who still has­n’t tried it, es­pe­cially if you’re us­ing Zig’s mas­ter branch, please do try out in­cre­men­tal com­pi­la­tion by pass­ing -fincremental –watch to zig build! The Zig core team have ben­e­fited from in­cre­men­tal com­pi­la­tion in our work­flows for a good year now, and we’re also hear­ing good things from users. The fea­ture is rel­a­tively sta­ble at this point, and peo­ple are of­ten sur­prised how much time they can save just by get­ting up-to-date com­pile er­rors in mil­lisec­onds rather than sec­onds.

I haven’t re­ally per­son­ally used in­cre­men­tal com­pi­la­tion with the LLVM back­end, but all of the in­cre­men­tal test cov­er­age in CI is now en­abled for the LLVM back­end, and I’ve had pos­i­tive feed­back from users, so it’s def­i­nitely worth giv­ing a shot. As al­ways, if you en­counter bugs in in­cre­men­tal com­pi­la­tion, please re­port them if you can!

Thank you, and I hope you find this use­ful :)

March 10, 2026

Type res­o­lu­tion re­design, with lan­guage changes to taste

Author: Matthew Lugg

Today, I merged a 30,000 line PR af­ter two (arguably three) months of work. The goal of this branch was to re­work the Zig com­pil­er’s in­ter­nal type res­o­lu­tion logic to a more log­i­cal and straight­for­ward de­sign. It’s a quite ex­cit­ing change for me per­son­ally, be­cause it al­lowed me to clean up a bunch of the com­piler guts, but it also has some nice user-fac­ing changes which you might be in­ter­ested in!

For one thing, the Zig com­piler is now lazier about an­a­lyz­ing the fields of types: if the type is never ini­tial­ized, then there’s no need for Zig to care what that type looks like”. This is im­por­tant when you have a type which dou­bles as a name­space, a com­mon pat­tern in mod­ern Zig. For in­stance, when us­ing std.Io.Writer, you don’t want the com­piler to also pull in a bunch of code in std.Io! Here’s a straight­for­ward ex­am­ple:

const Foo = struct { bad_­field: @compileError(“i am an evil field, mua­haha”), const some­thing = 123; }; comp­time { _ = Foo.something; // `Foo` only used as a name­space }

Previously, this code emit­ted a com­pile er­ror. Now, it com­piles just fine, be­cause Zig never ac­tu­ally looks at the @compileError call.

Another im­prove­ment we’ve made is in the dependency loop” ex­pe­ri­ence. Anyone who has en­coun­tered a de­pen­dency loop com­pile er­ror in Zig be­fore knows that the er­ror mes­sages for them are en­tirely un­help­ful—but that’s now changed! If you en­counter one (which is also a bit less likely now than it used to be), you’ll get a de­tailed er­ror mes­sage telling you ex­actly where the de­pen­dency loop comes from. Check it out:

const Foo = struct { in­ner: Bar }; const Bar = struct { x: u32 align(@alig­nOf(Foo)) }; comp­time { _ = @as(Foo, un­de­fined); }

$ zig build-obj re­pro.zig er­ror: de­pen­dency loop with length 2 re­pro.zig:1:29: note: type repro.Foo’ de­pends on type repro.Bar’ for field de­clared here const Foo = struct { in­ner: Bar }; ^~~ re­pro.zig:2:44: note: type repro.Bar’ de­pends on type repro.Foo’ for align­ment query here const Bar = struct { x: u32 align(@alig­nOf(Foo)) }; ^~~ note: elim­i­nate any one of these de­pen­den­cies to break the loop

Of course, de­pen­dency loops can get much more com­pli­cated than this, but in every case I’ve tested, the er­ror mes­sage has had enough in­for­ma­tion to eas­ily see what’s go­ing on.

Additionally, this PR made big im­prove­ments to the Zig com­pil­er’s incremental com­pi­la­tion” fea­ture. The short ver­sion is that it fixed a huge amount of known bugs, but in par­tic­u­lar, over-analysis” prob­lems (where an in­cre­men­tal up­date did more work than should be nec­es­sary, some­times by a big mar­gin) should fi­nally be all but elim­i­nated—mak­ing in­cre­men­tal com­pi­la­tion sig­nif­i­cantly faster in many cases! If you’ve not al­ready, con­sider try­ing out in­cre­men­tal com­pi­la­tion: it re­ally is a lovely de­vel­op­ment ex­pe­ri­ence. This is for sure the im­prove­ment which ex­cites me the most, and a large part of what mo­ti­vated this change to be­gin with.

There are a bunch more changes that come with this PR—dozens of bug­fixes, some small lan­guage changes (mostly fairly niche), and com­piler per­for­mance im­prove­ments. It’s far too much to list here, but if you’re in­ter­ested in read­ing more about it, you can take a look at the PR on Codeberg—and of course, if you en­counter any bugs, please do open an is­sue. Happy hack­ing!

February 13, 2026

io_ur­ing and Grand Central Dispatch std.Io im­ple­men­ta­tions landed

Author: Andrew Kelley

As we ap­proach the end of the 0.16.0 re­lease cy­cle, Jacob has been hard at work, bring­ing std.Io.Evented up to speed with all the lat­est API changes:

io_ur­ing im­ple­men­ta­tion

Grand Central Dispatch im­ple­men­ta­tion

Both of these are based on user­space stack switch­ing, some­times called fibers”, stackful corou­tines”, or green threads”.

They are now avail­able to tin­ker with, by con­struct­ing one’s ap­pli­ca­tion us­ing std.Io.Evented. They should be con­sid­ered ex­per­i­men­tal be­cause there is im­por­tant fol­lowup work to be done be­fore they can be used re­li­ably and ro­bustly:

bet­ter er­ror han­dling

re­move the log­ging

di­ag­nose the un­ex­pected per­for­mance degra­da­tion when us­ing IoMode.evented for the com­piler

a cou­ple func­tions still unim­ple­mented

more test cov­er­age is needed

builtin func­tion to tell you the max­i­mum stack size of a given func­tion to make these im­ple­men­ta­tions prac­ti­cal to use when over­com­mit is off.

With those caveats in mind, it seems we are in­deed reach­ing the Promised Land, where Zig code can have Io im­ple­men­ta­tions ef­fort­lessly swapped out:

const std = @import(“std”);

pub fn main(init: std.process.Init.Min­i­mal) !void { var de­bug_al­lo­ca­tor: std.heap.De­bugAl­lo­ca­tor(.{}) = .init; const gpa = de­bug_al­lo­ca­tor.al­lo­ca­tor();

var threaded: std.Io.Threaded = .init(gpa, .{ .argv0 = .init(init.args), .environ = init.en­v­i­ron, }); de­fer threaded.deinit(); const io = threaded.io();

re­turn app(io); }

fn app(io: std.Io) !void { try std.Io.File.std­out().writeStreamin­gAll(io, Hello, World!\n”); }

$ strace ./hello_threaded ex­ecve(”./​hel­lo_threaded”, [”./hello_threaded”], 0x7ffc1da88b20 /* 98 vars */) = 0 mmap(NULL, 262207, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f583f338000 arch_prctl(ARCH_SET_FS, 0x7f583f378018) = 0 prlim­it64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_­max=RLIM64_IN­FIN­ITY}) = 0 prlim­it64(0, RLIMIT_STACK, {rlim_cur=16384*1024, rlim_­max=RLIM64_IN­FIN­ITY}, NULL) = 0 sigalt­stack({ss_sp=0x7f583f338000, ss_flags=0, ss_­size=262144}, NULL) = 0 sched_getaffin­ity(0, 128, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31]) = 8 rt_sigac­tion(SI­GIO, {sa_handler=0x1019d90, sa_­mask=[], sa_flags=SA_RE­STORER, sa_re­storer=0x10328c0}, {sa_handler=SIG_DFL, sa_­mask=[], sa_flags=0}, 8) = 0 rt_sigac­tion(SIG­PIPE, {sa_handler=0x1019d90, sa_­mask=[], sa_flags=SA_RE­STORER, sa_re­storer=0x10328c0}, {sa_handler=SIG_DFL, sa_­mask=[], sa_flags=0}, 8) = 0 writev(1, [{iov_base=“Hello, World!\n”, iov_len=14}], 1Hello, World! ) = 14 rt_sigac­tion(SI­GIO, {sa_handler=SIG_DFL, sa_­mask=[], sa_flags=SA_RE­STORER, sa_re­storer=0x10328c0}, NULL, 8) = 0 rt_sigac­tion(SIG­PIPE, {sa_handler=SIG_DFL, sa_­mask=[], sa_flags=SA_RE­STORER, sa_re­storer=0x10328c0}, NULL, 8) = 0 ex­it_­group(0) = ? +++ ex­ited with 0 +++

Swapping out only the I/O im­ple­men­ta­tion:

const std = @import(“std”);

pub fn main(init: std.process.Init.Min­i­mal) !void { var de­bug_al­lo­ca­tor: std.heap.De­bugAl­lo­ca­tor(.{}) = .init; const gpa = de­bug_al­lo­ca­tor.al­lo­ca­tor();

var evented: std.Io.Evented = un­de­fined; try evented.init(gpa, .{ .argv0 = .init(init.args), .environ = init.en­v­i­ron, .backing_allocator_needs_mutex = false, }); de­fer evented.deinit(); const io = evented.io();

re­turn app(io); }

fn app(io: std.Io) !void { try std.Io.File.std­out().writeStreamin­gAll(io, Hello, World!\n”); }

ex­ecve(”./​hel­lo_evented”, [”./hello_evented”], 0x7fff368894f0 /* 98 vars */) = 0 mmap(NULL, 262215, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70a4c28000 arch_prctl(ARCH_SET_FS, 0x7f70a4c68020) = 0 prlim­it64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_­max=RLIM64_IN­FIN­ITY}) = 0 prlim­it64(0, RLIMIT_STACK, {rlim_cur=16384*1024, rlim_­max=RLIM64_IN­FIN­ITY}, NULL) = 0 sigalt­stack({ss_sp=0x7f70a4c28008, ss_flags=0, ss_­size=262144}, NULL) = 0 sched_getaffin­ity(0, 128, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31]) = 8 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70a4c27000 mmap(0x7f70a4c28000, 548864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70a4ba1000 io_ur­ing_setup(64, {flags=IORING_SETUP_COOP_TASKRUN|IORING_SETUP_SINGLE_ISSUER, sq_thread­_cpu=0, sq_thread­_i­dle=1000, sq_en­tries=64, cq_en­tries=128, fea­tures=IOR­ING_FEAT_S­IN­GLE_MMAP|IOR­ING_FEAT_N­ODROP|IOR­ING_FEAT_­SUB­MIT_STA­BLE|IOR­ING_FEAT_R­W_CUR_­POS|IOR­ING_FEAT_CUR_PER­SON­AL­ITY|IOR­ING_FEAT_­FAST_POLL|IOR­ING_FEAT_POL­L_32BITS|IOR­ING_FEAT_SQPOL­L_NON­FIXED|IOR­ING_FEAT_EX­T_ARG|IOR­ING_FEAT_­NA­TIVE_­WORK­ERS|IOR­ING_FEAT_RSR­C_­TAGS|IOR­ING_FEAT_C­QE_SKIP|IOR­ING_FEAT_LINKED_­FILE|IOR­ING_FEAT_REG_REG_RING|IOR­ING_FEAT_RECVSEND_BUN­DLE|IOR­ING_FEAT_MIN_­TIME­OUT|IOR­ING_FEAT_R­W_ATTR|IOR­ING_FEAT_NO_IOWAIT, sq_off={head=0, tail=4, ring_­mask=16, ring_en­tries=24, flags=36, dropped=32, ar­ray=2112, user_addr=0}, cq_off={head=8, tail=12, ring_­mask=20, ring_en­tries=28, over­flow=44, cqes=64, flags=40, user_addr=0}}) = 3 mmap(NULL, 2368, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, 3, 0) = 0x7f70a4ba0000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, 3, 0x10000000) = 0x7f70a4b9f000 io_ur­ing_en­ter(3, 1, 1, IORING_ENTER_GETEVENTS, NULL, 8Hello, World! ) = 1 io_ur­ing_en­ter(3, 1, 1, IORING_ENTER_GETEVENTS, NULL, 8) = 1 mun­map(0x7f70a4b9f000, 4096) = 0 mun­map(0x7f70a4ba0000, 2368) = 0 close(3) = 0 mun­map(0x7f70a4ba1000, 548864) = 0 ex­it_­group(0) = ? +++ ex­ited with 0 +++

Key point here be­ing that the app func­tion is iden­ti­cal be­tween those two snip­pets.

Moving be­yond Hello World, the Zig com­piler it­self works fine us­ing std.Io.Evented, both with io_ur­ing and with GCD, but as men­tioned above, there is a not-yet-di­ag­nosed per­for­mance degra­da­tion when do­ing so.

Happy hack­ing,

Andrew

February 06, 2026

Two Package Management Workflow Enhancements

Author: Andrew Kelley

Proposed new US funding rules: We can cancel any grant at any time

arstechnica.com

This is the end

Peer re­view now op­tional, po­lit­i­cal staff would screen grants for for­bid­den top­ics.

Russell Vought, di­rec­tor of the Office of Management and Budget (OMB), dur­ing a tele­vi­sion in­ter­view at the White House in Washington, DC, on Monday, July 7, 2025.

Credit:

Getty | Al Drago

Last August, the Trump ad­min­is­tra­tion is­sued an ex­ec­u­tive or­der in­tended to fun­da­men­tally al­ter how grant fund­ing is han­dled by the US gov­ern­ment. Under the sys­tem that had made the US a sci­en­tific su­per­power, peer re­view­ers rated the sci­en­tific qual­ity and fea­si­bil­ity of grant ap­pli­ca­tions, and sub­ject-mat­ter ex­perts within the fund­ing agen­cies used these rat­ings to de­ter­mine which grants got funded. Under the pro­posed rules, po­lit­i­cal ap­pointees would have the fi­nal say, and they were specif­i­cally in­structed not to routinely de­fer” to peer re­view­ers.

In the in­terim, the ad­min­is­tra­tion has lost many court cases be­cause it turns out that is­su­ing ex­ec­u­tive or­ders does­n’t cir­cum­vent le­gal re­quire­ments, and the or­ders can be va­cated if they lack strong jus­ti­fi­ca­tion. To avoid that same fate, the Office of Management and Budget (OMB) has de­cided to merge the ex­ec­u­tive or­der with other ad­min­is­tra­tion pri­or­i­ties and send it through the for­mal fed­eral rule­mak­ing process.

The re­sult is a hor­ror show for US sci­ence re­search. Not only is peer re­view made a sec­ondary con­sid­er­a­tion, but the new rules would al­low any fed­eral agency to can­cel any grant at any time based on the vague as­ser­tion that it is­n’t in the national in­ter­est.” The doc­u­ment would also ban any grants on a num­ber of cul­ture war top­ics, limit in­ter­na­tional col­lab­o­ra­tions, and block spend­ing on things like pub­lish­ing pa­pers and at­tend­ing con­fer­ences.

It is, in short, a recipe for how the gov­ern­ment can fin­ish the job of crip­pling American sci­ence.

Putting the OMB in charge

Previously, the rules gov­ern­ing grant­mak­ing were han­dled on an agency-by-agency ba­sis. The OMB is­sued over­all guid­ance, but the Department of Energy was­n’t ex­pected to fol­low the ex­act same pro­ce­dures that were de­vel­oped for the National Institutes of Health, to give two ex­am­ples. The new doc­u­ment is meant to change that sit­u­a­tion, turn­ing what had been guid­ance into rules. By pub­lish­ing them, the OMB is start­ing the for­mal rule­mak­ing process, which will then pro­ceed through pub­lic feed­back and a fi­nal rule pub­lished in the Federal Register.

The doc­u­ment it­self is an odd grab-bag of mi­cro­manag­ing grant processes, as­ser­tion of pres­i­den­tial power, and air­ing of cul­tural griev­ances. In many spots, it’s not even in­ter­nally con­sis­tent—it in­sists, for ex­am­ple, that Federal fi­nan­cial as­sis­tance must not dis­crim­i­nate on the ba­sis of the view­point,” and then turns around and com­plains that grants were of­ten used… to pro­mote a woke’ pol­icy agenda that did not re­flect the val­ues of the vast ma­jor­ity of the American pub­lic.”

Its lack of co­her­ence, how­ever, will not pre­vent it from caus­ing stag­ger­ing dam­age to the US sci­en­tific sys­tem.

For starters, it would for­mal­ize the dep­re­ca­tion of peer re­view as a fac­tor in de­cid­ing which grants to fund. Peer re­view re­mains ad­vi­sory and does not re­place agency dis­cre­tion,” the doc­u­ment states. That was al­ways tech­ni­cally true, as agen­cies like the NIH and National Science Foundation re­served the op­tion of fund­ing some lower-scor­ing grants if ex­perts within those agen­cies felt they had merit that the re­view­ers had over­looked. But those were con­sid­ered ex­cep­tions and were rel­a­tively rare.

Nearly every­thing about that will be chang­ing if the OMB has its way. The peo­ple mak­ing those sorts of de­ci­sions will no longer be ex­pert staff, but po­lit­i­cal ap­pointees. Scientific merit is meant to mat­ter less than vague stan­dards like in the na­tional in­ter­est.” And the doc­u­ment states bla­tantly that any grant pro­gram would need to be aligned with ad­min­is­tra­tion poli­cies and pri­or­i­ties.”

The ad­min­is­tra­tion has been on a los­ing streak in court cases in­volv­ing its wide­spread can­cel­la­tion of grants in 2025, in part be­cause the agen­cies do­ing the ter­mi­nat­ing did­n’t fol­low any for­mal pro­ce­dure. The new rules would for­mally de­clare that agen­cies don’t need a rea­son. All grant ap­provals would in­clude lan­guage warn­ing the re­cip­i­ent that they could be can­celed at any time if the agency pro­vid­ing the fund­ing de­cides that the grant is no longer in the na­tional in­ter­est.

Grants meet the cul­ture war

The doc­u­ment makes clear what sorts of things might be con­sid­ered ad­min­is­tra­tion pri­or­i­ties and na­tional in­ter­est—and they’re largely a war on woke. For ex­am­ple, the Trump ad­min­is­tra­tion can­celed PEPFAR, a pro­gram meant to limit the spread of HIV in Africa; it’s a step that is es­ti­mated to lead to hun­dreds of thou­sands of deaths. But to the OMB, that’s a good thing, be­cause the al­ter­na­tive was woke: Far-left ac­tivists hi­jacked the crit­i­cal work done by the US President’s Emergency Plan for AIDS Relief (PEPFAR), which was es­tab­lished to re­spond to the AIDS cri­sis in Africa. Due to waste­ful spend­ing, PEPFAR be­came a left-wing for­eign aid en­ti­tle­ment that at­tempted to pro­mote abor­tion and gen­der ide­ol­ogy.”

(Its cited source for that is an ed­i­to­r­ial from the Heritage Foundation, a far-right-wing think tank.)

While it de­mands viewpoint neu­tral” be­hav­ior from every­one re­ceiv­ing money, it has no is­sues with en­gag­ing in view­point dis­crim­i­na­tion it­self. For ex­am­ple, it out­right bans any fund­ing for theories of dis­parate-im­pact li­a­bil­ity,” the idea that ap­par­ently race-neu­tral rules might have im­pacts that dif­fer based on the race of the peo­ple in­volved. Also banned: any at­tempts to com­pen­sate for the his­toric dis­crim­i­na­tion that has kept women and mi­nori­ties from hav­ing equal op­por­tu­ni­ties in so­ci­ety. That’s con­sid­ered DEI, and thus for­bid­den.

Also out: fund­ing for what it terms gender ide­ol­ogy,” which it de­fines as an ef­fort to deny the bi­o­log­i­cal re­al­ity of sex or the sex bi­nary in hu­mans.” Apparently, study­ing hu­man chro­mo­so­mal dis­or­ders, which can re­sult in un­usual com­bi­na­tions of X and Y chro­mo­somes, is no longer wel­come in the US. Ending gov­ern­ment-spon­sored pro­mo­tion of di­vi­sive gen­der ide­ol­ogy is crit­i­cal to sci­en­tific in­quiry, pub­lic safety, and trust in gov­ern­ment,” the OMB as­serts, based on no ev­i­dence what­so­ever.

There’s also a po­lit­i­cal lit­mus test for fund­ing that harkens back to the McCarthy era, when those with un-American” ideas were os­tra­cized. OMB pro­poses a new pro­vi­sion that agen­cies may con­sider an ap­pli­can­t’s af­fil­i­a­tions with or­ga­ni­za­tions en­gaged in ac­tiv­i­ties that vi­o­late Federal law, un­der­mine pub­lic safety or na­tional se­cu­rity, or ad­vo­cate for the over­throw of the United States Government,” the doc­u­ment notes.

Good luck col­lab­o­rat­ing or pub­lish­ing

These would all be prob­lem­atic on their own, but the OMB is just warm­ing up. If you had for­eign col­lab­o­ra­tors, you might be out of luck. The doc­u­ment sug­gests an out­right ban on fed­eral fund­ing of col­lab­o­ra­tions in­volv­ing Chinese re­searchers. But even our al­lies are ap­par­ently meant to be col­lab­o­rated with as a last re­sort. When de­sign­ing re­search and de­vel­op­ment pro­grams, and eval­u­at­ing ap­pli­ca­tions,” the OMB states, Federal agen­cies must ap­ply a do­mes­tic-first frame­work, un­der which in­ter­na­tional el­e­ments may be in­cluded only if the Federal agency de­ter­mines that such el­e­ments are jus­ti­fied, con­sis­tent with pro­gram ob­jec­tives, and in the na­tional in­ter­est of the United States.”

(There are some in­di­ca­tions that agen­cies started ap­ply­ing this stan­dard even be­fore the OMB doc­u­ment was pub­lished.)

Research jour­nals gen­er­ally re­quire sci­en­tists to pay for the priv­i­lege of pub­lish­ing there. But if the OMB gets its way, mak­ing these pay­ments from a grant will be for­bid­den un­less you get ap­proval from the fund­ing agency: OMB is re­vis­ing the sec­tion to make pub­li­ca­tion costs un­al­low­able un­less such costs are ex­pressly re­quired by statute or ap­proved in ad­vance by the Federal agency on a case-by-case ba­sis.” The same ap­proval will be needed to pay for travel to a con­fer­ence.

Amazingly, OMB is cre­at­ing this mas­sive ad­min­is­tra­tive has­sle in a doc­u­ment that claims it is reducing re­cip­i­ent bur­den.” Its jus­ti­fi­ca­tion for that claim is that it’s elim­i­nat­ing any DEI re­quire­ments.

If you wanted to crip­ple sci­ence re­search and were dis­ap­pointed that Congress con­tin­ued to fund it, this is the sort of doc­u­ment you would pro­duce. It pulls US sci­en­tists out of the in­ter­na­tional com­mu­nity, leaves them un­able to com­mu­ni­cate their find­ings and meet with other sci­en­tists, and leaves grant ap­pli­ca­tions sub­ject to cul­ture war lit­mus tests and the whims of non-ex­pert bu­reau­crats. Those lucky enough to see a grant funded will live in con­stant fear that it could be can­celed when­ever the winds change in Washington, DC.

Public com­ment on the pro­posed rule is now open.

John is Ars Technica’s sci­ence ed­i­tor. He has a Bachelor of Arts in Biochemistry from Columbia University, and a Ph.D. in Molecular and Cell Biology from the University of California, Berkeley. When phys­i­cally sep­a­rated from his key­board, he tends to seek out a bi­cy­cle, or a scenic lo­ca­tion for com­muning with his hik­ing boots.

189 Comments

Investigation: Hallucinations in Ernst & Young Report on Loyalty Fraud | GPTZero

gptzero.me

GPTZeroInvestigations·

Exclusive

Chasing the Hallucinations

Ernst & Young (EY) Canada pub­lished a cy­ber­se­cu­rity re­port on loy­alty pro­gram safe­guards. We chased down every ci­ta­tion. Most were hal­lu­ci­nated.

View Investigation

MAY 14, 2026

Earlier this year, an en­gi­neer at GPTZero coined the term vibe cit­ing” to de­scribe the ac­ci­den­tal cre­ation of fake ref­er­ences via LLM hal­lu­ci­na­tions. It turns out that the fric­tion of cre­at­ing and check­ing ci­ta­tions is lead­ing many re­searchers, con­sul­tants, lawyers, and pub­lic of­fi­cials to em­brace the vibe (if you know what we mean).

Among the con­verts are the au­thors of a 2025 Ernst & Young re­port ti­tled Points of Attack: Uncovering Cyber Threats and Fraud in Loyalty Systems. This re­port, stuffed with fake ci­ta­tions and in­ac­cu­rate claims, is sur­fac­ing in news­pa­pers, blog posts, and AI search overviews, poi­son­ing the data that both hu­man re­searchers and AI agents rely on.

GPTZero be­gan tar­get­ing vibe ci­ta­tions with our Hallucination Check tool in 2025, which we used to fur­ther in­ves­ti­ga­tions into a gov­ern­ment pub­li­ca­tion, two dif­fer­ent Deloitte re­ports, and pres­ti­gious ma­chine learn­ing / ar­ti­fi­cial in­tel­li­gence con­fer­ences like NeurIPS and ICLR. Over the past few months we’ve set up an au­to­mated pipeline to search for vibe ci­ta­tions by find­ing and scan­ning pub­lic re­ports from ma­jor con­sult­ing firms. What we’ve found sug­gests that the vibe cit­ing epi­demic is al­ready en­demic, even among the ma­jor play­ers.

Instead of re­leas­ing our re­sults all at once, we’re go­ing to fo­cus on one re­port at a time. This ap­proach both pre­vents in­di­vid­ual ex­am­ples be­ing over­looked and al­lows us to il­lus­trate the neg­a­tive im­pacts of vibe cit­ing on re­search qual­ity and pub­lic trust.

On the menu: Ernst & Young (EY)

Ernst & Young is one of the big four” global con­sult­ing firms, pro­vid­ing ac­count­ing and con­sult­ing ser­vices to gov­ern­ments and pri­vate en­ti­ties from 150 of­fices around the world. The Canadian mem­ber firm (EY Canada) pro­vides mil­lions of dol­lars of ser­vices to the Canadian gov­ern­ment an­nu­ally.

In late 2025, EY Canada pub­lished a 44-page re­port on cy­ber se­cu­rity ti­tled Points of Attack: Uncovering Cyber Threats and Fraud in Loyalty Systems. While cred­ited to three em­ploy­ees (two part­ners and one se­nior man­ager), the doc­u­ment is a col­lage of vibe ci­ta­tions, mis­at­tri­bu­tions, fake sta­tis­tics, and AI-written text.

Why the Vibes Are Bad

EY Canada’s re­port does­n’t use foot­notes or nor­mal aca­d­e­mic ci­ta­tions. Instead, it ref­er­ences sources di­rectly in the text and/​or in­cludes them in a re­sources table (p. 41 – 43). This table pro­vides a source ti­tle, de­scrip­tion, and URL for all sources, as well as the pub­lisher and date in cer­tain cases. Almost all of the URLs are bro­ken or fake, and more than half of the ti­tles don’t cor­re­spond to real sources.

GPTZero uses a very spe­cific de­f­i­n­i­tion of be­cause of the po­ten­tial rep­u­ta­tional cost (to both us and the re­port’s au­thors) of false pos­i­tives. One of our team mem­bers man­u­ally ver­i­fied Hallucination Check’s re­sults to en­sure their ac­cu­racy.

During our pre­vi­ous analy­sis of aca­d­e­mic con­fer­ence sub­mis­sions, we found that many au­thors pri­mar­ily used AI to gen­er­ate and for­mat their ref­er­ences, re­sult­ing in pa­pers with vibed ci­ta­tions but low AI text scores over­all.

However, it’s hard to find hu­man fin­ger­prints in Points of Attack — harder, even, than find­ing a hu­man-writ­ten LinkedIn post. Not only does the text scan as AI-generated, it’s rid­dled with com­mon LLM er­rors like fake sta­tis­tics, mis­at­tri­bu­tions, and in­ter­nal con­tra­dic­tions.

1/4

EY Report, Page 4

A bold claim in the ex­ec­u­tive sum­mary

In the re­port’s Executive Summary, its au­thors claim the global loy­alty points mar­ket is $200 bil­lion, and that 30 – 50% of those points go un­used.

EY Report, Page 42

A fake Forbes ci­ta­tion

The ci­ta­tion we just looked at sup­ports the au­thor’s orig­i­nal claim of a $200 bil­lion global mar­ket.

EY Report, Page 10

A con­tra­dic­tory claim

Yet on page 10, the $200 bil­lion fig­ure is now the es­ti­mate of unre­deemed loy­alty points, not the col­lec­tive value of all points glob­ally. Since the au­thors have al­ready claimed that up to 50% of points are unre­deemed, this new sta­tis­tic re­quires a global mar­ket value of at least $400 bil­lion.

EY Report, Page 43

A sec­ond fab­ri­cated ci­ta­tion: McKinsey

A few rows down, a fab­ri­cated McKinsey & Company re­port pro­vides ev­i­dence for the lat­ter claim — $200 bil­lion as the value of unre­deemed points glob­ally. Two in­vented ci­ta­tions, two in­com­pat­i­ble num­bers.

We chased the source of this McKinsey ci­ta­tion back to an ob­scure fin­tech

blog­post

by Financial IT, which was pub­lished six months ear­lier.

1/2

Financial IT, Page 1

A sim­i­lar claim

Six months be­fore EYs re­port, a blog post on the ob­scure U.K. fin­tech mag­a­zine Financial IT claims that more than $200 bil­lion in points sit idle each year.” The lan­guage is nearly iden­ti­cal to the EY re­port.

Financial IT, Page 3

The vibes are iden­ti­cal

The blog’s sources sec­tion cites McKinsey & Company: Loyalty Economics Report (2022)” — a re­port that does not ex­ist. This fab­ri­cated ci­ta­tion ap­pears ver­ba­tim in the EY re­port’s ref­er­ence table, laun­der­ing an in­vented source from a low-qual­ity blog into a Big Four pub­li­ca­tion.

Some of the re­port’s most du­bi­ous claims weren’t even cited at all.

1/2

EY Report, Page 6

The source is at­trib­uted to Paystone

On page 6, the au­thors claim that 72% of cus­tomer loy­alty pro­grams have re­ported theft or fraud. This fact is at­trib­uted to a 2019 post by the Canadian pay­ment proces­sor Paystone.

EY Report, Page 11

Actually, the source is Forter

However, on page 11, the same sta­tis­tic is at­trib­uted to a dif­fer­ent source — the un­usu­ally-named NRF 2020 sum­mary” pub­lished by the dig­i­tal fraud pre­ven­tion com­pany Forter. Neither of these sources are in­cluded in the re­port’s ref­er­ence table. In fact, while the sta­tis­tic is ref­er­enced on both the Paystone and Forter pages, the orig­i­nal source seems to be a 2017 sur­vey by Ipsos.

Contradicting ref­er­ences, low-qual­ity sources, and out-of-date sta­tis­tics are all in­di­ca­tions of AI slop.

1/2

EY Report, Page 6

The 89% claim

On page 6, the au­thors claim that loy­alty pro­gram fraud at­tacks have in­creased 89% since 2019.

EY Report, Page 11

A spe­cific source for this claim

Yet on page 11, this 89% in­crease is lim­ited to a sin­gle year, 2018 to 2019, and the sta­tis­tic is at­trib­uted to a spe­cific source: the Forter Fraud Attack Index. Surprisingly, this source both ex­ists and par­tially con­firms the sec­ond ver­sion of the claim. However, like many of the sources used in the EY re­port, it is sub­stan­tially out of date. Poorly para­phrased sta­tis­tics are also a sign of AI slop.

Why Vibes Matter

It’s dif­fi­cult to mea­sure the pub­lic im­pact of EYs re­port. Points of Attack seems to have made few waves in Canada; how­ever, it was re­cently ref­er­enced in a Canberra Times ar­ti­cle that was syn­di­cated to more than 60 news­pa­pers across Australia. It may also have cir­cu­lated through client brief­ings, in­ter­nal decks, and other pro­pri­etary me­dia that aren’t in the pub­lic do­main. Yet vibe ci­ta­tions don’t just de­ceive read­ers or cor­po­rate au­di­ences — they also have an­other, more in­sid­i­ous, im­pact.

Publishing a re­port on­line is es­sen­tially a form of data in­jec­tion into the pool of knowl­edge that is the in­ter­net. When the re­port in­cludes fake in­for­ma­tion (either vibed ci­ta­tions or false claims) it can poison the well” by mis­lead­ing fu­ture re­searchers, es­pe­cially if the re­port is pub­lished by a well-known con­sult­ing firm and hosted on a high-traf­fic web­site.

This risk has been ag­gra­vated by the emer­gence of AI deep re­search” tools which rely on dif­fer­ent sig­nals than hu­mans when choos­ing sources and are there­fore more vul­ner­a­ble to data poi­son­ing.

Conclusion

GPTZero is Chasing the Vibe (Citations)

Our re­search over the past few months proves that vibe cit­ing is a clear and pre­sent dan­ger to re­searchers, aca­d­e­mics, con­sul­tants, and (frankly) any­one who drinks from the dig­i­tal pool by search­ing the web. Our Hallucination Check tool is our an­swer to this threat: a way to iden­tify vibe ci­ta­tions and hal­lu­ci­na­tions with­out man­u­ally check­ing every ci­ta­tion. It is al­ready be­ing used to screen sub­mis­sions by elite aca­d­e­mic con­fer­ences like IJCAI, ICLR, and ICSE.

Now, more than ever, it’s crazy to ac­cept ci­ta­tions on faith — even those from a rep­utable source like Ernst & Young.

Try GPTZero’s Hallucination Check for your­self, or reach out to GPTZero’s team.

Written by Om Ogale

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.

Visit pancik.com for more.