← All decisions

Set Hex-publish metadata (0.1.0, BSD-3-Clause) and audit the public API surface, informed by glemy-games as a real external consumer

architecturepackagingapi-designdocumentation

Context

Stage 2 of the same request behind decision 0064 ("cleaning up the engine's refinements, and releasing fully functional APIs as a properly documented library"): now that glemy-games consumes glemy as a real external package dependency rather than same-repo relative imports, that's real evidence to audit the public API against, instead of guessing. The user specified the two genuinely non-technical forks directly: starting published version 0.1.0 (not the 1.0.0 already sitting in gleam.toml, which predated any external consumer) and licence BSD-3-Clause.

Options considered

Mark modules glemy-games doesn't happen to use as internal_modules — rejected
Checked directly: every single module (physics, physics/bounds, physics/collision, physics/collision_sweep, physics/entity, physics/rect, physics/vector2, render, io, cooldown, random, stopwatch) is genuinely imported by glemy-games -- there is no module-level candidate for internal_modules today. Left as a real mechanism to use later if an actual internal-only module appears, not applied speculatively now.
Rename bounds.x_fraction to x_fraction_from_left, for surface symmetry with y_fraction_from_top — rejected
Read both functions' actual doc comments and implementations before proposing this: y_fraction_from_top's suffix exists specifically because that mapping is inverted relative to the world-y axis (gravity pulls toward smaller y, so 'top' means max.y -> 0.0), which is genuinely surprising and needs the qualifier. x_fraction has no inversion -- it maps world_x directly, min.x -> 0.0, max.x -> 1.0 -- so it needs no qualifier to avoid misleading a reader. The asymmetry is correct information, not an inconsistency; renaming it would add a redundant qualifier, not fix a real gap.
Demote entity.loosely_equals / rect.nearest_point / collision.resolve to internal, since glemy-games never calls them directly — rejected
Checked each individually rather than by usage count alone: collision.resolve is called by collision_sweep.gleam itself (genuine internal composition, same layered-API shape as rect.overlaps/penetration_axis, which games DO call directly for custom shape resolution) -- a real, general-purpose primitive for a consumer bypassing the bulk sweep. rect.nearest_point is a genuinely general geometric primitive (distance from a point to the nearest point on a rect), independently useful beyond collision detection, and already has its own direct test coverage. entity.loosely_equals mirrors vector2.loosely_equals (which glemy-games does call directly, from its own tests) -- the same tolerance-comparison convenience one level up, useful to any consumer writing its own tests against entities, which is exactly why glemy's own test suite needed it. None of the three are pub only by accident.

Decision

gleam.toml: version 0.1.0 (not 1.0.0 -- the user's own call, an honest 'first real external consumer, API may still move' signal rather than the stability promise 1.0.0 implies), licences = ["BSD-3-Clause"] (the user's own choice), description, repository, and links (live demo, glemy-games) filled in. Added LICENSE (BSD-3-Clause) to both glemy and glemy-games (the latter had none, being a new public repo). Audited every pub item across physics.gleam/physics/*/render.gleam/io.gleam by checking glemy-games' actual import/usage grep output, not assumption: found every module genuinely externally consumed (no internal_modules candidates), 100% doc-comment coverage on every pub item (a few apparent gaps in an automated line-before check turned out to be doc comments separated by @target(javascript)/@external annotation lines, not real gaps), and no naming inconsistency that survived reading the actual code -- several apparent asymmetries (x_fraction vs y_fraction_from_top; overlap vs overlaps; restitution/genuine_impact_velocity duplicated verbatim across bounds.gleam and collision.gleam) turned out to be already-deliberate, already-documented, already-cross-referenced design choices, not gaps.

Verification

gleam build, gleam test (170 passed), gleam test --target javascript (190 passed), and deno task check-warnings (25/25, unchanged baseline) all still green after the gleam.toml/LICENSE changes -- metadata-only changes, as expected, with zero source changes needed as a result of the audit itself.

Consequences

glemy is now Hex-publish-ready on the metadata front (name/version/description/licences/repository all set); Stage 3 (the actual gleam publish) is the only remaining step in the original three-stage request. The audit's main finding is negative but still real and worth recording: this project's existing promotion-at-second-caller discipline (decisions 0047, 0048, 0050, 0058, 0062 among others) already produced a public surface with no accidental exposure to trim -- Stage 2's 'cleanup' turned out to mean 'confirm, with real external-consumer evidence in hand, that no cleanup is needed' rather than a backlog of renames. If a future real second external consumer (beyond glemy-games) surfaces a genuine naming or internal-surface issue, that's new evidence to act on then, not something this audit missed.

References