<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[xjokerabab notes]]></title><description><![CDATA[xjokerabab notes]]></description><link>https://xjokerabab.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 20 Oct 2026 19:51:21 GMT</lastBuildDate><atom:link href="https://xjokerabab.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why the IP ChatGPT and Claude See Isn't the IP You Think]]></title><description><![CDATA[You open a "what's my IP" page, it shows an address in the country you expect, and you conclude your network is fine. Then ChatGPT loops on a verification…]]></description><link>https://xjokerabab.hashnode.dev/why-the-ip-chatgpt-and-claude-see-isn-t-the-ip-you-think</link><guid isPermaLink="true">https://xjokerabab.hashnode.dev/why-the-ip-chatgpt-and-claude-see-isn-t-the-ip-you-think</guid><category><![CDATA[networking]]></category><category><![CDATA[AI]]></category><category><![CDATA[Devops]]></category><category><![CDATA[cli]]></category><dc:creator><![CDATA[xjokerabab]]></dc:creator><pubDate>Mon, 19 Oct 2026 12:44:52 GMT</pubDate><content:encoded><![CDATA[<p>You open a "what's my IP" page, it shows an address in the country you expect, and you conclude your network is fine. Then ChatGPT loops on a verification page, or Claude says it's unavailable in your region, and nothing adds up.</p>
<p>Often the explanation is boring: <strong>the "what's my IP" page and the AI service never saw the same connection.</strong> An IP check only reports the public exit used to reach <em>that</em> site, over <em>that</em> address family, through whatever rule matched <em>that</em> hostname. An AI service on a different hostname can take a different path.</p>
<p>This post covers the three usual causes (dual-stack, domain-based proxy rules, terminal vs. browser), how to ask the service side which IP it sees, and the curl commands I use. At the end I mention a small tool I built for this, <a href="https://ipforai.cc/en">IP for AI</a>, but you can do everything here with curl alone.</p>
<h2>Cause 1: IPv4 and IPv6 are two different exits</h2>
<p>On a dual-stack network your machine has two public identities. They can sit on different ASNs, show up as different regions, or one can go through a proxy while the other goes direct. A common setup: the proxy covers IPv4, and IPv6 quietly bypasses it.</p>
<p>Which family a given request uses isn't fixed. DNS can return both A and AAAA records, the OS sorts the candidates (RFC 6724 default address selection), and the client races connection attempts (RFC 8305, Happy Eyeballs v2). The page, the sign-in redirect and static assets can sit on different hostnames, so one session can even mix families. Seeing IPv4 on one site tells you nothing about what a different hostname got a second later.</p>
<p>One TCP connection has exactly one source address, so any single check sees one family. Force each family on purpose:</p>
<pre><code class="language-bash">curl -4 -sS https://ipforai.cc/json
curl -6 -sS https://ipforai.cc/json
</code></pre>
<p>If both come back with the same country and network type, good. If IPv4 says one region and IPv6 says another, you've found a variable worth testing.</p>
<h2>Cause 2: domain-based proxy rules</h2>
<p>Rule-based clients (Clash/Mihomo and similar) choose a route per hostname. That's the point of split routing, and it also means "my IP" depends on which domain you ask.</p>
<p>Things that typically go wrong:</p>
<ul>
<li>The rule set covers <code>chatgpt.com</code> but not some other hostname the app actually requests.</li>
<li><code>DOMAIN-SUFFIX</code> and <code>DOMAIN-KEYWORD</code> behave differently. Suffix matches a domain and its subdomains. Keyword checks for a substring in the hostname, not the URL path.</li>
<li>Rule order: an earlier broad rule catches the request before your AI rule does.</li>
<li>DNS caching, or a client that doesn't cover every app, makes results look inconsistent between runs.</li>
</ul>
<p>The opposite case also happens: every AI domain resolves to the same exit, and people assume split routing is "off" when it's working exactly as configured. A shared exit isn't automatically a bug. Compare against your rules, not against a guess.</p>
<h2>Cause 3: your terminal is not your browser</h2>
<p><code>curl</code> in a terminal follows the <code>HTTPS_PROXY</code> / <code>https_proxy</code> environment variables and your OS routing. Your browser may use a system proxy, an extension, or something else. A VPS has no browser at all. If you test in one place and the failure happens in the other, you've compared two different paths.</p>
<h2>Ask the other side: the <code>cdn-cgi/trace</code> endpoint</h2>
<p>A local check can't tell you what a remote service saw. The useful trick is that sites served through Cloudflare expose a plain-text diagnostic endpoint at <code>/cdn-cgi/trace</code>. Several AI front-ends are on Cloudflare, so you can ask <em>their</em> edge which IP your request arrived from:</p>
<pre><code class="language-bash">curl -s https://chatgpt.com/cdn-cgi/trace
</code></pre>
<p>The output is <code>key=value</code> lines. Trimmed, it looks like this:</p>
<pre><code class="language-text">h=chatgpt.com
ip=&lt;your public exit as seen by this hostname&gt;
loc=JP
http=http/2
tls=TLSv1.3
warp=off
</code></pre>
<p><code>ip</code> is the source address of that connection and <code>loc</code> is the country Cloudflare assigns to it. Because the request went to <code>chatgpt.com</code>, it went through whatever proxy rule matches <code>chatgpt.com</code>. That's the point.</p>
<p>Run it per hostname and per family:</p>
<pre><code class="language-bash">for host in chatgpt.com claude.ai grok.com; do
  for fam in -4 -6; do
    printf '%-12s %s  ' "$host" "$fam"
    curl $fam -s -m 8 "https://$host/cdn-cgi/trace" \
      | grep -E '^(ip|loc)=' | tr '\n' ' '
    echo
  done
done
</code></pre>
<p>Then compare with the exit a neutral site sees for the same family:</p>
<pre><code class="language-bash">curl -4 -sS https://ipforai.cc/json | jq -r '.ipv4.ip // .ipv6.ip'
curl -6 -sS https://ipforai.cc/json | jq -r '.ipv6.ip // .ipv4.ip'
</code></pre>
<p>(<code>/json</code> fills only the family the server saw the request arrive on, so the other field is <code>null</code>. <code>-4</code> controls how your machine connects. If there's another relay layer in front of you, the server can still record the other family, so print whichever field is filled.)</p>
<p>If <code>chatgpt.com</code> over IPv4 shows a different IP or country than the neutral check over IPv4, that hostname is taking a different path. Sometimes that's intended, sometimes it's a rule that doesn't do what you think.</p>
<h3>Limits of this trick</h3>
<ul>
<li>It only works on hostnames served through Cloudflare. If a service isn't, there's no <code>/cdn-cgi/trace</code> and you get no echo. Don't read an exit into a missing answer.</li>
<li>It shows the exit for <em>that hostname</em>. An app's API, auth and asset hosts may route differently. The trace on a front-end domain is evidence, not proof of what every request in a session used.</li>
<li>A matching exit doesn't mean your account, subscription or region is fine. It removes one network variable. That's all.</li>
</ul>
<h2>A debugging loop that actually attributes the cause</h2>
<ol>
<li>Record both exits separately: IP, country, ASN, and whether it looks like data-center or residential.</li>
<li>Record the service-side exits from the trace endpoints for the services you care about.</li>
<li>Check whether failures follow one address family or one hostname.</li>
<li><strong>Change one thing</strong>, retest, and record again. Proxy covering IPv6, a single rule, one DNS setting. Change three things at once and you won't know which fix worked.</li>
<li>A short IPv4-only or IPv6-only test is a fine diagnostic. Don't leave it as your permanent setup; fix the proxy coverage or routing instead.</li>
<li>If the exits are aligned and stable and the service still fails, stop blaming the network. Look at the browser session, the exact error message, and the provider's status page.</li>
</ol>
<h2>The tool I built for this</h2>
<p>After running those loops by hand too many times, I put them into <a href="https://ipforai.cc/en">ipforai.cc</a>. It's free and needs no account. What it does today:</p>
<ul>
<li>Profiles your current <strong>IPv4 and IPv6 exits separately</strong>: region, ASN, network type (data-center / residential evidence), routing hints, and proxy / VPN / Tor and risk-list signals where data exists.</li>
<li>Computes a <strong>0–100 network environment score</strong> with itemized evidence. It's a reference for the network only, not any platform's official score, and not a ban predictor.</li>
<li>An <strong>AI routing exit</strong> page that compares the exits supported AI endpoints echo back against the site's own exit.</li>
<li>DNS-exit and WebRTC comparisons in the browser, plus symptom-first guides such as <a href="https://ipforai.cc/en/guides/chatgpt-ipv4-ipv6-mismatch">IPv4/IPv6 exit mismatch</a>.</li>
</ul>
<p>For servers there's a read-only POSIX <code>sh</code> script: it needs only curl, writes no config, installs nothing and needs no API key. It probes public endpoints of 11 AI services and compares routing exits for 20+ services against the same-family local exit. Please read it before running it:</p>
<pre><code class="language-bash">curl -fsSL https://ipforai.cc/sh -o /tmp/ipforai-check.sh
less /tmp/ipforai-check.sh
sh /tmp/ipforai-check.sh
</code></pre>
<p>The cloudflare-mode routing probes in that script use the same <code>cdn-cgi/trace</code> approach shown above, so nothing in it is magic. Usage and output are documented at <a href="https://ipforai.cc/en/cli">/cli</a>, and the script mirror and JSON docs are on <a href="https://github.com/xjokerabab/ipforai">GitHub</a>.</p>
<h2>Takeaway</h2>
<p>"My IP" isn't one value. It depends on the address family, the hostname, the matching rule and the client making the request. Before you blame your IP's "reputation," check that the service saw the IP you think it did. Ask the service side, check both families, and change one variable at a time.</p>
<p>If you've hit a dual-stack or routing edge case these checks don't explain, I'd like to hear about it in the comments.</p>
]]></content:encoded></item><item><title><![CDATA[Tracking the US Visa Bulletin as Open Data (Not Screenshots)]]></title><description><![CDATA[Every month the US Department of State publishes the Visa Bulletin — the official chart that tells employment- and family-based immigrant applicants…]]></description><link>https://xjokerabab.hashnode.dev/tracking-the-us-visa-bulletin-as-open-data-not-screenshots</link><guid isPermaLink="true">https://xjokerabab.hashnode.dev/tracking-the-us-visa-bulletin-as-open-data-not-screenshots</guid><category><![CDATA[immigration]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[data]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[xjokerabab]]></dc:creator><pubDate>Sun, 18 Oct 2026 11:19:24 GMT</pubDate><content:encoded><![CDATA[<p>Every month the US Department of State publishes the <a href="https://travel.state.gov/content/travel/en/legal/visa-law0/visa-bulletin.html">Visa Bulletin</a> — the official chart that tells employment- and family-based immigrant applicants whether their priority date is current. For years, the practical workflow for a lot of people (including me) looked like this: open a PDF, squint at a table, paste a number into a spreadsheet, argue with friends about whether “C” means what they think it means.</p>
<p>I got tired of that. So I built a small data site and an open dataset that re-publishes the bulletin in a form you can actually query.</p>
<p><strong>Site:</strong> <a href="https://yiminshuju.com">yiminshuju.com</a><br /><strong>Full bulletin tables:</strong> <a href="https://yiminshuju.com/paiqi/">yiminshuju.com/paiqi</a><br /><strong>Open data:</strong> <a href="https://github.com/xjokerabab/visa-bulletin-cn">github.com/xjokerabab/visa-bulletin-cn</a></p>
<h2>What the site is (and isn’t)</h2>
<p><a href="https://yiminshuju.com">yiminshuju.com</a> aggregates:</p>
<ul>
<li><p>US green card <strong>Visa Bulletin</strong> dates (employment EB-1–EB-5 and family F1–F4)</p>
</li>
<li><p><strong>USCIS processing times</strong> by form and service center</p>
</li>
<li><p>Canada <strong>Express Entry</strong> draw scores (where published)</p>
</li>
<li><p>A light multi-country policy index of <em>public</em> numbers</p>
</li>
</ul>
<p>It is <strong>data only</strong> — not a law firm, not a consultancy, not “we’ll get you a green card.” Every figure is tied back to an official source and stamped with an update date. If the government didn’t publish a field, the cell stays empty. No interpolated “estimates” dressed up as facts.</p>
<h2>The part that usually confuses people: Table A vs Table B</h2>
<p>The bulletin has two charts that look almost identical and mean very different things:</p>
<table>
<thead>
<tr>
<th>Chart</th>
<th>Official name</th>
<th>Practical meaning</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Table A</strong></td>
<td>Final Action Dates</td>
<td>When a visa number can actually be <em>used</em> (final adjudication rhythm)</td>
</tr>
<tr>
<td><strong>Table B</strong></td>
<td>Dates for Filing</td>
<td>When USCIS <em>may</em> allow you to file adjustment of status early — <strong>only if</strong> USCIS says it is using Chart B that month</td>
</tr>
</tbody></table>
<p>A priority date that is “current” on Table B is not the same as being ready for final action on Table A. Mixing them up is one of the most common ways people misread the bulletin. The <a href="https://yiminshuju.com/paiqi/">paiqi page</a> keeps A and B side by side for China / Worldwide / India so you can compare without flipping PDFs.</p>
<p><code>"C"</code> generally means <em>Current</em> (no backlog for that category that month). Treat it as a status code, not a calendar date.</p>
<h2>Why open data instead of another blog post</h2>
<p>Screenshots rot. PDFs get replaced. Chat threads lose the source link.</p>
<p>The companion repo <a href="https://github.com/xjokerabab/visa-bulletin-cn"><code>visa-bulletin-cn</code></a> stores structured bulletin snapshots so you can:</p>
<ul>
<li><p>Diff month-over-month movement by category and chargeability</p>
</li>
<li><p>Build your own alerts (“EB-2 China Table A moved”)</p>
</li>
<li><p>Cite a stable URL instead of “see the screenshot I sent last Tuesday”</p>
</li>
</ul>
<p>Sync happens after each new DOS bulletin drop; the site and the repo are meant to stay in step. Always treat the Department of State / USCIS originals as authoritative if anything disagrees.</p>
<h2>A 30-second read of your own case</h2>
<ol>
<li><p>Confirm category and country of chargeability (e.g. China-mainland birth, EB-2).</p>
</li>
<li><p>Look at <strong>Table A</strong> — is your priority date earlier than the final action cutoff?</p>
</li>
<li><p>Look at <strong>Table B</strong> — only relevant if USCIS is accepting Chart B filings that month.</p>
</li>
<li><p>Separately check <a href="https://yiminshuju.com">USCIS processing times</a> for the form you actually filed (I-140, I-485, etc.). Processing time ≠ visa availability.</p>
</li>
</ol>
<p>That’s it. No score, no “approval probability.”</p>
<h2>Stack notes (for the curious)</h2>
<p>Nothing exotic: scrape/parse official bulletin text into structured rows, render on a static-ish front end, keep the historical series in git. The interesting product decision wasn’t the framework — it was <strong>refusing to invent missing numbers</strong>. Empty beats estimated when you’re dealing with immigration cutoffs.</p>
<p>If you maintain your own pipeline, the repo is the cleaner input than OCR on a PDF.</p>
<h2>Links</h2>
<ul>
<li><p>Home / overview: <a href="https://yiminshuju.com">https://yiminshuju.com</a></p>
</li>
<li><p>Full Visa Bulletin tables: <a href="https://yiminshuju.com/paiqi/">https://yiminshuju.com/paiqi/</a></p>
</li>
<li><p>Open bulletin data: <a href="https://github.com/xjokerabab/visa-bulletin-cn">https://github.com/xjokerabab/visa-bulletin-cn</a></p>
</li>
</ul>
<h2>Caveats</h2>
<p>This is a convenience layer over public government data. It is not legal advice, not a prediction of your case, and not a substitute for the official Visa Bulletin or USCIS notices. If you need a strategy call, talk to a licensed attorney — not a chart.</p>
<p>Questions, corrections, or “this category looks wrong” issues are welcome on the GitHub repo.</p>
]]></content:encoded></item></channel></rss>