Skip to content

feat: human-claim governance + bump v1.15.0#65

Merged
jackparnell merged 3 commits into
TheColonyCC:mainfrom
ColonistOne:feat/claims-wrappers
Jun 3, 2026
Merged

feat: human-claim governance + bump v1.15.0#65
jackparnell merged 3 commits into
TheColonyCC:mainfrom
ColonistOne:feat/claims-wrappers

Conversation

@ColonistOne
Copy link
Copy Markdown
Collaborator

@ColonistOne ColonistOne commented Jun 3, 2026

Summary

Wraps the agent-facing slice of the platform's /api/v1/claims surface — 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/register only creates user_type=agent accounts, so an SDK user is in practice always an agent. The operator-side methods would be 403 FORBIDDEN for ~100% of SDK callers and would only be reachable by a vanishingly small audience of humans who somehow obtained an api_key outside 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_request is 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}/confirm
  • reject_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 IDs

Read primitives (either party)

  • list_claims()GET /claims — unwraps the {"data": [...]} envelope _raw_request applies to bare-list JSON so the public return type is a real list
  • get_claim(claim_id)GET /claims/{id} — 404 uniformly for "doesn't exist" and "you're not party to it"

Sync + async + MockColonyClient all 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 repo TheColonyCC/colony-chat) has on _raw_request for 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

  • 12 new unit tests across sync + async covering URL / method / body-shape assertion per endpoint + the 404-on-confirm and 410-on-expired-pending safety paths
  • 4 new mock-method invocations in tests/test_testing.py::test_all_methods_work
  • Full unit-test suite: 700 → 720 passing locally
  • mypy src/colony_sdk clean
  • ruff check + ruff format --check clean
  • Live integration test against staging — deferred to release time

Release

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

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
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

ColonistOne and others added 2 commits June 3, 2026 21:24
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>
@jackparnell jackparnell merged commit 5ed64ae into TheColonyCC:main Jun 3, 2026
7 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.

2 participants