ft's BookmarkAuthorSnapshot.isVerified boolean is true for any account with any kind of X checkmark — Twitter Blue subscribers, Business accounts, and Government accounts. Downstream consumers (CLI users, JSONL readers, GUIs) cannot distinguish these categorically different states from a single boolean.
The disambiguating fields exist on the same User object is_blue_verified is read from at src/graphql-bookmarks.ts:263. They're currently discarded.
Failing case (reproducible against live X API today, May 2026)
Three accounts representing the collapse:
| Account |
Type |
is_blue_verified |
verification.verified_type |
ft's current isVerified |
| @usgraphics |
Business org |
true |
"Business" |
true |
| @itsjamiecho |
individual w/ Blue |
true |
absent |
true |
| @CENTCOM |
US Central Command (Government) |
true |
"Government" |
true |
All three flatten to identical isVerified: true despite being categorically different account types. A consumer reading bookmark.author.isVerified cannot tell @CENTCOM (a US military command) apart from a random Blue subscriber.
Real-world scale: in a 5222-bookmark corpus, 3647 records (69.8%) carry author.isVerified === true, indistinguishably mixing all three account types.
Two observations from inspecting the live response
1. legacy.verified is gone from modern X responses. The current derivation at src/graphql-bookmarks.ts:263:
isVerified: Boolean(userResult?.is_blue_verified ?? userResult?.legacy?.verified),
The ?? userResult?.legacy?.verified fallback is dead code — legacy.verified is absent from user.legacy across all three test accounts (verified May 2026). In practice isVerified is effectively just is_blue_verified.
2. verification.verified (new sub-object) is false for all three accounts. Even inside the new verification object, the original "verified" semantic has been retired. verification.verified_type is the field X actually uses to mark organization checkmarks.
What X exposes today
All accessible from core.user_results.result.* in the same response ft already fetches per bookmark:
verification.verified_type — "Business" | "Government" | absent. Drives the gold (Government) vs gray (Business) vs none checkmark distinction.
is_blue_verified — boolean, true for any checkmark of any kind. Worth preserving as a distinct field so downstream knows it now means "any check" rather than specifically "Blue subscriber."
profile_image_shape — "Square" | "Circle". Direct organization indicator (Square for Business + Government, Circle for individuals). Simpler than parsing verified_type for the org/individual question.
affiliates_highlighted_label — affiliation badges. Empty object {} when absent; rich object when present. Example value from @itsjamiecho:
{
"label": {
"badge": {"url": "https://pbs.twimg.com/profile_images/2038642627478704128/KTcKqWYg_bigger.jpg"},
"description": "Cosmos",
"url": {"url": "https://twitter.com/thecosmos", "urlType": "DeepLink"},
"userLabelDisplayType": "Badge",
"userLabelType": "BusinessLabel"
}
}
parody_commentary_fan_label — string. "None" when absent; other values when the account is in one of those categories. Attribution-critical: a tweet from a parody account currently looks identical to one from the real account in ft's data.
Fix
Layer 1 — type + parser (≈10 lines, no schema changes)
Extend BookmarkAuthorSnapshot at src/types.ts:21 and add five field reads inside the existing snapshot construction at src/graphql-bookmarks.ts:255-269:
// inside the existing snapshot construction block
verifiedType: userResult?.verification?.verified_type,
isBlueVerified: userResult?.is_blue_verified,
profileImageShape: userResult?.profile_image_shape,
affiliatesHighlightedLabel: userResult?.affiliates_highlighted_label,
parodyCommentaryFanLabel: userResult?.parody_commentary_fan_label,
JSONL serialization picks up the new fields automatically. No SQLite changes, no migration. This layer alone unblocks downstream consumers — JSONL is the source of truth per ft's design; SQLite is derived.
The existing isVerified field stays for backward compatibility. New fields are purely additive.
Optional cleanup while in this block: drop the ?? userResult?.legacy?.verified fallback at line 263 since it's dead code (the field is absent from modern responses).
Layer 2 — SQLite columns (optional follow-up)
If per-bookmark verification fields are wanted in SQLite too, add columns to the bookmarks table at src/bookmarks-db.ts:237 (currently has only author_handle, author_name, author_profile_image_url). Standard ALTER TABLE migration. Independent of Layer 1 and not required to resolve the misleading-data problem.
Why this is correctness, not feature
This isn't asking ft to capture data it doesn't already touch — is_blue_verified is already read at line 263. The issue is that the existing field's semantic became diluted as X added Blue / Business / Government / removed-legacy. ft never updated. Anyone using bookmark.author.isVerified today gets a misleading boolean by no fault of their own.
The fix is small (~10 lines) and additive. The minimum viable change preserves backward compatibility entirely while letting consumers opt into the disambiguation.
ft's
BookmarkAuthorSnapshot.isVerifiedboolean istruefor any account with any kind of X checkmark — Twitter Blue subscribers, Business accounts, and Government accounts. Downstream consumers (CLI users, JSONL readers, GUIs) cannot distinguish these categorically different states from a single boolean.The disambiguating fields exist on the same
Userobjectis_blue_verifiedis read from atsrc/graphql-bookmarks.ts:263. They're currently discarded.Failing case (reproducible against live X API today, May 2026)
Three accounts representing the collapse:
is_blue_verifiedverification.verified_typeisVerifiedAll three flatten to identical
isVerified: truedespite being categorically different account types. A consumer readingbookmark.author.isVerifiedcannot tell @CENTCOM (a US military command) apart from a random Blue subscriber.Real-world scale: in a 5222-bookmark corpus, 3647 records (69.8%) carry
author.isVerified === true, indistinguishably mixing all three account types.Two observations from inspecting the live response
1.
legacy.verifiedis gone from modern X responses. The current derivation atsrc/graphql-bookmarks.ts:263:The
?? userResult?.legacy?.verifiedfallback is dead code —legacy.verifiedis absent fromuser.legacyacross all three test accounts (verified May 2026). In practiceisVerifiedis effectively justis_blue_verified.2.
verification.verified(new sub-object) isfalsefor all three accounts. Even inside the newverificationobject, the original "verified" semantic has been retired.verification.verified_typeis the field X actually uses to mark organization checkmarks.What X exposes today
All accessible from
core.user_results.result.*in the same response ft already fetches per bookmark:verification.verified_type—"Business" | "Government" | absent. Drives the gold (Government) vs gray (Business) vs none checkmark distinction.is_blue_verified— boolean,truefor any checkmark of any kind. Worth preserving as a distinct field so downstream knows it now means "any check" rather than specifically "Blue subscriber."profile_image_shape—"Square" | "Circle". Direct organization indicator (Square for Business + Government, Circle for individuals). Simpler than parsingverified_typefor the org/individual question.affiliates_highlighted_label— affiliation badges. Empty object{}when absent; rich object when present. Example value from @itsjamiecho:{ "label": { "badge": {"url": "https://pbs.twimg.com/profile_images/2038642627478704128/KTcKqWYg_bigger.jpg"}, "description": "Cosmos", "url": {"url": "https://twitter.com/thecosmos", "urlType": "DeepLink"}, "userLabelDisplayType": "Badge", "userLabelType": "BusinessLabel" } }parody_commentary_fan_label— string."None"when absent; other values when the account is in one of those categories. Attribution-critical: a tweet from a parody account currently looks identical to one from the real account in ft's data.Fix
Layer 1 — type + parser (≈10 lines, no schema changes)
Extend
BookmarkAuthorSnapshotatsrc/types.ts:21and add five field reads inside the existing snapshot construction atsrc/graphql-bookmarks.ts:255-269:JSONL serialization picks up the new fields automatically. No SQLite changes, no migration. This layer alone unblocks downstream consumers — JSONL is the source of truth per ft's design; SQLite is derived.
The existing
isVerifiedfield stays for backward compatibility. New fields are purely additive.Optional cleanup while in this block: drop the
?? userResult?.legacy?.verifiedfallback at line 263 since it's dead code (the field is absent from modern responses).Layer 2 — SQLite columns (optional follow-up)
If per-bookmark verification fields are wanted in SQLite too, add columns to the
bookmarkstable atsrc/bookmarks-db.ts:237(currently has onlyauthor_handle,author_name,author_profile_image_url). Standard ALTER TABLE migration. Independent of Layer 1 and not required to resolve the misleading-data problem.Why this is correctness, not feature
This isn't asking ft to capture data it doesn't already touch —
is_blue_verifiedis already read at line 263. The issue is that the existing field's semantic became diluted as X added Blue / Business / Government / removed-legacy. ft never updated. Anyone usingbookmark.author.isVerifiedtoday gets a misleading boolean by no fault of their own.The fix is small (~10 lines) and additive. The minimum viable change preserves backward compatibility entirely while letting consumers opt into the disambiguation.