tools/test_launcher_bridge.py tested crates/coa-core/src/launcher_bridge.py,
which the Rust launcher replaced; check.yml and release.yml still ran it, so
the release build failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A console shutdown request is sometimes lost, and the world then keeps
running until the stop times out. While the world still runs and its
console still answers after 15 s, the launcher asks again (twice at most);
asking twice is harmless. Verified on a disposable repack with the first
World::ShutdownServ call suppressed in a debugger: the second request
stopped the world.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Five preview fragments exceeded the body (300) or title (90) limits, so the
changelog-fragments check failed on every push to this branch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Manager starts servers with coa-core::launcher (no Python bridge),
the bug-report relay runs as coa-launcher relay-worker, and manage.py is
no longer edited. Preview identity in tauri.conf.json is kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repacks ship no .bat files, and the Manager starts servers with
coa-core::launcher, so the realm-profile patch it wrote into manage.py
served no one. It is no longer applied (realm creation, realm switching and
start).
Recognising the edits older Managers made (realm patch, bridge import fix)
moves into legacy_launcher, so updates and file checks still treat such a
file as unmodified. Nothing there writes a file.
manage.py itself stays complete in the repack: Managers up to 0.9.10 run it
through their bridge and patch its text, so it cannot become a thin wrapper
until those Managers are no longer supported.
Verified: coa-core unit tests; examples/manager_launcher_e2e on a disposable
repack (manage.py unchanged after a start with a realm profile).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
launcher::relay does what BugReport/relay.py and manage.py relay-worker do,
with the same spool: the <key>.status files the world reads, the journal
relay.sqlite3 (deliveries, settings), relay.lock (byte 0) and the
relay-ready record. Service answers map to the same states and retry times;
a post interrupted mid-flight stays uncertain and is never resent.
When coa-launcher.exe supervises a world it runs the relay itself; the
Python supervisor still runs relay.py.
Verified:
- examples/relay_equivalence: the same reports and scripted service answers
through relay.py and the Rust relay give identical statuses, journal rows
(including retry times) and posts, and each continues the other's journal.
- examples/manager_launcher_e2e on a disposable repack: supervisor and relay
are coa-launcher.exe, start/stop interoperates with manage.py.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
send_without_answer closed the socket right after writing "server shutdown".
With the reply still unread, Windows resets the connection, and the world
can drop the command: a world supervised by coa-launcher.exe ignored the
shutdown and the stop timed out after 90 seconds. The reply is now read up
to the next prompt, the end of the connection or 10 seconds.
The E2E also checks which supervisor runs the world and that manage.py
stops a world the Manager started.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
driver::run now calls coa-core::launcher::ops::run in-process instead of
running Scripts/manage.py through launcher_bridge.py. Failures carry a typed
code (Error::Service) instead of being guessed from stderr text.
Moved into the launcher: realm profiles (realm id, name and databases from
Settings/realm-profile.json), extra worlds sharing the main database,
the shared world startup deadline and console readiness check, the owned-world
check on shutdown, force-stop-all, and an environment block without
AC_REALM_SERVER_PORT for update validation.
The world supervisor is Scripts/coa-launcher.exe when the repack ships it,
otherwise manage.py watch-world. Extra worlds get an unmodified manage.py.
The realm patch of manage.py stays for the repack's own .bat files.
Verified with examples/manager_launcher_e2e on a disposable repack.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
std::process::Command lets a Windows child inherit every inheritable handle of the parent: a
MySQL started by the launcher kept the caller's files and pipes open (found by the SQUID test,
whose log stayed locked). Services now start through CreateProcessW with
PROC_THREAD_ATTRIBUTE_HANDLE_LIST = [log, NUL], as Python's subprocess does. The MySQL client's
outputs are read while it runs (a full pipe stopped it) and its last error line is reported.
E2E on a disposable repack: launcher_e2e PASS again; squid_equivalence PASS: Rust and
squid_playerbots.py leave identical journals, acore_playerbots tables (row counts) and
playerbots.conf (4106 lines), and a second run of either changes nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- services: exclusive-bind port check, readiness by listener row or the server side of a
loopback connection, MySQL client, start MySQL/auth, stop-all (world through its console,
database last), status.
- world: start-world through a supervisor process (coa-launcher watch-world) that keeps the
bug-report relay (still BugReport/relay.py via the repack's Python) alive; detailed logging.
- squid: squid_playerbots.py in Rust with the same journals (coa_squid_migrations,
coa_squid_pending, coa_bots_installed).
- coa-launcher.exe: the manage.py commands and error texts (the Manager reads them).
- Services no longer inherit the launcher's stdin/stdout/stderr: a server holding the
output pipe kept whoever read the launcher's output waiting.
E2E (examples/launcher_e2e, disposable stable repack on free ports): coa-launcher start-all ->
manage.py sees and stops it; manage.py start-all -> coa-launcher sees and stops it; a second
Rust-only cycle leaves nothing running.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
First part of moving Scripts/manage.py into coa-core (plan §17, PY-1). Same formats on disk as
manage.py so both can run on one server: .state records, the byte-0 control lock msvcrt.locking
takes, configuration.json. prepare renders byte-for-byte what manage.py renders (checked against
the real script, COA_MANAGE_PY). State files are flushed to disk before they replace the old ones,
and a damaged record counts as no process instead of failing every later start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ten settings in a new bot settings section: the switch, where it applies (dungeons, raids,
battlegrounds/arenas, open world), the damage, healing, damage-taken and tank-threat
multipliers (1 = unchanged, the module's defaults) and the per-boss tuning (advanced).
Translations in the five locales.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rows were separate grids with an auto-width action column, so the columns moved from row
to row; every column has a fixed width now. CoA's modules are not in the public catalogue:
their last push comes from the GitHub API (cached 12 h).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The SQL review listed '( statements)': the page read file_path and statement_count, the
backend sends file, target_schema, line_count and what each file does.
- After a build from a link, a module with SQL files was installed without them (its NPCs
missing) and the panel kept offering a second install; now the SQL confirmation opens
instead, and the link panel closes once the module is installed.
- The catalogue says when a filter hides modules, with Show all.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Build cache (build_cache.rs): the build folder of a module is unpacked for a
build and packed into <module>.tar.zst afterwards (object files ~4-6x
smaller), modification times kept so Ninja recompiles only what changed.
A cache made for another core is dropped instead of unpacked; .ilk and .map
files are not kept; total limit 2 GB, least recently built first. The build
log moves next to the archive (build-cache/<module>.log).
- "Build cache" in the Modules menu: size per module (packed, built when, for
this core or not), remove one, remove all, remove downloaded sources.
Builds now hold the server's busy guard, so the cache is never cleared
under a running build.
- Module sources: "Add from a link" downloads GitHub's archive of the commit
instead of a full git clone, and game-client files (.mpq, .dbc, maps,
textures, archives) are left out and listed in .coa_skipped_assets.
mod-bg-battle-for-gilneas: 365 MB repository, 3.1 MB kept (was refused at
the 300 MB limit).
- Overlay: Helias's battleground modules (Gilneas, Twin Peaks, Slavery Valley)
are Incompatible: they need the server's DBC files replaced (CoA ships its
own) and a client patch.
Checked: build_cache unit tests; examples/build_cache_ninja_check with real
MSVC + CMake + Ninja: after pack/unpack nothing is recompiled, after one edit
one file is; coa-core lib tests 865 passed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Header is just "Modules" with "Add from a link" (the GitHub URL bar is folded
away until asked for) and a menu for builds/logs, build tools and the
diagnostics export. The build-tools bar shows only when something is missing.
- Two tabs (Installed, Catalog) styled like the settings page.
- Catalogue: one list of rows (name, owner, category, stars, one action); CoA's
own modules first. Compatibility and sort are drop-downs; 20 functional
categories as chips with counts. "Checked by CoA" is the curated list only.
- Categories: owner's reviewed list (181 modules, high/medium confidence) plus
keyword rules for every other module (coa-module-categories.json).
- Catalogue statuses come from the current overlay on every read (a cached copy
kept the old Verified marks), and no more made-up entries for overlay rules
the public catalogue does not list (fake AGPL-3.0, 0 stars, duplicate mod-cfbg).
- Window size, position and maximized state persist (tauri-plugin-window-state,
visibility left to the app).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overlay reason was drawn as a red blocked notice on every card, so modules
marked Verified looked incompatible. mod-cfbg is built into the CoA core and is
now Incompatible; the Verified marks on duel-reset, pvp-titles, starter-guild and
skip-dk-starting-area had no build or test behind them and are removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Six overlapping, differently coloured chips become four groups that do not
overlap (all, checked by CoA, community, incompatible), each with a count that
follows the search; the sort list gets a label and no emoji.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A new server goes on to the preview core without compiling any module
(recommended modules are declined once; modules come from the Modules page).
- Choosing a server with the classic core makes a modular copy next to it:
every acore_* database (read from the running database, or from a private
copy of the stopped data files opened by the new server's own mysqld),
module configs and realm profiles, ports and console login. The old server
is only read. The copy then takes the preview core with the modules the old
server had switched on.
- Installs and the preview update run on unused ports, so a server running on
the shipped ports (the old one, or any other) no longer stops them; the
schema check after "Preparing database" used the shipped port before.
- Dungeon Clear is part of SQUID's Playerbots: no card of its own (it said
"Always on" while SQUID was off), switched with SQUID, settings on the SQUID card.
E2E (examples/preview_bare_and_copy_e2e, disposable servers, another server
running on the shipped ports): fresh install committed with no plugins and a
clean boot report; copy of a stopped and of a running classic server: data
identical, old server's files byte-for-byte unchanged, Content Scaling and
Companions built on the copy, preview core committed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The install used the stable image and left the preview core for a later
update, so a fresh Modules Preview server showed every module as built in
and no Plugin SDK. install_new now applies the preview update right after
the base install (same signed update and module build every server takes);
a failure leaves the classic core and the done screen says so, and modules
that did not build are listed. A hand-picked package and Docker keep the
old behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tauri::generate_context! needs ../dist. The tests run before tauri-action builds the frontend, so a
run without a warm target cache cannot compile the app (seen on preview/modules-v2, run 42224568581).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Modules page had a 'Register test-realm-v03' button and the app registered a hardcoded local
folder into an empty server list at startup. Both pointed at a developer's machine. The startup
registration now happens only when COA_TEST_REALM_DIR is set. test_detect_toolchain skips when the
local spike realm is absent (CI runners).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build_module_with_bundle reports a failed compile as Ok(success: false). rebuild ignored the flag,
installed the package left by the previous build (made for the old core) and only then switched the
module off as 'does not match the installed core'. Now the failed build stops there and the reason
names the first compiler error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After a stable->preview update the recommended modules are built from their sources and deploy
their own .conf.dist over the one the package shipped. The next core update saw a file that
matched neither the recorded nor the new hash and stopped with 'modified outside CoA Server
Manager'. A template that exactly matches what an installed module deploys is now skipped.
Adds preview_core_update_e2e (core with a new plugin ABI on an existing preview server).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
preview_channel_e2e installs from the stable channel, takes the preview from the published preview channel
the way the Manager does, and checks the server is current afterwards. preview_migration_e2e gains a squid
mode that keeps SQUID's SQL journals and expects SQUID's Playerbots instead of Companions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The core matches a DLL's .coapl id with its plugin lock entry. The adapter
used the repository name (mod-coa-content-scaling) while the registry and
lock use the module id (content-scaling), so the stable->preview e2e saw the
core reject Content Scaling. The build now writes the module id and refuses
a DLL that does not carry it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
derive-preview takes the higher of the requested minimum and the stable
package's. Adds the stable->preview migration e2e example (disposable server,
own ports, seeded character and module setting, production updater).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stable packages from 0.261104.94 need Manager 0.9.8; the preview was 0.9.7.
Conflicts kept the preview's module screen and plugin-aware module logic, took
master's requires-squid compatibility value and version 0.9.9 under the
preview's own product name and identifier.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
coa-release derive-preview verifies the stable update package, unpacks it,
replaces the core binaries with the plugin host build (same core commit),
adds Core/plugin-sdk.zip and Core/plugins/recommended.json, and repacks it
with the stable migrations, configuration and scripts unchanged. The result
is signed with the preview key by coa-release sign.
Tried on server-0.261104.94 and a CI plugin host: 37256 files, 3417
migrations, signature/archive/schema contract verified; the stable key
rejects the package (env-driven test).
New servers in the preview Manager are installed from the stable image; the
preview core arrives as the first update.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- keys/preview-signing.pub: preview packages and the preview pointer are
signed with a separate key, so a stable Manager (stable key only) can never
accept them. The preview Manager trusts both keys for packages (it starts
from stable servers and stable base packages); each channel pointer must
carry its own key's signature.
- Channel 'preview': pointer preview.json on the preview-channels branch,
releases preview-server-<version>. The app resolves it first and falls back
to stable until a preview release exists.
- coa-release public-key prints the public half of the signing key;
sign-channel writes the channel's own release tag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A core that loads Content Scaling, Companions and SQUID as plugins ships
Core/plugins/recommended.json with the module repositories and commits. During
the update (the move from a monolithic stable server) the Manager downloads
each module as GitHub's archive of that commit (no git needed), builds it with
its bundled trees, installs and enables it, before the trial start. Rules keep
the bot choice: SQUID only if it was switched on in playerbots.conf, otherwise
Companions. Handled modules are remembered so a removed module is not
reinstalled; a failed one is retried at the next core change.
Verified on a CI core: Content Scaling (+packs) and Companions downloaded,
built, installed and written to the plugin lock in 225 s.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Modules must be compiled by the core's exact compiler. The Toolchain tab now
offers Microsoft's stable-channel Build Tools bootstrapper (VS 18) with the
14.44 toolset, core build tools, Windows SDK 26100 and CMake preselected:
downloaded from aka.ms, Authenticode-checked for Microsoft, run in its own UI
(modify mode for an existing Build Tools 18). Shows the required and selected
cl.exe versions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The core changes almost daily and a plugin loads only into the core it was
built for. update::apply now brings every enabled plugin to the new core
before the trial start: a build already in the store is reused, otherwise it
is rebuilt from the sources recorded at its last build (build recipe). A
plugin that cannot be rebuilt is switched off with the reason (and plugins
that depend on it); the core update always goes ahead. A rollback puts the
builds for the restored core back. The update result lists rebuilt and
switched-off modules.
Also: plugin.json records the real compiler instead of a fixed string.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The loader is chosen only from directories the build compiles: Companions
has a reference pilot/ whose loader was picked and never compiled (LNK2019).
- A bundled tree inside the primary one (Content Scaling's content-packs/)
is compiled only as the bundle (was LNK2005 on every pack symbol).
- Env-driven test builds the preview modules against a CI core pair and
requires the realm's host fingerprint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>