Мирослава Кацарова е сред най-запомнящите се гласове в българския джаз през последните две десетилетия. Умно, елегантно и с безупречна дикция тя пее на няколко езика, сред които български, френски и португалски, а предаванията ѝ по Радио Jazz FMSingin’n’swingin и Desafinado информират и са предизвикателство за истински претенциозните меломани.
Мира Кацарова и нейната компания „Блу Ем“ са лицето на „Пловдив Джаз Фест“, на чиято сцена ежегодно музицират световни артисти – икони в импровизационната музика. Да формира вкус и да създава жива, дишаща общност е сред талантите ѝ; това обяснява защо за концертите на „Пловдив Джаз Фест“ се стича публика от цялата страна.
И макар че невинаги е живяла в Пловдив, за Мирослава Кацарова градът е един от важните топоси в личната ѝ география.
Преживявам този град като отражение на моите спомени от детските години. Днешното пренаселване на градовете е враждебно, губи се очарованието на тази романтична провинция, в която аз съм израснала. Къщите в Пловдив бяха с дворове, бяха естествена градина със смокинови и нарови дръвчета, с асми, които проектираха дантели върху камъните. Моята баба гледаше рози и хортензии. Помня ароматите им, както и мириса на камък и дърво. А Старият град тогава беше фокус, хората отиваха там, за да се разхождат.
Нейният дядо е футболната легенда Никола Щерев – Старика, един от най-важните играчи във футболния клуб „Ботев“ Пловдив през 20-те и 30-те години на миналия век. Той създава първата детско-юношеска футболна школа в България, внасяйки от Виена модел за изграждането на младите спортисти в екип. Съвместявал е тази мисия с кариерата си на активен футболист и капитан на отбора. Никола Щерев се е интересувал от олимпийски спортове и е водил кореспонденция с бащата на съвременните олимпийски игри Пиер дьо Кубертен. Притежавал работилница, произвеждаща ски, а там, където днес са Пеещите фонтани, е имало естествено езеро. През зимата, когато замръзвало, то се превръщало в пързалка, неотменна част от градската култура. Никола Щерев откривал сезона – на кънки и с грамофона, който донесъл на съпругата си Мария от Париж.
Имали са много красива любов с баба, която е била с 13 години по-млада от него.
Никола е бил и планинар, запален турист, който през зимата е търсил възможност със специални ски да проправя пътеки извън пистите, стигал е по този начин от Пловдив до Пампорово.
Дъщеря му Снежанка, майката на Мира Кацарова, от пет-шестгодишна се е спускала красиво и стремглаво по известната днес писта „Стената“. Семейната легенда твърди, че заради близкото познанство на Никола Щерев с влиятелни генерали връх Снежанка е кръстен на „най-малката скиорка“. А разбира се, и заради факта, че по онова време е бил вечно бял.
Майка ми до много късни години караше ски в този елегантен стил, който вече не се вижда. Аз също бях научена на него – той е фин, без агресия, но по пистите вече има съвсем други отношения.
Говорим за отминалите кодове на старата градска култура, но нейните производни са свързани със съвременността. Тази чувствителност към вкусовете, ароматите, утопичното е силно осезаема в текстовете, които Мира Кацарова сама пише за авторските си песни.
Песните, които се опитвам да изпълнявам, са свързани с пределите между световете. И аз внимателно навлизам в тази реалност, опитвам се да я проучвам издълбоко. Не искам да изляза и да пея като шампион, не харесвам този вид отношение към музиката. Когато пея, искам това да е една човешка история – с цялата ми уязвимост, съмнения, несигурност и страхове. В музиката ти се откриваш като свободен човек, без предразсъдъци и съображения с дребното. С музиката можеш да кажеш неща, които са неназовими, затова аз възприемам тези песни като сънища, които не си спомняш докрай.
Философските търсения на Мирослава Кацарова са в диалог с идеите, стабилизирани от богословското ѝ образование. Преди това в Езиковата гимназия тя учи френски език и е пленена от символистите, от декадентския чар на Рембо и Бодлер, а и от екзистенциалистите – чете Сартр, Камю, търсейки себе си.
Бях истински Боготърсач. Борих се с идеите на екзистенциализма, че смисъл няма, че сме като Сизиф. И когато прочетох Ортодокса на Павел Евдокимов, осъзнах, че много дълбоко споделям философията на православното християнство, но не по начина, по който е профанизирана тази дълбока идея. Разбрах, че съм религиозен човек и че откривам човешкото във всичките му проявления като сила, тъй като православното християнство ни спасява от онзи плашещ, непристъпен Бог. Така стигнах и до изкуството като смисъл на човешките отношения. За мен това са музиката, литературата, живописта, киното, театърът – те са моят смисъл. Те са начинът тихо, ненатрапливо да пренареждаме този свят.
Успоредно с всичко, което преживява и търси, Мирослава Кацарова пее.
Открих джаза в гимназията през песните на Били Холидей, макар че вкъщи майка и татко слушаха инструментален джаз. После Майлс Дейвис и Джон Колтрейн, после Чик Кърия, Хърби Хенкок, Кийт Джарет, Йелоу Джакетс, Ян Гарбарек – този свят ме завладя лавинообразно. Благодарение на тях усетих абстракцията. Много ходех по джаз срещи и поисках да пея, но нямаше кой да те научи тогава как да импровизираш с гласа си. Единствената голяма джаз певица по онова време беше Йълдъз Ибрахимова; Камелия Тодорова не беше в България през 80-те. И аз се пуснах на един джемсешън, знаех няколко джаз стандарта от слушане, знаех блус схемата пак от слушане, без да съм наясно, че това е блус схема. Импровизирах. Аналитична съм и това много ми помогна, но цялата работа беше един огромен късмет, попаднах точно на хората. Чуха ме Рупето, Веселин Веселинов – Еко, Васил Петров, по-късно Христо Йоцов. Аз не наричах себе си джаз певица, казвах, че пея джаз, без да ползвам дефиниции.
В изкуството обаче късметът на начинаещия е само първата стъпка за възможната реализация. Професионалистите в една сфера виждат таланта, но оценяват вътрешната подготвеност на артиста да продължи личните си търсения. Постепенно Мирослава Кацарова намира своята сцена, канена е да прави гигове, следва концертиране, създаване на албуми, джазът се превръща в път.
Работата ѝ с публики и желанието ѝ да променя средата естествено я отвеждат до идеята за истински форум, свързан с импровизационната музика. През 2015 г. стартира „Пловдив Джаз Фест“ – Мира в щастлива колаборация със съпруга си Танко Кацаров използва всичките си лични контакти за да осигури допълнителни спонсорства.
Тогава чух новия албум на Кърт Елинг, в който има една песен по текст на Джеймс Джойс – Where love is, – и си рекох: хайде да доведем тук артисти, които ни вълнуват до сълзи. И понеже имам луд мъж, той се обади на агентката на Кърт Елинг. Оказа се, че има свободна дата на 2 ноември. Така започна всичко.
Оттогава тя програмира фестивала, а българските меломани имат шанса да чуят на живо иконични артисти, като в последните години е добавено и лятно издание под открито небе.
По време на „Пловдив Джаз Фест“ като съпътстваща програма млади изпълнители получават възможност за творчески работилници и джемсешъни, както и за близък, неформален контакт със знаменитостите. Ежегодно в един от фестивалните дни тематично е подбрана и литературна среща.
Как обаче става селекцията? Още повече когато се налага програмата да бъде синхронизирана с тежкия график на световен артист, обичайно запълнен за няколко години напред. Влиятелните имена в музиката, както и във всяко изкуство внимателно подбират сцените си и тук негласно, но императивно важи репутацията. Изграждането на доверие между екипите на изпълнителя и фестивала е многогодишен процес, в който няма място за грешки.
Сложно е на много нива, но аз тръгвам винаги от мечтата. Слушам страшно много музика и мога да кажа, че интуицията на един професионалист се отглежда. Ако не залагаш на суетна показност, а на реален интерес – а при мен е така, аз не мога да живея без тази музика, – виждаш, че сетивата ти се изострят за тенденциите. После започва другото: дали можем да си ги разрешим финансово. Ако е на ръба, ние го правим. Рисково. За световните имена се налага да съобразим и дали артистът е на турне в Европа – обратното е убийствено за бюджета на един фестивал.
За да се случи магията на сцената, договорите имат технически и хоспиталити изисквания, които – заедно с обезпечаване на финансирането – изискват целогодишен труд.
Тази година на 6, 7 и 8 ноември в Пловдив ще концертират Арън Паркс, Шай Маестро, Елина Дуни, Ема Смит, Дженк Ердоган, а първият ден е отделен за специален проект, посветен на 100-годишнината на Майлс Дейвис по идея на Росен Захариев – Роко – ще участват Стив Хамилтън (пиано), Васил Хаджигрудев (контрабас), Борислав Петров (барабани) и двамата гост-музиканти Петър Момчев (тенор саксофон) и бийтбоксърът Александър Деянов – Скилър.
Какво според Мирослава Кацарова е важно на сцената? Самоконтрол, концентрация, за да следиш всеки тон на колегите си, и борба с егото.
Имам свободата да избирам с кого да работя, и съм благодарна, че това са музиканти, които са много талантливи, можещи и освен че имат любопитство към света, те са откриватели и приключенци. Всичко това ги отличава от занаятчиите. Обменяме идеи и по този начин растем.
Хората, които тихо и кротко променят средата, формират общности и задават посоки, в които има смисъл да тръгнем заедно. Тук ви срещаме с тях. Това са „Тези хора“.
„Ергенът“ идва всяка година точно като сезонните алергии и с приблизително същия ефект върху организма. Напролет сервират рози и романтични сълзи по поръчка, наесен пък скандали, за които човек се срамува, че изобщо ги знае. После социалните мрежи избухват с гневни коментари: „Ужас, това повече няма да го гледам.“ До следващия епизод.
С годините зрителите са приели неписан договор с продукцията: едните ще прекрачват грубо границите, а другите ще сядат пред екрана. Това е най-странното постижение на формата.
Погазването на етични норми се е превърнало в зрителско очакване, което от своя страна служи на продуцентите за алиби.
Само че тазгодишният „есенен Ерген“ поставя въпроса докъде може да стигне това алиби. Има основателни причини да не го подминаваме с умора. Защото в ефир участничка говори за самоубийство, друга преживява криза, наложила лекарска намеса, а заплахите за физическа саморазправа стават все по-брутални.
Когато психическата криза стане телевизионен сюжет
В епизодите от 29 и 30 септември 2026 г. една участничка е отчаяна, защото е принудена да спи в стая с петима мъже без нейно съгласие. Тя има порив да напусне предаването, а след това изрича желание за самоубийство. Участничката споменава и начина. По време на сцената не се появява информация къде зрителите, които преживяват суицидна криза, могат да потърсят помощ. Действителното психическо състояние на участничката не може да се установи от телевизионните кадри. Остава неясно дали е просто фраза, или наистина симптом на крайно отчаяние. Но само по себе си изказването е достатъчно тревожно, за да постави въпроса за отговорността на продукцията.
Световната здравна организация има ясни професионални препоръки за медийното представяне на суицидни мисли и поведение. Сред тях са избягването на сензацията, ненужното повторение и конкретизирането на метода за самоубийство, както и предоставянето на информация за достъпна помощ. Изследвания показват, че начинът на медийно представяне може да увеличи рисковете за уязвими хора или обратно – да има предпазващо въздействие.
Тези препоръки сами по себе си не представляват законова забрана. Те съществуват именно за ситуации, в които редакционното решение може да има последствия отвъд непосредствения зрителски интерес. Защо информацията за помощ не е намерила място в монтажното решение?
Няколко дни по-късно друга участничка преживява тежка криза пред камерите. Състоянието ѝ се влошава, тя крещи неистово, че умира. Впоследствие има лекарски екип на терен. Медицинска помощ очевидно е потърсена. Това е важно и трябва да бъде отбелязано. Но остава другият въпрос:
защо момент на тежка криза се превръща в публично зрелище? В една телевизионна продукция камерите могат да бъдат изключени.
Кадрите могат да останат неизлъчени. И в двата случая отговорността не може да бъде прехвърлена върху участниците.
„Ще ти разбия главата“, или речникът на последния сезон
Психическите кризи далеч не са единствената тревожна особеност. Вербалната агресия между участниците твърде често придобива характер на открита заплаха за физическа саморазправа. Особено тревожна е конкретността на заплахите, които се отправят в ефир. Това не са абстрактни обиди, а подробно описани сценарии на насилие: разбити глави, влачене по пода, насилствено подстригване, затваряне в багажници.
Няма нужда да гадаем дали заплахите биха били изпълнени. Достатъчно е, че са произнесени и излъчени. Разбира се, в риалити телевизията има жанрово очакване хората да се карат и напрежението да ексалира. Заплахата за физическа саморазправа обаче е нещо друго: тя е насочена към тялото на конкретен човек и законът я третира като престъпление, когато може да събуди основателен страх.
Още по-показателно е, че регулаторът вече е изразявал опасения за съдържанието на формата. През септември 2025 г. Съветът за електронни медии (СЕМ) установява нарушения на Закона за радиото и телевизията в „Ергенът: Любов в рая“. В по-късни документи на СЕМ се разглеждат проблемни сцени, включително вербална агресия и расистки коментари. Въпросът за границите на допустимото следователно е поставян и преди. Сходни прояви обаче продължават да намират място в ефир.
Особено показателни са конфликтите, в които личните нападки прерастват в ксенофобия.
Няколко от участничките многократно приписват на украинката в предаването негативни качества, които обясняват с произхода ѝ. Звучат и обобщения, че молдовките и украинките са „ескорти в Дубай“, а „наглите“ украинки трябва да знаят мястото си и да „бъдат по-ниски от тревата“.
Зад обидните стереотипи прозира една по-дълбока претенция за мнима власт: правото да определяш мястото на другия. На един човек се внушава, че произходът и съдбата на бежанец задължава да бъдеш по-тих, смирен, благодарен за мястото, което е „позволено“ да заемеш. Сякаш равноправието е жест на благоволение, който едни могат да окажат, а други трябва да заслужат. Случайността на месторождението става основание за морална присъда, а географията получава правото да определя характера.
Европа познава добре тази логика от миналото, когато нацизмът я превърна в идеология. В телевизионния рай тя се появява в умален, привидно безобиден вид, като поредна реплика с коктейл в ръка край басейна. При това стереотипът за „ескортите“ не е никак невинен, защото омаловажава реалната експлоатация, на която жени от всички страни от бившия Източен блок (вкл. България) нерядко стават жертва.
От персонаж към карикатура
Hurt people hurt people, гласи една популярна формула: наранените хора нараняват. Не знаем какво стои зад нечии крясъци, нито какви лични истории или ескалации, предизвикани от изолирания живот в имението, остават извън кадър. Но когато сезон след сезон се моделират все по-трайни и еднотипни фигури, трудно можем да говорим за непреднамереност на продуцентите.
Парите например отново заемат централно място в представите за любов и партньорство. Една от участничките се самоопределя като „жена трофей“ и почти във всеки епизод подробно излага финансовите си очаквания. Друга, с театрално преувеличен руски акцент, предлага семинари, учудващо дублиращи вече позната „търговска марка“ за такива обучения.
В това саморазбиране има елемент на еманципация. Жените открито заявяват желанията си, определят условията на партньорството и не се извиняват за материалните си претенции. В крайна сметка свободата предполага и правото на личен избор, който не всекиму се харесва или се вписва в дадени очаквания. Странно е обаче, когато независимостта изисква зависимост от платежоспособността на партньора.
Към тази галерия се прибавя и друг добре разпознаваем телевизионен образ: жената, която крещи и обижда вулгарно. Така между „жената трофей“ и „агресивната, вечно готова за конфликт жена“ (а.к.а. „женска злоба“, както се нарича във форуми и синхрони) се наслага все по-траен образ нажената като карикатура.
Тук се проявява и един от най-парадоксалните ефекти на икономиката на вниманието. Публиката може да осъжда видяното и едновременно с това да допринася за разпространението му. Всеки скандален откъс получава нов живот като повод за спор в социалните мрежи. „Ергенът“ продава карикатури. Социалните мрежи ги превръщат в доказателство, че карикатурата е реалност. Голяма част от заплахите от една участничка към друга са наречени „заслужено наказание“.
Обществото получава тревожен речник за отношенията между хората и интернализираната мизогиния.
Няма основание да приписваме на телевизионно предаване отговорност за насилието в обществото ни. Дългосрочно погледнато обаче, екранът може да притъпи ухото към него. Първата агресия смущава, втората звучи познато, а десетата вече е повод за забава. В един момент зрителите не се питат защо някой унижава друг човек пред милиони зрители, защо някой има тежка криза в екранно време, а изпитват тръпка какво ще се случи в следващия епизод.
Най-лесният отговор на тази критика е, че никой не е принуден да гледа. Публиката има избор. Участниците са пълнолетни и доброволно са се съгласили да бъдат снимани. Всичко това е вярно. И нищо от него не отменя редакционната отговорност. Съгласието за участие в телевизионен формат не прави всяко последващо решение на продукцията етично. Телевизионният оператор има власт върху кастинга, условията на снимане, монтажа и разпространението. Тази власт предполага и отговорност. И тук никой не очаква от риалити предаване да преподава уроци по здравословни отношения. Но
от една национална телевизия можем да очакваме поне да различава човешкото страдание от телевизионната атракция.
Защото това, с което сме свикнали, невинаги е това, което трябва да приемаме. И защото най-опасната граница не е тази, която телевизията прекрачва пред очите ни. А тази, която постепенно преставаме да забелязваме.
Темата за психичното здраве е важна за нас. Ако вие или ваш близък минава през трудности и има нужда от психологическа подкрепа в криза, може да се свържете със спешните служби на номер 112 или да намерите специализирани линии за подкрепа за България в сайта Find A Helpline.
Artificial intelligence (AI) coding assistants have changed how fast we can ship. They have not changed how mobile users experience a crash. That gap is the pressure every mobile stability program now operates under.
The Grab superapp, which millions of users across Southeast Asia use to book rides, order food, and more, operates at a large scale. On Android alone, it spans millions of lines of code, with many engineers shipping code into every release on a weekly release cycle. Maintaining app stability is not just a technical goal; it is a product commitment to those users. With the rise of AI coding assistance, the volume of change in every release has grown, and so has the number of ways a single change can break something in an already large codebase.
At this scale, crashes leaking into production are an ongoing risk. A high volume of merge requests lands every week across many product teams, many shipping features behind flags that are switched on independently of releases. Any one of those changes can introduce a crash. Most of the time, the stack trace points straight to the responsible change and team. The hard cases are the exceptions: crashes without a usable stack trace, such as native crashes without debug symbols, where finding the cause means cross-referencing release timelines, flag rollouts, and session metadata.
The cost of a crash is also steeper on mobile than on the web. A web fix can go live in minutes; a mobile crash that ships stays on users’ devices. With more than 100 million downloads on Google Play as of October 2026, not every user has auto-update enabled, and until a force update reaches them, some will run a broken version for months. Meanwhile, the crash degrades their experience, drags down the crash-free session rate, and can hurt the app’s ranking on Google Play. If it is severe enough to need a hotfix, the team also has to prepare an out-of-cycle build, pulling time away from planned work.
We keep the Grab superapp stable with a set of layered practices. Data points and tooling examples come from Android. The Grab iOS app follows the same strategy with platform-equivalent tooling (SwiftLint in place of Android Lint), and both apps share one release pipeline for Grab Early Access (GEA), our early access build, as well as staged rollout, production monitoring, and crash triage.
A layered defense for app stability
Our strategy is rooted in a shift-left mindset: the earlier we catch a crash, the cheaper and less disruptive it is to fix. A crash caught by a lint rule costs nothing. A crash caught in GEA takes an engineer fewer hours to fix. A crash that reaches production costs user trust. That is why we invest most heavily in prevention: the goal is to stop crashes before they reach production, not to fix them there.
The system is a series of filters, each anchored to a specific phase of the feature development lifecycle, so the right check runs at the right time, and a crash that slips past one layer has another waiting downstream.
The colors mark the three phases on the stability side: prevention (pre-merge through pre-prod), the release gate (staged rollout and feature flags), and response (post-release).
Prevention: Our primary line of defense
Lint checks: Stopping crashes at the code level
Lint is the cheapest layer we have: static analysis that flags unsafe patterns, application programming interface (API) misuse, and likely crashes before the code ever runs. We use Android Lint on Android and SwiftLint on iOS. Both run in continuous integration (CI) on every merge request, and high-severity findings are merge blockers. Pre-existing issues never block a merge request: on Android, a lint baseline records them, and on iOS, SwiftLint reports only on the lines a merge request changes. Either way, a merge request fails only on the findings it introduces.
Our rules come from three sources:
Platform rules. Built-in checks cover well-known dangerous patterns, such as incorrect API usage and threading mistakes, and form the foundation for every build.
Community rules. Open-source rule sets cover third-party libraries and patterns the built-in checks miss. We adopt the ones relevant to our stack.
Custom rules. Both Android Lint and SwiftLint support custom rules, and we have built our own on both platforms. When a post-mortem or crash investigation traces a production crash to a specific code pattern, we write a rule that blocks that pattern from coming back.
Custom rules matter more as AI-assisted coding grows. An assistant can write code that looks right in general without knowing which patterns have crashed our app before. Custom rules turn those lessons into checks that apply equally to hand-written and AI-generated code.
Lint routinely blocks merge requests carrying Fatal issues: the kind that typically crash the app immediately or stop it from running.
Testing strategy: Multiple layers of confidence
Lint catches unsafe patterns statically, but it cannot run the code. Tests are where we catch crashes and regressions that only appear at runtime. No single test type covers everything, so we apply multiple complementary layers:
Layer
Focus
Unit tests
Business logic correctness at the function and class level
User interface (UI) component tests
Rendering and interaction behavior of individual UI components
End-to-end (E2E) automation tests
Integrity of critical user journeys
Quality assurance (QA) manual testing
Real-device exploratory testing for new features and significant code changes
Each layer targets a different class of crash risk. Unit tests block logic errors before they merge. UI component tests catch crashes tied to rendering or state mismatches; like unit tests, they run pre-merge on every merge request, so a rendering regression is blocked before it lands. E2E automation covers the flows with the highest business impact and runs on a per-team schedule and on every release train. QA manual testing focuses on new features and significant code changes, plus a full regression pass on every release, catching the edge cases that automation misses on real devices.
Grab Early Access (GEA): A one-week pre-production gate
Even with strong lint rules and test coverage, some crashes only surface under real-world conditions. GEA is an early build app by Grab. GEA builds are actively monitored for crashes, and any new crash surfaced during the GEA window automatically creates a ticket assigned to the responsible team. Issues reported by internal users, including functional defects and feature breakage, are ticketed the same way. Teams are required to resolve all blocking GEA issues before the release proceeds to production. GEA’s user base is large enough to expose real-world edge cases that automated tests miss, but small enough that issues are contained before reaching production users. GEA is a mandatory quality gate on every release cycle.
A crash that only a handful of internal users see in GEA would, at production scale, translate into a substantial spike in the crash rate, extra support load, and potentially a hotfix. Catching these crashes before they ever reach production users makes GEA one of our most important stability gates.
The impact adds up. Across both platforms, GEA catches new crashes every month, and each is fixed before the release reaches production. Each of them could otherwise have reached production users, including the long tail of users who do not auto-update and would have kept hitting them for months.
The release gate: Staged rollout and feature flags
Prevention keeps crashes out of the build. But the moment a release enters production, it meets something neither lint rules nor GEA can fully replicate: the full diversity of the real world, with thousands of device models, operating system (OS) versions, carrier configurations, and usage patterns that no internal test environment can mirror. So we treat the release boundary as its own critical checkpoint, a release gate between a validated build and full user exposure. Two mechanisms operate at this gate: staged rollout monitoring to limit the blast radius of the release itself, and feature flags to decouple feature activation from deployment.
Staged rollout monitoring
We do not ship to all users at once. Every release follows a staged rollout over the course of a week, starting with a small percentage of users and expanding in steps to the full user base. Each increment gives the monitoring system time to accumulate meaningful signal before the next expansion. During this window, we run a dedicated monitor that tracks the crash rate of the new version in isolation, separately from the baseline of all active versions. The separation matters: a regression in the new release can be masked in aggregate metrics if the older, stable versions dominate the user base.
If the new release shows an abnormal crash rate at any point during rollout, an automated system pauses the release before it expands further. The rollout does not resume until the responsible team has reviewed the issue and explicitly approved continuation. The pause gives us a hard stopping point: a regression introduced by the new release is contained to the fraction of users who received it, instead of compounding across the full install base.
In recent months, several Android rollouts were paused for on-call review. Most resumed after investigation: either the signal turned out to be noise, or the crash sat behind a feature flag that could be turned off without a new build. A small number stayed halted at the first stage until a hotfix shipped. We tune the monitor to be sensitive on purpose: a paused rollout takes an engineer a few hours to fix, while a missed regression can cost weeks. In one of the halted cases, only a small number of users hit the new crash before the halt, and the rest of the user base never saw it. Without the automated halt, the rollout would have kept expanding on schedule, taking the crash to the full user base.
Feature flags: Controlled activation with an instant kill switch
Even when a release ships cleanly, the features inside it are gated independently. All significant new features ship behind feature flags, decoupling deployment from activation. Flags let us roll out a feature gradually, monitor crash rates at each increment, and, critically, disable a feature instantly if its crash rate exceeds a defined threshold, without waiting for the next release cycle. For a team shipping weekly, the kill switch is what makes fast iteration safe, and it is also our first lever when something does reach production.
Response: When prevention falls short
No prevention layer is perfect. Crashes can still reach production: a misconfigured remote flag opens an unexpected code path, an OS update from a device manufacturer changes system behavior in ways no test environment can predict, or a bug slips past GEA and the rollout monitor because it only triggers under a specific combination of device state and user action. When that happens, the goal shifts from prevention to containment. For these scenarios, speed of detection, stopping the bleeding, and accuracy of diagnosis become the priority.
Real-time monitoring and on-call response
We maintain real-time crash rate monitoring across all active versions, with two complementary signals that can trigger an on-call alert:
Hard threshold breach. The crash rate of an active version crosses an absolute limit we define as unacceptable.
Abnormal trend. The crash rate spikes sharply relative to its own recent baseline, even if it has not yet crossed the absolute threshold.
We watch both because they catch different failure modes. A hard threshold catches slow drift: if the crash rate creeps up a little with each release, every step looks normal against its recent baseline and the trend alert never fires, yet over a year the rate can quietly increase. An abnormal trend catches the opposite case: a sudden regression, early, before it grows large enough to breach the threshold.
When either signal fires, an on-call engineer is immediately notified. The engineer begins by reviewing Firebase Crashlytics reports to identify which crash issues are driving the anomaly, then loops in the team responsible for the affected area. From there, the response follows a three-step decision framework, ordered from cheapest to most expensive:
Disable the responsible feature flag. If the crash is tied to a feature behind a flag, turning the flag off stops new users from hitting the issue immediately, with no new build required. Turning off a flag is by far the fastest mitigation we have.
Apply a server-side fix. If no flag covers the affected code path, the team looks for any server-side lever that can contain the impact: updating an API response, changing a config value, throttling a backend dependency. Any change that takes effect without shipping a new app build is preferred over one that does.
Ship a hotfix. If neither of the above is available, the team evaluates whether the crash warrants an out-of-cycle hotfix release, using defined criteria: business criticality of the affected flow, crash severity, user impact, and time to the next scheduled release. After the hotfix is delivered, a post-mortem is required. The goal is not just to document what went wrong, but to identify concrete action items that close the gap in our prevention layer, such as adding a lint rule to block the same pattern, wrapping a similar feature behind a flag, or improving test coverage for the affected code path. Every hotfix should make the next one less likely.
Automated crash triage
Automated ticket creation in GEA and production is not a collection of separate tools; it is one triage pipeline that follows a release from GEA into production. In production, running in parallel with real-time monitoring, it creates a production issue ticket for crashes that cross a minimum threshold. We assess crashes by type, user impact, and whether they’re actionable. Tickets are created for issues that meaningfully affect users; low-volume, device-specific crashes that we can’t address are monitored but don’t receive tickets. This keeps the team focused on the problems users are most likely to feel.
For crashes that do qualify, the ticket is routed to the owning team with a service-level agreement (SLA) tied to severity: Urgent, High, Medium, or Low. The initial priority is set automatically based on crash rate and user impact, but teams can re-evaluate and adjust the priority based on the business criticality of the affected feature.
Feature flag rollout history: Diagnosing crash spikes
Some of the hardest on-call moments start the same way: the app suddenly begins crashing, alerts fire, and there is no obvious reason why. Nothing shipped that day, and in the worst cases the crash arrives without a usable stack trace to point anywhere. With many product teams working on the same app simultaneously, the culprit is often not new code in the latest release; it is a feature flag quietly rolled out to a wider user segment in the background. Finding that flag by asking around does not scale: without a central view, an on-call engineer can spend hours before the responsible rollout turns up.
So we maintain a feature flag rollout history: a dashboard that correlates flag activation events with crash rate changes over time. Instead of polling every team, the on-call engineer gets an immediate view of whether any flag rollout aligns with the onset of the spike, turning a slow manual search into a quick read of a timeline.
Deep observability: Enriched diagnostics for hard-to-debug crashes
Firebase Crashlytics is our primary crash monitoring tool, but some crashes resist easy diagnosis: crashes with unusable stack traces, native crashes from third-party libraries without debug symbols, or issues that only manifest on specific device configurations. Without a clear stack trace, there is no obvious starting point for investigation.
We handle these cases in two ways.
First, we use Crashlytics’ built-in export to BigQuery, so we own a copy of the crash data. The data is pseudonymized and handled under Grab’s data protection policies. That copy gives us two things Crashlytics alone cannot:
Query the data when needed: full Structured Query Language (SQL) analysis across device attributes, app versions, and session metadata, surfacing patterns invisible in individual crash reports.
Build internal dashboards that serve app stability investigations, broken down by crash category, device tier, or release version.
Second, we enrich every crash session with custom metadata attached directly to Crashlytics. Among the most useful attributes we track:
Last visited screen: the last screen the user was on before the crash occurred (for example, the last Activity and Fragment on Android), helping reconstruct the navigation path that led to the failure.
Install source: whether the app was installed from Google Play or a third-party store (Android only). Some third-party stores distribute unofficial copies of the app, and more than once we have traced a crash back to a corrupted copy served by one of them. Knowing the install source lets us recognize these failures as environmental, instead of chasing them as code defects.
Session history: from the session data, we can reconstruct the sequence of screens and actions leading up to the crash, which is often the key to a crash investigation.
We attach many other custom attributes, but these three have proven the most useful in hard investigations. Together with structured logs and breadcrumbs, they give us a trail of events leading up to the crash, often the only meaningful signal when the stack trace alone is not enough.
Crashes we control, not eliminate
Different crashes call for different responses. Some are fixed in our code, while others, such as rare native crashes in operating system (OS) code, out-of-memory errors on devices near their limits, or failures from unofficial and sideloaded installs, are better handled through monitoring and containment.
We keep these categories at an acceptable baseline and monitor them on dedicated dashboards, separate from actionable issues. If any of them starts trending up instead of sitting flat, that spike triggers the same triage process as any other anomaly.
Conclusion
Sustaining stability across a codebase of millions of lines on Android alone, with many engineers shipping a release every week and AI assistance accelerating the rate of code change, is not the work of any single tool or team. It is the cumulative effect of a layered defense: lint rules and tests blocking bad code at the merge gate, QA and GEA catching what slips through, staged rollout limiting the blast radius of what reaches production, and on-call response combined with automated triage closing the loop on what production reveals.
The principle behind every layer is the same: shift left. A crash caught earlier is cheaper, smaller in impact, and less disruptive to fix. As the volume of code shipped per release continues to grow, the layered defense matters more, not less: the cost of a crash that reaches production is unchanged, but the number of opportunities to introduce one is rising. AI is speeding up how fast code is written; the layered defense is what makes that speed safe. Stability is not about having zero open problems; it is about knowing which problems you own and which ones you are watching.
Join us
Grab is a leading superapp in Southeast Asia, operating across the deliveries, mobility, and digital financial services sectors. Serving over 900 cities in eight Southeast Asian countries: Cambodia, Indonesia, Malaysia, Myanmar, the Philippines, Singapore, Thailand, and Vietnam. Grab enables millions of people every day to order food or groceries, send packages, hail a ride or taxi, pay for online purchases or access services such as lending and insurance, all through a single app. We operate supermarkets in Malaysia under Jaya Grocer and Everrise, which enables us to bring the convenience of on-demand grocery delivery to more consumers in the country. As part of our financial services offerings, we also provide digital banking services through GXS Bank in Singapore and GXBank in Malaysia. Grab was founded in 2012 with the mission to drive Southeast Asia forward by creating economic empowerment for everyone. Grab strives to serve a triple bottom line. We aim to simultaneously deliver financial performance for our shareholders and have a positive social impact, which includes economic empowerment for millions of people in the region, while mitigating our environmental footprint.
Powered by technology and driven by heart, our mission is to drive Southeast Asia forward by creating economic empowerment for everyone. If this mission speaks to you, join our team today!
On October 19, 2026, at approximately 17:00 UTC, Cloudflare became aware that private keys associated with eight eMudhra intermediate certificates were compromised. These certificates were widely trusted by browsers, operating systems, and also within Cloudflare. Because the keys themselves are weak, an attacker can create a forged certificate for any domain and use it to impersonate servers to intercept or modify traffic. This is a serious security incident with implications across the Internet. For reference, here is a link to more information about how SSL certificates work and why they are so critical to the operation of the Internet.
We immediately prioritized patching critical services across Cloudflare to protect our customers ahead of the public disclosure of the vulnerability. Our security review has not identified active exploitation of this issue on Cloudflare services.
We have released updates for the Cloudflare One Clients, also known as WARP or the 1.1.1.1 app, and Cloudflare Tunnel, also known as cloudflared. We have also deployed mitigations across our CDN, Developer, and Zero Trust products. If you are using Cloudflare Zero Trust with Gateway and an up-to-date client (see below), you are automatically protected.
Our response
We prioritized updating services that use public certificates to authenticate remote endpoints, including proxies connecting to origins and applications calling external APIs. In parallel, we updated shared trust stores, base images, and other shared foundations, providing a common mitigation path for services that inherit their certificate trust from those sources. We paired these updates with reloads, restarts, and image deployments needed to activate them. Applications with bundled or custom trust stores received separate assessment and updates. This work addresses certificate-based authentication, not a weakness in TLS’s encryption algorithms.
Teams across Cloudflare are presently working on further remediation. We are making progress, but there's much work still to be done. Some customers will need to take action on software or trust configurations that they operate, especially on their origin servers. The recommended actions are summarized below.
What customers should do
Developer guidance
For developers, look beneath the SDK.
An API client may delegate certificate verification to an HTTP library, a language runtime, the operating system, or a custom trust configuration. Updating the SDK alone may not change the underlying policy.
Once you patch, you may notice certificate errors in your dashboards. It's important to not resolve these errors by disabling verification. That would remove the authentication protection these updates are intended to restore.
This incident affects many software stacks that rely on the WebPKI for authentication. Mozilla’s Dennis Jackson has crowdsourced a list of commonly used packages that have been patched. We advise readers to upgrade as soon as possible. (Note that some of these may be indirect dependencies of your software stack, so look at the dependency tree.) Apply the relevant dependency updates, rebuild affected images, and confirm whether applications require a reload, restart, or redeployment.
Dennis Jackson’s test site provides browser checks, non-browser testing instructions, and package update information. Results apply to the verification path being tested, not every application on the device. Validate through the application’s actual TLS path. A successful browser test does not prove that a background service is protected. Neither does a curl test if the application uses a different verifier.
Timeline
The timeline of events so far is below.
Date and Time
Event
October 19, approximately 17:00 UTC
Cloudflare becomes aware of the compromise and begins assessment.
October 20, 02:00 UTC
Cloudflare One Client and WARP app security updates published across platforms (except Cloudflare One Agent on iOS, for which app review is still pending).
CDN and server-side Zero Trust mitigations fully deployed.
Looking forward
The impact of this incident is not felt equally. Browser maintainers were able to remediate the issue with a flip of a switch. They of course have just one application to update, instead of hundreds, but they do have a neat trick up their sleeves: most browsers use quick-revocation mechanisms (like Chrome CRLSets). At Cloudflare we also use such a mechanism for some of our products. To bring it to more systems at Cloudflare and industry, we’re excited about projects like upki that understand a trust store can’t be a static list of root certificate authorities, but needs the ability to be quickly updated with information like revocation and certificate transparency keys.
The PHP security team has let it be
known that there is a high-stakes security update coming at
14:00 UTC on October 21. “All PHP users are encouraged to
prepare now so they can upgrade as soon as the release is available“.
Anybody running a PHP site probably needs to be prepared for this one.
Engineering teams that own large Java estates face recurring upgrade deadlines. When they hand one of those upgrades to an AI agent, the agent brings its own permissions and its own bill. Consider a central engineering group with a few hundred Java services, several of which run on a Java Development Kit (JDK) version that reaches end of support in two quarters. Upgrading each service by hand means a dependency audit, a javax to jakarta migration, a test framework migration, and a release. The deadline does not move while the team works through the list.
Agents change the arithmetic. An agent upgrades a repository in place, where it runs the build, edits the source, and commits as it goes, and it finishes in minutes a job that takes a developer weeks. Across a few hundred services you don’t sit at a terminal approving each step. You invoke the agent from a pipeline, repository after repository, and an autonomous process with shell access to your source code now runs throughout your estate.
That speed comes with a footprint you must manage. The agent runs shell commands against the code that it’s changing, it uses the AWS credentials in its environment, and it bills you by the agent minute while it works. Before you point it at a few hundred repositories, you decide what permissions the agent holds and how much it can spend. That decision repeats wherever a runtime deadline meets a service count too large to upgrade by hand.
AWS Transform custom provides the agent, and you enforce that decision with three configuration controls. You write a trust allowlist to set which of the agent’s actions run without asking you. You scope an execution identity to limit what the agent can ask the service to do. You also set a cap on agent minutes, which stops a run at the limit you choose, and you configure an account-level alert on cumulative spend across runs. None of the three requires new infrastructure, because you manage each one as configuration, so you can adopt agentic transformation on a schedule you set.
The agent runs transformations through the AWS Transform CLI, either interactively on your machine or non-interactively in a pipeline, so the controls must hold in both places. In this post, we walk through the three controls against a working repository and give the measured result of each one. We show how a real run produced the trust allowlist, why interactive runs and pipeline runs need different controls, and how to scope an execution identity to approved transformations. The complete source code is available in the sample repository.
Unbounded agent risks
An agentic transformation runs as a process on a machine you own, rather than handing you a patch to review, and that footprint carries three distinct risks. The agent can run tools without limit, the identity it runs under can do more than run transformations, and the spend it accrues has no ceiling unless you set one. Each risk needs its own control, and you meet all three on the way to your first fleet-wide upgrade.
Tool execution
The agent works by calling tools. It reads a file, writes a file, runs the build, inspects git history, and commits, and the shell commands among them run with the privileges of whoever started the run. On your first run against one service, each of those calls stops for your approval, and after enough prompts the flag that trusts every tool looks like the obvious way to get through the day. That flag stops the prompts by removing the check behind them, which is the risk. The agent can then run whatever a transformation asks of it, on a machine that holds your source code and your credentials.
Identity
The AWS credentials in your environment decide what the caller can do to the service, and the managed policy that gets a first run working also covers authoring. If an identity can both run a transformation and rewrite its definition, it can also change what runs next time. On a laptop that identity belongs to a person exercising judgment, but in a pipeline it belongs to a role that the rest of the build inherits, and the pipeline is where your other few hundred runs will happen.
Spend
Billing is per agent minute, and the meter runs while the service plans, reasons, analyzes, and edits. A single run on a small service costs little, so the risk isn’t the run you watch but a fleet-wide upgrade of a few hundred automated runs, on a bill nobody reads until the end of the month.
Solution overview
The following diagram shows where each of the three controls intercepts a transformation run.
Figure 1: Where each of the three controls intercepts a transformation run
Invocation: A developer runs the AWS Transform CLI interactively, or a pipeline runs it non-interactively. The two paths carry different controls.
Trust settings: Before the agent runs a shell command or writes a file, the CLI checks the trust settings file in your home directory. A command that matches the allowlist runs. A command that does not match returns to the person at the terminal as an approval prompt.
Identity: AWS Transform custom authorizes each call the CLI makes against the AWS Identity and Access Management (IAM) identity in your environment. When you attach the execute-only managed policy and scope it to the transformations you approve, the policy bounds the service actions that the caller can request, including requests that originate from the agent.
Spend: The run carries an agent-minute cap and stops when it reaches it. Underneath that, an AWS Budgets budget filtered to AWS Transform watches monthly spend across runs and notifies a subscriber at a threshold you set.
Inside a transformation run
AWS/java-version-upgrade is one of the AWS managed transformations, prebuilt and maintained by AWS rather than authored in a customer account. Running atx custom def list shows the AWS managed definitions alongside any custom ones you have created. The definition for this one covers a range of build systems and source and target JDK versions, with dependency modernization that includes Jakarta EE migration, database drivers, object-relational mapping (ORM) frameworks, and updates across the Spring libraries.
The target version is an input rather than a property of the transformation. The definition gives three ways to supply it: interactive chat with the agent, an additionalPlanContext configuration parameter, or a configuration file. We specified the target version in the prompt we gave to atx.
The sample repository is a small Spring Boot REST service with a single endpoint, running on Java 8 and Spring Boot 1.5. It stands in for one of the few hundred services in the opening scenario. The transformation takes it to Java 17 and Spring Boot 3.2, so the javax.servlet and javax.annotation imports become their jakarta equivalents and the JUnit 4 test moves to JUnit 5. We kept the business logic trivial from the beginning so anyone can follow along. If the logic were more complicated, it would introduce a monetary barrier for readers who want to try it themselves, and it would take longer to run.
In a run (AWS Transform CLI 3.10.0), the transformation made 43 tool calls across the sample’s 4 files: 13 shell commands, 11 file writes, 11 file reads, 6 editor operations, and 2 version control operations. Every shell command ran with the permissions of the identity that started the run, inside the working tree of the repository being upgraded. The counts in this post come from this definition and this sample in August and September 2026, so expect different counts on other CLI versions, definitions, and repositories.
The documentation describes multi-step transformations as using Git to commit intermediate steps. In that run, the 2 version control operations produced a single checkpoint commit on the result branch.
Prerequisites
The walkthrough requires the following:
An AWS account and an AWS Region where AWS Transform custom is available, listed in the getting started guide.
The AWS Transform CLI and Node.js 22 or later, which the CLI requires. Install the CLI with curl -fsSL https://transform-cli.awsstatic.com/install.sh | bash, then confirm with atx --version. The confirmation runs in this post used version 3.10.0.
Git, with the sample checked out as a valid repository, because the transformation commits its intermediate steps. On CLI 3.10.0, a run also stopped when the working directory wasn’t a repository, which is behavior we measured rather than a documented requirement.
JDK 8 to build the sample before the upgrade, JDK 17 after it, and Maven 3.6 or later. The commands in this post were verified on macOS. On Linux, set JAVA_HOME to a JDK 8 path directly instead of using the macOS-specific /usr/libexec/java_home helper.
AWS credentials with permission to call AWS Transform custom. Control 2 covers which policy to attach.
Restricted networks additionally need transform-cli.awsstatic.com, transform-custom.<region>.api.aws, and *.s3.amazonaws.com reachable. The repository README carries the full setup detail.
Control 1: Scope which tools run without asking
This control starts on a laptop, because that is where the allowlist gets built.
Our first run of AWS/java-version-upgrade against the sample repository used AWS Transform CLI 3.9.0 with no trust configuration, and it raised 23 approval prompts across four files. The later runs used 3.10.0, and the CLI version history lists no change to trust settings or approval prompts in that release.
Before the allowlist, you have two options. Either you grant blanket tool trust for the session, which comes with the risk of tool calls you don’t want the agent to make. Or you walk through every prompt carefully, reading what it says and deciding whether you want that tool call to run, which adds to the overall time the agent takes to complete the task.
Across a few hundred repositories, either choice makes the documented shortcut the obvious thing to reach for. The --trust-all-tools flag (-t) approves the tool calls the agent requests without asking.
The middle position is a trust settings file at ~/.aws/atx/trust-settings.yaml. The file is split into three categories. trustedTools covers the tool calls that are allowed automatically. trustedShellCommands are the shell commands you allow the agent to run on its own without prompting you. And alwaysPromptCommands are the commands the agent has to ask you about before executing, in interactive mode. A fourth mechanism sits alongside the file: answering t at an approval prompt trusts that tool for the rest of the session, which the prompt text itself names when it reports that a tool “hasn’t been trusted this session.”
We first made a test run with no trust configuration in place, so we could see which tool calls the agent makes for this specific transformation. We logged each tool call and added the shape of each command to the file, to make it straightforward for you to use. Twenty-three prompts collapse into a short list, because the agent asks for variations of the same few operations.
Rerunning with that first list (CLI 3.10.0) dropped the count from 23 prompts to 3, and all three were the same shape: cd <path> && <command> compounds in the validation phase. The matcher is a full-command-string glob, so JAVA_HOME=* mvn * does not match a string that starts with cd. Command shapes vary between runs, and this one issued a bare mvn during execution and cd ... && mvn during validation, so the shipped file carries both forms. With both forms added, a third run on a clean clone (CLI 3.10.0) reached zero prompts.
The following excerpt shows the shape of the file. The repository copy carries the full set, including the cd-prefixed variants:
The mkdir -p matters on a fresh install, because ~/.aws/atx/ does not exist until the CLI has run at least once.
Patterns match against the full command string, which is why JAVA_HOME=* mvn * is listed separately from mvn *. The validation command pins JDK 8 because Spring Boot 1.5 can’t start its context on later versions, which is what puts that prefix in the run at all.
The alwaysPromptCommands entries are matched against each sub-command in a compound expression rather than against the whole string. In an interactive run, session trust and the --trust-all-tools flag don’t approve a match.
Important: alwaysPromptCommands doesn’t force a prompt in 2 cases.
A matching trusted pattern takes priority. The documentation states that trustedShellCommands patterns match the full command string and take priority over the always-prompt list, so a trailing * spans pipes, semicolons, and &&. In our verification run (CLI 3.10.0), the trusted pattern /usr/libexec/java_home * matched a compound that continued ; echo "---" ; ls ..., and the chained tail ran without a prompt. By the same rule, mvn * trusts mvn --version; printf canary even with printf * in alwaysPromptCommands. The file in this post uses mvn * to reach zero prompts on the sample, so narrow that pattern to the Maven goals your builds run before you reuse the file.
Non-interactive mode (-x) does not enforce alwaysPromptCommands, as the documentation states, so the list has no effect on a pipeline run.
Keep the two lists non-overlapping and the trusted patterns as narrow as the runs allow. The following diagram shows the order in which the CLI evaluates a proposed shell command.
Figure 2: How the CLI evaluates a proposed shell command in interactive mode
With the allowlist in place, a full run of AWS/java-version-upgrade completed with no approval prompts and without blanket trust. The run made 43 tool calls, each one covered by the allowlist or by a built-in trusted tool, with a green build and 2 of 2 tests passing on AWS Transform CLI 3.10.0. This lets us focus on other tasks, and we’re only interrupted when the task finishes or something unexpected comes up. The startup banner on that version also identified six built-in trusted tools: file_read, grep, both transformation-registry tools, document_manager for add operations, and editor for view and find-line operations. Those calls don’t prompt, so a prompt inventory understates the agent’s effective tool surface. Default trust is also scoped by path rather than only by tool. The same file_write tool runs without prompting when it targets the CLI artifacts directory and prompts when it targets the repository.
In a pipeline
The trust settings file governs interactive runs only. On CLI 3.10.0, -x without --trust-all-tools stops before the transformation starts, with the error Must explicitly --trust-all-tools when running in non-interactive mode, which we hit in a test. A pipeline run therefore trusts every tool, and the allowlist has no effect on it. The interactive path does not fit a pipeline either, because without a terminal it stops at the plan approval step and reports Input is not a TTY.
This control therefore belongs on a developer machine. A pipeline needs its boundary somewhere else, and that somewhere else is the next two controls.
Control 2: Separate the identity that runs from the identity that authors
The pipeline from the opening scenario needs an identity, and that identity should run the upgrade and little else.
Three AWS managed policies cover AWS Transform custom, and the split between them is the control. The following table describes each policy at version 4, the current version on September 30, 2026. Check the managed policies page for a later version before you attach one.
Policy
What it grants
Who gets it
AWSTransformCustomExecuteTransformations
Run existing transformations, and read and update campaigns
The pipeline execution role
AWSTransformCustomManageTransformations
The preceding, plus authoring: upload and delete transformation packages, manage knowledge items, tag resources
The people or pipelines that author definitions
AWSTransformCustomFullAccess
Both of the preceding, reasonable for a first run but wider than a governed setup needs
Nobody, after setup is complete
The execute-only policy also carries its own iam:CreateServiceLinkedRole statement scoped to the AWS Transform service-linked role, so a first run works without AWSTransformCustomFullAccess even in a fresh account.
Give the pipeline execution role the execute-only policy. Authoring stays with whoever maintains the transformation definitions, so a build step holding that role is not authorized to rewrite the definition that it’s about to run:
aws iam attach-role-policy \
--role-name my-transform-ci-role \
--policy-arn arn:aws:iam::aws:policy/AWSTransformCustomExecuteTransformations
Then confirm what the identity holds, rather than what you meant to give it:
aws iam list-attached-role-policies --role-name my-transform-ci-role
aws sts get-caller-identity
The execute-only policy still lets the role run whatever is in the registry. For transformations you publish yourself, you can narrow it further, because transformation packages are AWS resources with Amazon Resource Names (ARNs). The transform-custom:ExecuteTransformation action takes a package resource and supports the aws:ResourceTag condition key. Tag the packages you publish, and scope the role to the tag:
We confirmed the mechanics with the IAM policy simulator: it allows the execute call when the tag is present and returns an implicit deny when the tag is absent. Note the scope of the example, though. The Resource element names packages in your account, and an AWS managed package such as AWS/java-version-upgrade is not a resource in your account, so a role holding only this policy can’t run it. The execute-only managed policy itself grants ExecuteTransformation on Resource "*" for that reason. The practical split is tag-scoping for the definitions you publish, alongside the managed policy’s broader grant for the AWS managed catalog.
The second statement is the limit of this approach. The actions table in the service authorization reference lists no resource type and no condition keys for ConverseStream, so that statement stays at "*". A role scoped to one transformation can still open a conversation with the service.
The broader limit is that IAM bounds the API surface and not the edits. The execute-only policy still authorizes whatever the transformation does to your working tree, because the scope of changes inside a repository is a local filesystem question. That’s what Control 1 is for on a laptop, and what code review of the resulting branch is for in a pipeline.
Control 3: Cap what a run can spend
Now think about the same upgrade from the cost perspective. The fleet-wide upgrade from the opening scenario means a few hundred runs, but you’re constrained by your budget. With the spend control, you can bound the agent minutes used by each run and use the account-level budget to watch cumulative spend across the fleet.
Start with what an agent minute measures. You’re billed per agent minute, but an agent minute is not a wall-clock minute. The two match only while a single agent is running, and AWS Transform can run several agents at once on one task, so each of them accrues its own minutes. Per the AWS Transform pricing page, minutes accrue while the service is actively planning, reasoning, analyzing, or modifying code, and not while it waits on local compilation, tests, or builds.
AWS Cost Explorer recorded 54.0 agent minutes for the discovery run (CLI 3.9.0) and 45.8 agent minutes for the clean-clone confirmation run (CLI 3.10.0). At the published rate of USD $0.035 per agent minute, the confirmation run cost approximately USD $1.60. A 30-agent-minute cap would therefore stop this particular upgrade partway through, which makes it a useful review checkpoint rather than a budget sized for uninterrupted completion. In practice, the number is experimental. It depends on your budget for the task, and it can take multiple iterations at a smaller scale first to get an understanding of the agent minutes your tasks need.
We wanted to see what the CLI does when it hits the cap, so we ran the same transformation non-interactively on a scratch clone with --limit 1. On AWS Transform CLI 3.10.0 the run stopped at 1.09 agent minutes, printed Budget limit reached: 1.09 / 1.00 Agent Minutes. Exiting., and returned process exit code 2. The repository was left clean. The exit code is the part we were checking. The web documentation describes the message and the resume path but not an exit code. The CLI --help output on 3.10.0 does state that the run exits with code 2 when the limit is reached, and the run confirmed it. It’s also what turns spend into control flow, because a pipeline can tell a budget stop from a transformation failure. The 0.09-minute overshoot comes from how coarsely the CLI receives usage events, so treat the limit as a close bound rather than an exact fractional-minute cutoff.
The work is preserved. Review the partial result, then resume the same conversation with a higher cap. The trust settings file from Control 1 still governs the resumed interactive session:
A pipeline can handle the bounded stop separately:
status=$?
if [ "$status" -eq 2 ]; then
echo "Agent-minute budget reached; review before resuming"
exit 0
elif [ "$status" -ne 0 ]; then
echo "Transformation failed"
exit 1
fi
Entering /usage during an interactive session reports the accumulated agent minutes without ending the conversation. Minutes persist across an interruption, so when you resume a session after Ctrl+C, the count continues rather than starting over. Per the pricing page, an interrupted transformation can be resumed for up to 24 hours before it’s stopped automatically. We did not test the expiry, so treat that window as documented rather than measured.
The per-run cap says nothing about how many runs start, so back it with an account-level AWS Budgets budget. A budget like the one in this sample sends a notification and does not stop runs, so the next run still starts after the alert. AWS Budgets also updates its data up to 3 times a day, which means a fleet of runs can pass the threshold before the alert arrives. To stop new runs at a threshold, you can configure a budget action that applies an IAM policy or a service control policy (SCP), which this post does not cover.
The sample repository ships a monthly budget of USD $50 filtered to the AWS Transform service, with an alert at 80 percent of actual spend:
Edit the email address in guardrails/notifications.json before running that command, because the file ships a placeholder. To see where the month stands, query AWS Cost Explorer for the same service dimension:
Use the cap to bound each run, and use the budget to find out when the runs together cost more than you planned.
Limits of these controls
Retention is a separate question from permissions. The --do-not-learn flag opts one execution out of lesson extraction for that transformation definition. A different control governs whether your content is used for service improvement, and you configure it as an AI services opt-out policy in AWS Organizations. Neither one changes the fact that the transformation sends code to the service to do the work. Both govern what happens to it afterward.
Retained lessons also reach back into later runs. In the verification run, the agent diffed against a baseline commit carried in from a previous run on the same repository, so a README that we had added by hand between the two runs appeared in the diff, and the validation summary credited the transformation with adding it. Lessons persist repository-specific facts across runs, and on a repository that changes between runs they can misattribute human work to the agent.
The number of commits a run produces is not fixed. The same transformation on the same repository produced two commits on the first run and a single commit on each of the next two, and the commits covered a different set of plan steps each time. Review the result branch with git log and git diff rather than assuming one commit per plan step.
Clean up
The controls in this post are configuration rather than provisioned infrastructure, so there is little to tear down. Delete the budget when you no longer want the alert:
The trust settings file at ~/.aws/atx/trust-settings.yaml and the policy attachments on the execution role are yours to keep or remove. If you also deployed the sample application to AWS to see the upgraded service running, run npx cdk destroy from the infra/ directory. One artifact survives by design. The container image stays in the AWS Cloud Development Kit (AWS CDK) bootstrap repository in Amazon Elastic Container Registry (Amazon ECR), because cdk destroy does not remove bootstrap assets. Storage for it costs about a cent a month, and deleting the image from the cdk-*-container-assets-* repository clears it. Leaving the sample deployed costs roughly USD $13 a month, so tear it down when you’re finished with it.
Conclusion and next steps
You can now put a few hundred upgrades on a schedule, because the execution identity and the agent-minute cap apply to each run wherever it executes. A trust settings allowlist adds a third control on a developer machine. That allowlist took the interactive sample run from 23 approval prompts to zero without blanket tool trust. We built the execution identity from the AWS Transform managed policies in IAM and narrowed it to approved transformations with a resource tag. An AWS Budgets budget and alert on the account backed the agent-minute cap on each run. Because every measurement came from running AWS/java-version-upgrade against the sample repository, you can repeat the runs in your own account before you decide what to change. We ran them in August and September 2026, with the confirmation runs on AWS Transform CLI 3.10.0.
The configuration leaves room to grow. If you publish your own transformation definitions, tag them and scope the execute permission to the tag, which holds a pipeline role to the transformations you have reviewed. And if you run transformations over proprietary repositories, the --do-not-learn flag covers a single execution. An artificial intelligence services opt-out policy in AWS Organizations covers service improvement across the account.
Setuid (and setgid) binaries have long been a source of headaches, and security
vulnerabilities, on Linux systems. They are largely seen as something to be
avoided; SUSE’s security team, for example, forbids
the inclusion of setuid or setgid binaries in packages unless they have been
reviewed and explicitly allowed. Thorsten Kukuk wants to go a step further and
disallow them entirely. At the 2026 All Systems Go! conference, he spoke
about his work to disable setuid system-wide, as well as some of the hurdles
that remain.
When an AI agent crawls your documentation looking for answers, it doesn’t browse like a human. It scores structure, extracts entities, checks factual consistency, and moves on, often in under a second. If your content doesn’t surface clearly in those evaluations, it won’t appear in AI-generated answers regardless of its current search ranking. This problem is called Agent Engine Optimization (AEO), and solving it requires running multiple evaluation steps that are expensive, stateful, and failure-prone.
In this post, you build a five-step AEO scoring pipeline using AWS Lambda durable functions. Each step (fetch, score, analyze, publish, record) runs as a checkpointed operation that suspends without incurring additional costs between stages, retries without re-spending on prior work, and reads like ordinary Python. You score content against five AEO signals, see a real audit example, and walk away with a deployable AWS Serverless Application Model (AWS SAM) template.
A note on fetching: The pipeline uses a plain HTTP GET, mimicking how non-rendering AI crawlers (GPTBot, ClaudeBot, PerplexityBot) see pages today. Sites that rely on client-side JavaScript may score lower because most AI agents do not execute JavaScript.
Solution overview
The pipeline runs as a single Lambda durable function that chains five checkpointed steps. Scoring is fully deterministic (pure Python, no large language model (LLM)), so the same page consistently produces the same score. Amazon Bedrock generates prose analysis explaining the results. For production deployments that surface generated content to end users, consider adding Amazon Bedrock Guardrails for responsible AI controls. Because the function suspends between steps without incurring additional costs, a failure at step 3 resumes from step 3. The deterministic scores from step 2 are already checkpointed.
The following architecture diagram shows the five pipeline stages:
Fetch – Retrieve the target page through an HTTP GET and extract structured signals (headings, token count, robots.txt rules, llms.txt, AGENTS.md).
Score – Apply the deterministic rubric: threshold-based checks produce a reproducible 0–100 score with no LLM involvement.
Analyze – Send the scores and raw signals to Amazon Bedrock, which generates prose findings and fix recommendations (temperature 0 for consistency).
Record – Persist the score and metadata to Amazon DynamoDB for trend tracking.
Figure 1: The five checkpointed stages of the AEO scoring pipeline, from fetch through record.
This gives you retry safety, cost predictability, and simpler debugging. The pipeline runs fully automated by default, with an optional callback gate for workflows requiring human approval.
Why Lambda durable functions
An AEO audit is five operations that depend on each other, any of which can fail mid-flight. Without checkpointing, a retry means re-running every step from the beginning, including Bedrock calls that already returned valid results.
Lambda durable functions solve this with checkpointed steps. Each step’s output is persisted before the next begins. When a Bedrock call gets throttled at step 3, only step 3 retries. The pipeline doesn’t re-run steps 1 and 2 or re-spend on their inference tokens.
Between steps, the function suspends with no environment held open, so you pay nothing while waiting. The pipeline reads as a single Python file, top to bottom. Each step’s checkpoint is independently inspectable, so debugging a failed run means looking at one step’s result rather than replaying the full execution log.
Prerequisites
An AWS account with Amazon Bedrock model access enabled.
A SAM template in the GitHub repository provisions the DynamoDB table, S3 bucket, Lambda durable function, and required IAM roles. You deploy the full stack with sam build && sam deploy --guided.
Estimated time: 20–30 minutes. Each audit run uses a single Bedrock inference call plus brief Lambda durable function and DynamoDB usage. See the AWS Pricing Calculator for estimates based on your Region and usage volume.
The five AEO signals
Scoring evaluates content against five signals drawn from Addy Osmani’s Agent Engine Optimization framework. Each signal maps to a capability an AI agent needs when deciding whether to use your content. Scoring is deterministic: every point maps to a measurable threshold (file exists, token count under ceiling, heading hierarchy valid). No LLM is involved in producing the number.
1. Discoverability (0–25)
This signal checks whether the URL returns server-rendered HTML, whether an llms.txt file exists at the domain root, and whether AI crawlers receive a successful response. A page returning HTTP 200 with parseable content passes. A page returning 403 or 429 to AI user agents fails.
2. Parsability (0–25)
This signal scores heading hierarchy (H1 through H6), presence of code blocks and tables, and whether the page has semantic landmarks. Because agents parse structurally rather than linearly, it’s essential for sites to be well organized and logical. Osmani suggests serving Markdown and HTML, leading each section with the outcome, and using tables for parameter references, among other tips that make your site easier to parse.
3. Token efficiency (0–25)
It measures total token count against a 30,000-token ceiling and a 15,000-token quick-start target. Pages bloated with navigation elements or repeated boilerplate score lower.
4. Capability signaling (0–15)
This signal checks for AGENTS.md or skill.md files describing available actions, required inputs, authentication, and rate limits. Without these, agents discover capabilities through trial and error.
5. Access control (0–10)
It checks robots.txt for AI-specific rules (GPTBot, ClaudeBot, PerplexityBot). Pages with explicit Allow or Disallow rules for AI user agents score higher than pages with no AI-specific rules, where access is open by default. Either choice is fine. The signal rewards making the decision on purpose.
Deterministic scores feed into the analyze step, where Bedrock generates prose explanations and actionable fix recommendations.
Example: auditing a real page
To see the pipeline in action, here are the results from a technical documentation page: a conceptual overview for a cloud computing service.
Target: A technical documentation page (conceptual overview, 958 words)
Overall score: 58/100
Signal
Score
Key finding
Discoverability
17/25
Server-rendered, llms.txt exists (but bloated at 295 KB / ~74K tokens compared to the recommended 5K token limit). No AGENTS.md.
Parsability
14/25
Invalid heading hierarchy (H1 to H6 to H2). No fenced code blocks or tables despite being technical documentation. 63.9% HTML noise ratio.
Token efficiency
25/25
1,245 tokens. Well under both the 15K quickstart target and 30K ceiling.
Capability signaling
0/15
No skill.md. Agents cannot discover what actions this documentation enables.
Access control
2/10
No AI-specific rules in robots.txt. Access is accidental rather than intentional.
Top three fixes:
Create a skill.md declaring what agents can do with this service (available actions, required inputs, constraints).
Fix the heading hierarchy to follow valid nesting (H1, H2, H3) and add fenced code blocks with language tags.
Add an AGENTS.md at the domain root and explicit AI crawler rules to robots.txt.
The scoring is deterministic, and every point maps to a measurable condition. Amazon Bedrock then runs LLM inference on the results to generate the prose findings.
Under the hood: Steps and callbacks
Every step in the preceding audit, from fetch through record, runs as a checkpointed step. The callback is optional and sits after the analyze step, if you want a human to review the report before it’s published.
Lambda durable functions expose two core primitives: steps and callbacks. This pipeline runs fully automated by default (five steps, no human gate), but you can opt into a callback-based approval gate when the use case calls for it.
Steps
A step is a unit of work. The runtime checkpoints its return value before the next step begins. You declare one with the @step decorator:
If this step succeeds, its return value is persisted. On retry, completed steps are skipped and their cached results passed forward. Two rules:
Keep return values small. Return structured results, not raw API responses.
One side effect per step. A step that calls Bedrock and also writes to DynamoDB is harder to reason about on retry. Make one external call per step.
Callbacks
By default, the pipeline runs all five steps without stopping. To add a human review gate, turn on the callback. The function suspends without incurring additional costs until an external signal arrives. In practice, you wire this to a Slack bot or approval dashboard rather than a CLI command. Resumption happens through the SendDurableExecutionCallbackSuccess AWS API call with the callback ID. Because this is an authenticated API call, only principals with the appropriate IAM permissions can signal completion.
# In the handler (called on DurableContext, not inside a step):
callback = context.create_callback(name="review_report")
send_to_reviewer(callback.callback_id, report)
# Execution suspends here until the external system calls
# SendDurableExecutionCallbackSuccess with the callback ID.
result = callback.result()
The function suspends at callback.result() without incurring additional costs. The external system calls SendDurableExecutionCallbackSuccess with the callback ID and the approval payload. Timeouts raise TimeoutError for fallback routing.
When to add a callback
Run fully automated when…
Add a callback when…
Scheduled audits or continuous integration and continuous delivery (CI/CD) regression monitoring
Downstream actions are gated (auto-filing tickets)
By default, the pipeline skips the callback entirely. To turn it on, set APPROVAL_GATE=true in the function’s environment variables.
Clean up
To avoid ongoing charges, delete the stack when you’re done experimenting:
sam delete --stack-name aeo-scoring-pipeline
This removes the Lambda durable function, DynamoDB table, S3 bucket (if empty), and the associated IAM roles. If your S3 bucket contains audit reports you want to keep, download them first or remove the DeletionPolicy: Delete setting from the template before deploying.
Conclusion
You now have a five-step AEO scoring pipeline in a single Lambda function that checkpoints between steps without incurring additional costs. Some steps involve LLM inference you don’t want to pay for twice. Durable checkpoints help make sure you do not.
Run your first audit: aws lambda invoke --function-name AeoScoringPipeline --payload '{"url": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html"}'
Next steps: schedule audits using Amazon EventBridge, add Slack alerts when scores drop, or extend the rubric with domain-specific signals.
When platform teams manage containerized applications at scale on Amazon Elastic Container Service (Amazon ECS), configuring ingress networking for each service often becomes a bottleneck. For every new service, teams must provision and connect Application Load Balancers (ALBs), AWS Certificate Manager (ACM) certificates, AWS WAF web ACLs, and security groups, then keep those resources in sync as services scale, update, or operate. This per-service overhead slows down deployment velocity and increases the risk of configuration drift across an organization.
Today, we’re announcing Amazon ECS Gateway, a new account-level resource that simplifies ingress networking for containerized workloads by dynamically provisioning and managing the necessary infrastructure on your behalf, with all resources created directly in your account.
ECS Gateway introduces a clear separation of responsibilities between platform teams and application teams.
Platform teams create and configure a gateway, defining organizational networking standards including subnets, security groups, TLS certificates, listener settings, and WAF web ACLs, in a single place. They then associate the gateway with one or more ECS clusters, making it available to services running on those clusters.
Application teams opt their services in by adding a gateway connector parameter when creating or updating a service. ECS provisions the required per-service resources automatically: an ACM certificate, a unique DNS hostname, listener rules, target groups, and a service security group that permits inbound traffic only from the ALB. No networking expertise required.
ECS Gateway offers host-based routing using ALBs and enables up to 25 services to share a single ALB, optimizing infrastructure costs. ECS manages the full lifecycle of the underlying infrastructure, provisioning the first ALB when your first service connects, adding more ALBs as capacity is reached, and removing them when no longer needed. Each service receives a unique DNS hostname, giving your teams a ready-to-use endpoint the moment provisioning completes.
A first look at ECS Gateway
In the ECS console, platform team can create a gateway and sets its configuration. The infrastructure role is an IAM role that ECS assumes to provision and manage networking resources such as ALBs, security groups, and certificates in your account. To create a gateway, provide a gateway name and select an infrastructure role. You can optionally associate the gateway with ECS clusters during creation or later.
Choose a load balancing scheme, either public or VPC-internal traffic routing. Under Additional Settings, you can also set up a listener, port, maximum count of load balancers the gateway can scale to, and a web ACL lets you protect your web applications. Some settings, including the name, scheme, VPC, subnets, IP address type, listener protocol and port cannot be changed after gateway creation.
Using AWS Command Line Interface (AWS CLI), call CreateGateway with a name (unique per account), an infrastructure role, and a configuration object. No infrastructure is provisioned until a service connects with a gateway connector.
To create and manage the ECS Gateway programmatically, including calling APIs and searching documentation, try the AWS MCP Server and plugins with your preferred AI coding tool. To learn more, visit the Amazon ECS Gateway documentation.
ECS Gateway:Behind the scenes
A gateway can be associated with up to 10,000 clusters, and a single cluster supports up to five gateway associations. This many-to-many relationship gives platform teams the flexibility to share a gateway across environments or assign multiple gateways (for example, public and private) to a single cluster.
Platform teams can control access by choosing which gateways to associate with which clusters. For additional control, use IAM policies to restrict who can deploy services to specific clusters.
Application teams add the gateway connector to each service definition in CreateService or UpdateService. If you have an existing ECS service with its own load balancer, you can adopt ECS Gateway incrementally by calling UpdateService to add a gateway connector. Both ingress paths remain available, allowing you to validate the gateway connection before removing the existing load balancer configuration.
At deployment time, Amazon ECS evaluates the gateways associated with the cluster and connects the service to every compatible gateway. A gateway is compatible when its access type matches the service’s connector filter, it is in the same VPC as the service, and it covers all Availability Zones used by the service’s configured subnets.
For each connection, Amazon ECS assigns the service to an ALB with available capacity and provisions the per-service resources: an ACM certificate, a unique DNS hostname, a listener rule routing traffic for that hostname to the service target group, and a service security group allowing inbound traffic only from the ALB security group. If no existing ALB has capacity, ECS creates a new one (up to maxAlbCount referring to quota limit). Once provisioning completes, the gateway route becomes ACTIVE, and the service URL is ready to receive traffic.
ECS Gateway handles common operational scenarios automatically:
Redeployments: On each deployment, ECS re-evaluates gateway associations. If new compatible gateways have been associated since the last deployment, your service connects to them. If a gateway has been disassociated, your service disconnects and the route is removed. Your service always reflects the current state of the cluster gateways at deployment time.
Service deletion: ECS automatically disconnects the service from every gateway, removes all gateway routes, and cleans up all per-service resources. If the service held the last route on an ALB, that ALB is deprovisioned.
Things to Know
Here are a few important details to keep in mind:
Networking: ECS Gateway is available for ECS services using the awsvpc network mode across all launch types (Amazon ECS EC2, AWS Fargate, and ECS Managed Instances). Your service Availability Zones (AZs) must be a subset of each gateway’s AZs on the cluster. A gateway ALB only routes traffic to tasks in AZs where it has subnets. We recommend creating gateways and services for a given cluster with the same set of AZs.
Capacity: If maxAlbCount is reached and no ALB has available capacity, the deployment fails. Default quota limit of maxAlbCount is 10. Plan your maxAlbCount setting according to the number of services you expect to connect.
Observability: Use ALB metrics in CloudWatch with the TargetGroup dimension to monitor per-service traffic, and LoadBalancer dimension to monitor traffic across the shared ALB. Use describe-target-health to check real-time target status. Configure CloudWatch alarms for metrics such as HealthyHostCount, TargetResponseTime, and HTTPCode_Target_5XX_Count, using gateway ARN-based tagging so monitoring scales automatically with your maxAlbCount.
Now available
Amazon ECS Gateway is available now in all commercial AWS Regions where ECS is available at no additional charge. You pay only for the underlying infrastructure provisioned in your account when services connect to a gateway, including applicable ALB charges, CloudWatch logs and metrics, ACM certificates, and data transfer charges. To learn more, visit the Amazon ECS Pricing page.
To get started, create your first gateway today in the ECS console, and send feedback to AWS re:Post for ECS or through your usual AWS Support contacts.
The work to support block sizes larger than the page size on XFS has been
difficult. Many users of XFS run stable kernels, which means that they aren’t testing
new XFS code as it is released. That has made Daniel Gomez wonder whether
adopting Rust for some of the data structures underlying XFS, particularly
XArrays, could reduce the number of bugs lurking in the code. At
Kangrejos 2026, he led a discussion about the potential problems with converting
XArray to Rust. The assembled kernel developers had a number of reasons to be
cautious about replacing the XArray code, but Gomez was determined to experiment
with the possibility, citing both security and performance improvements.
Mozilla has announced
that it has received a report that private keys associated with eight eMudhra intermediate certificates have
been compromised:
These keys could allow attackers to issue fraudulent HTTPS certificates for
websites they do not control. An attacker who could intercept a user’s
connection could use those certificates to impersonate websites and potentially
read or modify traffic.
Mozilla has blocked the affected certificates using its OneCRL
centralized list of revoked certificates, and has updated the trusted
certificate list in Network
Security Services (NSS) 3.131.1.
There is a single-page
site about the compromise that goes into more detail. According to the site
the certificates have also been blocked in Chrome since October 17, Apple
devices since the 19th, and Microsoft blocked the certificates on the
20th. There is also a table that displays whether a browser or other client
still trusts the compromised certificates.
The NetBSD foundation has issued
instructions to block the certificates on NetBSD installations. Users of
other browsers and operating systems may wish to check for updates or guidance
to disable the compromised certificates.
Член 4 Страните по Договора ще се консултират съвместно всеки път, когато по мнение на някоя от тях е възникнала заплаха за териториалната цялост, политическата независимост или сигурността на която и да е от тях.
Член 5 Страните по Договора се договарят, че въоръжено нападение, предприето срещу една или повече от тях, в Европа или в Северна Америка, ще се разглежда като нападение срещу всички тях, вследствие на което те се договарят, че в случай на такова въоръжено нападение всяка от тях, упражнявайки правото си на индивидуална или колективна самоотбрана, признато в член 51 от Устава на Организацията на обединените нации, ще окаже помощ на нападнатата страна или страни по Договора, като незабавно предприеме, индивидуално и съгласувано с останалите страни по Договора, такива действия, каквито смята за необходими, включително употребата на въоръжена сила, за възстановяване и поддържане на сигурността в Северноатлантическата зона.
Военните конфликти, в които е участвала България през своята най-нова история, винаги са били предшествани от поляризация в общественото мнение. Достатъчно е да си припомним разделението, което цари сред българския елит и избирателите в навечерието на двете световни войни, както и отчаяните опити на българските монарси да лавират между силните на деня в Европа. Някой би нарекъл тези исторически събития специфични само за българското житие, но ако погледнем историята на международните отношения ще видим, че не е така.
Въпреки че войната взема много човешки жертви и води до тотално разрушение, може би една от най-фаталните последици от нея е слагането на край на солидарността между хората. Всъщност смело можем да кажем, че днес България дори няма нужда да влиза в нов военен конфликт, тъй като тук вече се води вътрешна война, а изходът от нея ще е решаващ за дългосрочното бъдеще на нашата страна.
Но какво тогава трябва да ни притеснява в случващото се съвсем близо до нашите териториални води?
Войната в Украйна продължава вече четири години, а през цялото това време нашата морска граница изглеждаше неестествено спокойна. Анексията на Крим през 2014 г. и последвалата ескалация на конфликта останаха някак си далечни за българина, който обикновено посрещаше новините за ставащото с отегчение от факта, че постоянно го занимават с едно и също, с недоверие, че войната може да стигне до България, или с неоправдана истерия, че страната ни ще стане жертва на амбициите на Запада Русия да бъде победена на всяка цена.
Тези наративи бяха същинското проявление на войната у нас, тъй като в началните ѝ етапи Москва нямаше интерес да я изнася извън границите на Украйна. Реално целта на Русия в тази война е Америка, но пътят към нея минава през Украйна – една руска победа би принудила Вашингтон отново да приеме Москва като глобален актьор в международната система. САЩ обаче декларираха категоричната си подкрепа за България и Румъния, а Европа започна усилено да се въоръжава. Истинската война на Стария континент се водеше на когнитивно ниво – в интернет, в социалните мрежи, дори и в медиите.
Нещата започнаха да се променят след 28 февруари тази година, когато САЩ нанесоха първите си въздушни удари срещу Иран – преломен политически момент, който за пореден път показа, че Вашингтон разглежда ядрената програма на Техеран като екзистенциална заплаха за сигурността си. По това време Украйна вече разполагаше с най-силната армия от дронове в Европа, докато Русия се опитваше да допълни конвенционалната си стратегия с ядрено говорене. В същото време присъединяването на Финландия и Швеция към НАТО лиши Русия от стратегическото ѝ превъзходство в Калининградска област, а Полша даде да се разбере, че е готова да посрещне решително всяко руско нападение срещу границите ѝ.
Така Черно море остана единствената уязвима точка, в която Кремъл можеше директно да провокира Алианса. Тази опасност не беше отчетена навреме нито от България, нито от останалите страни в региона, тъй като падането на иранския режим изглеждаше въпрос на време, а подобен развой би отслабил стратегическите позиции на Русия и би освободил американски ресурс за възпиране на Москва. Оказа се обаче, че Иран има технологии и стратегия, с която да воюва, и това сякаш даде кураж на Русия да продължи да предизвиква НАТО.
Основната причина за уж закъснялото желание на Русия да изнесе конфликта се появи, когато руските загуби на фронта рязко се повишиха, след като Киев започна все по-широко да прилага асиметрична стратегия, основана на масовото използване на дронове. Нещо повече, Кремъл имаше нужда конфликтът да излезе извън рамките на руско-украинската война, за да легитимира собствената си теза, че истинският сблъсък е със САЩ и НАТО. Това би могло да стане по два начина.
Първият е директен военен конфликт между Вашингтон и Пекин за Тайван – сценарий, на който Русия, изглежда, много се надяваше, но той така и не се реализира. Подобен конфликт би отворил втори фронт на глобалното противопоставяне със САЩ и би отклонил американски ресурси и внимание от войната в Украйна. За Китай обаче това би означавало да рискува собствения си възход в името на руския стратегически интерес.
Това постави руските политици в особено положение – те или трябваше да признаят, че в продължение на четири години Русия не може да победи Украйна, или все пак да търсят как да изнесат конфликта извън украинските граници, с което да покажат на партньорите си, че войната с Киев е част от американския план за унижението на руснаците.
Как би започнала войната в Черно море?
Първото и основно условие за пламването на конфликт в Черно море парадоксално са действията на самото НАТО, или по-конкретно стъпките, които Алиансът ще предприеме, за да отговори на инцидентите с нападнатите кораби в басейна. Тук следва да отбележим, че макар в официалната позиция на българското правителство да не се назовава по име държавата, която стои зад тези атаки, случващото се недвусмислено е заплаха за националната ни сигурност. И не само защото е в териториалните ни води, а защото задълбочава разделението в обществото, което съществува от началото на войната в Украйна. Всъщност управляващите вече няколко пъти намекнаха, че всички доказателства сочат в полза на Русия, макар че самата Русия отрича.
Ситуацията е класическа провокация към страна членка на НАТО. Такива провокации суперсилите са предприемали по време на Студената война, за да проверят какви ще бъдат действията на отсрещната страна. Или по-просто казано – хвърлена ръкавица. Затова и най-недалновидното, което Алиансът би могъл да направи, е да не демонстрира решителност.
За щастие, в Европа вече се чуха множество гласове в подкрепа на страната ни, а България, Румъния и Турция вече обсъждат задълбочаване на тристранното си сътрудничество за сигурността и безопасността на корабоплаването в Черно море. До голяма степен това изчерпва и прагматичните стъпки, които бихме могли да предприемем на този етап, макар в публичното пространство все повече да се дискутира задействането на член 4 от Северноатлантическия договор.
Може ли обаче член 4 може да влоши нещата?
Механизмът на съюзническите консултации, залегнал в член 4, е доста стар и може да служи като последна политическа бариера пред ескалация, която би поставила на дневен ред член 5. Тук идва и обективната реалност – Русия иска точно това. Атаките с дронове ще продължат, докато член 4 не бъде задействан, което ще даде основание на Москва да започне подготовка за потенциално нахлуване в Европа просто защото нито руският президент, нито неговите генерали ще чакат задействането на члена за колективната отбрана.
САЩ са свръхфокусирани върху войната с Иран и възпирането на Китай и макар техните войски все още да са разположени в Европа, реалната тежест за отбраната на Стария континент пада върху самите европейци. Затова и един потенциален конфликт между Русия и Алианса в Черно море би могъл да започне именно след задействането на член 4 или ако някой от съюзниците директно отговори на провокациите (освен ако договорката между Тръмп и Путин за руския дизел не се окаже толкова обещаваща, че да разубеди руснаците във „виновността“ на Европа).
Основният предупредителен сигнал за евентуална война в Европа би бил зачестяването на атаките с дронове в Черно море, а той вече е налице. Големият проблем е, че ако НАТО задейства член 4, Москва може да използва това като аргумент пред Тръмп, че Европа, а не Русия тласка Алианса към война.
За Кремъл подобно внушение не противоречи на стратегическото му противопоставяне със САЩ – напротив, то би могло да отслаби трансатлантическата връзка и да остави европейските съюзници без пълната подкрепа на Вашингтон. Ролята на Америка ще е решаваща при евентуален опит на Русия да нападне европейските държави – ако това се случи по време на междинните избори, може да бъде използвано от привържениците на Тръмп като аргумент Вашингтон да не се въвлича в още една война.
Изглежда, че американският президент е сред малкото лидери, които разполагат с реални инструменти да повлияят върху сметките на Кремъл за евентуална ескалация в Европа. Сделката между Тръмп и Путин за руския дизел би могла да даде на Москва допълнителен икономически стимул да се въздържа от подобни провокации, но руснаците едва ли ще се трогнат от това.
Да, някой би нарекъл този опит изключително циничен, защото предложението Европа отново да купува руски газ я връща в прегръдката на Москва, докато зависимостта ѝ от американските енергийни доставки остава. Но и Тръмп не би се трогнал от това, тъй като е доста обиден на някои европейски държави, че не го подкрепиха във войната с Иран.
В същото време Москва не трябва да си прави илюзии, че САЩ ще гледат безучастно какво се случва в Европа. В най-лошия случай ще предприемат политика на офшорно балансиране, отваряйки по-широк фронт за възпиране на Русия на територията на НАТО. В публични изказвания на високопоставени военни от Алианса се допуска при евентуална руска атака той да нанася бързи удари по военни цели на руска територия, включително в района на Санкт Петербург, при избягване на ядрена ескалация.
Стратегическият проблем е, че Алиансът никога не е бил предвиден да напада или да воюва срещу СССР, а да защитава Европа от него. И ако след 11 септември беше ясно, че елитните части на НАТО могат да се справят с „Ал Кайда“, когато срещу тях стои ядрена сила, сценариите могат лесно да се размият.
Най-решаващата променлива за изход от ескалацията обаче остава ядреният фактор, който на този етап е и най-успокояващият. Докато Русия говори как ще изпепели цяла Европа, едва ли Европа има от какво да се страхува – това е остаряла реторика от съветско време, която може да е в състояние да разбуни духовете в обществото, но сама по себе си не означава непосредствена ядрена заплаха за Алианса. Реалната употреба на ядрено оръжие срещу страна от НАТО би създала риск от ответен удар и ескалация с катастрофални последици и за самата Русия.
Когато обаче подобно говорене отстъпи място на зачестили провокации от страна на Москва, това би могло да е сигнал, че Русия се готви да изнесе конфликта извън границите на Украйна. Сред факторите, които ограничават подобна ескалация, остава способността на САЩ бързо да съсредоточават военни сили там, където възниква заплаха, включително чрез самолетоносачите си, разположени в Близкия изток. Един от тях е атомният самолетоносач „Джордж Х. У. Буш“, чието Седмо палубно авиокрило разполага със значителни възможности за нанасяне на удари по наземни цели. Затова за Москва би било по-изгодно да избягва пряка провокация срещу Алианса и да остави НАТО да направи следващия ход.
Ролята на България и реалната опасност от война
Може би най-сигурният сценарий, при който Русия няма да бави започването на война срещу европейците и би действала решително срещу Алианса, е, ако САЩ започнат сухопътна операция срещу Иран. Тогава американските стратегически ресурси ще са толкова ангажирани с военните действия в гигантската държава, че едва ли ще успеят да се намесят пълноценно в Европа, освен с настоящото си военно присъствие на Стария континент, което и без това е силно редуцирано.
Една голяма стратегическа грешка, която европейците допуснаха, е, че ако иранският режим беше свален по-рано, южният фланг на Русия отдавна щеше да бъде оголен и Москва щеше да възприеме малко по-различен подход. За нещастие, това така и не се случи, като нежеланието на Европа да се намеси не трябва да се търси само в една посока – както вече пояснихме в един от предишните материали.
В останалите сценарии всичко зависи от реакциите на НАТО на следващите провокации, а отговорът на България ще е особено важен за целостта на Алианса. В това отношение новите многостранни формати в Черно море са обнадеждаващи.
Липсата на противоракетна система и противодронова защита обаче крият сериозни рискове от инцидент, което от своя страна се корени в погрешната стратегия, по която се модернизираха въоръжените сили на страната ни. Тази модернизация беше завършена някак си на парче, а крайъгълният камък на всяка подобна реформа е придобиването на способности, с които една държава да се защитава от ракети и дронове, следвано от обновяване на военния авиопарк и флота. Затова и до осигуряването на такива ресурси съюзническата подкрепа от съседите ни ще има водеща роля, а присъединяването ни към Европейската инициатива за защита от дронове е повече от закъсняло.
И накрая, нека не забравяме, че прибързаното активиране на член 4 и член 5, както и необузданите призиви НАТО да използва „цялата си мощ“ срещу Русия са проява на същата истерия, която наблюдаваме и в онзи сегмент от обществото ни, който мечтае за завръщането на добрия стар СССР.
Реалностите обаче са други – въпреки стратегическата надпревара и санкциите САЩ и Русия продължават да имат пресечни икономически и енергийни интереси.
Отношенията с Китай и Иран заемат далеч по-важно място в дневния ред на американската президентска администрация и това може да се промени най-рано след междинните избори. Ето защо решението да бъде въведен мораториум върху военните удари срещу цивилните и търговските кораби в Черно море и засилването на натовското присъствие в черноморския регион са може би най-адекватната политика, която страните в региона могат да следват на този етап. Така, ако един ден се стигне и до задействането на член 4 или член 5, България ще е изчерпала възможностите за деескалация, преди да потърси съюзническа защита, а за Москва ще бъде далеч по-трудно да представи този избор като поредното българско „предателство“ спрямо Русия и да задълбочи още повече разделението в българското общество.
Заглавно изображение: Военнослужещи и техника на НАТО по време на учението Steadfast Dart2026, което тества способността на Алианса за бързо разполагане и подсилване на силите му. Снимка: НАТО
OpenBSD 8.0 has been
released. There are many new features, including the addition of hibernate
support for arm64, an increase in the kernel virtual address space for amd64 to
512GB, quite a few improvements for the qwx driver that supports
Qualcomm WiFi 6 devices, and much more. See the full changelog for
details.
Cloudflare and VoidZero are now working with Max Schwenk of Owner.com on tsrs, a Rust port of the TypeScript compiler. We are doing this work in close collaboration with the TypeScript team, and incubating tsrs as part of the Oxc JavaScript compiler toolchain.
Our goal is to help developers spend less time waiting for their code to be checked and more time building. Making TypeScript faster and more memory-efficient also helps bring complete development environments to more places, including right in your browser.
To be clear, we are not forking TypeScript. We believe the TypeScript team should remain in full control of the language’s design and direction. They have maintained a long-term vision while guiding TypeScript’s adoption across the JavaScript community. We do not want to change that.
The TypeScript team can move quite fast on many things, but for some features they may spend years intentionally exploring options and making prototypes before picking the right implementation. A Rust port has to follow those decisions closely, or it will eventually fall apart and become incompatible. We have to preserve the TypeScript language strictly based on its original implementation – and the TypeScript team should remain solely responsible for deciding what that looks like.
Performance and memory improvements
Early benchmarks of our Rust port of TypeScript are promising: tsrs is up to 8x faster and uses ~70% less memory compared to TypeScript 7.0 when using the same number of type check workers:
As you can see, the next version of TypeScript already brings many performance improvements, making TypeScript 7.1 beta up to 2.5x faster than TypeScript 7.0. Some of these optimizations were upstreamed from tsrs, and we’re hoping to find more.
You may have seen recent benchmarks of different TypeScript ports with various performance claims, often due to using larger machine types and different options compared to TypeScript’s defaults. We worked with the TypeScript team to ensure the above benchmarks are comparing the same configuration.
By default, tsrs ships with an adaptive configuration dependent on the machine type that uses more memory but is even faster:
Try tsrs
TypeScript in Rust aims to be a faithful port of TypeScript. You can try an experimental release by installing the tsrs package from npm:
npm install tsrs
npx tsrs
Why now?
We’ve seen many attempts at porting TypeScript to other languages over the years. Because of the complexity involved, only one of the ports succeeded: the TypeScript team’s port of TypeScript from JavaScript to Go.
However, frontier AI models can now do large-scale ports almost independently in a matter of days. We have now seen slopforks, faithful ports, and completely re-architected versions of TypeScript in Rust or C++. There is clearly a demand for even faster TypeScript.
Why Rust?
You might be thinking: “TypeScript’s Go port already made TypeScript 10x faster and far more memory efficient than the previous version written in TypeScript. Why isn’t that enough?”
However, it’s not just about speed. Rust offers some unique advantages: running in WebAssembly. The Rust + Wasm story has always been strong, and one of the reasons comes down to the fundamentals of Rust’s language design. When you compile a Go program to Wasm, you have to compile Go’s garbage collector along with it. But Rust’s memory management model enables straightforward memory interactions between a WebAssembly guest and host. This is one of the key things that makes Rust a much better fit for the WebAssembly use-case: memory efficiency.
Cloudflare Workers have supported Wasm for a long time. Just a few weeks ago we announced supporting native Rust in Workers with the new Emscripten target for wasm-bindgen. When you run entire software build and deployment systems in tight loops on Workers, the benefits of a small memory footprint pay off quickly. It means you can run these workloads so efficiently that it’s now possible to run fully encapsulated development systems in places where they couldn’t have been run before.
This enables new possibilities when combined with agents: You are now able to run a development toolchain end-to-end in a fully sandboxed environment on Cloudflare. But with Wasm, you can also run those environments safely client-side in your browser, or on an embedded device, or an IoT application.
How will the tsrs port be maintained?
First, we are working with Theo Browne to merge tsc-rs and tsrs into a single package that supports all of TypeScript’s features including Language Server Protocol (LSP) and content mappers. Second, we’ve seen a lot of success with how we maintain Vinext in sync with its upstream, Next.js. We explained how we do this in a recent blog post:
Each morning, an agent reviews the changes, fetches diffs, and opens tracking issues for anything that could affect Vinext. Every night, the compatibility matrix is regenerated as we run the Next.js test suite against Vinext. When one of these tests or issues reveals a gap, agents are now in the position where they can identify the change across both codebases, build a reproduction, port any relevant tests, and propose a fix.
We will apply the same process to TypeScript, taking extreme care that we don’t introduce diverging behaviors from upstream TypeScript. When we come across performance improvements, we’ll attempt to contribute them back to the TypeScript Go codebase so everyone wins.
Finally, we recognize that there are some differences to the upstream version of TypeScript right now, like for example the order in which diagnostics are printed. We aim to reduce those differences to a minimum by the time we publish a stable release.
What’s next?
Cloudflare is already the home of many free and open source Rust tools that power the JavaScript ecosystem, such as Vite, Rolldown, Oxlint, and Oxfmt. With more than 10 million developers building on Cloudflare, we care a lot about making the underlying developer toolchain faster, more portable, and easier to run in more places. We are excited to experiment with deeper tsrs integrations into our stack, for example for type-aware lint rules in Oxlint.
Like with Vinext, our goal is to run tsrs as a well-maintained healthy open source project — without getting in the way of TypeScript itself. The Oxc team has already begun refactoring the codebase to make it faster, use less memory, and make it maintainable. We know the TypeScript team is taking this seriously – they are experimenting with memory and performance improvements for tsc. We are excited to collaborate with the TypeScript team and the JavaScript community to build the best and fastest implementations of TypeScript together.
I am delighted to share the news that Blythe Masters has been appointed as the next Chair of the Raspberry Pi Foundation’s Board of Trustees. Blythe brings a wealth of experience to our governance at a time when our mission to enable all young people to realise their full potential through the power of computing and AI has never felt more urgent.
Blythe Masters
Blythe is one of the most prominent figures in global financial services and fintech. A graduate and Senior Scholar of Trinity College, University of Cambridge, she spent nearly three decades at JPMorgan, rising to its Executive Committee and holding senior leadership roles including Chief Financial Officer of the Investment Bank and Head of Global Commodities. After leaving JPMorgan in 2014, Blythe served as CEO of Digital Asset and later became a Founding Partner at Motive Partners, the fintech-focused investment firm. Most recently, Blythe served as Group CEO of FNZ, the global wealth technology platform and Motive Partners portfolio company.
Blythe has extensive corporate governance experience, currently serving as the Chair of JPMorgan Securities plc and non-executive director on the board of SymphonyAI. She has previously served on numerous other boards including A.P. Moeller Maersk, Credit Suisse, Santander Consumer USA, Forge, and GCM Grosvenor.
Blythe also has significant experience in nonprofit governance, having served as the co-chair of the Global Fund for Women, vice chair of ID2020, chair of the NYC chapter of Susan G. Komen Breast Cancer Foundation, chair of the Hyperledger Foundation, and numerous other trustee roles.
Blythe takes over the Chair from Sir John Lazar who has led the Board of Trustees since 2020. Under Sir John’s leadership the Foundation has supported hundreds of thousands of educators and tens of millions of students all over the world to develop the skills, knowledge, and mindsets to shape their world through computing and AI.
Sir John Lazar
We have achieved so much under his leadership and I have learned a huge amount from working with him. We are all profoundly grateful to Sir John for his contribution.
Blythe will take up the role at the end of March 2027 and John will be staying on to manage the transition and handover. While it is hard to imagine a world where John isn’t our Chair, I am genuinely excited about the prospect of working with Blythe.
What is a Board of Trustees?
As a charity, the Foundation is governed by a Board of Trustees that is responsible for ensuring we use our resources effectively to advance our charitable goals. We are fortunate to have an exceptionally strong and diverse group of Trustees who bring significant experience and expertise from a wide range of backgrounds. Trustees generally serve two three-year terms. Trustees are volunteers who provide their time and expertise to the Foundation for no remuneration.
Justin.sh is reporting on a confidential Cellebrite document that has been leaked to him:
Cellebrite calls it Advanced Unlocks (AU from here on), not to be confused with the “advanced unlocking services” they’ve marketed for years. A press release from earlier this year confirms AU is a new product for 2026.
[…]
According to Cellebrite, AU:
is a “next-generation AFU vector that is more resilient to Apple’s OS changes”
works with Stolen Device Protection enabled, which tightens USB restrictions
is enabled by a dedicated appliance with a stated range (!) of about 8 meters.
AU = Advanced Unlocks, Cellebrite’s term. AFU = after first unlock.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.