Host Function Context Audit¶
Host functions registered on Lua states via
internal/plugin/hostfunc/functions.go:Register run as Go code inside
the goroutine dispatched by Host.invoke. While Go code runs,
gopher-lua's per-instruction context check is suspended — a host
function that blocks ignores the plugin-level CPU deadline.
This audit table documents each registered host function and confirms it either completes in O(1) time or respects its context parameter for any potentially-blocking work. A meta-test locks this invariant against future regressions.
Invariant¶
Every exported host function registered on a Lua state MUST either:
- complete in O(1) time (no loops of unbounded length, no I/O), OR
- respect
L.Context()for any call that could block (RPC, I/O, channel wait).
The meta-test
TestHostFuncsRespectContextOnPreCancelledCtx in
internal/plugin/hostfunc/context_audit_test.go invokes every
registered host function with a pre-cancelled context and asserts it
returns within 250 ms.
Meta-test scope and limitation¶
The meta-test invokes each hostfunc with zero arguments. Most
hostfuncs call L.CheckString(1) (or similar argument-validation) as
their first action, which raises a Lua error and returns immediately
before any blocking call. This means the meta-test primarily catches:
- A new hostfunc that blocks unboundedly without respecting context AND accepts zero arguments.
- A hostfunc whose argument validation itself is slow (> 250 ms).
It does NOT catch:
- A hostfunc that validates args first and then does a blocking call
without respecting
L.Context(). Under legitimate traffic (valid args), such a hostfunc would hangHost.invoke's wait-for-drain bound.
Covering that gap requires per-hostfunc test fixtures (each hostfunc
has a different argument shape) wired against fake backends that
block on ctx.Done(). A future contributor wanting to strengthen the
guarantee should add a companion subtest that calls each
blocking-capable hostfunc (KV, world queries, world mutations,
session streams, focus) with valid-shaped arguments and a blocking
fake backend, and asserts each returns promptly on context
cancellation.
Until that companion test lands, this file + code review are the authoritative enforcement of the context-respect invariant.
Audit table¶
Maintain this table when adding or changing a host function.
The functions holomush.log and holomush.new_request_id are O(1).
holomush.log appends a log record via slog with no blocking I/O.
holomush.new_request_id generates a ULID using crypto/rand which
does not block under normal operation.
The KV functions (holomush.kv_get, holomush.kv_set,
holomush.kv_delete) respect L.Context() directly: each derives
context.WithTimeout(L.Context(), defaultPluginQueryTimeout) with a
5-second backend cap. When the plugin-level CPU deadline fires, the
outer L.Context() is already cancelled, so the KV call returns
promptly rather than waiting the full 5 seconds.
The world query functions (holomush.query_location,
holomush.query_character, holomush.query_location_characters,
holomush.query_object) delegate to world.Service methods that accept
a context parameter and return promptly on cancellation.
The world mutation functions (holomush.create_location,
holomush.create_exit, holomush.create_object,
holomush.find_location, holomush.set_property,
holomush.get_property) likewise delegate to context-aware service
methods.
The command functions (holomush.list_commands,
holomush.get_command_help) read from an in-memory registry with no
blocking calls.
The session-stream functions (holomush.add_session_stream,
holomush.remove_session_stream) and focus functions
(holomush.join_focus, holomush.leave_focus,
holomush.present_focus, holomush.query_stream_history) delegate to
services that accept context parameters.
Adding a new host function¶
When adding a new host function:
- Confirm it either completes in O(1) time or accepts a context.
- Add its name to the
RegisteredFunctionsForAuditlist ininternal/plugin/hostfunc/functions.goso the meta-test exercises it. - If the function does I/O, document the bounding mechanism (RPC deadline, channel timeout, etc.) in this file.