Skip to content

fix(tools): getAccounts defaults to limit=100; getActor validates the UUID up front#69

Open
sVIKs wants to merge 1 commit into
corezoid:mainfrom
sVIKs:fix/get-accounts-dx
Open

fix(tools): getAccounts defaults to limit=100; getActor validates the UUID up front#69
sVIKs wants to merge 1 commit into
corezoid:mainfrom
sVIKs:fix/get-accounts-dx

Conversation

@sVIKs

@sVIKs sVIKs commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Two dead-end traps, found by a live audit of real assistant sessions

1. getAccounts silently hides the accounts you just created

The backend's default page is ~30 rows and the response carries no has-more marker. Every actor already owns 20+ system accounts (Reactions ×10, edges, Default, …), so the accounts created last — exactly the ones the caller wants to see — fall off the first page. The result reads as «the account was never created / the transaction didn't work». In our project logs this was the single most expensive support mystery (days of debugging «empty accounts» during a data-migration engine build).

Fix: a Resolve hook requests limit=100 (the backend max) when the caller does not page explicitly; explicit paging is untouched. The Summary now documents the backend default, that total:true counts only fact-type accounts, and the pair-access ghost: createAccount on a (nameId, currencyId) pair you cannot see returns 200 and already exist on retry, yet the account never appears in any listing — pointing at createAccountPair.

Verified live (mw, fresh binary over stdio JSON-RPC): actor with 61 accounts — unpaged getAccounts returns all 40 visible fact rows; the previous binary returned the backend's 30-row page.

2. getActor answers 403 for a typo

The backend returns 403 Access Denied for any malformed/truncated actorId (e.g. 6bf39ec9), which reads as a permissions problem when it is a copy-paste accident.

Fix: a Resolve hook validates the 36-char UUID form before the request and fails fast:

[Error] getActor: actorId "6bf39ec9" is not a full actor UUID (36 chars, 8-4-4-4-12) —
the backend would answer a misleading 403 Access Denied for it. Pass the complete UUID,
or resolve the actor by its external key with getActorByRef(formId, ref)

Verified live: instant format error instead of the 403.

Tests

  • scenario tests: default limit applied / explicit limit passed through; truncated UUID rejected with the explanation / full UUID passes to /actors/<uuid>
  • op_bound_test now binds a UUID-shaped id (real binds carry actor UUIDs)
  • full go test ./... + go vet green; make discovery regenerated with no drift

🤖 Generated with Claude Code

… UUID up front

Two dead-end traps found by a live audit of real assistant sessions:

getAccounts: the backend default page is ~30 rows and the response has
no has-more marker. On an actor with 20+ system accounts (Reactions,
edges, Default, ...) the accounts created last — exactly the ones the
caller just made and wants to see — fall off the first page, and the
result reads as "the account was never created / the transaction did
not work". This was the single most expensive support mystery in our
project logs. The tool now requests limit=100 (the backend max) when
the caller does not page explicitly; explicit paging is untouched. The
Summary documents the backend default, the fact-only `total`, and the
pair-access ghost (createAccount on a pair you cannot see succeeds but
the account never appears in any listing — see createAccountPair).

getActor: the backend answers 403 Access Denied for any malformed or
truncated actorId, which reads as a permissions problem when it is a
typo. A Resolve hook now validates the 36-char UUID form before the
request and fails fast with the real reason plus the getActorByRef
alternative.

Verified live against mw (fresh binary over stdio JSON-RPC):
- actor with 61 accounts: unpaged getAccounts returns all 40 visible
  fact rows (the old binary returned the backend 30-row page)
- getActor("6bf39ec9"): instant format error instead of 403

Tests: scenario tests for the default/explicit limit and the UUID
rejection/pass-through; the bound-arg test now binds a UUID-shaped id
(real binds carry actor UUIDs). Full suite + vet green; discovery
artifacts regenerated with no drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@gh-corezoid

Copy link
Copy Markdown

AI Review

Adds two Resolve hooks to fix silent DX traps: getAccounts now defaults to limit=100 (bypassing the backend's invisible ~30-row page), and getActor validates UUID format up front instead of letting the backend return a misleading 403.

Checklist

Check Result
U1 — Conventional commit format ⚠️ warning
U2 — No leaked credentials ✅ pass
U3 — No merge commits ✅ pass
U4 — PR targets correct base branch ❌ fail
U5 — Build & tests (Go) ✅ pass
U6 — Architectural & design review ⚠️ warning
S1 — No manual edits to public/ ✅ pass
S2 — API path parameter names match spec ✅ pass
S3 — New tools have eval scenarios ✅ pass (no new tools)
S4 — Discovery artifacts committed ✅ pass (gendiscovery reads SKILL.md, not Go tool text)
S5 — All manifest files version-synced ⏭️ skip (no manifests changed)
S6 — README / ARCHITECTURE §4 updated ⏭️ skip (no new tools added)

Issues found

[error] U4 — Wrong base branch
This PR targets main, but CONTRIBUTING.md and the repo branching model require every feature/fix PR to target develop. The source branch fix/get-accounts-dx is neither develop, release/*, nor hotfix/*, so the CI guard (.github/workflows/guard-base-branch.yml) will block it.

Fix: change the PR base to develop.

[warning] U1 — Commit subject line is 83 characters (limit: 70)

fix(tools): getAccounts defaults to limit=100; getActor validates the UUID up front

The conventional-commit convention caps subject lines at 70 characters; this is 83. Consider splitting into two commits (one per tool) or shortening the description, e.g.:

fix(tools): getAccounts defaults to limit=100; getActor validates UUID

(70 chars exactly)

[warning] U6 — UUID guard is inconsistently applied
requireActorUUID is wired to getActor, but other tools that also accept an actorId path parameter — notably getAccounts (/accounts/{actorId}) and similar — will still reach the backend with a truncated ID and receive a misleading 403. The guard could be reused on those operations without behavioural risk. This is advisory; the PR's stated fix is complete as-is.


This review was generated automatically. A human maintainer should still make the merge decision.

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.

3 participants