Skip to content

feat: merge the asobi_lua runtime into asobi (wave 1a) - #339

Merged
Taure merged 1 commit into
mainfrom
feat/merge-asobi-lua
Aug 3, 2026
Merged

feat: merge the asobi_lua runtime into asobi (wave 1a)#339
Taure merged 1 commit into
mainfrom
feat/merge-asobi-lua

Conversation

@Taure

@Taure Taure commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Wave 1a of the asobi_lua merge. One-way move of the Lua runtime, bots, tests
and guides out of widgrensit/asobi_lua and into this repo. No module was
renamed - asobi_lua_* and asobi_bot_* keep their names, so game scripts
and Erlang callers are unaffected.

asobi_lua the repo is untouched, asobi_engine is untouched, nothing was
published.

What was broken / what had to change

Three things could not survive a plain file copy.

1. asobi_lua_app.erl was an application callback for an application that
no longer exists.
asobi_lua_app.erl:8-19 loaded the game config and then
started asobi_lua_sup. Both had to move somewhere, and where matters:
because asobi_lua depended on asobi, it started second, so the config load
landed after every asobi_sup child was already up.

That ordering is load-bearing in a bad way. asobi_guest_reaper:start_link/0
(src/asobi_guest_reaper.erl:26) reads guest_auth and returns ignore when
it is false - and asobi_lua_config:apply_guest_auth/1
(src/lua/asobi_lua_config.erl:126) is what sets it, always too late. That is
exactly #327, filed today. This PR preserves that order rather than
accidentally fixing it
: asobi_sup:init/1 gains lua_game_config_spec() and
lua_sup() as the last two children, after guest_reaper_spec(). Moving the
load earlier would silently close #327 inside a 100-file move PR, which is the
wrong place for it. Flagging for the reviewer: if you would rather this PR
fix #327 too, say so and I will hoist the load and re-run.

Failure semantics: a bad game config still aborts the boot. It now surfaces as
a supervisor failed_to_start_child instead of a bare application-start error,
so it also takes the already-started core children down with it. Still
fail-closed, but it is a change in shape - src/asobi_sup.erl:60-72.

2. Six documented operator knobs would have gone silently dead.
dev_errors, reload_mode, max_heap_words, terrain_providers,
config_watch_interval and rate_limits were read with
application:get_env(asobi_lua, ...). application:get_env/3 against an
application that is never loaded returns the default without complaint, so
after the merge every {asobi_lua, [...]} block in a self-hoster's sys.config
would quietly stop having any effect. New src/lua/asobi_lua_env.erl reads
asobi_lua first and falls back to asobi, so existing deployments keep
their exact behaviour and {asobi, ...} is the home for new config.
rate_limits is the one key both halves read; the group names are disjoint
(log/log_global vs auth/api/...), so one merged map carries both.

3. Test fixture lookup pointed at the wrong application. 18 moved test
modules resolved fixtures via code:lib_dir(asobi_lua), which now returns
{error, bad_name}. Repointed at code:lib_dir(asobi); the fixtures live at
test/fixtures/lua/ here, same relative layout.

Everything else

  • src/lua/ (runtime), src/lua/bots/ (bot processes), include/asobi_lua_bots.hrl,
    test/* and test/fixtures/lua/**.
  • luerl ~> 1.5 added to rebar.config deps and to applications in
    src/asobi.app.src. vsn untouched. rebar.lock picked up luerl 1.5.1;
    cowlib was already at 2.19.0 so asobi_lua's explicit cowlib pin was not needed.
  • ex_doc extras gained self-hosting, security-sandbox,
    security-trust-model, security-lua-known-limitations, plus new
    Lua Runtime and Bots module groups.
  • nightly.yml picks up prop_lua_bridge_input_threading and
    prop_lua_error_containment at high numtests - asobi_lua's nightly ran them,
    so dropping them would have been a silent coverage loss.

Guide reconciliation

Three filenames collided.

  • guides/lua-scripting.md and guides/lua-bots.md here were stubs whose only
    content was "this lives in asobi_lua, go read it there". Replaced with the
    real content, since the thing they pointed at is now in this repo.
  • guides/security-known-limitations.md is a genuine collision: this repo's is
    about core runtime limits, asobi_lua's is about the Lua sandbox. asobi_lua's
    landed as guides/security-lua-known-limitations.md, retitled
    "Known limitations (Lua sandbox)". Neither was overwritten.
  • security-sandbox.md, security-trust-model.md, self-hosting.md are new.
    Fixed the cross-links: the core known-limitations page now links locally to
    security-sandbox.md instead of to a github.com/widgrensit/asobi_lua URL, and
    self-hosting's ../README.md#quickstart anchor was repointed at this README's
    #try-it-in-60-seconds.

What the tests assert

  • test/asobi_sup_lua_children_tests.erl - pins the fold. asobi_lua_config
    and asobi_lua_sup are both supervised; they are the last two children in
    that order; asobi_guest_reaper starts strictly before the config load (the
    guest_reap_after never runs: reaper returns ignore before guest_auth is set #327 ordering, pinned so a later refactor cannot change it by accident); the
    asobi_lua_sup spec is type => supervisor; and asobi_lua_sup still has its
    own four children in order.
  • test/asobi_lua_env_tests.erl - a legacy {asobi_lua, K} value is still
    honoured, an {asobi, K} value is read when the legacy key is unset, the
    legacy key wins when both are set, and the default / undefined come back
    when neither is.
  • The 22 moved test modules and 5 moved property modules run as-is.

Verification

command result
rebar3 fmt / rebar3 fmt --check clean
rebar3 xref clean
rebar3 eunit 928 tests, 0 failures (159s)
rebar3 dialyzer clean, no warnings
rebar3 ex_doc clean, no warnings

Not verified, honestly:

  • rebar3 ct was not run - it needs Postgres. test/asobi_lua_SUITE.erl
    came across and compiles, but it has never executed in this repo. Note that
    ci.yml:48 records that an asobi_lua_SUITE.beam "removed in refactor: extract Lua scripting into asobi_lua #59" used to
    resurrect itself from a stale cache and crash CT on luerl:init/0 undef -
    that specific failure mode is gone now that luerl is a real dep, but CI is
    the first place the suite will actually run.
  • Downstream breakage is guaranteed and out of scope. asobi and
    asobi_lua now both define asobi_lua_* modules. Any consumer depending on
    both - the asobi_lua repo itself, and asobi_engine - will get duplicate
    modules on the next asobi pin bump. asobi_lua's bump-asobi-pin.yml
    automates that bump, so it will fire on merge. Wave 1b needs to land close
    behind this.
  • The application:set_env(asobi, ...) calls at src/lua/asobi_lua_config.erl:126
    and :434 are left exactly as they were
    - now internal writes rather than
    cross-application ones. Per the brief, the core-owned write path is S3.
  • asobi_lua's docs/adr/0001 and 0002 were not moved - their numbers
    collide with this repo's existing docs/adr/0001 and 0002 and renumbering
    someone else's decision records is a maintainer call.
  • No ADR was written for this merge. The brief calls it ADR 0008, but this
    repo's docs/adr/ stops at 0005, so I did not want to guess the number.
    Code comments reference "the asobi_lua merge" in prose instead.
  • Wider docs still describe asobi_lua as a separate repo and image (README,
    guides/comparison.md, guides/exit.md, guides/glossary.md, the three
    migrate-from-*.md). Those statements are still true today - the repo and
    ghcr.io/widgrensit/asobi_lua both exist - so I left them for the wave that
    actually retires them.

One deviation from the brief

The brief said to copy asobi_lua/src/** into src/lua/ "preserving its
internal structure", which literally would have produced src/lua/lua/*.erl.
I collapsed that redundant level: the inner src/lua/ files sit directly in
src/lua/, and src/bots/ is preserved as src/lua/bots/. Trivial to undo if
you want the literal layout.

Related: #327 (not closed by this PR - the ordering it describes is deliberately
preserved here).

Moves the Lua runtime, bots and their tests out of widgrensit/asobi_lua and
into this repo as an in-tree subsystem. Module names are unchanged, so a
game's Lua scripts and any Erlang caller keep working against the same API.

- src/lua/ holds the runtime, src/lua/bots/ the bot processes, include/ the
  bots header, test/fixtures/lua/ the script fixtures.
- luerl becomes a direct dep and an entry in asobi.app.src applications.
- asobi_lua_app is gone; asobi_sup now supervises the game-config load and
  asobi_lua_sup as its last two children, which is exactly where they ran
  when asobi_lua was a separate application started after asobi.
- asobi_lua_env keeps reading the legacy `{asobi_lua, ...}` app-env keys and
  falls back to `{asobi, ...}`, so no existing sys.config silently goes dead
  now that the asobi_lua application no longer exists.
- guides: the lua-scripting / lua-bots stubs are replaced by the real
  content they pointed at; sandbox, trust-model and self-hosting move in;
  asobi_lua's known-limitations lands as security-lua-known-limitations.md
  so it does not overwrite the core page of the same name.
@Taure
Taure merged commit 733cec4 into main Aug 3, 2026
15 checks passed
@Taure
Taure deleted the feat/merge-asobi-lua branch August 3, 2026 23:13
@Taure
Taure restored the feat/merge-asobi-lua branch August 3, 2026 23:13
@Taure
Taure deleted the feat/merge-asobi-lua branch August 3, 2026 23:14
Taure added a commit that referenced this pull request Aug 4, 2026
… hits

#337 wrapped the match-result write in asobi_repo:transaction/1 so the
match record and the player_stats bump land together. #339 brought
asobi_lua_SUITE across from the asobi_lua repo, where it mocks asobi_repo
strictly and stubs only insert/1,2.

Together, the finish path calls asobi_repo:transaction/1 on a strict mock
that has no such function, the call is undef, the match server dies
mid-finish, and the suite reports match_did_not_finish - naming the
symptom and not the cause. Two tests, on main and on every branch cut
from it.

The suite runs without a repo pool, so transaction/1 runs the fun inline
rather than passthrough reaching for a database that is not there.
record_match/2 is stubbed too: stats persistence has its own tests and
this suite is the Lua match lifecycle.
Taure added a commit that referenced this pull request Aug 4, 2026
* fix: register the Lua game-mode providers at application start

#333 inverted mode resolution so asobi_game_modes resolves {lua, Script}
through a provider registry instead of hardcoded asobi_lua_* atoms, and
returns lua_runtime_unavailable when a kind has no provider. The writer
was asobi_lua's own application-start callback.

#339 then merged the Lua runtime into asobi and removed that application
without moving the registration, so nothing ever populated the registry:
every Lua mode resolved to lua_runtime_unavailable. Both PRs were green
on their own base and red together, which is why main went red on merge.

Register from asobi_app:start/2, ahead of the supervision tree so the
matchmaker cannot observe an empty registry. The mapping itself lives in
asobi_lua_sup next to the bridges, so asobi_game_modes still knows
nothing about the scripting runtime, and tests that resolve a lua mode
without booting the application call the same function.

asobi_lua_config_tests now registers in its fixture and unregisters in
teardown; asobi_game_modes_tests:lua_without_provider establishes the
absence it asserts on rather than inheriting it from module order.

* fix: stub the transaction path asobi_lua_SUITE's strict repo mock now hits

#337 wrapped the match-result write in asobi_repo:transaction/1 so the
match record and the player_stats bump land together. #339 brought
asobi_lua_SUITE across from the asobi_lua repo, where it mocks asobi_repo
strictly and stubs only insert/1,2.

Together, the finish path calls asobi_repo:transaction/1 on a strict mock
that has no such function, the call is undef, the match server dies
mid-finish, and the suite reports match_did_not_finish - naming the
symptom and not the cause. Two tests, on main and on every branch cut
from it.

The suite runs without a repo pool, so transaction/1 runs the fun inline
rather than passthrough reaching for a database that is not there.
record_match/2 is stubbed too: stats persistence has its own tests and
this suite is the Lua match lifecycle.
Taure added a commit to widgrensit/asobi_lua that referenced this pull request Aug 4, 2026
* chore: retire asobi_lua to a Docker alias for asobi

The Lua runtime moved into asobi (widgrensit/asobi#339). asobi main now defines
16 of this repo's 17 modules, so any asobi pin at or past that merge makes the
release unbuildable:

    ===> Error generating release:
    Duplicated modules:
        asobi_lua_game_error specified in asobi and asobi_lua
        asobi_lua_dev_errors specified in asobi and asobi_lua

Urgent part: .github/workflows/bump-asobi-pin.yml ran daily and moved the pin to
asobi main unattended. The next run would have hit exactly that error and left
ghcr.io/widgrensit/asobi_lua unpublishable. It is deleted, not paused.

The published image keeps building. It is now an alias: same name, same tags,
same bin/asobi_lua entrypoint, same port, same environment, but the release is
assembled from asobi alone, whose own supervision tree starts the Lua runtime.
Nothing changes for anyone running it.

- Delete src/, include/ and test/ - all duplicated by asobi. Only
  asobi_lua_app.erl was unique, and asobi_sup already does its job.
- Pin asobi to the v0.51.4 tag rather than a branch, since nothing bumps it
  automatically any more.
- Replace the erlang-ci delegation with a release build plus an assertion that
  no Lua module ships twice. Delete the nightly property soak; its suites moved.
- Close the tracker to new issues via .github/ISSUE_TEMPLATE/config.yml
  redirecting to widgrensit/asobi. Existing issues stay open and readable.
- Deprecation notice at the top of README, plus AGENTS.md and SECURITY.md.

* chore(deps): pin asobi v0.53.0, the release carrying the ported fixes

v0.51.4 predated widgrensit/asobi#353, which ported the four commits that
landed in this repo after the merge snapshot was taken. Publishing the alias
against v0.51.4 would have shipped an image missing asobi_lua#131, #132, #133
and #134 - exactly the regression this retirement was held back to avoid.

Verified in the assembled prod release: asobi-0.53.0 is the only asobi lib,
each shared module ships exactly once, and the three code fixes are present
in the fetched dependency source.
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.

guest_reap_after never runs: reaper returns ignore before guest_auth is set

1 participant