Skip to content

docs: voice.md docstrings for the undocumented public surface - #65

Merged
iamalwaysuncomfortable merged 19 commits into
feat/shield-swap-updatefrom
docs/docstring-coverage-and-invite-minting-removal
Jul 30, 2026
Merged

docs: voice.md docstrings for the undocumented public surface#65
iamalwaysuncomfortable merged 19 commits into
feat/shield-swap-updatefrom
docs/docstring-coverage-and-invite-minting-removal

Conversation

@iamalwaysuncomfortable

Copy link
Copy Markdown
Member

Documents the public API that had no docstrings, and removes the invite-minting methods from the SDK surface.

Base is feat/shield-swap-update, not master.

Docstring coverage — 206 objects

Surface Objects
network_client.py / async_network_client.py 39 + 41
facade/ (async_client, client, records) 31
scanners, _client_common, _scanner_common, codegen, devnode, encryptor 27
shield-swap api.py, client.py, async_client.py 36
shield-swap journal, profile, _routing, types, errors, lifecycle, _core, mcp 32

Follows .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 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 rather than copied blindly:

  • wait_for_transaction_confirmation yields to the event loop via asyncio.sleep
  • AsyncDexCall.simulate explains why it is not awaited
  • three cross-references repointed at the async classes instead of RecordScanner / AleoNetworkClient

Three 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 cap
  • decrypt_enabled — gates find_credits_record(s), not owned(), which decrypts opportunistically and silently skips when no view key is stored
  • codegen.main() — exits via argparse on a usage error rather than returning 1

Invite minting removed

ApiClient.generate_access_codes and its async mirror are gone. redeem_access_code stays, so a code obtained out-of-band from an operator still works, and human-pasted referral invites keep going through redeem_code.

This reduces SDK surface, not access. POST /access/generate is 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_exposed guards against quiet reintroduction.

codegen/amm_api.openapi.json deliberately still lists /access/generate — it is a capture of the live API, the endpoint does exist, and regen-openapi.sh would restore it.

Reviewer notes

Not a docs-only diff. 23 of 26 changed .py files are provably docstring-only (AST-identical to HEAD once docstrings are stripped). Three carry real code changes:

  • api.py — the method removal
  • tests/test_api_client.py — reworked mint→redeem test, plus the new guard
  • tests/test_gen_context.pya test threshold moved, see below

A test assertion changed. 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, pushing the page past test_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

Gate Result
pytest python/tests -m "not slow" (sdk) 890 passed, 17 skipped
pytest (shield-swap) 174 passed, 9 skipped
pyright strict (sdk) 0 errors, 0 warnings
pyright (shield-swap) 15 errors — identical on HEAD, none from this PR
gen_context.py --check clean

The 15 shield-swap pyright errors were confirmed pre-existing by stashing this work and re-running: 12 are Optional[str]-into-str looseness on token0_program/token1_program, 3 are unresolved mcp imports (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_proofs therefore remains undocumented here, since that PR replaces it.

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
iamalwaysuncomfortable merged commit bc96c42 into feat/shield-swap-update Jul 30, 2026
6 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.

1 participant