Skip to content

fix(accounts): self-heal unusable user_id via /me before Graph calls - #264

Merged
ajianaz merged 2 commits into
developfrom
fix/self-heal-user-id
Sep 10, 2026
Merged

ajianaz merged 2 commits into
developfrom
fix/self-heal-user-id

Conversation

@ajianaz

@ajianaz ajianaz commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What

  • New user_id_resolution module: is_user_id_usable() predicate (non-empty numeric string) + 4 unit tests.
  • ThreadsClient::ensure_resolved_user_id(): when the stored user_id is unusable (NULL / empty / token-in-id-slot — observed live on the ajianaz account), resolve the real id via GET /me, persist the correction to the DB, and return the healed account. No-op for healthy accounts.
  • Wired into all six call sites that build /v1.0/{user_id}/... URLs: create_container, create_container_full, publish_container, fetch_user_insights, fetch_publishing_limit, fetch_mentions.
  • Store::pool() getter (the private pool was unreachable cross-module).

Why

The ajianaz account carried user_id NULL for weeks because an OAuth exchange path failed to persist it. Every user-id-scoped call built URLs with the raw access token as the path segment and Meta rejected them: Unsupported get request. Object with ID 'THAASBUF...' (verified live on v0.9.4 — publishing-limit + mentions fail ONLY for ajianaz while profile-via-/me works, proving the token itself is healthy). With self-healing, the first affected call repairs the account permanently — no manual SQL, no re-OAuth.

Testing

  • 4 unit tests for the usability predicate (numeric ok; empty / token-shaped / alphanumeric rejected).
  • Full workspace: 251 passed / 0 failed; clippy -D warnings clean; fmt clean.
  • Post-deploy live check: ajianaz mentions fetch + publishing-limit flip from FAILED to 200 on the first call.

Security review notes (cora findings addressed)

  • The self-heal warning logs only the LENGTH of the stored value, never the value itself — in the failure mode the stored value IS the raw access token.
  • The regression test uses a synthetic token-shaped string, not a real production token.

…265)

## What

- New user_id_resolution module: is_user_id_usable() predicate
  (non-empty numeric string) + 4 unit tests.
- ThreadsClient::ensure_resolved_user_id(): when the stored user_id is
  unusable (NULL/empty/token-in-id-slot — observed on the ajianaz
  account), resolve the real id via GET /me, persist it to the DB, and
  return the healed account. No-op for healthy accounts.
- Wired into all six call sites that build /v1.0/{user_id}/... URLs:
  create_container, create_container_full, publish_container,
  fetch_user_insights, fetch_publishing_limit, fetch_mentions.
- Store::pool() getter (private pool was unreachable cross-module).

## Why

The ajianaz account carried user_id NULL for weeks because an OAuth
exchange path failed to persist it. Every user-id-scoped call (mentions
fetch, publishing limit, publishing itself) built URLs with the raw
token as the path segment and Meta rejected them with 'Unsupported get
request'. The token is valid — /me proves it — so the account heals
itself on the first affected call, with zero cost for healthy accounts.
Live root cause evidence: see the 2026-09-10 multi-account audit
(publishing-limit + mentions fail only for ajianaz; profile via /me
works).

## Testing

- 4 unit tests for the usability predicate (numeric ok, empty/token/
  alphanumeric rejected).
- Full workspace: 251 passed / 0 failed; clippy -D warnings clean;
  fmt clean.
- Live verification plan post-deploy: ajianaz mentions fetch +
  publishing-limit flip from LIMITS_FETCH_FAILED/MENTIONS_FETCH_FAILED
  to 200 on the first call.
@github-actions

Copy link
Copy Markdown

🔍 Cora AI Code Review

✅ No issues found. Code looks good!


Review powered by cora-code · BYOK · MIT

@ajianaz
ajianaz merged commit 17ea1ea into develop Sep 10, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant