尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证What an iPhone 18 Pro really costs over 36 months — plan, phone, fees and trade-in — across Tello, Mint, T-Mobile, AT&T and Xfinity Mobile.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗What an iPhone 18 Pro really costs over 36 months — plan, phone, one-time fees, and the trade-in you hand over — compared across Tello, Mint Mobile, T-Mobile, AT&T, Verizon and Xfinity Mobile.
A static tool in the Rising Company Daylight theme. No build step: index.html +
app.js + calc.js read data/pricing.json.
total = monthly plan × 36
+ phone price − promo credits (buying from Apple: − trade-in value instead)
+ one-time fees (activation · device connection charge)
+ trade-in given up (maker's trade-in estimate of the phone the carrier or Apple takes)
The phone you trade in is out-of-pocket at what Apple would pay for it, whichever route takes it. Handed to a carrier for bill credits, an iPhone 16 Pro costs you the $510 Apple offers. Traded to Apple, the $510 comes off the new phone and is counted back as the phone given up — so Tello unlimited with an iPhone 18 Pro Max is $25 × 36 + ($1,299 − $510) + $510.
Every (carrier, plan, route) combination is priced: the "buy from Apple with trade-in, bring your own" route on every plan, plus each promotion the plan qualifies for. Sorted cheapest first.
Lines (1–5) prices the plan as an account total for that many lines. Each line picks its own new phone (or none) and its own trade-in (or none). Promotions credit each line on its own trade-in; a line without a qualifying trade-in pays full price on that route. One-time fees are per line regardless. T-Mobile promotions credit at most four devices per account. Xfinity's first-year price covers one line; Mint's $10 intro 6 months applies per line. Verizon's myPlan gives new 3+-line accounts a $10/mo account credit for 36 months; Simplicity is one flat price per line.
The Extra savings card holds account-level toggles:
An Xfinity trade-in credit field appears on a line whose trade-in Xfinity has not priced. The route list can be filtered to one carrier; the filter shows every route for that carrier with its overall rank.
cmp=.python3 -m http.server 8000 # then open http://localhost:8000
node --test tests/ # calculator + analytics tests
The page fetches data/pricing.json, so it needs to be served — file:// blocks fetch.
data/pricing.json was captured from the carriers' own pages on 2026-09-21 with
agent-browser (the carrier sites block plain HTTP fetches; a headed session gets through).
Sources are listed in meta.sources and on the page.
What's in it:
phones — iPhone 18 Pro and iPhone 18 Pro Max storage tiers with one retail price each.
Apple, T-Mobile, AT&T and Verizon list the same figure (carriers show it as $x.99); Xfinity does
not publish one, so Apple's is used everywhere.tradeIns — the phone you hand over, valued by its maker's own trade-in program ("up to"
values, top storage, good condition): Apple Trade In's full iPhone table; Samsung's
standalone trade-in (run by Likewize, pays without a purchase) for Galaxy S20–S25, Note20,
Z Fold3–7 and Z Flip3–7; the Google Store estimator for Pixel 6–10 (Google pays the same
whichever Pixel is bought). Each entry names its brand and valueSource. Galaxy S26 and
Pixel 11 are in neither maker's program yet, so they are not offered.carriers[].plans — monthly is the account total keyed by line count ("1"…"5",
T-Mobile Beyond to "8"). T-Mobile and AT&T totals were read from their plan pages per
line count; Xfinity, Tello and Mint charge the same per line. A plan with no price for the
requested count is skipped rather than guessed. premiumDataGb and minutes let the
calculator filter by usage.carriers[].promos — per-plan eligibility, requires (trade-in / new line / port-in /
existing line),
bill-credit term, and trade-in tiers keyed by device id, with an otherwise tier
for anything not listed. stackable promos (AT&T's $200 online credit) add on top of a
main promo and, with appliesToByod, on top of a bring-your-own phone.verified: false. Xfinity's separate iPhone Duo credit was quoted at checkout for every
trade-in too: $1,000 for an iPhone 14 or newer and the newest Galaxy and Pixel flagships,
$500–$700 for older phones, and nothing for a Pixel Fold (a one-time $50 instead). Credits
only kick in on Mobile Plus.promos[].models — a promo that names models credits only those new phones. Most
T-Mobile offers name the 18 Pro and Pro Max; T-Mobile's Beyond trade-in and port-in offers,
every AT&T and Verizon offer, and Xfinity's no-trade-in and upgrade offers also cover iPhone
Duo; Xfinity's trade-in credit for a new line has a separate Duo offer.Things worth knowing that the marketing copy hides:
The calculator already takes these as inputs; the page just pins them for now.
phones[]).minDataGb, minutes) so Tello's smaller plans and
AT&T Value 2.0 come into play.Every input is in the URL, so a shared link opens on the situation the sender priced.
The link preview has to carry its weight: og.png is a picture of the page's own
carrier chart — same segments, same colors, same cheapest-first ranking — so the point
survives a timeline and the click is verification rather than curiosity.
og.js holds the card's data model (CARD_SCENARIO, cardModel). The scenario is the
one the page itself computes on first load: one line, an iPhone 18 Pro 256, an iPhone 16
Pro to trade, not switching. A card that disagrees with the page it links to is a worse card.
Regenerate it whenever data/pricing.json moves:
python3 -m http.server 8000
agent-browser set viewport 1240 720 2 # 2x — the card is 1200x630 CSS px
agent-browser open http://localhost:8000/tools/og.html
agent-browser wait --load networkidle
agent-browser screenshot "#card" og.png # writes 2400x1260
Then restamp the landing page, which owns eight strings derived from the data — the
?v= cache stamps, the headline spread in the tags, the six totals in the alt text,
the two dataset dates, the no-JS hero line and the footer:
node tools/restamp.mjs # rewrite in place
node tools/restamp.mjs --check # exit 1 if index.html has drifted
Scrapers cache og:image by URL, so without a new stamp Facebook, Slack and X keep
serving the old numbers for days — the exact failure a weekly re-crawl exists to avoid.
The whole refresh is written up as a skill: .claude/skills/refresh-carrier-pricing.
tests/og.test.mjs pins all of it: the scenario, the arithmetic behind each bar, the
numbers printed on the committed card, the stamp against meta.crawledAt, and the
spread quoted in the tags. Moving the data without regenerating the card is a failing
test, not a stale share.
The tool answers every situation at one URL, but the question arrives in several
hundred shapes — "verizon vs t-mobile iphone 18 pro", "is xfinity mobile worth it".
seo.js builds a model for each of those, and tools/gen-seo.mjs renders them:
node tools/gen-seo.mjs # 15 compare/ pages, 6 carrier/ pages, sitemap.xml, robots.txt
Output is committed, like og.png. Regenerate it whenever data/pricing.json moves;
tests/seo.test.mjs fails if the committed pages carry a stale crawl date.
Each page states numbers the calculator produced, names its sources, and deep-links into the tool pre-loaded with the situation it describes. The carrier pages carry the part the carriers' own pages never show: each promotion priced against buying the same phone outright on the same plan, which holds the plan constant so the difference is the deal and nothing else.
Two scenarios drive everything, both in scenario.js:
HEADLINE_SCENARIO — one line, an iPhone 18 Pro 256, an iPhone 16 Pro to trade, not
switching. What the landing page computes on first load, so the card agrees with it.NO_TRADE_IN_SCENARIO — the same line with nothing to trade. The generated pages lead
with it, and their tool links carry it (l=iphone-18-pro-256:-) so the tool opens on
the numbers the page quoted.SWITCHER_SCENARIO — the same line switching in with an iPhone 16 Pro to trade.
Every promotion requires a port-in, a trade-in or both, so the no-trade-in scenario
filters all of them out; a page about whether a deal is worth taking has to price
the case where it is on the table.Both spread in USAGE_FLOOR (50 GB premium data, unlimited minutes) — the floor
app.js has always applied. It lives in scenario.js because leaving it out prices
plans the page never shows: the social card once shipped a Tello plan with 300 minutes
and no data as the cheapest route.
PostHog, provisioned through the Vercel Marketplace (vercel integration add posthog,
US region). analytics.js holds the whole of it.
The project token in analytics.js is a public write-only key — the same one PostHog's
own snippet puts in the page source. There is no build step to inject it from the
environment, so it is written in. The Marketplace also set *_POSTHOG_PROJECT_TOKEN and
*_POSTHOG_HOST on the Vercel project for anything that later needs them.
Nobody signs in here, so nobody is identified: person_profiles: "identified_only" keeps
readers anonymous. shouldTrack() drops localhost and .local, so serving the folder
locally never reaches the numbers.
Alongside PostHog's automatic pageviews and click autocapture:
situation_priced — the situation someone actually priced (lines, phones, trade-ins,
switching, Costco, carrier filter) and what won it (carrier, plan, route, total, spread).
Debounced, and a situation already reported is not reported again until something
changes — tab switches re-render without being a new data point.tab_selected · route_compared / route_uncompared · carrier_filtered ·
routes_expanded · compare_tray_used · summary_card_jumpedCounts and ids only. No prices typed by the reader, no free text, no identifiers.
Everything the page shows comes from data/pricing.json, and each entry names its source.
If a price has moved, a promotion is missing, your carrier is not here, or a checkout showed
you a trade-in credit the carrier does not publish, open a pull request or an issue at
https://github.com/rising-company/true-cost-to-phone. Keep meta.crawledAt honest, note
where a number came from, and run node --test tests/ — the tests pin the arithmetic and a
few facts worth not losing (T-Mobile's tiers, Xfinity's one-line intro, the Costco rules).
node --test tests/ — zero-dependency, matching the other static tools in this workspace
(www/stream). This deviates from handbook ADR-0006 (Vitest) because there is no
package.json to hang it on; the layout (tests/ folder, node environment) is the same.