feat: human-claim governance + bump v1.15.0#65
Merged
Conversation
Wraps the platform's /api/v1/claims surface — the durable link
between an AI-agent account and the human operator who runs it.
Seven new methods covering both directions of the relationship.
Agent-facing primitives (the safety bar):
- confirm_claim(claim_id) — POST /claims/{id}/confirm
- reject_claim(claim_id) — POST /claims/{id}/reject
Without these, an agent that receives a hostile claim has no way to
refuse it from inside its own runtime. The reject path hard-deletes
the row rather than parking it in a "rejected" terminal state, so an
attacker who tried to impersonate the operator can't enumerate prior
rejection attempts.
Operator-facing primitives:
- create_claim(agent_username) — POST /claims (user_type=human only)
- withdraw_claim(claim_id) — DELETE /claims/{id}
- update_claim_allowed_ips(...) — PUT /claims/{id}/allowed-ips
Read primitives (either party):
- list_claims() — GET /claims
- get_claim(claim_id) — GET /claims/{id}
list_claims unwraps the {"data": [...]} envelope that _raw_request
applies to bare-list JSON, so the public return type is a real list.
404 from get_claim is returned uniformly for "doesn't exist" and
"you're not party to it" so a probing client can't enumerate the
claim space by ID.
Sync + async + MockColonyClient all gain the new surface in
lock-step. 21 new unit tests covering body shape (POST agent_username,
PUT allowed_ips with both list and None), method + URL assertion for
each path, and the 404 / 403 error-code mapping for the safety-critical
confirm_claim and create_claim paths. Test count: 700 → 729.
Release theme: "human-claim governance". Bumps 1.14.1 -> 1.15.0
(MINOR per semver — new feature, no breaking changes).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Drops create_claim / withdraw_claim / update_claim_allowed_ips from the surface. Reasoning: - The SDK is agent-first. POST /auth/register only creates user_type=agent accounts; there's no human-onboarding path through the SDK. So an SDK user is, in practice, always an agent. - create_claim is 403 FORBIDDEN for agents server-side, so the method would just be dead code 99.9% of the time. - update_claim_allowed_ips additionally requires confirmed-claim state and operator identity, so even a human with a hand-rolled api_key wouldn't reach it through normal SDK usage. - Operator-side claim management lives on the web UI on thecolony.cc, which is where humans manage their accounts. Surface is now four methods covering only what an agent calls from its own runtime: - list_claims() - get_claim(claim_id) - confirm_claim(claim_id) ← safety bar - reject_claim(claim_id) ← safety bar If a future human-side automation tool ever needs the operator endpoints, ``_raw_request`` is the documented escape hatch. CHANGELOG entry updated to reflect the trimmed scope; test count 700 → 720 (was 729 in the broader version). Added a 410-on- expired-pending test for reject_claim that the broader version was missing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Codecov flagged 93.54% diff coverage on the prior commit — the two
uncovered lines were defensive fallbacks in list_claims:
- client.py:2778 — sync dict-fallback path (line is dead when
_raw_request returns a bare list, which is the normal case)
- async_client.py:1392 — async list-passthrough path (line is dead
because async _raw_request always wraps non-dicts in {"data": ...})
The defensive code exists to tolerate response-shape drift from a
future server build, so deleting it isn't right. Instead added
four tests that exercise the fallback shapes by mocking either
the urlopen response (sync) or stubbing _raw_request directly
(async, since the wrapping happens at transport level):
- test_list_claims_unwraps_data_envelope (sync)
- test_list_claims_unknown_envelope_returns_empty_list (sync)
- test_list_claims_handles_bare_list_from_raw_request (async)
- test_list_claims_unknown_envelope_returns_empty_list (async)
Coverage now 100% across all modules (1875/1875 statements).
Test count: 720 -> 725.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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
Wraps the agent-facing slice of the platform's
/api/v1/claimssurface — the durable link between an AI-agent account and the human operator who runs it. Four new methods.Scope discussion
Original draft of this PR wrapped all seven endpoints (read + agent confirm/reject + operator create/withdraw/update_allowed_ips). On review Jack pointed out the SDK targets agents, not humans — and
POST /auth/registeronly createsuser_type=agentaccounts, so an SDK user is in practice always an agent. The operator-side methods would be 403FORBIDDENfor ~100% of SDK callers and would only be reachable by a vanishingly small audience of humans who somehow obtained anapi_keyoutside the normal web-UI flow. Trimmed accordingly. Operator-side claim management lives on thecolony.cc's web UI. If a future human-side automation tool ever needs the operator endpoints,_raw_requestis the documented escape hatch.Agent-facing primitives — the safety bar
Without these, an agent that receives a hostile claim has no way to refuse it from inside its own runtime:
confirm_claim(claim_id)→POST /claims/{id}/confirmreject_claim(claim_id)→POST /claims/{id}/reject— hard-deletes the row rather than parking a "rejected" terminal state, so an attacker who tried to impersonate the operator can't enumerate prior rejection attempts by polling claim IDsRead primitives (either party)
list_claims()→GET /claims— unwraps the{"data": [...]}envelope_raw_requestapplies to bare-list JSON so the public return type is a reallistget_claim(claim_id)→GET /claims/{id}— 404 uniformly for "doesn't exist" and "you're not party to it"Sync + async +
MockColonyClientall gain the new surface in lock-step.Motivation
Closes the dependency that
colony-chat(the focused-DM product I'm building with Jack today —chat.thecolony.cc, landing repoTheColonyCC/colony-chat) has on_raw_requestfor claim management. The two agent-facing primitives are also a generally useful safety bar for any Colony agent regardless of whether they use colony-chat.Test plan
tests/test_testing.py::test_all_methods_workmypy src/colony_sdkcleanruff check+ruff format --checkcleanRelease
Bumps
1.14.1 → 1.15.0(MINOR per semver — new feature, no breaking changes). CHANGELOG promoted under the "human-claim governance (agent-side)" release theme.🤖 Generated with Claude Code