Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

feat: game-declared registration mode via a config.lua global - #132

Merged
Taure merged 1 commit into
mainfrom
fix-asobi_lua-122
Aug 3, 2026
Merged

feat: game-declared registration mode via a config.lua global#132
Taure merged 1 commit into
mainfrom
fix-asobi_lua-122

Conversation

@Taure

@Taure Taure commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Closes #122

Registration posture (open / oauth_only / closed) was only settable through the release's sys.config, which no engine-hosted game can edit - so every hosted (game, env) silently ran the open default. This follows the ADR 0004 precedent used for guest_auth: make it a game-declared Lua global read through asobi_lua_config, so self-hosters and engine-hosted games get the same control with zero asobi_engine diff.

What changed

  • New global in the game's config script (config.lua in multi-mode, else match.lua):
    registration = "open" | "oauth_only" | "closed"
  • New asobi_lua_config:apply_registration_mode/1, called from maybe_load_game_config/0 alongside apply_guest_auth/1 and exported so asobi_engine's bundle loader can reuse it.
  • apply_guest_auth/1 and the new function now share a config_script_state/1 helper instead of each open-coding the script lookup.
  • Guide + moduledoc updated.

Semantics

  • Omitting the global leaves the app env untouched, so a self-hoster's sys.config (or asobi's open default) still wins - the Lua global is additive, not an override that resets on every boot.
  • An unrecognised value is logged at error level and ignored, rather than silently downgrading the posture to open.
  • Applied at boot only; reload_game_modes/0 (the config watcher path) does not touch it, matching the guest-auth rule that a live bundle write cannot flip auth posture.

Tests

Four new cases in asobi_lua_config_tests: single-mode sets the mode, multi-mode reads it from config.lua, absent global keeps the operator's app env, invalid value keeps the configured mode.

rebar3 fmt --check, xref, dialyzer, eunit green. The one asobi_lua_world_integration_tests failure (badkey solid in the spawn-templates test) reproduces unchanged on origin/main and is unrelated to this branch.

Registration posture was only reachable through the release sys.config, so
every engine-hosted game silently ran the `open` default. Games can now
declare `registration = "open" | "oauth_only" | "closed"` in the same
config script that carries `guest_auth`, applied by
asobi_lua_config:apply_registration_mode/1 at boot.

Omitting the global leaves the app env untouched so a self-hoster's
sys.config still wins; an unrecognised value is logged and ignored rather
than downgrading the posture to `open`.
@Taure
Taure merged commit 4b4bf8e into main Aug 3, 2026
16 checks passed
@Taure
Taure deleted the fix-asobi_lua-122 branch August 3, 2026 09:50
Taure added a commit to widgrensit/asobi that referenced this pull request Aug 4, 2026
…pshot (#353)

* fix: atomize spawn-template base_state and zone.spawn override keys

Ported from widgrensit/asobi_lua#131 (af391ff), which landed after the
asobi_lua snapshot merged into this repo.

Entities created by game.zone.spawn kept the binary key shape Luerl
decodes, because asobi_zone_spawner merges a template's base_state (and
any override table) straight into the new entity while only x/y/type are
stamped as atoms. Every atom-keyed consumer in asobi_zone then read the
wrong shape - snapshot_entities' `persistent` check, the crossing
clauses, asobi_spatial - until some later zone_tick happened to
round-trip the entity through atomize_entities/1 and fix it up.

Convert base_state and override keys at the same boundary #270 uses for
tick results, so a spawned entity has the same key shape whether or not
a tick has elapsed since it was created.

* fix: validate game.broadcast event names for immediate script feedback

Ported from widgrensit/asobi_lua#134 (1bc28be), which landed after the
asobi_lua snapshot merged into this repo.

#303 already rejects an out-of-shape broadcast event name at the socket
boundary, so a script that trips one of those rules lost the event with
only a server-side log line to explain why. game.broadcast now asks the
same guard before the fan-out and returns `{ error = "..." }` at the call
site.

Reworked from the asobi_lua original: in a single repo the two halves can
share an owner, so asobi_ws_handler exports event_name_binary/1 and
asobi_lua_api calls it instead of restating the length, charset and
reserved-name rules. That removes the "both lists must move together"
hazard the split-repo version had to carry.

* test: real-Postgres CT coverage for the game.storage.* write path

Ported from widgrensit/asobi_lua#133 (3354e5e), which landed after the
asobi_lua snapshot merged into this repo.

asobi_lua_api_tests mocks asobi_repo for every game.storage.* case, so the
suite could only ever confirm the assumption baked into the mock. #296
(update_all/2 rejecting a raw jsonb map, second set silently dropped)
shipped past exactly that.

asobi_lua_storage_SUITE drives game.storage.set/get/player_set/player_get
through Luerl against the Docker Postgres, asserting both the Lua-visible
result and the row in the database: set -> set -> get, version bump, and
both directions of the global vs player-scoped namespace isolation.

Verified the suite fails against both defect shapes: dropping the
`player_id IS NULL` predicate from storage_find/3 fails
global_write_does_not_clobber_player_row, and restoring the unscoped
update_all/2 write fails set_twice_updates_the_row plus
player_write_does_not_clobber_global_row.

Setup uses asobi_test_helpers:start/1 rather than the standalone
pgo/kura_migrator boot the asobi_lua original needed, and ci.yml already
passes extra-services-compose, so no CI change was required.

* feat: game-declared registration mode via a config.lua global

Ported from widgrensit/asobi_lua#132 (4b4bf8e), which landed after the
asobi_lua snapshot merged into this repo.

Registration posture was only reachable through the release sys.config,
which no engine-hosted game can edit, so every hosted game silently ran
the `open` default. A game can now declare
`registration = "open" | "oauth_only" | "closed"` in the same config
script that carries `guest_auth`.

Reworked for ADR 0006. The asobi_lua original called
application:set_env(asobi, registration, Mode) from the loader, which in
this repo would be both an unowned writer and the trust inversion ADR
0006 exists to prevent - a game bundle overwriting operator config. So
registration becomes a second layer exactly like the mode registry:
asobi_game_config writes the declared value to `script_registration`,
never to the operator's `registration` key, and asobi_registration
composes the two with the operator layer on top. A bundle can pick a
posture for a deployment that states none, and can never widen one that
does.

Omitting the global leaves both keys alone, so a self-hoster's sys.config
still wins; an unrecognised value is logged and dropped by the loader
rather than downgrading the posture to `open`.
Taure added a commit that referenced this pull request Aug 4, 2026
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.
Taure added a commit 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 subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Registration mode should be a game-declared config option, not unreachable

1 participant