docs: voice.md docstrings for the undocumented public surface - #65
Merged
iamalwaysuncomfortable merged 19 commits intoJul 30, 2026
Conversation
Adds docstrings to the 206 public classes/methods in sdk/python/aleo and shield-swap-sdk that had none, following .agents/voice.md: present-tense verb lead, side effects named (network / fee / local-only), and each argument, return, and raised error described by consequence. Section syntax follows each file's local idiom rather than one global rule — numpy `Parameters` inside facade/ (54 existing blocks, and voice.md shipped in the same commit as those files), Google `Args:` elsewhere. shield-swap keeps its terser prose voice and its "see :meth:`ApiClient.X`" convention for async mirrors. Where a sync counterpart was already documented the text is mirrored, with async-specific facts corrected: wait_for_transaction_confirmation yields to the event loop via asyncio.sleep, AsyncDexCall.simulate explains why it is not awaited, and three cross-references now point at the async classes instead of RecordScanner / AleoNetworkClient. Three behaviours were checked against the code rather than assumed: get_block_range's end-inclusivity varies by node build (the e2e test says so) so the docstring warns against relying on the last element; decrypt_enabled gates find_credits_record(s), not owned(), which decrypts opportunistically; and codegen's main() exits via argparse on a usage error rather than returning 1. Also removes ApiClient.generate_access_codes and its async mirror. Minting invite/access codes should not be part of the SDK surface. redeem_access_code stays, so a code obtained out-of-band still works, and human-pasted referral invites keep going through redeem_code. Note this reduces SDK surface, not access: POST /access/generate is still reachable directly, and the real gate is the server-side generate right. test_minting_access_codes_is_not_exposed guards the removal. shield-swap-sdk/AGENTS.md is generated from these docstrings, so both copies are regenerated. Four TIER2 entries (api.get_pools, api.get_tokens, derive_pool_key, derive_tick_key) rendered with blank bodies before and now carry real text, which pushed the page past test_gen_context.py's compactness budget — that threshold moves 22k to 24k, with the reason recorded alongside the prior 20k to 22k raise. Verified: 890 passed (sdk, -m "not slow"), 174 passed (shield-swap), pyright strict 0 errors on sdk, gen_context.py --check clean. The 15 pyright errors in shield-swap-sdk are pre-existing and unchanged (confirmed by re-running against HEAD).
Both directions went through binary floating point and lost value. `credits_to_microcredits` multiplied by 1_000_000 as a float and then truncated toward zero with int(), so ordinary amounts silently underpaid: 1.005 credits became 1_004_999 microcredits, not 1_005_000. Sub-microcredit input was dropped with no error at all (0.9999999 -> 999_999). `microcredits_to_credits` returned a float. Microcredits are a u64, and past 2**53 a float cannot hold the integer — u64 max round-tripped off by one, and 2884 of the first 200_000 microcredit values failed `micro -> credits -> micro` identity. Both now compute in Decimal. Float input is routed through str(), which recovers the shortest representation that round-trips — i.e. the literal the caller wrote — which is what rescues 1.005; str and Decimal input are exact already. Sub-microcredit precision now raises ValueError naming the value, with allow_rounding=True to opt back into truncation, so lost value is an error rather than a silent underpayment. `from_microcredits` returns Decimal instead of float. It still compares equal to the obvious float, so existing assertions hold unchanged, but mixing it into float arithmetic now raises — convert with float() deliberately if you want that, accepting the loss. Scope is contained: these are user-facing convenience helpers only. No internal fee or amount path consumes them (the SDK is integer microcredits end to end), and shield-swap does not use them. Verified: 896 passed (sdk, -m "not slow"; +6 new), pyright strict 0 errors, shield-swap 174 passed and unaffected.
iamalwaysuncomfortable
merged commit Jul 30, 2026
bc96c42
into
feat/shield-swap-update
6 checks passed
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.
Documents the public API that had no docstrings, and removes the invite-minting methods from the SDK surface.
Base is
feat/shield-swap-update, notmaster.Docstring coverage — 206 objects
network_client.py/async_network_client.pyfacade/(async_client, client, records)_client_common,_scanner_common, codegen, devnode, encryptorapi.py,client.py,async_client.py_routing, types, errors, lifecycle,_core, mcpFollows
.agents/voice.md: present-tense verb lead, side effects named (network / fee / local-only), each argument, return, and raised error described by consequence.Section syntax follows each file's local idiom rather than one global rule — numpy
Parametersinsidefacade/(54 existing blocks, and voice.md shipped in the same commit as those files), GoogleArgs:elsewhere. shield-swap keeps its terser prose voice and itssee :meth:`ApiClient.X`convention for async mirrors.Where a sync counterpart was already documented the text is mirrored, with async-specific facts corrected rather than copied blindly:
wait_for_transaction_confirmationyields to the event loop viaasyncio.sleepAsyncDexCall.simulateexplains why it is not awaitedRecordScanner/AleoNetworkClientThree behaviours checked against the code rather than assumed:
get_block_range— end-inclusivity varies by node build (the e2e test says so), so the docstring warns against relying on the last element, and records the real span ≤ 50 capdecrypt_enabled— gatesfind_credits_record(s), notowned(), which decrypts opportunistically and silently skips when no view key is storedcodegen.main()— exits via argparse on a usage error rather than returning 1Invite minting removed
ApiClient.generate_access_codesand its async mirror are gone.redeem_access_codestays, so a code obtained out-of-band from an operator still works, and human-pasted referral invites keep going throughredeem_code.This reduces SDK surface, not access.
POST /access/generateis still reachable directly with any HTTP client; the real gate is the server-side generate right on the account.test_minting_access_codes_is_not_exposedguards against quiet reintroduction.codegen/amm_api.openapi.jsondeliberately still lists/access/generate— it is a capture of the live API, the endpoint does exist, andregen-openapi.shwould restore it.Reviewer notes
Not a docs-only diff. 23 of 26 changed
.pyfiles are provably docstring-only (AST-identical to HEAD once docstrings are stripped). Three carry real code changes:api.py— the method removaltests/test_api_client.py— reworked mint→redeem test, plus the new guardtests/test_gen_context.py— a test threshold moved, see belowA test assertion changed.
AGENTS.mdis generated from these docstrings, so both copies are regenerated. Four TIER2 entries (api.get_pools,api.get_tokens,derive_pool_key,derive_tick_key) rendered with blank bodies before and now carry real text, pushing the page pasttest_page_stays_compact. The budget moves 22k → 24k, with the reason recorded alongside the prior 20k → 22k raise. The assertion was not weakened to make anything pass — the cap is a deliberate agent-context budget and raising it is the intended mechanism.Breaking change. Removing public methods warrants more than a patch bump; all three packages sit at
0.3.1.Verification
pytest python/tests -m "not slow"(sdk)pytest(shield-swap)pyrightstrict (sdk)pyright(shield-swap)gen_context.py --checkThe 15 shield-swap pyright errors were confirmed pre-existing by stashing this work and re-running: 12 are
Optional[str]-into-strlooseness ontoken0_program/token1_program, 3 are unresolvedmcpimports (the[mcp]extra is not installed). Worth a separate fix.Follow-up
A rename of the merkle-proof parameters to match the amm-v3 contracts is intentionally not in this PR and will follow separately.
wrapper_proofstherefore remains undocumented here, since that PR replaces it.