Thursday, December 18, 2025

Using AI to develop MAPS

 The AI Coding Journey: From Copilot to Gemini Pro

As we all know, AI is the current "it" thing. I’ve been using it for everything from household fixes to troubleshooting complex phone settings. For example, I finally configured my phone to stay on DND for everyone except my contacts—a task significantly more complicated than it sounds when you're balancing multiple Google Voice and carrier numbers. Recently, however, I decided to see what AI could do for my coding workflow.

I started with GitHub Copilot in VSCode, which was decent until I hit my monthly query limit. I then pivoted to the Google Gemini Pro Trial (a 12-month free pass), which also integrates directly into VSCode.

The Good, The Bad, and The "Try Again"

Using Gemini is simultaneously amazing and frustrating. The "diff-like" interface for approving code changes is brilliant. However, the experience degrades over long, protracted conversations; the history helps the AI stay context-aware, but it makes the response time crawl.

I’ve also encountered several technical quirks:

  • Failed Applications: Sometimes it fails to modify the file, requiring a "Try again" prompt.
  • The "Unknown Problem": Occasionally, it hits a wall that requires a full VSCode restart.
  • Loss of Agency: It’s easy to let the AI inject so much code that you no longer fully "know" your own project.

A perfect example of AI going down the wrong path happened while I was building a YouTube downloader. The AI insisted on using a complex PHP OOP library to wrap yt-dlp and ffmpeg. We spent hours fighting version mismatches between the apt version of yt-dlp and the GitHub binary. Finally, I had to step in: "Wait—I can run this perfectly at the command line with a cookies.txt file. Let’s jettison the library and just have PHP construct the shell command." It was a reminder that while AI is a powerful tool, it still needs an experienced dev to keep it from over-engineering itself into a corner.

Modernizing MAPS with Gemini

For the uninitiated, MAPS is my homegrown spam filtering system. It triggers from a user’s ~/.forward file, extracts the "From" address, and checks it against a MariaDB backend.

  • Whitelist: Delivered immediately.
  • Blacklist: Bounced with a "Not allowed" message.
  • Nulllist: Silent discard.
  • Unknown: The email is held, and the sender gets a registration link. If they click and identify themselves, their mail is released, and they are whitelisted.

Recent AI-Assisted Improvements:

  1. Persistent Sessions: Gemini helped me rewrite the login logic so the session cookie refreshes every time I visit the site. Instead of a hard 30-day expiration, it now only expires if I haven't logged in for 30 days.
  2. Subject Line Encoding: We’ve been working on better handling of non-ASCII subject lines. It's a work in progress—getting diverse character sets (like Chinese) to render correctly is a moving target.
  3. Safe HTML Rendering: This was a huge win. Previously, my email display was "raw" (and ugly) to prevent scripts or worms from executing. The AI implemented a sanitization module that:

    • Strips all scripts.
    • Disables all href links.
    • Converts links into "hover-only" tooltips so I can see the URL without the risk of clicking it.

Next, I moved on to my most ambitious change yet...

Android App - MAPS Mobile

I got this bright idea that I could make an Android App from my MAPS system. Going to the webpage on a phone, with tiny fonts, was really not mobile-friendly. Could I actually use Gemini to help me develop an Android app? I've never done one before.

Consulting Gemini about how to do this revealed that I needed to install Gradle and the Android SDK, both of which were easy to do on Linux. Gemini even showed me how I can create a VSCode task to build with Gradle and install using the adb CLI, which I also have been using to use scrcpy to view my Android phone on my Linux Desktop. Sweet! Now I can actually type Shift-Ctrl-B to build and install the app on my phone, then move my mouse cursor to the scrcpy window to test the changes. True, it's kind of a pain to have to remember to upload backend changes to my cloud server, but I wanted to access my live data as emails processed by my spam filter age quickly. Luckily, Gemini even taught me to ssh tunnel to my MariaDB in the cloud through localhost.

I've implemented the MAPS Mobile app with a lot of the functionality, querying, and directing Gemini on what I wanted to see changed or implemented. The mobile app doesn't implement all the functionality or the process flow of the web page. But the app is really what I need and what is practical for an Android app. And it is my first one!

Take aways

  • AIs aren't always right. You need to guide them. In order to guide them, you need ot know what you are doing. College grads and others are  trying to enter the field because they see it as the next big thing, but often lack the background to properly guide the AIs
  • Many businesses will miss this as they eye the bottom line (i.e., cost $$$) before understanding the practicality of this, much like they invested a lot into offshore tech support without asking the question: Won't this worsen communication between our employees and customers?
  • AI needs to be told when there is a better, more architecturally intelligent path. I.e. You still need qualified people
  • Coding with your vibe buddy, Mr. AI, needs to be learned like anything else
  • Vision you and your AI buddy to be a team, not a substitute.

Monday, November 27, 2017

Hit Count and Last Hit


After having left MAPS pretty much alone for a long time, though I did implement "nuke" which helps nuke whole domains, I finally have implemented new functionality for MAPS. You see over this last year or so I've been getting a lot of spam mostly oriented in which the domain name was wildly varying. So lots of mail loops were happening. Whacking whole domains became a favorite past time of mine and hence the "nuke" script (not an official part of MAPS mind you). Still it seemed like a losing battle.

Then I got to thinking - something I've been thinking for a while - how effective are all of my null list entries, now numbering in the 17K area! I thought that I could easily add some fields to the list table, namely a hit_count and a last_hit field, and then during scrubbing time see if these null list entries were at all effective, and if not then to automatically remove them.

So I added the fields and changed MAPS such that it records the hits and when the last hit happened. Then in mapsscrub check to see if last_hit is older than the number of days the user is keeping history. If it's 0 then simply remove that entry. Note this happens only for the null list. White list and black list are to be managed by the user. You purposely add somebody to the white or black list for a reason. Do we want to auto age these off? Probably not.

If the hit count is not 0 then how do we age off these apparently no longer effective null list entries? Well the though was to age them by subtracting 1 from the hit count. Thus if we had a null list entry that was fairly active for a little while and say accumulated a hit_count of 10 but then was largely un-hit, the hit_count would go 9, 8, 7, 6, 5... down to 0 and then the entry would be removed. I might want to change this as some null list entries are getting hit_counts in the thousands now! Assuming the user has a 30 day history then perhaps after 30 days of inactivity I should age any null list entry off the list in 7 days? Note that any activity in those 30 days would immediately reset the clock for at least the next 30 days (assuming a history of 30 days).

With this in place I decided to change the mail loop procedure to auto add the sender to the null list. Previously I was whacking off the whole domain - here we are just auto adding the individual sending address. But it's automatically added, automatically tracked for effectiveness and automatically aged off. Beside I still have the option of perusing the top returning domains and can whack whole domains still. Now any hits on any users in the domain will continue to insure that that domain null list entry will remain and not automatically age away...

No more @defaria.com




Due to an influx of spam getting through MAPS with a format of <something>@defaria.com I finally decided to fix MAPS to handle that better. Now if the from is from defaria.com (or the current domain) then the user name is looked up in /etc/passwd using getpwent and if there is no user of that name it is simply nulllisted. This is an obvious attempt by spammers to forge from email addresses.

Also removed logging of when the message is obviously garbled or not conforming to standards. Plus I no longer log if the user uses andrew@defaria.com but fails to have a name such as "Andrew DeFaria <andrew@defaria.com>". The former turns out to be mostly Nigerian spam anyway.

Finally, replaced /usr/local/maps with a direct checkout form CVS!

MAPS Scrubber




Updated mapsscrub to also report total number of user emails in the database. Also fixed header.

Added page drop down




Added a page drop down to list.php. This is useful when one wants to say go to the last page.

Move list entry bug




Found a bug today. While adding to the blacklist an entry was on the white list, MAPS correctly adds the entry to the black list and deletes the entry on the white list. However it fails to resequence the white list causing problems down the line.

Login bug


Squashed a nasty bug, well actually a lack of implementation. After converting some of the web pages to PHP I neglected to implement Login in PHP! Now implemented.