<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Ascendy Engineering</title><description>Ascendy Engineering blog — decisions and tradeoffs from backend/frontend/infra work.</description><link>https://blog.ascendy.ai/</link><item><title>Reviewing it line by line was slower than writing it — working with agents calls for a C-level mindset</title><link>https://blog.ascendy.ai/en/blog/from-ic-to-c-level-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/from-ic-to-c-level-en/</guid><description>Reviewing AI code line by line took longer than writing it. When models were weak, that was right. Past my trust threshold, my experience: agent-to-agent review beats a tired human. My take: the posture is C-level.</description><pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate><category>ai-agent</category><category>engineering-management</category><category>ai-collaboration</category><category>developer-mindset</category><category>opinion</category></item><item><title>When a reviewer just says &apos;looks good,&apos; what&apos;s the point? — introducing redteam, an adversarial agent-pair harness</title><link>https://blog.ascendy.ai/en/blog/redteam-launch-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/redteam-launch-en/</guid><description>Hand review to a second model and you often get &apos;looks good&apos; — a rubber stamp. redteam (open source, v0.1.0) makes review tiered findings, not pass/fail, and escalates a surviving blocker: retry → rescue → human.</description><pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate><category>ai-collaboration</category><category>adversarial-review</category><category>open-source</category><category>developer-tools</category><category>agent-harness</category></item><item><title>We dropped the reranker from vector search — what &apos;find all the baby photos&apos; broke</title><link>https://blog.ascendy.ai/en/blog/dropping-the-reranker-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/dropping-the-reranker-en/</guid><description>We dropped the reranker from photo search. &apos;Find all the baby photos&apos; returns thousands — a recall problem, not the precision@k a reranker is for. So we used MRL embeddings: low-dim filter, then high-dim refine.</description><pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate><category>vector-search</category><category>embeddings</category><category>reranker</category><category>matryoshka</category><category>retrieval</category><category>rag</category></item><item><title>Self-improvement loops have arrived — but someone still has to write the correction down</title><link>https://blog.ascendy.ai/en/blog/capture-is-the-bottleneck-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/capture-is-the-bottleneck-en/</guid><description>I wished my AI tool would learn from my complaints and fix itself. The loop exists now — it only closes if the correction is captured, and capture is still manual. The hard part was never improve; it&apos;s capture→route.</description><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><category>ai-agent</category><category>feedback-loop</category><category>self-improvement</category><category>developer-tools</category><category>process-design</category></item><item><title>Making cancel-and-refund idempotent — put the terminal state transition last</title><link>https://blog.ascendy.ai/en/blog/idempotent-cancel-refund-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/idempotent-cancel-refund-en/</guid><description>Cancelling a costly async job and refunding it must survive a crash mid-way. What makes it idempotent: marker and balance in one transaction, cleanup re-scanned by marker, and the terminal transition placed last.</description><pubDate>Sun, 07 Jun 2026 00:00:00 GMT</pubDate><category>idempotency</category><category>distributed-systems</category><category>race-condition</category><category>transactions</category><category>reliability</category></item><item><title>Everything you can click should also be sayable — yet enabling it started with a menu</title><link>https://blog.ascendy.ai/en/blog/conversational-parity-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/conversational-parity-en/</guid><description>I asked an AI agent to recall my past conversations. It told me to enable a toggle in Settings — the conversational feature itself gated behind menu-diving. The industry proved parity works, then stopped halfway.</description><pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate><category>ai-agent</category><category>ux</category><category>conversational-ui</category><category>product-design</category><category>opinion</category></item><item><title>Two AIs picked the same answer — the worth was catching the wrong reasoning inside it</title><link>https://blog.ascendy.ai/en/blog/right-answer-wrong-reasoning-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/right-answer-wrong-reasoning-en/</guid><description>Claude and Codex independently reached the same decision. Yet the second AI&apos;s worth wasn&apos;t disagreeing with the conclusion — even with the same answer, it caught the wrong reasoning holding that right answer up.</description><pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate><category>ai-collaboration</category><category>adversarial-review</category><category>decision-making</category><category>code-review</category><category>reasoning</category></item><item><title>A report arriving changes nothing — the broken link was &apos;route&apos;, not &apos;measure&apos;</title><link>https://blog.ascendy.ai/en/blog/monitoring-closed-loop-route-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/monitoring-closed-loop-route-en/</guid><description>A report that just arrives is worth zero — it only matters in a closed loop. Our broken link wasn&apos;t &apos;measure&apos;, it was &apos;route&apos;: improvements surfaced but evaporated in human-memory relay. The human was the bottleneck.</description><pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate><category>monitoring</category><category>observability</category><category>feedback-loop</category><category>process-design</category><category>automation</category><category>agent-ops</category></item><item><title>A plausible-fake default quietly swallows missing prod config — tie validation to an environment signal</title><link>https://blog.ascendy.ai/en/blog/placeholder-defaults-mask-config-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/placeholder-defaults-mask-config-en/</guid><description>A secret drift evaporated env keys. The nasty one fell silently: a default was a plausible fake (example.com), so the code quietly hit a fake host and failed — no error, no log. Tie validation to an environment signal.</description><pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate><category>configuration</category><category>fail-fast</category><category>silent-failure</category><category>observability</category><category>twelve-factor</category><category>defense-in-depth</category></item><item><title>I believed it converted, but it only renamed — and the failed jobs vanished from the list</title><link>https://blog.ascendy.ai/en/blog/rename-not-convert-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/rename-not-convert-en/</guid><description>A bulk photo edit failed wholesale with no error UI. One path renamed HEIC to .jpg instead of converting it, so a strict API rejected it; and failed jobs were filtered out of the list — hiding the outage entirely.</description><pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate><category>image-processing</category><category>heic</category><category>silent-failure</category><category>error-contract</category><category>debugging</category></item><item><title>The rename PR was the widest PR — a rename is a doc sweep, not a filename change</title><link>https://blog.ascendy.ai/en/blog/rename-pr-is-a-doc-sweep-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/rename-pr-is-a-doc-sweep-en/</guid><description>Renaming one file looked like &apos;a filename + a line.&apos; The real work: sweeping every live doc describing its behavior. Review caught 6 I missed; round-2 caught one the reviewer missed. The round cycle is a cumulative net.</description><pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate><category>code-review</category><category>documentation</category><category>refactoring</category><category>ai-agents</category><category>convergence</category><category>developer-tooling</category></item><item><title>Public to serve, secret to keep — reclassifying an ownership-proof key</title><link>https://blog.ascendy.ai/en/blog/serving-a-public-but-secret-key-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/serving-a-public-but-secret-key-en/</guid><description>We classified an ownership-proof key as &apos;public&apos; and committed it to git. But the docs call it semi-secret. A value served publicly yet kept out of git? Serve it from an edge Worker secret, not a static file.</description><pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate><category>cloudflare-workers</category><category>secrets-hygiene</category><category>secret-classification</category><category>code-review</category><category>indexnow</category></item><item><title>The constraint that blocked the deploy — required anti-affinity and the missing second node</title><link>https://blog.ascendy.ai/en/blog/anti-affinity-deploy-order-trap-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/anti-affinity-deploy-order-trap-en/</guid><description>To break a SPOF we added &apos;required&apos; anti-affinity — but no node could satisfy it yet. An unrelated team&apos;s CD stalled 25 hours; helm failed 5 times. A spread constraint before the room to spread blocks the deploy.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>kubernetes</category><category>helm</category><category>pod-anti-affinity</category><category>continuous-deployment</category><category>deploy-order</category><category>root-cause-analysis</category></item><item><title>One recreate and the vector DB never came up — compose `${VAR}` interpolation ≠ env_file</title><link>https://blog.ascendy.ai/en/blog/compose-interpolation-not-env-file-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/compose-interpolation-not-env-file-en/</guid><description>Recreating one worker dragged the vector DB along, and it hung at &apos;starting&apos;. The cause: an empty storage key — compose&apos;s ${VAR} interpolation resolves from the host shell at parse time, not from a service&apos;s env_file.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>docker-compose</category><category>vector-database</category><category>object-storage</category><category>silent-failure</category><category>credentials</category><category>root-cause-analysis</category></item><item><title>How you call the second AI, and when to stop it — a headless adversarial review loop</title><link>https://blog.ascendy.ai/en/blog/headless-adversarial-review-loop-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/headless-adversarial-review-loop-en/</guid><description>Call the review agent as a headless subprocess with forced output, not by driving its screen — ending screen-parsing&apos;s fragility. And a human-drawn &apos;stop line&apos; the reviewer judges converges it: 9→7→3→APPROVED.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>ai-agents</category><category>code-review</category><category>automation</category><category>dogfooding</category><category>developer-tooling</category><category>convergence</category></item><item><title>Three alarms, one root — a node host freeze that split three ways</title><link>https://blog.ascendy.ai/en/blog/host-freeze-three-alarms-one-root-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/host-freeze-three-alarms-one-root-en/</guid><description>Search down, metrics going backward, a node flapping — three alarms in different domains, one root: a node&apos;s host freeze. Plus a silent hang that still showed 1/1 Running, and a single-node-pool drain trap.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>kubernetes</category><category>elasticsearch</category><category>observability</category><category>incident</category><category>root-cause-analysis</category><category>health-probes</category></item><item><title>How a fixed bug came back — and how the diagnosis flipped a second time</title><link>https://blog.ascendy.ai/en/blog/nuxt-client-middleware-skips-initial-route-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/nuxt-client-middleware-skips-initial-route-en/</guid><description>A session-expired redirect broke; the fix was alive, only the path to it was cut. We blamed a &apos;Nuxt trait&apos; — also wrong: middleware ignores `.client`, a naming artifact. A fact-check drove the code fix.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>nuxt3</category><category>ssr</category><category>middleware</category><category>session-expired</category><category>incident-prevention</category><category>playwright</category></item><item><title>The green light was lying — an ERROR right next to succeeded</title><link>https://blog.ascendy.ai/en/blog/silent-primary-write-dual-write-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/silent-primary-write-dual-write-en/</guid><description>A worker logged the same ERROR every run — yet the next line, the task ended succeeded. A dual-write hid the primary write&apos;s failure, and a create-guard never propagated a new schema to an existing collection.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>vector-database</category><category>schema-migration</category><category>observability</category><category>debugging</category><category>idempotency</category><category>silent-failure</category></item><item><title>GitHub Actions to GCP without a long-lived key — the hard part wasn&apos;t WIF</title><link>https://blog.ascendy.ai/en/blog/wif-github-actions-gcp-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/wif-github-actions-gcp-en/</guid><description>We swapped the SA-key-in-a-Secret path for Workload Identity Federation. The WIF spec is short; six days went into the details around it — and what static review catches differs from what only a live run reveals.</description><pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate><category>workload-identity-federation</category><category>github-actions</category><category>gcp</category><category>ci-cd</category><category>oidc</category><category>security</category></item><item><title>Photo clouds solved storage, not finding — why we built Ascendy</title><link>https://blog.ascendy.ai/en/blog/why-we-built-ascendy-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/why-we-built-ascendy-en/</guid><description>Fixing a teary birthday photo with AI swapped my child&apos;s face. That detour led elsewhere: photo clouds solved storage, not finding. Why we built Ascendy — turning forgotten photos into raw data that understands you.</description><pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate><category>ascendy</category><category>product</category><category>photo-cloud</category><category>natural-language-search</category><category>ai-agents</category></item><item><title>The benevolent lie — how much hallucination do you allow in an AI-written post?</title><link>https://blog.ascendy.ai/en/blog/benevolent-lie-hallucination-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/benevolent-lie-hallucination-en/</guid><description>An AI draft slipped in a detail not in the source — &apos;3am, the third OOM.&apos; It reads well, but I don&apos;t know if it&apos;s true. When human memory is itself a kind of hallucination, where&apos;s the line between color and fact?</description><pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate><category>ai-writing</category><category>hallucination</category><category>fact-checking</category><category>vibe-coding</category><category>memory</category><category>editorial</category></item><item><title>The bottleneck in writing wasn&apos;t the answer — it was the question. Why I built an agent that interviews me</title><link>https://blog.ascendy.ai/en/blog/interview-harness-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/interview-harness-en/</guid><description>I gave topic and writing to agents and the prose went lifeless — not for lack of a human author, but because the source had no first-hand scene. So the agent interviews me: the bottleneck is the question, not the answer.</description><pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate><category>ai-writing</category><category>interview</category><category>editorial-workflow</category><category>writing-process</category><category>ai-agents</category><category>meta</category></item><item><title>We paired two AI models and got slower — so we routed work by tier</title><link>https://blog.ascendy.ai/en/blog/agent-os-dogfooding-journey-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/agent-os-dogfooding-journey-en/</guid><description>A solo dev&apos;s three-stage evolution of an LLM coding-agent harness: single model → cross-model pairing → routing work into tiers. Turning the speed-vs-quality tradeoff into a system, with an operating-room analogy.</description><pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate><category>llm-agents</category><category>pair-programming</category><category>claude-code</category><category>codex</category><category>agent-os</category><category>dogfooding</category><category>developer-workflow</category></item><item><title>Commenting out a feature doesn&apos;t bring it back — the double-trigger race we found restoring it</title><link>https://blog.ascendy.ai/en/blog/commented-out-listeners-race-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/commented-out-listeners-race-en/</guid><description>An auto-sync trigger we commented out was never restored, so the feature silently died. Restoring it exposed a double-trigger race: an await between check and act defeated the re-entrancy lock.</description><pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate><category>capacitor</category><category>concurrency</category><category>race-condition</category><category>incident-prevention</category><category>vue</category></item><item><title>ERROR showed, INFO vanished — the two traps that swallowed our Celery logs</title><link>https://blog.ascendy.ai/en/blog/celery-silent-info-logs-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/celery-silent-info-logs-en/</guid><description>A Celery worker logged zero INFO lines while ERROR showed fine. Two layers: Python logging uninitialized at the worker entry point, and a YAML block scalar that let bash chop the worker command apart.</description><pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate><category>celery</category><category>python-logging</category><category>docker-compose</category><category>yaml</category><category>observability</category><category>debugging</category></item><item><title>Only one model kept 404&apos;ing — a preview-alias time bomb meets branch asymmetry</title><link>https://blog.ascendy.ai/en/blog/preview-model-alias-timebomb-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/preview-model-alias-timebomb-en/</guid><description>In a multi-provider agent chat, one model path always 404&apos;d. Two layers: that path fell through to the base model, and that base was a preview alias the provider later retired. A CI guard for model lifecycle.</description><pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate><category>llm</category><category>model-lifecycle</category><category>regression-testing</category><category>incident-prevention</category><category>multi-provider</category></item><item><title>The first question in cost optimization isn&apos;t hardware — a self-hosted AI inference war story, part 2</title><link>https://blog.ascendy.ai/en/blog/ai-serving-evolution-part2-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/ai-serving-evolution-part2-en/</guid><description>After moving to managed GPU, always-on pods still leaked fixed cost. We split workloads by latency budget: search-path embeddings on always-on pods, async captioning on serverless — moving cold start off the user&apos;s path.</description><pubDate>Sat, 30 May 2026 00:00:00 GMT</pubDate><category>gpu</category><category>inference</category><category>serverless</category><category>triton</category><category>vllm</category><category>cost-optimization</category><category>latency-budget</category><category>war-story</category></item><item><title>One GPU should be enough, right? — A self-hosted AI inference war story, part 1</title><link>https://blog.ascendy.ai/en/blog/ai-serving-evolution-part1-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/ai-serving-evolution-part1-en/</guid><description>Moving image-preprocessing inference from an external API to self-hosted GPUs and back to managed GPU: single-GPU OOM, CPU-offload latency, a two-GPU split, and the hidden cost of self-hosting GPU inference.</description><pubDate>Sat, 30 May 2026 00:00:00 GMT</pubDate><category>gpu</category><category>inference</category><category>triton</category><category>vllm</category><category>cost-optimization</category><category>oom</category><category>self-hosting</category><category>war-story</category></item><item><title>Following the spec produced a false negative — when docs and code drift apart</title><link>https://blog.ascendy.ai/en/blog/doc-chart-spec-drift-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/doc-chart-spec-drift-en/</guid><description>A governance doc&apos;s commands drifted from a Helm chart&apos;s runtime needs, so a verify following the doc exactly produced a false negative — misread as an environment problem. The structural weakness of doc-as-spec.</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><category>helm</category><category>documentation</category><category>agent-workflow</category><category>root-cause-analysis</category></item><item><title>This blog is written by AI agents — an editorial-desk model with a redaction gate</title><link>https://blog.ascendy.ai/en/blog/how-this-blog-is-written-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/how-this-blog-is-written-en/</guid><description>Backend, frontend, and infra AI agents hand over source material; an editorial-desk team redacts and publishes it. A multi-agent content pipeline with a public/private boundary and a human merge gate — and why.</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><category>lmo</category><category>ai-agents</category><category>editorial-workflow</category><category>astro</category></item><item><title>Why we didn&apos;t delete duplicate workload definitions in one PR — a phased transition</title><link>https://blog.ascendy.ai/en/blog/k8s-helm-transition-decision-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/k8s-helm-transition-decision-en/</guid><description>The same workloads lived in two places — raw manifests and a Helm chart. Why we chose a phased transition over a mass-deletion PR: an executable gate over a comment, and splitting reviewer cognitive cost.</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><category>kubernetes</category><category>helm</category><category>migration</category><category>decision-making</category><category>risk-management</category></item><item><title>Build-time env vs runtime env — a login outage that fell into the same trap twice</title><link>https://blog.ascendy.ai/en/blog/nuxt-build-vs-runtime-env-en/</link><guid isPermaLink="true">https://blog.ascendy.ai/en/blog/nuxt-build-vs-runtime-env-en/</guid><description>Production login broke twice in Nuxt 3, both from one cause: confusing build-time vs runtime env. The CI build container never received env, so the reCAPTCHA script was never emitted into the HTML.</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><category>nuxt3</category><category>recaptcha</category><category>env</category><category>build-vs-runtime</category><category>capacitor</category></item></channel></rss>