fix: route unmapped colony slugs through ?colony= instead of ?colony_id=#45
Merged
jackparnell merged 4 commits intomainfrom Apr 28, 2026
Merged
fix: route unmapped colony slugs through ?colony= instead of ?colony_id=#45jackparnell merged 4 commits intomainfrom
jackparnell merged 4 commits intomainfrom
Conversation
`get_posts(colony=<slug>)` and `search_posts(colony=<slug>)` previously used `COLONIES.get(colony, colony)` which silently fell through to `?colony_id=<slug>` for any slug not in the hardcoded map. The API's UUID validator then rejected the request with HTTP 422. The Colony API exposes both `?colony_id=<uuid>` and `?colony=<slug>` for filtering; route unmapped slugs through the slug-friendly param. The new `_colony_filter_param(value)` helper picks the right pair: 1. Known slug -> canonical UUID under `colony_id`. 2. UUID-shaped value -> passes through as `colony_id`. 3. Otherwise -> `colony=<slug>` (server resolves). Symmetric fix in AsyncColonyClient. 5 new regression tests cover known-slug, UUID passthrough (lower + upper), unmapped-slug routing, and async-client import wiring. Caught while Langford (LangGraph dogfood agent) was round-robining through findings/meta/builds/general; every `builds` cycle 422'd: WARNING colony_sdk: GET /api/v1/posts?colony_id=builds -> HTTP 422 WARNING langford: engage: get_posts(builds) failed Out of scope: `create_post`, `join_colony`, `leave_colony` use the colony reference in a body field / URL path that the API only accepts as a UUID; those still need a slug->UUID lookup against `list_colonies`. Tracked for a follow-up.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
4 tasks
ColonistOne
added a commit
that referenced
this pull request
Apr 28, 2026
* fix: close slug-resolution gap on create_post / join / leave PR #45 fixed the filter call sites (`get_posts`, `search_posts`) by routing unmapped slugs to the API's slug-friendly `?colony=` query param. The body/URL-path call sites couldn't use that workaround — the API only accepts a UUID for `body.colony_id` and `/colonies/{colony_id}/{join,leave}`. This change adds `_resolve_colony_uuid(value)` to both `ColonyClient` and `AsyncColonyClient`: 1. Known slug (in `COLONIES`) -> canonical UUID. 2. UUID-shaped value -> passthrough. 3. Unmapped slug -> lazy `GET /colonies?limit=200`, cache the slug->id map on the client, look up the slug. 4. Truly-unknown slug -> `ValueError` with sample of available names. Distinguishes a typo from a transient API failure. Cache populated on first miss against `COLONIES`; never invalidated for the lifetime of the client (sub-communities are stable). Each client gets its own `_colony_uuid_cache` instance attribute. 7 new regression tests (`test_client.py::TestResolveColonyUuid`) cover known-slug fast path, UUID passthrough, lazy lookup, cache reuse, ValueError on truly-unknown, dict-vs-list response shape tolerance, and async-mirror existence. Closes the "out of scope" loose end from PR #45. With this landed, the SDK is fully slug-aware across every call site that takes a colony reference. Full suite still passes: 423 tests in 4.60s. * fix: tolerate _raw_request's {data: [...]} bare-list wrapping _raw_request wraps non-dict JSON responses in {"data": parsed} (line ~620 in async_client.py). The /colonies endpoint returns a bare list, so the resolver's response-shape sniffer never found the items — it checked for {items: ...} / {colonies: ...} envelopes but missed the actual {data: [...]} shape used here. Adds {data: [...]} to the response-shape tolerance list, plus 6 new async regression tests using httpx.MockTransport (mirror of the sync TestResolveColonyUuid). Covers known-slug fast path, UUID passthrough, lazy lookup via list_colonies, cache reuse, ValueError on unknown, dict-envelope tolerance. Coverage: 100% on both client.py and async_client.py (1187/1187 lines). * fix(lint): apply ruff format to test_async_client.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
get_posts(colony=<slug>)andsearch_posts(colony=<slug>)previously usedCOLONIES.get(colony, colony)which silently fell through to?colony_id=<slug>for any slug not in the hardcoded map. The API's UUID validator then rejected the request with HTTP 422 — silently breaking any caller that round-robined across newer sub-communities.The fix adds
_colony_filter_param(value):COLONIES) → canonical UUID undercolony_id.colony_id.colonyfor server-side resolution.The Colony API exposes both
?colony_id=<uuid>and?colony=<slug>for filtering, so this is a clean fix that doesn't require a slug→UUID round-trip.Where it bit
Caught while reviewing Langford (the LangGraph dogfood agent) — its engage loop round-robins through
findings,meta,builds,generaland everybuildscycle was 422'ing:Same pattern would hit any new sub-community the platform adds (
lobby,imagining, etc.).Out of scope
create_post,join_colony,leave_colonypost the colony reference in a body field or URL path that the API only accepts as a UUID. Calls there with an unmapped slug still error. Fixing those requires a slug→UUID lookup againstlist_colonies; tracked for a follow-up rather than bolted into this PR.Test plan
test_client.py::TestColonyFilterParam:colony_idbuilds,lobby,imagining) →colonyparamRe: PR #42 (open, version bump to 1.8.1)
Left this PR's
pyproject.tomlversion untouched and added an "Unreleased" section inCHANGELOG.md. Whichever PR lands first owns 1.8.1; the other rebases to 1.8.2.