<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ramiz Raja — Writing</title>
    <link>https://codebyramiz.com/blog/</link>
    <atom:link href="https://codebyramiz.com/feed.xml" rel="self" type="application/rss+xml" />
    <description>Articles on building, testing and shipping Android and iOS apps.</description>
    <language>en-us</language>
    <lastBuildDate>Wed, 28 Oct 2026 00:00:00 GMT</lastBuildDate>
    <item>
      <title>Flutter vs React Native: How I Choose, and When I Go Native</title>
      <link>https://codebyramiz.com/blog/flutter-vs-react-native/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/flutter-vs-react-native/</guid>
      <pubDate>Wed, 28 Oct 2026 00:00:00 GMT</pubDate>
      <description>I have a production Flutter app on both stores, and React Native experience that is brownfield, SDK and sample work. Here is how the two render according to their docs, what my Flutter app needed from native code, and when I pick native instead.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Flutter</category>
      <category>React Native</category>
      <category>Cross-Platform</category>
      <category>Architecture</category>
    </item>
    <item>
      <title>Claude Code in Android Studio: The Editor Is the Easy Part</title>
      <link>https://codebyramiz.com/blog/claude-code-android-studio/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-android-studio/</guid>
      <pubDate>Tue, 27 Oct 2026 00:00:00 GMT</pubDate>
      <description>The Claude Code plugin for Android Studio shows diffs in the IDE and lets the agent read lint, but the phone is reached from the terminal. Counts from my agents' transcripts: thousands of leased adb commands, almost no use of Google's android CLI, a screenshot path that kept returning black frames, and a guard hook whose biggest rule mostly blocked commands that only mentioned a script.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI Agents</category>
      <category>Claude Code</category>
      <category>Android</category>
      <category>Testing</category>
    </item>
    <item>
      <title>Claude Code Compact: What Survives, With Counts From My Sessions</title>
      <link>https://codebyramiz.com/blog/claude-code-compact/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-compact/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>Claude Code compact replaces your conversation with a summary. The docs list what survives and what does not. I counted compactions across 4,121 of my own session transcripts, and here is the one rule I follow because of it.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Context</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Claude Code Hooks: Three I Run Every Day</title>
      <link>https://codebyramiz.com/blog/claude-code-hooks/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-hooks/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>Three Claude Code sessions each launched about twelve background commands and crowded a 12-core Mac, and no session could see the others. A CLAUDE.md rule cannot fix that; a hook can. Three hooks I run on every session: a budget guard that blocks background fan-out before it starts, a Stop hook that refuses to end a turn on an unverified still-running claim, and a cleanup pass that reaps what a session leaves behind. Which event each one hangs on, what the contract allows, and the two places mine are still wrong.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Workflow</category>
      <category>Automation</category>
    </item>
    <item>
      <title>Claude Code Pricing: What Each Plan Includes and What It Costs</title>
      <link>https://codebyramiz.com/blog/claude-code-pricing/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-pricing/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>Claude Code pricing depends on how you sign in: a subscription plan with usage limits, or pay-per-token through the API. Here is what Anthropic's pricing page and cost docs said on 2026-10-26, quoted and linked, with no numbers from memory.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Pricing</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Claude Code Statusline: A Setup That Shows Your Limits</title>
      <link>https://codebyramiz.com/blog/claude-code-statusline/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-statusline/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>A Claude Code statusline is a shell command that reads JSON on stdin and prints one line under the prompt. Here is the setting, the fields the docs list, the settings.json scopes, and my own script that shows context used and five-hour and seven-day usage with reset times.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Settings</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Claude Code Subagents: When One Beats Doing It Inline</title>
      <link>https://codebyramiz.com/blog/claude-code-subagents/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-subagents/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>A subagent is its own context window with its own prompt, tools and permissions. The docs say to delegate verbose or self-contained work that can return a summary, and to stay inline when it needs back-and-forth. Here is the shape, the decision table, and the bounded brief I hand over.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Subagents</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Claude Code vs Cursor: What I Measured Running Both as Coding Workers</title>
      <link>https://codebyramiz.com/blog/claude-code-vs-cursor/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-vs-cursor/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>I have used the Cursor CLI and Claude Code as bounded-task workers, and I keep a results log of the tasks I dispatch. Here are the counts from that log (9 Cursor composer rows, 20 Claude Sonnet rows), the failures, one older three-tool benchmark that did not include Claude Code, and the Cursor and Claude claims that come from their own docs.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Cursor</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Claude Code YOLO Mode: What It Removes and What I Run Instead</title>
      <link>https://codebyramiz.com/blog/claude-code-yolo-mode/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-yolo-mode/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>YOLO mode, the bypassPermissions mode behind --dangerously-skip-permissions. Here is what the docs say it removes, why I run auto mode with a long allowlist instead, and the one hook guard I added for a failure I actually saw.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Permissions</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>CLAUDE.md File: What to Put In It and What to Leave Out</title>
      <link>https://codebyramiz.com/blog/claude-md-file/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-md-file/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>A CLAUDE.md file is loaded into every session, so a long one costs context and, per the docs, reduces adherence. I cut mine from 3,639 words to 512 with a pointer index, then let it regrow to 9,555. Here is what belongs in it, what doesn't, and the numbers from my own git history.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>CLAUDE.md</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Codex Exec in a Script: The Flags, the Exit Codes and a Timeout</title>
      <link>https://codebyramiz.com/blog/codex-exec-script/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/codex-exec-script/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>Codex exec runs Codex without the interactive screen, so you can call it from a script. The docs cover sandbox, stdin and the output file. They do not describe a timeout, so I added one, plus an exit-code rule: no verdict is never a pass.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Codex</category>
      <category>Automation</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Using Codex as the Read-Only Reviewer for Claude Code</title>
      <link>https://codebyramiz.com/blog/codex-vs-claude-code/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/codex-vs-claude-code/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>I run Claude Code as the agent that plans, edits and dispatches, and Codex as the independent reviewer that returns a binary VERDICT on the changes I send it. Here is where each one sits in my workflow, one real failure the gate caught, and what I did not compare.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Codex</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Flaky Tests or No Result? Seven Bad Runs, Sorted</title>
      <link>https://codebyramiz.com/blog/flaky-mobile-ui-tests/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/flaky-mobile-ui-tests/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>A run that never produced a test result is not a flaky test and not a failing one. Here are seven red or incomplete runs from my Android logs, how I classified each, the one failure I could reproduce on purpose, and the ones I never explained.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Testing</category>
      <category>Android</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Gemini CLI vs Claude Code: What I Can and Cannot Say From My Logs</title>
      <link>https://codebyramiz.com/blog/gemini-cli-vs-claude-code/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/gemini-cli-vs-claude-code/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>If you want Gemini CLI vs Claude Code, my logs cannot give it to you: I have no Gemini CLI runs, only Gemini models run through Antigravity (22 rows) next to 20 Claude Code rows. Here are the counts, the failures, what Gemini CLI's own README says, and what I did not measure.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Gemini</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>SwiftUI vs UIKit: Counts From Eight of My iOS Apps</title>
      <link>https://codebyramiz.com/blog/swiftui-vs-uikit/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/swiftui-vs-uikit/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>Every one of my eight iOS apps imports both frameworks. Here are the file counts for SwiftUI and UIKit, the UIKit types that keep appearing, Apple's quoted description of the bridging types, and what the counts cannot tell you.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>iOS</category>
      <category>SwiftUI</category>
      <category>UIKit</category>
      <category>Architecture</category>
    </item>
    <item>
      <title>Xcode MCP: Setting It Up for Claude Code, and What I Saw</title>
      <link>https://codebyramiz.com/blog/xcode-mcp/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/xcode-mcp/</guid>
      <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
      <description>Xcode ships an MCP server that an agent started outside Xcode can use to build and act on your project. Here is Apple's setup, quoted, and four things I saw when I wired it to Claude Code on Xcode 27.0 on 2026-09-29.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>iOS</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Claude Code Skills: How to Write Ones Your Agent Actually Uses</title>
      <link>https://codebyramiz.com/blog/claude-code-skills/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/claude-code-skills/</guid>
      <pubDate>Sun, 25 Oct 2026 00:00:00 GMT</pubDate>
      <description>You write a detailed SKILL.md, and your agent still ignores it and improvises from scratch. I run 130 skills across three Claude Code profiles, and whether one gets used comes down to its description, a lean procedure with detail in side files, and one shared folder instead of copies. Here is what decides whether an agent loads and follows a skill.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Claude Code</category>
      <category>Workflow</category>
      <category>Automation</category>
    </item>
    <item>
      <title>Google Play Target API Level Requirement: A Checklist for an App Nobody Has Touched</title>
      <link>https://codebyramiz.com/blog/google-play-target-api-level-checklist/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/google-play-target-api-level-checklist/</guid>
      <pubDate>Thu, 22 Oct 2026 00:00:00 GMT</pubDate>
      <description>Play Console warns that your app must target a newer API level, and the app has not been built in a year. Here is the requirement as Google states it and the order I raise targetSdk in.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>Release</category>
      <category>Google Play</category>
    </item>
    <item>
      <title>Don't Trust an Agent That Says the Tests Passed</title>
      <link>https://codebyramiz.com/blog/agent-says-tests-passed/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/agent-says-tests-passed/</guid>
      <pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate>
      <description>A change came back with 768 passing tests reported. An independent reviewer, which did not rerun them, found two High bugs those tests did not cover. Another reviewer found no blocking issues in static review and still failed a module, because it could not run the tests itself. Here are the three checks I put between an AI coding agent and the word done: a hook that checks status claims, a binary verdict from a reviewer that did not write the code, and exit codes that separate a failure from a run that never produced a result.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Testing</category>
      <category>Workflow</category>
      <category>Android</category>
      <category>iOS</category>
    </item>
    <item>
      <title>When Your Coding Agent Hits a Rate Limit: A Fallback Ladder That Keeps Working</title>
      <link>https://codebyramiz.com/blog/coding-agent-rate-limit-ladder/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/coding-agent-rate-limit-ladder/</guid>
      <pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate>
      <description>Your coding agent just ran out of quota. Waiting kills the afternoon, and pasting the prompt into whatever tool is open wastes your best model on small work. Here is the ordered fallback ladder I run instead: free models first, paid rows one step at a time, automatic retries only when nothing was written, and a journal that decides the order.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>AI Agents</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>Twelve Cores, Seven Devices, One Disk</title>
      <link>https://codebyramiz.com/blog/running-multiple-claude-code-agents/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/running-multiple-claude-code-agents/</guid>
      <pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate>
      <description>Every guide to running multiple Claude Code agents in parallel says the same thing: give each one its own git worktree. That keeps the files apart. It doesn't keep the machine apart. On my setup, several sessions share a 12-core Mac, a Windows build PC and seven test phones, and what broke was never a merge conflict. It was CPU oversubscription, two test runs fighting over one port, phones left awake around the clock, a disk that went from 56 GB free to 1 GB overnight, and a test run that sat hung for seven hours. The guards that fixed each one, with the real config.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Multi-Agent</category>
      <category>Workflow</category>
      <category>Android</category>
      <category>iOS</category>
    </item>
    <item>
      <title>What Keeps Agent-Written Code Clean When Nobody Reads It</title>
      <link>https://codebyramiz.com/blog/clean-architecture-ai-agents/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/clean-architecture-ai-agents/</guid>
      <pubDate>Tue, 20 Oct 2026 00:00:00 GMT</pubDate>
      <description>AI agents write most of the code in my apps and I don't read it line by line. The clean architecture still has to hold, because the next feature, the next SDK swap and the next agent all depend on it. What I found: a rule written into a prompt decays, a boundary test doesn't, and a reviewer that isn't the writer catches layer mistakes before they become code. Real tests, a real reviewer verdict, and one boundary that did break.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Clean Architecture</category>
      <category>Android</category>
      <category>iOS</category>
    </item>
    <item>
      <title>Live Users, Zero Ad Requests</title>
      <link>https://codebyramiz.com/blog/admob-zero-ad-requests/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/admob-zero-ad-requests/</guid>
      <pubDate>Tue, 13 Oct 2026 00:00:00 GMT</pubDate>
      <description>AdMob reported zero ad requests for an app with people actively using it. Consent and app-ads.txt could not explain it: the build that reached the store had been compiled with ads off, because one git-ignored file was missing from the build machine. That case, the same fault on iOS, and the different failure that hides behind a 0% match rate.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AdMob</category>
      <category>Release Engineering</category>
      <category>Android</category>
      <category>iOS</category>
    </item>
    <item>
      <title>Your App Should Still Be Yours When the Developer Leaves</title>
      <link>https://codebyramiz.com/blog/your-app-should-still-be-yours/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/your-app-should-still-be-yours/</guid>
      <pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate>
      <description>If the person who builds your app stopped answering tomorrow, could someone else ship a fix next week? Two real handovers show where that question actually gets decided: eight months of work that had never reached the shared repository, arriving as a single commit, and an agency-built app whose App Store upload key sat in the repository. Then the checklist of what your business has to own, and what a developer should only ever be granted access to.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>App Handover</category>
      <category>App Rescue</category>
      <category>Mobile Development</category>
    </item>
    <item>
      <title>The Agent Taps the Phone. Nothing Touches the Mac.</title>
      <link>https://codebyramiz.com/blog/agent-drives-a-real-iphone/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/agent-drives-a-real-iphone/</guid>
      <pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate>
      <description>An agent will implement your iOS feature, write the test, and run it — then stop at the only question that matters: does this work on a phone? Two walls stand between you and letting it drive the device. The first is iOS itself: on Android a cable and a debugging switch inject a tap into any handset, while nothing on a physical iPhone accepts one without a signed on-device agent and a live tunnel. The second is self-inflicted — the assumption that the agent must work a pointer like a person, which makes the automation unusable even when it works. Here is the receipt from a real session, the three honest tiers of physical-device driving, the exact commands to reproduce the whole loop yourself, and the two bugs a simulator could never have caught.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>iOS</category>
      <category>Test Automation</category>
      <category>AI Agents</category>
    </item>
    <item>
      <title>Call, Text, and Share Without Asking for a Single Permission</title>
      <link>https://codebyramiz.com/blog/contact-actions-without-permissions/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/contact-actions-without-permissions/</guid>
      <pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate>
      <description>A row of quick actions under a phone number — call it, text it, save it, share it — looks like a convenience and builds like a permissions grab. The naive version asks the OS to place calls, send texts, and write to the address book: a runtime prompt in front of a button the user tapped because they were ready to act, a store-policy tripwire on Android, and a privacy disclosure on both platforms it never needed. None of it is required, because none of those actions is something the app has to do itself. Here's the permission-free version on Android and iOS, and the per-platform permission audits that prove it.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>iOS</category>
      <category>Permissions</category>
    </item>
    <item>
      <title>A Correct Fix That Quietly Broke the Feature Next to It</title>
      <link>https://codebyramiz.com/blog/regression-testing-when-fixes-break-things/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/regression-testing-when-fixes-break-things/</guid>
      <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
      <description>A one-line change did exactly what it was meant to: it made a half-finished unit of work report itself as a failure instead of a fake success. It shipped in the afternoon it was written. Before the day was out it had to be fixed again — because that honest little fix had quietly taught the app to abandon entire batches of work, without an error, a crash, or a single line in any dashboard. That's a regression: a bug your own progress created, invisible from the inside. Here's the one that got caught, and the test that now catches it for good.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>Testing</category>
      <category>Regressions</category>
    </item>
    <item>
      <title>Your iOS and Android Apps Are Supposed to Be the Same Product. One of Them Isn't.</title>
      <link>https://codebyramiz.com/blog/android-ios-feature-parity/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/android-ios-feature-parity/</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>Most companies with two mobile apps have one real product and one approximation of it. The gap never appears on a dashboard, because parity is nobody's number — it grows one reasonable 'we'll port that later' at a time, and the users on the weaker platform don't file tickets about features they've never seen. Taking a production Android app to iOS, screen by screen, taught me what closing that gap actually takes: an adversarial inventory of every surface, proof that filters mean the same thing and not just look the same, and the discipline to write down which differences are deliberate. Here's the method, with the failures it caught.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>iOS</category>
      <category>Feature Parity</category>
    </item>
    <item>
      <title>Your Crash-Free Rate Is 99.5% and Users Still Say the App Is Broken</title>
      <link>https://codebyramiz.com/blog/crash-free-and-still-broken/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/crash-free-and-still-broken/</guid>
      <pubDate>Wed, 12 Aug 2026 00:00:00 GMT</pubDate>
      <description>Your dashboard says 99.5% crash-free and your reviews say the app doesn't work. Both are true, because crashes are the failure class users actually forgive — they're loud, they're recoverable, and the app tells you about them. The expensive ones are silent: a send queue stuck in a state nothing reports, a concurrent write that leaves two people believing different things, a query that quietly stops matching real data. Nobody files a ticket for those. They just leave. Here's what those failures look like from the inside, and what to instrument so the app tells you instead of your reviews.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>iOS</category>
      <category>Stability</category>
    </item>
    <item>
      <title>Your App Hasn't Shipped in a Year. The Problem Usually Isn't the Code.</title>
      <link>https://codebyramiz.com/blog/your-app-hasnt-shipped-in-a-year/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/your-app-hasnt-shipped-in-a-year/</guid>
      <pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate>
      <description>Your app hasn't shipped an update in a year, and everyone has quietly agreed that's fine because nothing is on fire. It isn't fine: a frozen app is on a clock set by Apple and Google, not by you. In four rescues the blocker was never that the code couldn't be changed — it was a pipeline nobody could run, a build only one person could produce, a store gate nobody had decoded, or a platform floor that rose while the team stood still. Here's what's actually decaying, and the order I'd unblock it in.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>iOS</category>
      <category>Release</category>
    </item>
    <item>
      <title>You Cannot Test Android on Every Phone. Here's What to Prove.</title>
      <link>https://codebyramiz.com/blog/your-app-does-not-need-every-phone/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/your-app-does-not-need-every-phone/</guid>
      <pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate>
      <description>You cannot test an Android app on every phone. The device matrix is unbounded, and it changes without you shipping anything — a third-party update can break a flow that was proven working last month. So what do you actually have to prove? A four-device bench with a written ledger of what is and isn't covered, field telemetry filtered hard enough to trust, fallbacks that fail loudly instead of silently, and OEM work that expands only when a recorded failure calls for it.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
    </item>
    <item>
      <title>App Store Rejection for Requiring WhatsApp: Fixing Guideline 4.2.3(i)</title>
      <link>https://codebyramiz.com/blog/surviving-app-store-guideline-4-2-3i/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/surviving-app-store-guideline-4-2-3i/</guid>
      <pubDate>Wed, 22 Jul 2026 00:00:00 GMT</pubDate>
      <description>Apple rejected my app under Guideline 4.2.3(i) — Minimum Functionality — for requiring WhatsApp to be installed. Building a complete standalone send path wasn't enough: the next build was rejected on the same guideline. What actually cleared it was the empty first-launch screen, and an appeal made of screenshots instead of argument. What the guideline is really testing, and the five things I'd check before you resubmit.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>iOS</category>
    </item>
    <item>
      <title>How I Review AI Changes in a Production Mobile App</title>
      <link>https://codebyramiz.com/blog/two-agents-one-repo/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/two-agents-one-repo/</guid>
      <pubDate>Mon, 13 Jul 2026 00:00:00 GMT</pubDate>
      <description>The dangerous thing about an AI coding agent isn't that it writes bad code — it's that it will tell you the work is done when it isn't. A skipped test reported as passing. A readiness summary that says PASS over a build that actually died. The method that's held up for me on a production mobile codebase: split the planner from the coder so nothing approves its own work, and keep the state that matters in files instead of the chat. The loop, the artifacts, and the four questions to ask anyone putting AI on your app.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>AI-Assisted</category>
      <category>Multi-Agent</category>
      <category>Workflow</category>
    </item>
    <item>
      <title>How to Know an Android App Audit Actually Found Nothing</title>
      <link>https://codebyramiz.com/blog/the-audit-that-found-nothing/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/the-audit-that-found-nothing/</guid>
      <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
      <description>A full audit of an Android codebase came back with one line: no verified bugs found. That's either the best sentence in engineering or the most worthless one — and the difference is entirely in the process. Here's what had to happen first before I'd believe it.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>Testing</category>
      <category>AI-Assisted</category>
    </item>
    <item>
      <title>Before You Rewrite an Inherited App, Stabilize It</title>
      <link>https://codebyramiz.com/blog/stabilize-before-you-rewrite/</link>
      <guid isPermaLink="true">https://codebyramiz.com/blog/stabilize-before-you-rewrite/</guid>
      <pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate>
      <description>You inherited an unstable mobile app and someone has already said 'just rewrite it.' A rewrite trades a known set of bugs for an unknown one and deletes years of edge-case handling that exists nowhere else. Here's the five-step playbook I run instead — profile before touching anything, kill the worst pain in place, add boundaries so fixes hold, repair the release pipeline, and only then decide whether a rewrite has actually been earned.</description>
      <author>hello@codebyramiz.com (Ramiz Raja)</author>
      <category>Android</category>
      <category>iOS</category>
      <category>Flutter</category>
    </item>
  </channel>
</rss>
