Intel, 14A sürecinde kritik eşiğe yaklaşıyor: 10A ve 7A ise ufukta göründü
Intel, 14A üretim sürecinde 2028 risk üretim hedefini korurken 10A ve 7A teknolojilerinin geliştirilmesine başladı. Şirketin en yeni işlemcileri ise 18A süreciyle üretiliyor.
Intel, 14A üretim sürecinde 2028 risk üretim hedefini korurken 10A ve 7A teknolojilerinin geliştirilmesine başladı. Şirketin en yeni işlemcileri ise 18A süreciyle üretiliyor. The Problem We Were Actually Solving
We needed to support a large player base with thousands of concurrent players for the Treasure Hunt game mode. The game’s event-driven architecture meant that every player movement, item pickup, and treasure collection triggered a flurry of events that needed to be processed quickly and efficiently by the server. The catch was that the event bus was prone to congestion, leading to unpredictable delays and stalls.
What We Tried First (And Why It Failed)
Initially, we attempted to mitigate the congestion by introducing multiple event bus instances, each with its own set of event handlers. We also implemented a load balancer to distribute the traffic across multiple servers. However, this setup ultimately led to a “server farm effect,” where the load balancer would redirect traffic to a server that was already congested, resulting in an even bigger stall.
In hindsight, we should have recognized that our approach was focused on “distributing the pain” rather than “mitigating it.” By spreading the congestion across multiple servers, we were merely delaying the inevitable stall, rather than truly addressing the root cause of the problem.
The Architecture Decision
After a series of intense discussions with my team, we decided to take a different approach. We introduced a concept called “event chunking,” where we grouped related events into larger chunks and processed them in batches. This allowed us to significantly reduce the number of events being processed in real-time, making the system much more efficient and scalable.
We also implemented a custom event queue using Amazon SQS and a message-driven architecture. This enabled us to offload the event processing to worker nodes, freeing up the main server to focus on handling game logic and player input.
One of the key insights we gained from this experience was the importance of understanding the specific nature of the events being processed. By analyzing the event patterns and frequencies, we were able to optimize the event chunking and message-driven architecture to better suit the needs of our game.
What The Numbers Said After
After rolling out the new architecture, we were able to achieve a significant reduction in stall times, from an average of 10 minutes to under 5 seconds. The increased scalability also enabled us to handle a much larger player base, with our server supporting over 5,000 concurrent players with ease.
The metrics also revealed that the event chunking approach reduced the number of events being processed in real-time by a factor of 10, resulting in a corresponding decrease in server load. We also observed a significant reduction in latency, from an average of 200ms to under 50ms.
What I Would Do Differently
If I had to do it over again, I would focus even more on understanding the specific nature of the events being processed and the underlying systems requirements. I would also invest more time in analyzing the event patterns and frequencies to inform the design of the event-driven architecture.
One area I would explore further is the use of more advanced load balancing techniques, such as machine learning-based load balancers, to identify and redirect traffic to less congested servers. I would also consider implementing more sophisticated monitoring and alerting systems to detect early warning signs of congestion and prevent the stall from occurring in the first place.
In conclusion, the experience of building a scalable Hytale server taught me the importance of taking a holistic approach to solving complex engineering problems. By understanding the specific requirements of the system, analyzing the underlying systems and data, and implementing targeted solutions, we can create more efficient and scalable systems that meet the needs of our users.
I work on Camdiv, an anonymous one-to-one video chat. You open the page, you get matched with a stranger, you talk. It’s the Omegle-style format, and from the outside the hard part looks like the video: WebRTC, NAT traversal, keeping latency down.
It isn’t. WebRTC is mostly a solved problem. The hard engineering is moderation. You’re putting two anonymous strangers on a live camera together, with almost no friction, and you have a few seconds to catch it if one of them does something that gets your platform pulled from every app store on earth.
Three things shaped every decision below, and they fight each other the whole way. The first is cost: moderate live video naively and the bill alone will sink you. The second is false positives, because a wrong ban is a real person you just kicked off for nothing. The third took a near-miss to learn, so it gets the longest section here: you can’t actually trust the video frame you’re moderating.
Why live anonymous video is the worst moderation surface
Most moderation problems give you time. A user uploads a photo or writes a comment, and you can scan it before anyone else sees it. The content sits still while you decide.
Live video gives you none of that:
So whatever you build has to be automated, run per frame, stay fast, and be cheap enough to run nonstop. Those goals do not sit comfortably together.
The pipeline
The browser samples a JPEG from the local video every few seconds and sends it over Socket.IO to our backend. The backend forwards it to a separate moderation microservice (a small FastAPI app on its own host) over HTTPS, locked down with an internal shared key and an origin allowlist at the reverse proxy. The service runs the classifier and returns a compact verdict.
flowchart LR
A["Browser<br/>samples a JPEG every few seconds"] -->|Socket.IO| B["Backend<br/>Node / TypeScript"]
B -->|"HTTPS + internal key<br/>origin allowlist"| C["Moderation service<br/>FastAPI, isolated host"]
C -->|"verdict JSON:<br/>nsfw, minor, confidence, reason"| B
B --> D{Act on the verdict}
D -->|explicit| E[Confirmation + ban path]
D -->|possible minor| F[Human review queue]
D -->|safe| G[Do nothing]
Splitting moderation into its own service pays off in a few ways. A crash or memory spike in the ML host doesn’t take the chat backend down with it. The two scale independently, since the Node app is I/O-bound and the moderation box is CPU- and GPU-bound. And the heavy model dependencies stay out of the application runtime, so a backend deploy doesn’t have to drag a model toolchain along with it.
The verdict shape is deliberately tiny:
{ "unsafe": false, "minor": false, "score": 0.0, "reason": "...", "source": "gemini-safe" }
Two independent booleans, a confidence score, and a short human-readable reason that lands in our logs. That reason field has paid for itself many times over when I’m trying to work out why something did or didn’t fire.
The cost wall, and why we schedule the model instead of running it on every frame
Our moderator is a vision-language model (Gemini Flash Lite). Per call it’s cheap. The trouble is the multiplication: concurrent users times a frame every few seconds is millions of calls a day. Run a VLM on all of them and the model bill, long before infrastructure, becomes the thing that kills the company.
We started somewhere more conventional: an on-box NSFW CNN (NudeNet) with an escalation tier, where ambiguous scores got a second opinion from a hosted nudity API and Google Vision’s SafeSearch. It worked. But it was three systems to keep healthy, and the CNN was biased: much better at detecting female anatomy than male, which is a real gap on a platform where most of the abuse is the latter.
We replaced the whole thing with a single VLM because it reads context in a way a pure classifier can’t. It can tell a shirtless guy on a couch from actual exposure. It handles the common trick of holding explicit content up on a phone to the camera. And it returns structured JSON I can trust to parse, with a built-in safety filter whose refusal to even describe an image is itself a useful signal.
The cost math only works because of one decision: we don’t moderate every frame. Each chat gets a small number of model calls, front-loaded into the first minute, and then we stop.
flowchart TD
F["Frame arrives for a match<br/>(session key = userId:roomId)"] --> Q{"Scheduled check due<br/>in this match's first minute?"}
Q -- no --> S["Return safe — no model call"]
Q -- yes --> R{"Within global rate<br/>and daily budget?"}
R -- no --> S
R -- yes --> C["One VLM call · consume the slot"]
C --> V["Verdict: nsfw, minor, confidence"]
The premise, borne out by our logs, is that bad actors reveal themselves quickly. They don’t behave for ten minutes and then flip. They flip in the first few seconds, because the reaction is the whole point for them.
The part that matters is the session key. The schedule is keyed per match (userId:roomId), not per user. Every new match starts a fresh schedule. Key it per user instead and someone could behave for their first 60 seconds, exhaust the schedule, then expose themselves to every later partner for free. Keying per match means partner #2 is a brand-new session with a brand-new set of checks. You can’t outwait the system by being patient once.
On top of the per-match schedule there are global backstops: a rate limit, a daily budget ceiling, one in-flight call per room, and a lock that dissolves a room’s moderation the moment it returns an unsafe verdict. A bad chat costs exactly one billable model call instead of a flood of them.
The frame you can’t trust
Here’s the section I’d tell my past self to read first.
The model returns two independent flags: is this explicit, and does the person look like a minor. The naive enforcement rule writes itself: explicit plus minor equals instant permanent ban, no appeal, done.
We deliberately don’t do that, and here’s the attack that taught us why.
The frame we moderate is sampled and sent by a client. In a peer-to-peer video session, the bytes we classify can’t be cryptographically proven to have come from the partner’s live camera. A malicious client can send a frame of its own choosing. So if a single AI verdict on an unauthenticated frame triggered an instant permanent ban, any user could permanently ban any partner just by feeding our pipeline a chosen image. The most severe, least reversible action in the system would be trivially weaponizable by the person who stands to gain from it.
So we split enforcement by how severe and how reversible the call is:
flowchart TD
V["VLM verdict: nsfw, minor"] --> M{"Looks like a minor?"}
M -- yes --> H["Human review queue<br/>(HIGH priority if also explicit)<br/>never an automatic ban"]
M -- no --> N{"Explicit?"}
N -- no --> OK["Safe · do nothing"]
N -- yes --> CF{"Single frame at<br/>very high confidence?"}
CF -- yes --> BAN["Enforce ban + capture evidence"]
CF -- no --> ACC["Add to confidence over<br/>a short rolling window"]
ACC --> T{"Evidence adds up?"}
T -- yes --> BAN
T -- no --> WAIT["Wait — no action yet"]
Anything that flags a possible minor goes to a human review queue and is never auto-banned, however confident the model is. A person makes that call, looking at captured evidence, because the cost of getting it wrong in either direction is too high to hand to a script. Explicit-but-adult content goes through the confirmation path below.
If you take one thing from this post, take this: in any system where the input can be shaped by the party who benefits from the outcome, an automated decision is an attack surface. Authenticate the input before you automate the verdict.
Not banning the wrong people
Even for clear-cut explicit content, one frame shouldn’t end someone’s session. Cameras produce garbage: bad lighting, a weird angle, a half-second of motion blur that a model misreads.
So a single frame only acts immediately if it comes back at very high confidence. Below that bar, we add up confidence across a short rolling window and act only once the evidence agrees with itself. A one-off false flicker never reaches the threshold. A genuinely explicit stream trips it almost at once, because frame after frame says the same thing.
We check three signals when we ban: IP, a device fingerprint, and the account (sign-in is Google, with an age-verification gate). Stacking them makes coming back more than a one-click affair, without banning everyone behind a shared NAT because of one person.
Reports, without taking them at face value
Users can report each other. We treat a report as a signal, never as a verdict, because a report is weaponizable too.
Image reports (nudity, suspected minor) get validated by the model. We send the reported snapshot through the classifier, bypassing the schedule since a human explicitly asked us to look, and let that be the source of truth. High-confidence explicit gets enforced, borderline goes to human review, suspected-minor always goes to human review, and a clean frame quietly drops the report.
Reports we can’t check with an image model, like verbal or racial abuse, work differently. There we use a weighted score: independent reporters each add weight to a target, and a ban only triggers once enough distinct people report the same person inside a window. One furious stranger can’t get you banned. A pattern of them can.
Failing open, on purpose
Eventually your moderation service will be unreachable. A deploy, a crash, a network blip. You have to decide ahead of time what happens to live chats during that window: block everyone, or let them through?
We chose to fail open, behind a circuit breaker. After several failures in a row the backend trips the breaker, stops hammering the dead service for a cool-off period, then sends one test call to see if it’s back. While it’s tripped, chats keep flowing unmoderated.
stateDiagram-v2
[*] --> Closed
Closed --> Open: consecutive failures exceed threshold
Open --> HalfOpen: cool-off elapsed
HalfOpen --> Closed: test call succeeds
HalfOpen --> Open: test call fails
note right of Closed: calls flow normally
note right of Open: skip moderation,<br/>chats continue
It’s an uncomfortable tradeoff and I won’t pretend otherwise. It’s only defensible because of what’s around it: the per-match schedule re-checks every new pairing, user reports keep working, the face-presence gate still runs, and every action is logged so we can act after the fact. Failing closed, which freezes everyone’s video the instant the ML box hiccups, is its own kind of harm, and on a real-time product it’s the more visible one. Pick your failure mode on purpose. Don’t let it be an accident of which try/catch you forgot.
Due process: evidence and appeals
Automated enforcement gets things wrong sometimes. Ship it without a way to be wrong gracefully and you’ve built something you’ll regret.
So every ban captures the triggering frame as evidence and stores it server-side. Every ban is appealable. An admin reviews the evidence and either upholds or overturns it, and overturning also deletes the stored evidence. Bans persist with their trigger, confidence, and reason, so there’s an audit trail. The appeals queue isn’t something you bolt on later. It’s part of the enforcement system, and having it is what lets you turn the automation up at all.
What’s still hard
I don’t want to end on a victory lap. A few things here are genuinely unsolved for us:
What keeps me interested is that almost none of this is about video. It’s about building enforcement cheap enough to run nonstop, accurate enough to trust with real consequences, and fair enough that the appeals queue doesn’t make you wince. If you want to see where it ends up, it’s live at Camdiv.
Happy to go deeper on any piece in the comments. The scheduling math and the fail-open call are the two I’d most like to be argued with about.
Hola comunidad,
Hoy quiero compartir con ustedes sobre un servicio muy interesante que de manera simplificada nos ayuda a garantizar la resiliencia y disponibilidad de nuestra información en la nube: AWS Backup.
Además de explicar sus conceptos básicos, estaré detallando cómo implementar una estrategia de copias de seguridad robusta: Cross-Account y Cross-Region que en español sencillo es crear copias de respaldo en una región distinta dentro de una cuenta distinta de donde está el repositorio de información.
¿Qué es AWS Backup?
AWS Backup es un servicio de copias de seguridad completamente administrado por AWS diseñado para proteger los datos de diferentes servicios que almacenan datos.
Anteriormente, administrar backups significaba crear scripts personalizados o usar configuraciones individuales por servicio (ej. instantáneas manuales para RDS, S3, DynamoDB, etc.). AWS Backup resuelve esto brindando un panel de control único donde puedes configurar políticas de respaldo que aplican de forma unificada a todos tus recursos compatibles.
Principales beneficios:
Estrategia Cross-Account y Cross-Region
Para cumplir con arquitecturas bien diseñadas y prácticas sólidas de Disaster Recovery (DR), es recomendable aislar algunas copias de seguridad adicional a las que creas en tu cuenta principal, y por ello implementamos una estrategia de respaldo en otra región y en otra cuenta.
Implementación Práctica
He preparado un repositorio público en GitHub donde puedes encontrar las plantillas de infraestructura como código para desplegar este escenario:
https://github.com/pangoro24/aws-backup-cross-account–cross-region-solution
Pasos a Alto Nivel para la Implementación:
Te invito a revisar el archivo README.md dentro del repositorio para ver los comandos detallados de despliegue usando AWS CLI. Uno de los errores comunes es la asignación de permisos en las llaves de KMS. Si no se están creando las copias de seguridad, empieza por revisar cloudtrail y ver si hay acciones de Backup denegadas por falta de permisos.
Próximos pasos: puedes intentar restaurar los repositorios de información a partir de los respaldos creados y configurar el vault lock a conveniencia.
Costo
Luego de tener el demo activado por varias semanas y donde el bucket de s3 y la tabla de dynamodb solo tienen datos de prueba, realmente el costo lo verás en las llaves de kms así que podrán realizar varios respaldos y copias antes de que decidan eliminar la infraestructura. A medida que el tamaño de los repositorios de información sea más grande, entonces sí podrías ver gastos significativos en almacenamiento de las copias, las restauraciones y la transferencia de datos entre regiones. El detalle de los costos está acá: https://aws.amazon.com/es/backup/pricing/
Conclusión
La tranquilidad de saber que tus datos están seguros, respaldados y en otra cuenta dedicada no tiene precio. AWS Backup facilita drásticamente la configuración y el monitoreo de estas estrategias de recuperación ante desastres que antes requerían un esfuerzo inmenso de desarrollo personalizado.
¿Ya estás usando AWS Backup de forma centralizada en tu organización? ¡Déjame saber en los comentarios!
Gracias por leer.
Referencias:
Most ASP.NET Core logging setups tell you that something failed — but not what actually happened during the request lifecycle.
I built AsGuard to provide lightweight request + exception logging with a built-in dashboard and minimal setup.
GitHub Repository:
https://github.com/mahmood-alsarraj/asguard
Why AsGuard?
| Feature | Description |
|---|---|
| 🚀 Queue-based persistence | Non-blocking async writes – your API never waits for database |
| 📊 Built-in dashboard | Beautiful Razor UI with dark/light mode and live updates |
| 🔒 Sensitive data masking |
[AsGuardMasked] attribute + configurable header redaction |
| 📝 Body capture | Request/response bodies with content-type allowlist |
| 🔗 Correlation IDs | Distributed tracing with configurable headers (default: X-Correlation-ID) |
| ⚡ Live SSE updates | Real-time push notifications without SignalR |
| 🗄️ Multiple databases | SQL Server, PostgreSQL, SQLite, or In-Memory |
| 📈 Exception analytics | Trends, severity summaries, and configurable alerts |
| 🎯 Host ILogger capture | Automatically captures ILogger<T> warnings/errors |
| 🔔 Alerting system | Queue pressure, exception spikes, persistence failures |
| 📡 REST API | Full programmatic access to logs and stats |
| 🧹 Retention policies | Auto-cleanup with configurable intervals |
Quick Setup
dotnet add package AsGuard
builder.Services.AddRequestLogging(options =>
{
options.DatabaseProvider = LoggingDatabaseProvider.Sqlite;
options.ConnectionString = "Data Source=AsGuard.db";
options.DashboardRoute = "/request-logs-ui";
options.DashboardUsername = "admin";
options.DashboardPassword = "admin123";
options.EnableExceptionLogging = true;
options.LogRequestBody = true;
options.LogResponseBody = true;
});
var app = builder.Build();
app.UseExceptionHandler("/error");
// After the exception handler
app.UseRequestLogging();
Navigate to “/request-logs-ui”, enter your credentials, and watch your application’s heartbeat in real-time.
Final Thoughts
Modern applications need visibility.
Sometimes you don’t need a massive observability platform — you just need a fast and practical way to inspect requests and exceptions.
That’s the problem AsGuard aims to solve for ASP.NET Core developers.
Resources:
⭐ Star the repo if AsGuard helps you!
Open source repository:
https://github.com/arijeetganguli/agentra
PyPI:
https://pypi.org/project/agentra/
AI coding agents are becoming part of everyday engineering workflows.
Cursor, Claude, Copilot, Aider, Windsurf, and autonomous coding systems are now generating infrastructure code, migrations, CI pipelines, shell scripts, and production changes.
That changes the engineering risk model completely.
Most teams are currently relying on:
That approach breaks down quickly at scale.
AI agents can:
I started building Agentra to solve this problem.
Agentra is an enterprise AI engineering control plane for coding agents.
The idea is simple:
Treat AI coding workflows with the same rigor as infrastructure and DevSecOps systems.
What Agentra Does
Agentra sits between developers and coding agents.
It provides:
Instead of static prompt templates, Agentra dynamically builds optimized instructions based on the detected project stack.
Example:
ag init
Agentra detects:
Then it generates optimized governance instructions for:
Why Existing Approaches Are Not Enough
Most prompt engineering workflows are:
Security enforcement is usually disconnected from the actual runtime.
Agentra tries to close that gap.
Core Security Philosophy
Agentra follows several strict principles.
No Destructive Operations By Default
Examples:
EDR Safe Execution
Inline shell execution often triggers enterprise security systems.
Instead of:
python -c "..."
Agentra prefers:
create temp file → validate → execute
This reduces security tooling alerts from systems like CrowdStrike.
Secret Safety
Agentra blocks:
It prefers:
Prompt Injection Defense
Repositories increasingly contain hidden prompt attacks.
Agentra treats repository instructions as untrusted by default.
Token Optimization Matters
One thing I realized quickly:
Most AI engineering systems waste huge amounts of tokens.
Teams repeatedly inject:
Agentra aggressively minimizes context.
It uses:
The goal is:
Better outputs at lower cost.
Local First Architecture
Another important design decision:
Agentra is local first.
No hidden telemetry.
No forced cloud dependency.
No black box execution.
Enterprise engineering teams increasingly care about:
Local first architecture aligns with those requirements.
Karpathy Inspired Engineering Principles
I also wanted the platform to encourage simpler engineering.
Many AI generated codebases become:
Agentra includes engineering skills inspired by Andrej Karpathy style principles:
Enterprise Direction
The long term vision is larger than prompt templates.
Agentra is evolving into:
Think:
“DevSecOps for coding agents.”
Current Focus
The initial version focuses on:
The goal is to keep the first release focused and operationally useful.
Final Thoughts
AI coding systems are becoming part of the software delivery lifecycle.
That means:
The industry needs more than prompt templates.
It needs engineering control planes.
That is the direction behind Agentra.
Getting Started
Agentra is available as an open source Python package.
Install
pip install agentra
Initialize In Your Project
ag init
Agentra will:
GitHub Repository
GitHub:
https://github.com/arijeetganguli/agentra
The repository includes:
Contributions, feedback, and security discussions are welcome.
Like many Google Antigravity users, I was very excited about the Antigravity 2.0 announcement at Google I/O 2026.
Who would’t be enthusiastic about the new cost efficient Gemini 3.5 Flash? Plus, a standalone desktop app form factor that seems to rival Claude Code and OpenAI Codex at that!
There are a lot of great things to be eager to try it out but I want to provide some pointers in the upgrade and migration to save you some headaches and hassles later.
The upgrade path from Antigravity 1.0 to 2.0 is straightforward:
Now here’s the key point: Antigravity 2.0 is a huge departure from 1.0 in the sense that it is functionally no longer based on Microsoft’s VS Code. That means a huge majority of all the personalizations from 1.0 will not carry over to 2.0.
Yes, there was a quick patch that would let you import your customizations, including a migration flow that allows users to import settings, extensions, and keybindings from Antigravity 1.0. (Imagine a very eager person like me making the upgrade before this patch was applied). However any history and past work you’ve done in extensions like Claude, Cline, and Codex will not be carried over. Even your work history with the Gemini agents in 1.0 will not be ported.
If you want to retain as much information from your 1.0 setup, here’s the playbook I wish I’d had on day one.
Back up before you click update. Specifically, copy ~/.gemini/antigravity somewhere safe. The migration has a known quirk where past conversations, scratch space, and agent brain entries get stranded in ~/.gemini/antigravity-backup rather than carried into the new app. If you’ve already updated and your chat history looks gone, it isn’t — that’s where it went. You can rsync the backup directory back into ~/.gemini/antigravity (skip mcp_config.json, you want the new one) and restart.
Say yes to installing the Antigravity IDE alongside 2.0. The IDE isn’t being sunset — it’s positioned as a sibling product, still maintained, still the VS Code fork you remember. That’s where your keybindings, extensions, and editor muscle memory live. The cleanest mental model: 2.0 is for agent orchestration, the IDE is for everything VS Code-shaped you already do. Just don’t run both against the same working tree simultaneously — you’ll fight yourself.
If 2.0 isn’t your speed yet, you can stay on the IDE. Uninstall 2.0, install Antigravity IDE 1.23.2 from the releases page, set updates to manual. There’s no forced migration deadline on the IDE side — the deprecation pressure is on Gemini CLI users (June 18, 2026), not Antigravity IDE users.
The mental note that helped me most: this isn’t a version bump. It’s Google shipping a second product that shares a name with the first. Your 1.0 work doesn’t need to migrate — it needs to coexist. Once I stopped expecting parity and started treating 2.0 as a new tool in the kit, I felt better about this (but still licking my wounds from the re-work and missing stuff).
Here is a small failure mode that cost me time for longer than it should have.
The agent would run the test suite. Tests would fail. The agent would announce that tests failed. Then, when it needed to know which tests failed, would either guess, ask, or run the suite a second time to scrape the output. Sometimes it would run it a third time. The failing tests were right there in the output of the first run; the agent didn’t read them carefully enough to remember.
This is not the model being lazy. It is the model being honest about its attention. Test output is voluminous, the failure summary is buried at the bottom, and by the time the agent is reasoning about the next step (“which test failed, what assertion, what file”), the relevant lines have scrolled past whatever the agent actually retained. The cheapest way to get the information back is to run the command again.
Running the command again is the wrong answer. A full suite takes minutes. Doing it twice to learn something the first run already told you is a tax on every red-test loop, and the loops compound.
The fix: tee everything to a gitignored directory
The rule I added is short:
Every test command pipes through
teeinto.test-output/<scope>.log. The directory is gitignored. When you need to inspect failures,grepthe log; do not re-run the suite.
The agent’s commands now look like:
make test 2>&1 | tee .test-output/full.log
make test-parallel 2>&1 | tee .test-output/parallel.log
make vitest 2>&1 | tee .test-output/vitest.log
That is it. The fix is one Unix utility, deployed deliberately.
Why tee is the right tool
The trick is that tee does not replace the stream; it forks it. STDOUT still flows to the terminal in real time. The agent still sees the test run as it happens, still gets the streaming feedback that lets it react to a hang or an obvious early failure. Nothing about the foreground experience changes.
What changes is that the run is also persisted. After the command exits, the output exists as a file. The agent can grep -n FAIL .test-output/full.log, jump to the failing test, read three lines of context, and decide what to do without burning another full suite run to recover information.
You could imagine alternatives. Redirect everything to a file and tail it (loses interactive feedback). Tell the agent to “remember the test output” (the failure mode this is supposed to fix). Increase the agent’s context window (treats the symptom, not the cause). The tee approach is boring, which is its strength. It uses a tool that has been in every Unix shell since 1973, costs nothing, and survives every framework choice the project might make later.
The gitignored directory matters
.test-output/ is committed nowhere. It is ephemeral: overwritten on every run, never inspected by humans, never reviewed in a PR. Making it a real directory rather than /tmp keeps it scoped to the project, which means a grep from the repo root finds it without thinking.
I also keep the filenames stable. full.log, parallel.log, vitest.log; not timestamped. The agent never has to ask “which file is the latest”? The latest is the only one. If you want history, the agent can copy it before re-running. By default, nobody needs history; they need the most recent failure.
The general lesson
The interesting thing here is not tee. It is the shape of the fix.
An agent reading a 4,000-line test run and an agent grepping a file for FAIL are doing the same work in principle, but the second one is the work the tool is good at. Long, streaming output is something an agent should read past (most of it is success noise) and only return to when a question demands it. Persisting the output to disk turns the question “what failed?” from “scroll back through my context and hope” into “run a deterministic command and read the answer.”
Wherever an agent re-runs a command to recover information that was already produced, there is a tee waiting to be added. Build output. Type-check output. Linter output. Long-running scripts that print progress. Any time the command is expensive and the output is the artifact, persist the artifact. The rule shape (fork the stream, persist the artifact, grep the file) generalizes far past test runs.
The agent does not need a better memory. It needs the harness to stop throwing away information that was already on the screen.
Summary of the video https://www.youtube.com/watch?v=ttJZjP0p_uE
I have heard assembly code is the closest of how humans can write in a fashion that machines can understand. I have never understood how. Here’s the bit of how the translation occurs from assembly instruction to machine code.
In ARM Assembly, the following is the translation from assembly code to binary. After looking at each section in detail, we will try to translate ARM operations into binary operations that machine (ARM chip in this case) understands.
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:0 |
|---|---|---|---|---|---|---|---|
| cond | op | I | cmd | S | Rn | Rd | Src2 |
Cond
| Opcode [31:28] | Mnemonic extension | Interpretation | Status flag state for execution |
|---|---|---|---|
| 0000 | EQ | Equal / equals zero | Z set |
| 0001 | NE | Not equal | Z clear |
| 0010 | CS/HS | Carry set / unsigned higher or same | C set |
| 0011 | CC/LO | Carry clear / unsigned lower | C clear |
| 0100 | MI | Minus / negative | N set |
| 0101 | PL | Plus / positive or zero | N clear |
| 0110 | VS | Overflow | V set |
| 0111 | VC | No overflow | V clear |
| 1000 | HI | Unsigned higher | C set and Z clear |
| 1001 | LS | Unsigned lower or same | C clear or Z set |
| 1010 | GE | Signed greater than or equal | N equals V |
| 1011 | LT | Signed less than | N is not equal to V |
| 1100 | GT | Signed greater than or equal | Z clear and N equals V |
| 1101 | LE | Signed less than or equal | Z set or N is not equal to V |
| 1110 | AL | Always | any |
| 1111 | NV | Never (do not use!) | none |
SOME NOTES
ADD operation takes Opcode 1110 AL for always. ADDEQ it will execute if the previous instruction set Z flag to true (1). op
I
ADD, R1, R2, #0x28
cmd
| Opcode [24:21] | Mnemonic | Meaning | Effect |
|---|---|---|---|
| 0000 | AND | Logical bit-wise AND | Rd := Rn AND Op2 |
| 0001 | EOR | Logical bit-wise exclusive OR | Rd := Rn EOR Op2 |
| 0010 | SUB | Subtract | Rd := Rn – Op2 |
| 0011 | RSB | Reverse subtract | Rd := Op2 – Rn |
| 0100 | ADD | Add | Rd := Rn + Op2 |
| 0101 | ADC | Add with carry | Rd := Rn + Op2 + C |
| 0110 | SBC | Subtract with carry | Rd := Rn – Op2 + C – 1 |
| 0111 | RSC | Reverse subtract with carry | Rd := Op2 – Rn + C – 1 |
| 1000 | TST | Test | Scc on Rn AND Op2 |
| 1001 | TEQ | Test equivalence | Scc on Rn EOR Op2 |
| 1010 | CMP | Compare | Scc on Rn – Op2 |
| 1011 | CMN | Compare negated | Scc on Rn + Op2 |
| 1100 | ORR | Logical bit-wise OR | Rd := Rn OR Op2 |
| 1101 | MOV | Move | Rd := Op2 |
| 1110 | BIC | Bit clear | Rd := Rn AND NOT Op2 |
| 1111 | MVN | Move negated | Rd := NOT Op2 |
S
ADDS R1, R2, R3 means, put on the status like whether the operation will be Zero, Negative, Carry (this will be shown in CPSR register – which we will cover but not in this article)ADDS operation will set S status to 1 and let us start tracking the status. Rn (19:16)
ADD R1, R2, R3 Rn is R2
Rd (15:12)
ADD R1, R2, R3 Rd is R1
Src2 (11:0)
Immediate
| 11:8 | 7:0 |
|---|---|
| rot | imm8 |
ROR for rotate right. Register
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shamt5 | sh | 0 | Rm |
Register-shifted Register
| 11:8 | 7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|
| Rs | 0 | sh | 1 | Rm |
sh table
| Instruction | sh | Operation |
|---|---|---|
| LSL | 00 | Logical shift left |
| LSR | 01 | Logical shift right |
| ASR | 10 | Arithmetic shift right |
| ROR | 11 | Rotate right |
STARTING WITH THE EASY ONE ADD R5, R6, R7
Let’s unpack one section at a time
Combining them leads to
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 0100 | 0 | 0110 | 0101 | 00000 | 00 | 0 | 0111 |
| cond | op | I | cmd | S | Rn | Rd | shamt5 | sh | N/A | Rm |
Nicely formatted binary here:
1110 0000 1000 0110 0101 0000 0000 0111
Care to convert to hex?
0xE0865007
SLIGHTLY HARDER: ADD R5, R6, R7, LSR #4
#4 is a literal valueLSR has sh code as 01LSR amount is 4 so shamt5 is 00100| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 0100 | 0 | 0110 | 0101 | 00100 | 01 | 0 | 0111 |
| cond | op | I | cmd | S | Rn | Rd | shamt5 | sh | null | Rm |
LET’S DO MORE: ADD R0, R1, #42
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:8 | 7:0 |
|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 1 | 0100 | 0 | 0001 | 0000 | 0000 | 00101010 |
| cond | op | I | cmd | S | Rn | Rd | Rot | imm8 |
BRING SOME MORE! SUB R2, R3, #0xFF0
1100 and 7:0 1111 1111
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:8 | 7:0 |
|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 1 | 0010 | 0 | 0011 | 0000 | 1100 | 11111111 |
| cond | op | I | cmd | S | Rn | Rd | Rot | imm8 |
WHAT ABOUT THIS? LSL R0, R9, #7
MOV R0, R9, LSL #7
MOV R0, R9, LSL #7 applies to the following syntax: MOV{S}{cond} Rd, Operand2 where operand2 is (according to page 244 the same guide) can be Register with optional shift.. Hence, on page 246 of the guide it says, register with optional shift, is Rm{, shift}. | 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0000 | 00111 | 00 | 0 | 1001 |
| cond | op | I | cmd | S | Rn | Rd | shamt5 | sh | null | Rm |
OK TAKE A BREAK AND COME BACK! ROR R3, R5, #21
MOV R3, R5, ROR, #21
LSL above..| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0011 | 10101 | 11 | 0 | 0101 |
| cond | op | I | cmd | S | Rn | Rd | shamt5 | sh | null | Rm |
KEY TAKEAWAY:
OK AFTER YOUR DINNER… LSR R4, R8, R6
MOV R4, R8, LSR, R6
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:8 | 7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0100 | 0110 | 0 | 01 | 1 | 1000 |
| cond | op | I | cmd | S | Rn | Rd | Rs | N/A | sh | N/A | Rm |
PHEW LET’S SLEEP AFTER THIS… ASR R5, R1, R12
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:8 | 7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0101 | 1100 | 0 | 10 | 1 | 0001 |
| cond | op | I | cmd | S | Rn | Rd | Rs | N/A | sh | N/A | Rm |
1. What is CORS and why is it required?
CORS (Cross-Origin Resource Sharing) is a browser security mechanism that allows/restricts APIs from being accessed by another domain.
Example:
Frontend: http://localhost:3000
Backend API: http://localhost:8080
These are different origins because ports are different.
Without CORS configuration, browser blocks the request.
Why required?
To securely allow frontend applications to call backend APIs hosted on different domains/ports.
Interview Answer:
CORS is a browser security feature that controls cross-origin HTTP requests. It is required when frontend and backend run on different domains, ports, or protocols. In Spring Boot, we configure CORS to allow trusted origins to access APIs securely.
2. How do you configure CORS in Spring Boot?
Using @CrossOrigin
Java
@RestController
@CrossOrigin(origins = “http://localhost:3000″)
public class UserController {
}
Global Configuration
Java
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000") .allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
}
Real-time usage:
In production, React/Angular frontend calls Spring Boot APIs from another domain.
3. What is CSRF attack?
CSRF = Cross Site Request Forgery
It tricks a logged-in user into performing unwanted actions.
Example:
User logged into banking site
Malicious website sends transfer request automatically
Browser sends session cookie
Server thinks request is genuine
Interview Answer:
CSRF attack occurs when a malicious site tricks an authenticated user into sending unauthorized requests to another application where the user is already logged in.