Files
libakgl/docs/22-appendix-limits.md
Andrew Kesterson 35a58670d0 Document collision, and correct what it made false elsewhere
The new chapter 15 covers the opt-in setup, where resolution runs in the step
and why it runs after the move, shapes and the z-extrusion trap, the asymmetric
masks and the defaults that matter more than the mechanism, tiles as a source
rather than proxies, the response hook and the three ways it is easy to write
wrongly, sensors, the four queries, both partitioners, and what is still not
implemented.

Collision falsified claims in eight other chapters. The physics chapter said
"There is no collision detection, at all" and that collide always raises
AKERR_API; actors had six behaviour hooks; the heap had five pools and four
non-claiming acquires; the status band held five codes; and the design
philosophy had exactly two pluggable subsystems. The appendix gains a
collision.h status section, the three new pool ceilings and a table of the
collision constants that are deliberately not in a public header.

Also fixes chapter labels the renumbering commit left pointing at their old
numbers -- "18. Utilities" linked to 19-utilities.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
2026-08-02 07:25:52 -04:00

22 KiB
Raw Blame History

22. Appendix: limits, statuses and properties

Three reference tables that no single chapter owns: which function raises which status, every compile-time bound, and every configuration property the library reads.

The constant tables come in as excerpt= blocks against their headers, so they cannot drift from the values the library was built with — and so the hand-aligned columns those headers maintain survive.

A. Status cross-reference

What this table is. The statuses a caller can expect to see out of each function. It is built from the FAIL_* and HANDLE* sites in src/ — the function's own body and the static helpers only it calls — plus, where a nested libakgl call is part of the documented contract, that status too.

It is not exhaustive, and cannot be. Every libakgl function a given one calls can propagate anything from its own row, and so can libakstdlib: nearly everything that touches a file also carries whatever aksl_fopen, aksl_fread, aksl_fwrite and aksl_fclose report, including bare errno values such as ENOENT, EACCES and ENOSPC. Use the table to write the HANDLE arms you care about, not to prove a status cannot arrive.

(H) marks a status the function handles rather than raises.

What the statuses mean is Chapter 4.

error.h

Function Raises
akgl_error_init AKERR_STATUS_RANGE_OVERLAP, AKERR_STATUS_RANGE_FULL, AKERR_STATUS_NAME_FULL (all libakerror's)

heap.h

Function Raises
akgl_heap_init, akgl_heap_init_actor nothing — no failure path today
akgl_heap_next_actor, _sprite, _spritesheet, _character, _string, _collision_proxy, _collision_cell, _bspnode AKGL_ERR_HEAP
akgl_heap_release_actor, _sprite, _spritesheet, _character, _string, _collision_proxy, _collision_cell, _bspnode AKERR_NULLPOINTER

registry.h

Function Raises
akgl_registry_init and the eight akgl_registry_init_* AKERR_NULLPOINTER
akgl_registry_load_properties AKERR_NULLPOINTER, AKERR_KEY, AKERR_TYPE, AKGL_ERR_HEAP
akgl_set_property AKERR_NULLPOINTER
akgl_get_property AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS, AKERR_VALUE, AKGL_ERR_HEAP

game.h

Function Raises
akgl_game_init AKERR_NULLPOINTER, AKGL_ERR_SDL
akgl_game_update_fps, akgl_game_lowfps void — cannot report
akgl_game_state_lock AKGL_ERR_SDL
akgl_game_state_unlock nothing
akgl_game_update AKGL_ERR_SDL, plus whatever updatefunc, akgl_tilemap_scale_actor, the physics backend or the renderer raises
akgl_game_save AKERR_NULLPOINTER, AKERR_IO, AKERR_OUTOFBOUNDS
akgl_game_save_actors AKERR_NULLPOINTER, AKERR_IO
akgl_game_load AKERR_NULLPOINTER, AKERR_API, AKERR_EOF, AKERR_IO, AKERR_VALUE
akgl_game_load_versioncmp AKERR_NULLPOINTER, AKERR_VALUE, AKERR_API

actor.h

Function Raises
akgl_actor_initialize AKERR_NULLPOINTER, AKERR_KEY
akgl_actor_set_character AKERR_NULLPOINTERincluding "no such character"
akgl_actor_add_child AKERR_NULLPOINTER, AKERR_RELATIONSHIP, AKERR_OUTOFBOUNDS
akgl_actor_update AKERR_NULLPOINTER, AKERR_KEY (H)
akgl_actor_render AKERR_NULLPOINTER, AKERR_KEY (H), AKERR_OUTOFBOUNDS (H)
akgl_actor_automatic_face, _logic_movement, _logic_changeframe AKERR_NULLPOINTER
akgl_actor_cmhf_*_on, akgl_actor_cmhf_*_off AKERR_NULLPOINTER
akgl_registry_iterate_actor AKERR_NULLPOINTER, AKERR_KEYvoid; unhandled means the process exits

character.h

Function Raises
akgl_character_initialize AKERR_NULLPOINTER, AKERR_KEY
akgl_character_sprite_add AKERR_NULLPOINTER, AKERR_KEY
akgl_character_sprite_get AKERR_NULLPOINTER, AKERR_KEY
akgl_character_load_json AKERR_NULLPOINTER, AKERR_KEY for a state name that is not in AKGL_REGISTRY_ACTOR_STATE_STRINGS, and AKERR_TYPE from the JSON accessors
akgl_character_state_sprites_iterate AKERR_NULLPOINTERvoid; unhandled means the process exits

sprite.h

Function Raises
akgl_sprite_initialize AKERR_NULLPOINTER, AKERR_KEY
akgl_sprite_load_json AKERR_NULLPOINTER, AKERR_VALUE, AKERR_OUTOFBOUNDS
akgl_spritesheet_initialize AKERR_NULLPOINTER, AKERR_KEY, AKGL_ERR_SDL
akgl_spritesheet_coords_for_frame AKERR_NULLPOINTER

json_helpers.h

Function Raises
akgl_get_json_object_value, _boolean_, _integer_, _number_, _double_, _string_, _array_value AKERR_NULLPOINTER, AKERR_KEY for absent, AKERR_TYPE for wrong type
akgl_get_json_array_index_object, _integer, _string AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS for a short array, AKERR_TYPE
akgl_get_json_with_default AKERR_NULLPOINTER; handles AKERR_KEY (H), AKERR_OUTOFBOUNDS (H), AKERR_INDEX (H)

akgl_get_json_string_value and akgl_get_json_array_index_string also raise AKGL_ERR_HEAP when they have to claim a pooled string and the pool is empty.

physics.h

Function Raises
akgl_physics_init_null, akgl_physics_init_arcade AKERR_NULLPOINTER
akgl_physics_factory AKERR_NULLPOINTER, AKERR_KEY for an unknown backend name
akgl_physics_simulate AKERR_NULLPOINTER; handles AKGL_ERR_LOGICINTERRUPT (H)
akgl_physics_null_gravity, _collide, _move AKERR_NULLPOINTER
akgl_physics_arcade_gravity, _move AKERR_NULLPOINTER
akgl_physics_arcade_collide AKERR_NULLPOINTER, plus akgl_collision_resolve's. A no-op when self->collision is NULL

collision.h

Function Raises
akgl_collision_shape_box, _shape_circle, _shape_capsule, _shape_bounds, _shape_interacts AKERR_NULLPOINTER
akgl_collision_world_init AKERR_NULLPOINTER, AKERR_VALUE for a non-positive cell size, plus akgl_partitioner_factory's
akgl_collision_bind_tilemap AKERR_NULLPOINTER, plus akgl_get_json_properties_boolean's; handles AKERR_KEY (H) for a layer with no collidable property
akgl_collision_test AKERR_NULLPOINTER, AKGL_ERR_COLLISION when the ccd arena is exhausted — the message carries the high-water mark
akgl_collision_resolve AKERR_NULLPOINTER, plus akgl_collision_test's and the actor's own collidefunc's
akgl_collision_settle AKERR_NULLPOINTER, AKERR_VALUE when the shape is not clear within maxsteps
akgl_collision_solid_at, _box_blocked, _query_box, _substeps, _sync_actors AKERR_NULLPOINTER
akgl_collision_proxy_initialize, _proxy_sync, _cell_initialize AKERR_NULLPOINTER
akgl_partitioner_factory AKERR_NULLPOINTER, AKERR_KEY for an unknown partitioner name
akgl_partitioner_init_grid, _init_bsp AKERR_NULLPOINTER. The BSP's insert raises AKGL_ERR_HEAP past AKGL_MAX_HEAP_COLLISION_PROXY proxies
akgl_actor_collide_block AKERR_NULLPOINTER

renderer.h

Function Raises
akgl_render_2d_init AKERR_NULLPOINTER, AKGL_ERR_SDL, plus akgl_get_property's
akgl_render_2d_bind, _shutdown, _frame_start, _frame_end, _draw_texture, _draw_world AKERR_NULLPOINTER
akgl_render_2d_draw_mesh AKERR_API — not implemented

draw.h

Function Raises
akgl_draw_point, _line, _rect, _filled_rect AKERR_NULLPOINTER
akgl_draw_background AKERR_NULLPOINTER, AKGL_ERR_SDL
akgl_draw_circle AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS, AKGL_ERR_SDL
akgl_draw_flood_fill AKERR_NULLPOINTER, AKGL_ERR_SDL, AKERR_OUTOFBOUNDS past AKGL_DRAW_MAX_FLOOD_SPANS
akgl_draw_copy_region, _paste_region AKERR_NULLPOINTER, AKGL_ERR_SDL

tilemap.h

Function Raises
akgl_tilemap_load AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_tilemap_load_layers AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_tilemap_load_layer_tile AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_tilemap_load_layer_image AKERR_NULLPOINTER, AKGL_ERR_SDL
akgl_tilemap_load_layer_objects AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_tilemap_load_layer_object_actor AKERR_KEY
akgl_tilemap_load_tilesets AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS past AKGL_TILEMAP_MAX_TILESETS
akgl_tilemap_load_tilesets_each AKERR_NULLPOINTER
akgl_tilemap_load_physics handles AKERR_KEY (H) — every physics property is optional
akgl_get_json_tilemap_property AKERR_NULLPOINTER, AKERR_KEY, AKERR_TYPE
akgl_tilemap_draw, _draw_tileset AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_tilemap_scale_actor, akgl_tilemap_release AKERR_NULLPOINTER

controller.h

Function Raises
akgl_controller_open_gamepads, _list_keyboards AKERR_NULLPOINTER
akgl_controller_handle_event, _button_down, _button_up, _added, _removed AKERR_NULLPOINTER
akgl_controller_pushmap AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_controller_default AKERR_OUTOFBOUNDS, AKGL_ERR_REGISTRY — the library's only site
akgl_controller_poll_key, _poll_keystroke AKERR_NULLPOINTER

text.h, audio.h, assets.h, util.h, staticstring.h

Function Raises
akgl_text_loadfont AKERR_NULLPOINTER, AKGL_ERR_SDL
akgl_text_unloadfont AKERR_NULLPOINTER, AKERR_KEY
akgl_text_rendertextat AKERR_NULLPOINTER — including a NULL akgl_renderer, a NULL sdl_renderer, and a backend never run through akgl_render_2d_bind and so missing draw_texture. An empty string is not an error: it returns success having drawn nothing
akgl_text_measure, _measure_wrapped AKERR_NULLPOINTER. An empty string is legal and measures 0 wide by one line high
akgl_audio_tone, akgl_audio_sweep AKERR_OUTOFBOUNDS
akgl_audio_voice_active, akgl_audio_mix AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_load_start_bgm AKERR_NULLPOINTER, AKGL_ERR_SDL
akgl_path_relative AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS
akgl_rectangle_points, akgl_collide_point_rectangle, akgl_collide_rectangles AKERR_NULLPOINTER
akgl_compare_sdl_surfaces AKERR_NULLPOINTER, AKERR_VALUE
akgl_render_and_compare AKERR_NULLPOINTER, AKERR_IO, AKGL_ERR_SDL
akgl_string_initialize AKERR_NULLPOINTER
akgl_string_copy AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS, AKERR_VALUE

B. Compile-time limits

Everything below is fixed when the library is compiled. Only the AKGL_MAX_HEAP_* eight and AKGL_CCD_ARENA_BYTES are overridable, and even those have to be overridden for the whole build — see Chapter 5, "The ceilings are a compile-time ABI constraint". The rest are plain #defines with no #ifndef guard: changing one means editing the header and rebuilding libakgl and everything linking it.

The object pools

#ifndef AKGL_MAX_HEAP_ACTOR
#define AKGL_MAX_HEAP_ACTOR                    64
#endif
#ifndef AKGL_MAX_HEAP_SPRITE
#define AKGL_MAX_HEAP_SPRITE                   (AKGL_MAX_HEAP_ACTOR * 16)
#endif
#ifndef AKGL_MAX_HEAP_SPRITESHEET
#define AKGL_MAX_HEAP_SPRITESHEET              AKGL_MAX_HEAP_SPRITE
#endif
#ifndef AKGL_MAX_HEAP_CHARACTER
#define AKGL_MAX_HEAP_CHARACTER                256
#endif
#ifndef AKGL_MAX_HEAP_STRING
#define AKGL_MAX_HEAP_STRING                   256
#endif
#ifndef AKGL_MAX_HEAP_COLLISION_PROXY
#define AKGL_MAX_HEAP_COLLISION_PROXY          (AKGL_MAX_HEAP_ACTOR * 2)
#endif
#ifndef AKGL_MAX_HEAP_BSPNODE
#define AKGL_MAX_HEAP_BSPNODE                  (AKGL_MAX_HEAP_COLLISION_PROXY)
#endif
#ifndef AKGL_MAX_HEAP_COLLISION_CELL
#define AKGL_MAX_HEAP_COLLISION_CELL           (AKGL_MAX_HEAP_COLLISION_PROXY * 16)
#endif

Exceeding any of them is AKGL_ERR_HEAP.

Collision

Three of these are not in a public header, because nothing outside the broad phase may size anything against them:

Constant Value Where Bounds
AKGL_CCD_ARENA_BYTES 65536 collision_arena.h The narrowphase's whole allocation budget. Overridable. One GJK/EPA box pair measures 7,264 bytes
AKGL_COLLISION_GRID_COLS / _ROWS 128 src/collision_grid.c The dense cell-head array, 32 KB. A map wider than 128 cells wraps rather than growing
AKGL_COLLISION_GRID_MAX_SPAN 16 src/collision_grid.c Cells one proxy may occupy. Anything larger spills to one oversized chain, which is what makes AKGL_MAX_HEAP_COLLISION_CELL provable rather than hopeful
AKGL_COLLISION_MAX_SUBSTEPS 8 src/collision.c Sub-steps per actor per step, and therefore the speed above which tunnelling returns
AKGL_COLLISION_MAX_ITERATIONS 100 src/collision.c ccd_t.max_iterations. libccd's own default is (unsigned long)-1 — an unbounded loop inside a frame
AKGL_COLLISION_DEPTH_RATIO 2.0 collision.h The z extrusion, as a multiple of the largest planar half-extent. See Chapter 15 before changing it

Strings

AKGL_MAX_STRING_LENGTH is PATH_MAX, which is 4096 on Linux. That is the capacity of every akgl_String, and it is why the string pool is over a megabyte on its own.

Actors

/** @brief Longest actor name, including the terminator. Names are truncated, not rejected. */
#define AKGL_ACTOR_MAX_NAME_LENGTH      128
/** @brief Children one actor can carry. A child moves with its parent rather than simulating. */
#define AKGL_ACTOR_MAX_CHILDREN         8

AKGL_ACTOR_MAX_STATES is 32, fixed by the width of int32_t state rather than chosen. A ninth child is AKERR_OUTOFBOUNDS; an over-long name is silently truncated.

Sprites and spritesheets

#define AKGL_SPRITE_MAX_FRAMES                 16
#define AKGL_SPRITE_MAX_NAME_LENGTH            128
#define AKGL_SPRITE_MAX_REGISTRY_SIZE          1024
#define AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH  512

akgl_sprite_load_json bounds the frames array against AKGL_SPRITE_MAX_FRAMES before writing anything, and refuses a frame number that will not fit a uint8_t rather than truncating it into an index naming a different tile (TODO.md item 16).

AKGL_SPRITE_MAX_REGISTRY_SIZE is dead. It is defined in sprite.h and referenced nowhere in src/, include/, tests/ or util/. It bounds nothing. Do not size anything against it.

Tilemaps

/** @brief Widest map, in tiles. Width times height is what is actually bounded. */
#define AKGL_TILEMAP_MAX_WIDTH                        512
/** @brief Tallest map, in tiles. */
#define AKGL_TILEMAP_MAX_HEIGHT                       512
/** @brief Layers per map. Also the number of draw passes akgl_render_2d_draw_world makes. */
#define AKGL_TILEMAP_MAX_LAYERS                       16
/** @brief Tilesets per map. */
#define AKGL_TILEMAP_MAX_TILESETS                     16
/** @brief Entries in a tileset's offset table. Indexed by *local* tile id, so a tileset with a high `firstgid` still starts at 0. */
#define AKGL_TILEMAP_MAX_TILES_PER_IMAGE              65536
/** @brief Longest tileset name. */
#define AKGL_TILEMAP_MAX_TILESET_NAME_SIZE            512
/** @brief Longest resolved tileset image path. */
#define AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE        PATH_MAX
/** @brief Longest object name. Note that an object naming an actor is truncated at #AKGL_ACTOR_MAX_NAME_LENGTH (128) instead. */
#define AKGL_TILEMAP_MAX_OBJECT_NAME_SIZE             512
/** @brief Objects in one object layer. Not enforced by the loader -- a longer group writes past the array. */
#define AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER            128

Three corrections to what those comments say, all verified against src/tilemap.c:

  • AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER is enforced. The comment above says it is not. akgl_tilemap_load_layer_objects bounds j at the top of the loop body and raises AKERR_OUTOFBOUNDS; akgl_tilemap_load_tilesets does the same for AKGL_TILEMAP_MAX_TILESETS. Both landed in 0.5.0 (TODO.md, "Known and still open" item 17), and the header comment was not updated with them.
  • Width and height are not bounded individually. akgl_tilemap_load checks width * height >= AKGL_TILEMAP_MAX_WIDTH * AKGL_TILEMAP_MAX_HEIGHT, and the comparison is >=, so the true ceiling is 262143 tiles in any shape. A 1024×256 map loads; a 512×512 one does not.
  • AKGL_TILEMAP_MAX_TILES_PER_IMAGE is not checked anywhere. It sizes tile_offsets[65536][2] in the struct and nothing validates a tileset against it. It is also why akgl_Tileset is large: 512 KiB of offset table per tileset, whatever the image actually holds.

Controllers

/** @brief How many control maps exist -- effectively the local player limit. */
#define AKGL_MAX_CONTROL_MAPS 8
/** @brief Bindings per control map. The default map installed by akgl_controller_default uses 8 of them. */
#define AKGL_MAX_CONTROLS     32

AKGL_CONTROLLER_KEY_BUFFER is 32 — the keystroke ring, sized so a program polling once a frame never loses a key to a fast typist. AKGL_CONTROLLER_KEYSTROKE_TEXT is 8, enough for one UTF-8 code point and its terminator; a longer commit is truncated on a code point boundary rather than through the middle of one.

Drawing

AKGL_DRAW_MAX_FLOOD_SPANS is 4096 — the fixed stack of horizontal runs akgl_draw_flood_fill keeps instead of recursing per pixel. A region needing more pending runs at once reports AKERR_OUTOFBOUNDS rather than overflowing; an ordinary convex or moderately concave shape needs a few dozen.

Audio

/** @brief Sample rate of the generated stream, in frames per second. */
#define AKGL_AUDIO_SAMPLE_RATE 44100

/** @brief Frames the device callback generates per pass through the mixer. */
#define AKGL_AUDIO_MIX_FRAMES  512

AKGL_AUDIO_MAX_VOICES is 3. AKGL_AUDIO_SWEEP_TICK_HZ is 60, and it divides the sample rate exactly, so a sweep step boundary always lands on a whole frame — AKGL_AUDIO_SWEEP_TICK_FRAMES is 735.

The SDL_mixer side is separate: AKGL_GAME_AUDIO_MAX_TRACKS is 64 playback tracks, and slot 0 is unusedAKGL_GAME_AUDIO_TRACK_BGM is slot 1, and the rest are yours.

Time and the frame

Constant Value Meaning
AKGL_TIME_ONESEC_NS 1000000000 Nanoseconds in a second — the unit SDL_GetTicksNS reports in
AKGL_TIME_ONEMS_NS 1000000 Nanoseconds in a millisecond — the scale factor from JSON frame durations to internal ones
AKGL_GAME_STATE_LOCK_BUDGET_MS 1000 How long akgl_game_state_lock keeps trying before raising
AKGL_GAME_STATE_LOCK_RETRY_MS 100 How long it sleeps between attempts
AKGL_PHYSICS_DEFAULT_MAX_TIMESTEP 0.05 Default physics.max_timestep, in seconds — three frames at 60 Hz

AKGL_TIME_ONEMS_NS was called AKGL_TIME_ONESEC_MS until 0.5.0 and held 1000000 — a name and a value describing two different quantities. The state lock read it as a one-second budget and was wrong by a factor of a thousand, blocking for roughly sixteen minutes.

The status band

Constant Value
AKGL_ERR_BASE 256 (AKERR_FIRST_CONSUMER_STATUS)
AKGL_ERR_COUNT 5
AKGL_ERR_LIMIT 261 — the one-past-the-end sentinel, not a status

C. Configuration properties

Everything the library reads out of AKGL_REGISTRY_PROPERTIES. Every value is a string, including the numbers, and each is parsed by whoever reads it.

Property Default Read by Read when Meaning
game.screenwidth "0" akgl_render_2d_init once, at init Window and camera width in pixels. Passed straight to SDL_CreateWindowAndRenderer
game.screenheight "0" akgl_render_2d_init once, at init Window and camera height in pixels
physics.gravity.x "0.0" akgl_physics_init_arcade once, at init Constant acceleration on x, px/s²
physics.gravity.y "0.0" akgl_physics_init_arcade once, at init Constant acceleration on y, px/s². Positive is down
physics.gravity.z "0.0" akgl_physics_init_arcade once, at init Constant acceleration on z, px/s²
physics.drag.x "0.0" akgl_physics_init_arcade once, at init Fraction of environmental velocity shed per second on x
physics.drag.y "0.0" akgl_physics_init_arcade once, at init Same for y. The only brake on falling — there is no terminal velocity, and ey approaches gravity_y / drag_y
physics.drag.z "0.0" akgl_physics_init_arcade once, at init Same for z
physics.max_timestep "0.05" akgl_physics_init_arcade once, at init Ceiling on a single simulation dt, in seconds

That is the complete list — nine properties, read by two functions, each exactly once.

physics.engine is not read by anything. physics.h says in two places that akgl_game_init passes it to akgl_physics_factory; akgl_game_init never calls the factory, and the string does not appear in src/. Pass "null" or "arcade" to akgl_physics_factory yourself. Correcting the header is a source change and is deliberately out of scope for this manual.

Everything is read at init. Setting any of these after akgl_render_2d_init or akgl_physics_init_arcade has no effect at all, and reports success. See Chapter 6, and the startup order in Chapter 7.

A property set before AKGL_REGISTRY_PROPERTIES exists is silently discarded. akgl_set_property does not check SDL's return value. akgl_game_init and akgl_registry_init both create the registry; a hand-rolled startup that creates neither gets no configuration and no error.

Where to go next

  • Chapter 4 — what each status means.
  • Chapter 5 — the pools, and the ABI constraint on their ceilings.
  • Chapter 6 — the property store these live in.
  • The generated Doxygen reference — every function's own @throws list and full signature.