AI 资讯
Apple launches new Mac Studios with its ‘most powerful chip ever’ — the M5 Ultra
Apple is announcing new models of the Mac Studio, now using the existing M5 Max and a new M5 Ultra. This reunification under one chip generation comes over a year after Apple awkwardly split the Studio between M4 Max and M3 Ultra offerings. (The older sounding M3 Ultra was actually the more powerful one, and […]
AI 资讯
Apple’s new Mac Mini has fresh M6 and M5 Pro chip offerings — and higher prices
Apple is announcing a new generation of the Mac Mini, once again offering two models: one with a new M6 chip and a higher-end model with the M5 Pro found in this year's MacBook Pro. The new Minis have the same tiny design and footprint as the 2024 M4 / M4 Pro models, but with […]
AI 资讯
Using an AST to validate AI-generated PostgreSQL before it runs
If an LLM is generating PostgreSQL in your application, there is one moment worth treating separately: after the model returns SQL, but before your code calls db.query() . Prompt rules are useful. They can make the model more likely to produce the sort of query you want. They do not decide which tables the application is allowed to read, whether multiple statements are acceptable, or whether a function call should run. I have been working on sql-guard , a TypeScript package for that gap. It parses PostgreSQL into an abstract syntax tree (AST), checks the tree against an explicit policy, and rejects anything it cannot validate confidently. Why I did not want to check SQL with regex SQL is structured. A query may have joins, subqueries, aliases, unions, and common table expressions (CTEs). Checking raw text can catch an obvious keyword, but it cannot reliably answer what the query actually does. For example: SELECT * FROM public . users ; SELECT 1 ; DELETE FROM public . users ; WITH removed AS ( DELETE FROM public . users RETURNING id ) SELECT * FROM removed ; All three examples contain SELECT , but they are not equivalent. The second has two statements. The third uses a data-modifying CTE. A validator needs to understand the query structure rather than look for a few strings. An AST makes that possible. It lets the validator inspect statement types, source tables, function calls, and nested expressions. It also means an alias or CTE name cannot conceal the base table being read. The policy is the important part sql-guard is built around allowlists. You state what a particular feature may use, and the validator checks the generated SQL against that list. Here is a small policy for an assistant that can look at users and orders: import { validate } from ' sql-guard ' ; const policy = { allowedTables : [ ' public.users ' , ' public.orders ' ], allowedFunctions : [ ' count ' , ' lower ' ], }; const result = validate ( ' SELECT lower(u.email) FROM public.users AS u ' , po
AI 资讯
AI is hitting entry-level jobs hardest, Stanford study finds
Young employment in AI-impacted fields down 19% compared to more AI-resistant occupations.
AI 资讯
Quipu: cifrado post-cuántico en Rust puro, con una rueda para Python
Proteger datos que deben seguir siendo secretos dentro de diez años es un problema de hoy : un adversario puede capturar tu tráfico cifrado ahora y descifrarlo cuando exista la capacidad cuántica ( harvest now, decrypt later ). Quipu es una librería libre de cifrado híbrido post-cuántico para datos en reposo: combina criptografía clásica probada con la nueva, de modo que solo se rompe si ambas caen a la vez. Rust puro, y por qué Quipu nació apuntando a varios lenguajes: un núcleo en Rust con una C ABI encima y bindings para Python, Node y Go. Funcionaba, pero la lección fue clara: mantener una interfaz de C estable más cuatro bindings, cada uno con su empaquetado y sus pruebas de interoperabilidad, era complejidad que no pagaba para el objetivo real —proteger datos en reposo— y ampliaba la superficie de ataque con unsafe que no queríamos. Hoy Quipu es Rust puro : memoria segura, sin garbage collector , sin unsafe de primera parte . Y para quien no programa en Rust, se distribuye como rueda nativa de Python (vía PyO3) — que es la superficie que el cliente que no es de Rust de verdad necesita. Una sola base de código, una sola cosa que auditar. Es la misma filosofía que guía el resto: donde hay buena criptografía, se reutiliza; la simplicidad es una decisión de seguridad, no una comodidad. Instalación cargo add quipu # Rust pip install quipu-crypto # Python (rueda nativa, PyO3) Cifrar y descifrar en Python import quipu # Simétrico con contraseña blob = quipu . encrypt_stream ( b " datos sensibles " , " mi-passphrase " ) assert quipu . decrypt_stream ( blob , " mi-passphrase " ) == b " datos sensibles " # Post-cuántico para un destinatario pub , sec = quipu . generate_keypair () # X25519 + ML-KEM-1024 c = quipu . encode_to_recipient ( b " secreto " , pub ) assert quipu . decode_as_recipient ( c , sec ) == b " secreto " Qué hay debajo Cifrado: XChaCha20-Poly1305 (AEAD autenticado). Derivación de claves: Argon2id (resistente a fuerza bruta) + HKDF. Post-cuántico: X25519
AI 资讯
Why Your Eyes Burn by Evening: Digital Eye Strain and the 20-20-20 Rule
By the end of the day my eyes burn. The screen goes fuzzy for a second when I look up, focusing on something across the room takes longer than it should, and a dull headache creeps in around the temples. I used to write this off as "just tired." Turns out it has a name and a fairly simple mechanism behind it. What computer vision syndrome actually is Computer vision syndrome — digital eye strain, if you prefer the plainer name — isn't a diagnosis in the sense of "something broke." It's a cluster of symptoms that shows up after prolonged close-range screen work: dryness and burning, blurred focus when you shift your gaze to something far away, light sensitivity, headaches, and often neck and shoulder pain, because we unconsciously lean toward the screen and freeze in one position for hours. Two things happen at once. First, your eyes hold focus on a near object for a long stretch — the ciliary muscle, which controls how the lens changes shape for near vision, stays tensed the whole time instead of periodically relaxing the way it would if your gaze wandered farther away now and then. Second, you blink noticeably less often while concentrating, so the tear film that keeps your eyes moist doesn't get replenished as frequently — hence the dryness. Why a screen and not a book Reading a book for hours also holds your focus at close range, but it strains your eyes less, and there's a reason for that. A screen emits light rather than reflecting it the way paper does, which creates more contrast against the room's ambient lighting, especially if the room is dimmer than the display. Glare from windows and lamps forces you to squint and refocus. And a laptop or phone tends to sit closer to your face than a book or a printed document would, simply because the screen is smaller. There's also the nature of the work itself. Reading a book is a steady stream; working with software is a constant series of micro-refocuses between windows, tabs, and notifications. Your eyes keep re-ad
AI 资讯
How We Cut AWS Staging Costs by 87% With EventBridge Scheduler (Zero Code Changes)
How We Cut AWS Staging Costs by 87% With EventBridge Scheduler No code changes. No Lambda functions. No complex scripts. Just 4 schedulers and a realization that nobody uses staging at 3am. Here's a question every engineering team should ask themselves: "When was the last time someone actually used our staging environment at 2am?" For us? Never. Not once. Yet we were paying for it — EC2 running, ECS Fargate tasks spinning, compute burning money — every single hour of every single day, including weekends, holidays, and the 21 hours per day when nobody on our team was even awake. That's the hidden tax of staging environments. And most teams never fix it because the solution feels complicated. It isn't. This is how we cut our staging compute costs by 87.5% — using AWS EventBridge Scheduler, zero Lambda functions, and zero lines of application code. The Problem: Staging Was Running 24/7 For No Reason Our staging environment had two resources running around the clock: EC2 instance — our staging app server ECS Fargate service — our backend API container Our team actively uses staging for roughly 3 hours a day . That's it. The math was embarrassing: Running: 24 hours/day Used: 3 hours/day Wasted: 21 hours/day = 87.5% of compute going nowhere Monthly cost breakdown: EC2 + ECS Fargate (24x7): ~$19.18/month EC2 + ECS Fargate (3hr/day): ~$2.40/month Monthly saving: $16.78 Yearly saving: $201.35 Reduction: 87.5% $201/year saved on staging compute alone — with 45 minutes of setup and zero application code changes. Multiply that across dev environments, QA clusters, review apps, and load test environments. The savings compound fast. The Solution: AWS EventBridge Scheduler Most engineers reach for Lambda when they need to automate AWS tasks on a schedule. That works — but it means writing code, managing runtimes, setting up CloudWatch Logs, and maintaining a function forever. EventBridge Scheduler is the better tool here. It lets you call any AWS SDK action directly on a cron sche
创业投融资
US nutrition startup Berry Street merges with India’s Healthify as GLP-1 trends upwards
Berry Street founder Noah Kotlove and Healthify founder Tushar Vashisht will act as co-CEOs of the new entity.
AI 资讯
One View Per Layer: Four Sharp Edges I Found in My Own Code
There is a layer in my database called 1 . Somebody created it, presumably by accident, and it sat there for months looking harmless. It was the only layer in the system that never served a single tile, and nobody noticed, because it was empty anyway. That layer turned out to be a symptom of a SQL injection vulnerability. This post is about the design that produced it — which I still think is a good design — and the four things I got wrong inside it. The setup A web GIS with about 2.7 million features: 1.8 million points, 697,000 lines, 172,000 polygons. Users create layers through the UI, upload data into them, edit geometry, and expect to see it on a map. The features do not live in a table per layer. They live in three tables — one for points, one for lines, one for polygons — with a layer_id foreign key and a JSON column for attributes: project_pointfeature 1,820,288 rows project_linefeature 697,009 rows project_polygonfeature 171,830 rows That's a deliberate trade. A table per layer means DDL every time a user clicks "new layer", a migration story that never ends, and a schema that drifts. Three generic tables mean one schema, one set of indexes, and layers that are just rows in a metadata table. The cost lands on the tile server. The pattern Martin serves vector tiles from PostGIS. Point it at a database and it discovers spatial tables and views and publishes each as an MVT endpoint. It can be told to publish views but not tables: postgres : auto_publish : from_schemas : [ public ] publish_tables : false reload_interval : 5s So: give every layer its own view. A Django post_save signal on the Layer model creates it: CREATE OR REPLACE VIEW t19_saobracajni_znakovi AS SELECT f . id , f . feature_attrs , f . geom , f . layer_id , l . name AS layer_name , lg . name AS layer_group_name , p . title AS project_title FROM project_pointfeature f JOIN project_layer l ON f . layer_id = l . id JOIN project_layergroup lg ON l . layer_group_id = lg . id JOIN project_project p
AI 资讯
Presentation: Prompt to Prod: Engineering an Autonomous SDLC at Scale
Andrew Swerdlow shares how Roblox scales autonomous software development from prompt to production. He discusses building robust security sandboxes, extracting institutional knowledge via code review exemplars, updating engineering infrastructure, and redefining productivity metrics around feature velocity and long-running AI turns to achieve trusted, automated deployment at scale. By Andrew Swerdlow
AI 资讯
Four Alarm Slots, Three Failure Modes: Building a Nightly Drain That Survives Sleep, Races, and Timeouts
Every night my Mac quietly rewrites my long-term memory. Not metaphorically — a shell script drains that day's Claude Code conversation logs into an Obsidian vault, commits them to a private repo, and leaves a briefing on my desktop. It took three real outages to make it reliable. This is the script, the three failures, and the design that came out of them. Why This Setup Works Claude Code's "memory" disappears by default Claude Code sessions are independent of one another. The root cause of a bug you found during a long working session today, the reason you settled on a particular architecture after trial and error, the accumulated knowledge that "this direction already failed once" — none of it is available in the next conversation once you close the session. Even on a paid plan, even with the most capable model available, if context isn't carried over you have to explain everything from scratch every time. Many people have had the experience of thinking "I already looked this up before" or "I should have failed at this once already, and yet here I am heading down the same road again." In a phase where you're shipping personal projects in volume, this problem is fatal. Once three or four projects are running in parallel, tracking "where each project currently stands" by hand hits a wall fast. And Claude, unable to reference previous conversations, repeats the same deliberations. The solution is to build an environment, not a task My first attempt at this problem was "I'll write up a summary by hand every day." It didn't last. When work has momentum you don't feel like writing a summary, and when you're tired you can write even less. A system that depends on human willpower doesn't function during a high-volume solo-dev phase. The answer was to build an environment that automatically drains Claude's conversation logs into Obsidian every night. Once the environment is in place, willpower and motivation are irrelevant. The Mac just does it. The reason I chose Obsidia
AI 资讯
从 Demo 到生产:那些真正让 AI Agent 敢上线的护栏
从 Demo 到生产:那些真正让 AI Agent 敢上线的护栏 开场钩子: 你在网上看到的多数「AI Agent」都是 demo。它们之所以上不了生产,原因往往 只有一个 —— 而下面这个开源的小脚手架,专门解决它。 我们已经过了「能调通大模型」就算赢的阶段。现在真正难的是那没人讲的 10%: 是什么阻止 Agent 做出伤害性的事? 我在微软跑过一套约 25 个 Agent 的生产平台,现在也帮团队把 Agent 从笔记本推进到真实用户面前。两边的体会是一致的。 一个不太舒服的真相:能调 5 个工具的聊天机器人, 不是产品 。周末项目和你敢放到客户面前的 系统之间,差的只有三件事 —— 而且全都是不酷、不性感的工程: 你怎么给输出质量打分 (质量门)。 你怎么决定什么时候必须人签字 (审批门)。 你如何让整套东西模型无关 ,不被某个厂商锁死。 所以我写了一个很小的 harness,把这三件事摆在最显眼的位置。它故意做得很小 —— 一小时能 读完 —— 因为价值不在「框架」,在 模式 本身。 仓库: github.com/zhasun0818/ai-agent-scaffold 1. 质量门:别发布你无法打分的东西 Agent 的输出是「预测」不是「承诺」。上线前它必须过一道 检查 :是否达到你的标准。脚手架里 这是一个可插拔的 QualityGate ,你可以换成 LLM 裁判或测试套件: # agent_harness/eval.py @dataclass class EvalReport : passed : bool score : float checks : List [ str ] class QualityGate : def grade ( self , proposal : str , context : str = "" ) -> EvalReport : return self . grader ( proposal , context ) 循环在门没过之前拒绝执行: result . report = self . quality . grade ( proposal , f " state= { state } " ) if not result . report . passed : self . approval . log ( " quality-gate " , " blocked " , result . report . __str__ ()) return result 注意它 把拦截记录下来了 。生产里你会想把这些被拦的尝试都进可观测性系统。「这周我们拦下 了 12% 的 Agent 提议」是个真实 KPI —— 它说明门在工作。 2. 审批门:所有人都忘掉的那一步 这才是让企业真正点头说「可以」的东西。当 Agent 想加急订单、取消订阅、或动钱的时候,它应该 停下来问人 。沉默不等于同意。 # agent_harness/approval.py class ApprovalGate : def request ( self , action : str , detail : str ) -> bool : # 生产里:推一条通知到 Teams / Slack / 邮件,然后等待。 decision = input ( f " Approve { action } ? [y/N] " ). strip (). lower () self . audit . append ( AuditEntry ( time . time (), action , " human-reviewer " , decision , detail )) return decision . startswith ( " y " ) 在脚手架里,标记 needs_approval=True 就够了: @tool ( " expedite_order " , " Mark an order as expedited. " , needs_approval = True ) def expedite_order ( order_id : str ) -> str : return f " PO { order_id } : marked expedited " 而且因为有 审计链 ,你永远能回答「谁改的、为什么」—— 这通常是合规团队问的第一个问题。 3. 模型无关的 provider:别跟一个厂商结婚 模型每几周就变,价格也是。你的 Agent 循环不该知道自己在对谁说话: # agent_harness/providers.py class ModelProvider ( Protocol ): def
AI 资讯
From Demo to Production: The Guardrails That Make an AI Agent Safe to Ship
From Demo to Production: The Guardrails That Make an AI Agent Safe to Ship Hook: Most "AI agents" you see on the internet are demos. Here's the single most common reason they never reach production — and a small, open-source harness that gets past it. We are past the phase where the hard part of building an AI agent was calling the model. The hard part now is the 10% nobody talks about: what stops the agent from doing something harmful? I've seen this from both sides — I built and ran a ~25-agent platform in production at Microsoft, and now I help teams take agent ideas from a notebook to real users. The uncomfortable truth: a chatbox that can call 5 tools is not a product. The difference between a weekend project and a system you can put in front of customers is three things — and they're all boring, non-glamorous engineering: How you grade output quality (the quality gate). How you decide when a human must sign off (the approval gate). How you make the whole thing model-agnostic so you're not locked into one vendor. So I wrote a tiny harness that keeps these front and center. It's intentionally small — small enough to read in an hour — because the value isn't in a framework, it's in the pattern . Repo: github.com/zhasun0818/ai-agent-scaffold 1. The quality gate: don't ship what you can't grade An agent's output is a prediction, not a promise. Before it ships, you need a check that it passes your bar. In the harness this is a pluggable QualityGate — a rule of thumb you swap with an LLM judge or a test suite: # agent_harness/eval.py @dataclass class EvalReport : passed : bool score : float checks : List [ str ] class QualityGate : def grade ( self , proposal : str , context : str = "" ) -> EvalReport : return self . grader ( proposal , context ) The loop refuses to execute if the gate fails: result . report = self . quality . grade ( proposal , f " state= { state } " ) if not result . report . passed : self . approval . log ( " quality-gate " , " blocked " , result
AI 资讯
Concertos VR 2026: o futuro imersivo dos shows ao vivo
Concertos VR 2026: como o streaming imersivo está redefinindo o show ao vivo Introdução Você já imaginou estar no meio da plateia de um show de rock, sentir o pulsar dos graves e, ao mesmo tempo, poder pausar a cena, mudar de ângulo ou conversar com amigos que estão em outro continente – tudo sem sair da sua sala? Em 2026 isso já é realidade. Graças a headsets 4K mais baratos, plataformas de streaming de baixa latência e a mudança de comportamento do público, os concertos VR deixaram de ser ficção científica e se tornaram a principal forma de consumo musical ao vivo. Neste artigo vamos mostrar, passo a passo, como funciona essa revolução, apresentar casos de sucesso, analisar o impacto econômico e cultural e, principalmente, oferecer um guia prático para artistas, promotores e fãs que querem entrar nesse universo. 1. O que é um concerto VR? Um concerto VR é um evento musical transmitido ao vivo em 360° (ou 180°) e entregue em tempo real para um headset de realidade virtual. O espectador tem liberdade total para olhar ao redor, mudar de ponto de vista e interagir com objetos digitais – como luzes, efeitos e até avatares de outros fãs. Como a transmissão acontece (exemplo de pipeline) # 1. Captura 360° com câmeras Insta360 Pro 2 ffmpeg -i rtsp://camera1 -i rtsp://camera2 -filter_complex \ "[0:v]crop=3840:2160:0:0[left];[1:v]crop=3840:2160:0:0[right];[left][right]hstack=inputs=2[v]" \ -map "[v]" -c :v libx264 -b :v 15M -f rtp rtp://livevrx.com:5004 # 2. Ingestão no servidor de baixa latência (WebRTC) node livevrx-ingest.js --source rtp://livevrx.com:5004 --room concert2026 # 3. Distribuição para o headset (WebXR) <video id = "vrStream" autoplay playsinline webkit-playsinline src = "webrtc://livevrx.com/concert2026" crossorigin = "anonymous" > </video> Esse fluxo garante latência ≤ 30 ms , qualidade 4K por olho e sincronização perfeita entre áudio e vídeo. 2. Equipamento necessário Dispositivo Resolução mínima Preço (USD) 2026 Comentário Meta Quest 3 2 K por olho $399 M
AI 资讯
7 Basic iPhone Tricks I Built With iOS 27’s Revamped Shortcuts App
From halting my doomscrolls to automating air-quality checks, Apple’s streamlined Shortcuts app is my favorite iOS 27 feature.
AI 资讯
OVHcloud Raises Prices as AI Memory Demand Reprices Non-AI Infrastructure
OVHcloud will raise prices from September, with 2026-edition gaming servers up 87 percent and other recent servers 40 to 59 percent. Founder Octave Klaba says memory cost six times more in June than a year earlier, as RAM suppliers shifted capacity toward high-bandwidth memory for AI. AWS, buying years ahead, has repriced one reserved GPU product. By Steef-Jan Wiggers
AI 资讯
Fixing a pgvector CI mismatch in a FastAPI RAG backend
This is a submission for DEV's Summer Bug Smash: Clear the Lineup , powered by Sentry . Project Overview mini-agent is a public FastAPI backend for an AI support-agent demo. Its test suite covers API behavior, authentication, rate limiting, approval flows, and PostgreSQL/pgvector-backed retrieval. The GitHub Actions workflow starts PostgreSQL and Redis service containers before running the Python test suite. The application database initialization also executes: CREATE EXTENSION IF NOT EXISTS vector The dependency is also visible in the DocumentChunk.embedding column, which uses pgvector's Vector type. That made the database image part of the test contract, not just incidental infrastructure. Bug Fix or Performance Improvement On August 12, 2026, the CI run for the preceding commit reached the test step and failed: Failed workflow run Commit tested by that run The workflow was using the general-purpose postgres:17-alpine service image, while the application required the pgvector extension during database initialization. The test environment therefore did not match the database capability required by the code. The failure was specific enough to avoid a broad rewrite: the container initialized successfully, dependency installation passed, and the workflow stopped only at Run tests . That pointed to the application/database boundary rather than the GitHub Actions runner or Python installation. The fix changed one line: services: postgres: - image: postgres:17-alpine + image: pgvector/pgvector:0.8.6-pg17 Full change: Use pgvector image in CI The PostgreSQL major version, credentials, port mapping, health check, application environment, dependency installation, and test command all remained unchanged. This kept the patch narrow and made the CI database expose the same required extension as the application. Code The evidence is a direct before-and-after pair: The preceding workflow failed at Run tests . The one-line database-image commit triggered a new workflow. The new
开发者
An okay laptop with 16GB of RAM is better than a nice laptop with 8GB, and this $520 HP OmniBook proves it
Laptop prices are out of whack. $500 used to get you a tolerable laptop, and $900 got you a really good one. They often had similar CPU, RAM, and storage options because that stuff was comparatively cheap; the difference was often in build quality and screen rather than power. But RAMageddon has thrown everything off. […]
AI 资讯
How to Check Closed-Source Firmware for Known CVEs (No Source Code Needed)
A router, an IP camera, an industrial controller: somewhere in that device's firmware there's a Linux kernel with modules, a handful of statically linked binaries, and a userspace built from a dozen open source components. You don't have the vendor's source tree. What you have is a .bin file, or after unpacking it, a pile of .ko , .o and stripped ELF binaries. The question you actually need answered is boring but important: is any of this running something with a known CVE? This comes up constantly in embedded and IoT work, and it's a different problem from auditing your own codebase. You're not hunting for a new bug, you're checking for old ones the vendor never patched. In practice that's the more common finding: not a novel zero-day, but a five-year-old OpenSSL or BusyBox build nobody was tracking. Unpack first, guess later binwalk is still the first move. Point it at the firmware image and let it scan for known magic bytes: SquashFS, CramFS, JFFS2, gzip streams, kernel headers. Most consumer and SOHO firmware is a bootloader plus a compressed filesystem, and binwalk's extraction mode gets you the actual filesystem tree instead of one opaque blob. Once you have that, you're auditing files, not guessing at a blob. Fingerprint by version string, not by hash Hash-matching binaries against known-vulnerable databases sounds appealing and mostly doesn't work here, because vendors relink, strip and sometimes patch without touching anything else. What works more often: grep the extracted binaries for version banners. strings on busybox , openssl , dropbear , lighttpd , zlib and similar userspace binaries usually still leaks a version string even when the binary is stripped of debug symbols, because those strings are compiled-in constants the program itself prints or logs, not debug metadata. strings <binary> | grep -iE "openssl|busybox|dropbear|zlib" is unglamorous and it's the single highest-signal step in this whole process. Cross-reference what you find Once you have
开发者
완전자동매매 시스템에 사람이 직접 개입해야 했던 사례 3가지
자동으로 돌아가게 만든 것과, 자동으로 끝까지 처리되는 것은 다른 문장이었습니다 이 시스템은 사람 승인 없이 스스로 판단하고 매매하는 걸 목표로 설계했습니다. 실계좌 주문 실행과 안전장치 (새 창)도 그 목표에 맞춰 만들었습니다. 그런데 최근 한 달 사이 실계좌에서 세 번, 사람이 직접 개입해야 하는 상황이 있었습니다. 세 사례 모두 "왜 자동 로직이 이 상황을 못 넘겼는지"의 구조가 서로 달랐습니다. 1. 배분 규칙이 특정 주문을 구조적으로 굶겼다 특정 종목 하나가 여러 날째 매도 계획이 서 있는데도 계속 팔리지 않는 걸 발견했습니다. 시스템은 매일 이 종목을 매도 후보로 올렸지만, 실제 주문까지는 못 갔습니다. 원인은 하루 매매 한도를 여러 라운드에 나눠 배분하는 규칙이었습니다. 이 종목의 주문 금액이 그날 남은 매도 한도보다 항상 컸습니다. 라운드 순서를 아무리 바꿔도 통과할 수 없는 구조였습니다. 한도 자체는 정상 작동하고 있었습니다. 문제는 "이번엔 못 나가도 다음 기회에 나간다"는 전제가 이 종목엔 애초에 성립하지 않았다는 점입니다. 잔여 한도가 매번 주문 금액보다 작으면, 기회는 계속 오지만 한 번도 충분하지 않습니다. 당장 못 나간 주문 1건은 사람이 직접 처리했습니다. 실계좌에서 이뤄진 되돌릴 수 없는 매도였습니다. 이후 배분 규칙 자체를 손봐서 같은 구조로 다시 굶는 일이 없도록 정리했습니다. 2. 안전장치가 스냅샷과 누적치를 혼동했다 다른 날엔 반대 방향의 사고가 있었습니다. 누적 손실을 감지하는 안전장치가 정상적인 매수 2건을 잘못 차단했습니다. 지수는 그날 거의 보합이었는데, 이 안전장치가 재는 손실률은 훨씬 크게 찍혀 있었습니다. 원인을 보니 이 장치는 "고점 대비 누적 하락"을 감지하는 용도였는데, 정작 비교하는 현재값은 장중 순간 스냅샷이었습니다. 장중 잠깐의 변동이 누적 지표를 밀어 올려서, 실제로는 발동하면 안 될 상황에서 발동한 겁니다. 누적을 재는 장치와 순간을 재는 장치가 뒤섞여 있었던 셈입니다. 막힌 매수 2건은 사람이 판단해서 직접 집행했습니다. 이후 이 안전장치가 장중 순간값이 아니라 "그날 마감 대 전날 마감" 기준으로만 반응하도록 구조를 바꿨습니다. 장중 급락에는 이제 다른 안전장치가 대신 반응하도록 역할을 나눴습니다. 3. 개입 경로 자체가 "새로 사는 경우"를 몰랐다 두 번째 사례를 수습하는 과정에서 사고가 하나 더 있었습니다. 수동으로 낸 주문을 원장에 반영하는 도구를 썼는데, 반영이 안 되고 조용히 빠졌습니다. 이 도구는 사람이 손으로 낸 거래를 세 가지 경우 중 하나로 분류합니다. 기존 보유 종목을 판 경우, 기존 보유 종목을 더 산 경우, 그리고 시스템과 무관한 거래인 경우입니다. 그런데 이번 매수는 원장에 없던 새 종목을 사람이 처음 사들인 경우였습니다. 세 분류 중 어디에도 안 맞았고, 도구는 이걸 "시스템과 무관한 거래"로 잘못 넘겼습니다. 그 결과 실제로는 산 자산이 잠깐 원장 밖에 있는 것처럼 표시됐습니다. 이 도구는 애초에 사람 개입을 위해 만든 경로였습니다. 그런데 그 경로를 설계할 때, "사람이 아예 새로운 자리에 처음 진입하는 경우"는 상정하지 않았습니다. 개입 경로 자체가 개입의 한 형태를 놓치고 있었던 셈입니다. 순서(먼저 다른 매도를 부기하고, 그다음 이 매수를 부기)를 지켜서 바로 수습했고, 검증 결과 원장과 실계좌 잔고는 정확히 일치했습니다. 분류 로직에 이 경우를 추가하는 건 아직 남은 과제입니다. 세 사례를 묶어보면 셋 다 "자동으로 처리되게 만들었다"와 "실제로 끝까지 처리된다"가 다른 문장이라는 걸 보여줬습니다. 첫 번째는 규칙이 있었지만 그 규칙이 특정 입력에서 절대 통과할 수 없는 구조였습니다. 두 번째는 장치가 있었지만 재는 대상(순간 대 누적)이 설계 의도와 어긋나 있었습니다. 세 번째는 사람 개입을 위한 경로가 있었지만 그 경로 자체가 특정 개입 형태를 몰랐습니다. 세 가지 모두 "자동화가 이 케이스를 놓칠 수 있다"는 걸 사전에 안 게 아니라, 실제로 놓친 뒤에야 알았습니다. 일반화하면 완전자동을 목표로 설계할수록,