Skip to content

refactor: split the framework API into server/worlds/bots/events facets (D2/D3)#99

Merged
PimvanderLoos merged 6 commits into
masterfrom
feat/facet-api
Jul 15, 2026
Merged

refactor: split the framework API into server/worlds/bots/events facets (D2/D3)#99
PimvanderLoos merged 6 commits into
masterfrom
feat/facet-api

Conversation

@PimvanderLoos

@PimvanderLoos PimvanderLoos commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Why

  • ILightkeeperFramework had grown into a 23-method god-interface; D2 of the API v2 design calls for facets as the long-term shape, and D3 for migrating in place while there is still only one consumer.

How

  • New facet interfaces IServerControl/IWorlds/IBots/IEvents, reached via server()/worlds()/bots()/events(); implementations are package-private facade classes in internal holding the moved (line-for-line) method bodies — the single canonical codepath.
  • Every v1 method survives as a @Deprecated(forRemoval = true) default method delegating into its facet, so AA's existing call sites stay source- and binary-compatible for one release. PlayerHandleBotHandle rename deliberately deferred to the S6 login driver.
  • All in-repo consumers (unit + integration tests, README examples) migrated to the facet API; framework module only — no protocol change.

Tests

  • mvn --batch-mode -Perrorprone clean verify checkstyle:checkstyle pmd:check → BUILD SUCCESS (full reactor incl. both IT lanes).
  • New: DeprecatedDelegateTest proves every v1 default delegates (argument + return pass-through, verify on the facet); four *FacadeTest classes cover the moved logic; FrameworkApiVisibilityTest pins facade visibility.
  • Pre-PR deep review applied: single source of truth for the tick read restored; the shared-server-down error message now recommends the facet API.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added facet-based APIs for server control, world management, bot creation, and event capture.
    • Added support for joining synthetic players and creating worlds from templates through the new APIs.
    • Added server lifecycle controls, output, diagnostics, platform, directory, and tick access.
  • Documentation
    • Updated examples and guidance to use the facet-based API.
  • Refactor
    • Existing flat API methods now delegate to the new facets and are deprecated for removal.

PimvanderLoos and others added 5 commits July 15, 2026 09:28
Add the four facet interfaces that carve the ILightkeeperFramework god-interface
into cohesive slices, per the D2/D3 2.0 API restructure:

- IServerControl: command execution, console output, platform, filesystem
  access, process lifecycle, tick counter, captured server errors.
- IWorlds: main world, create (defaults/spec), template load, builder.
- IBots: join synthetic players (with/without UUID), builder.
- IEvents: capture Bukkit events (thin today; grows in S6/S7).

These interfaces are the new canonical API surface. Wiring the accessors and
routing implementations through them lands in the follow-up refactor commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P15FjGQzyNmX9T6Qmyq8Dn
…1 delegates

Complete the D2/D3 evolve-in-place restructure: the facet accessors become the
single canonical codepath and every flat v1 method becomes a deprecated delegate.

- ILightkeeperFramework gains abstract server()/worlds()/bots()/events()
  accessors; each former v1 method is now a @deprecated(forRemoval = true)
  default that delegates into the matching facet. waitUntil() stays plain (no
  facet mapping); currentServerTick() is deprecated on the public interface but
  DefaultLightkeeperFramework keeps its concrete impl because the identical
  signature is also on the untouched IFrameworkGatewayView seam.
- New package-private facade impls (ServerControlFacade/WorldsFacade/BotsFacade/
  EventsFacade) own the moved method bodies via constructor-injected internals;
  the deleted v1 impls no longer exist on DefaultLightkeeperFramework, which
  retains only lifecycle/close/ensureOpen plumbing and the gateway seam.
- Route in-repo production consumers (LightkeeperFrameworkAssert,
  FailureDiagnosticsWriter) through the facet accessors so the deprecated names
  have no remaining production callers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P15FjGQzyNmX9T6Qmyq8Dn
… split

Finish the D2/D3 restructure on the test side so the deprecated names have no
remaining callers outside their dedicated delegate coverage.

- Migrate every framework unit test and integration test that called a v1
  method to the facet form (framework.worlds().main(), server().currentTick(),
  bots().join(...), events().capture(...), etc.), including the mock-based
  consumers that now stub framework.server() and its facet methods.
- Add DeprecatedDelegateTest: a facet-stub ILightkeeperFramework proves every
  deprecated default delegates to the matching facet method (deprecation warnings
  suppressed only here).
- Add ServerControlFacadeTest/WorldsFacadeTest/BotsFacadeTest/EventsFacadeTest:
  per-facade delegation + null/blank validation coverage.
- Extend FrameworkApiVisibilityTest to pin the facade impls non-public with
  non-public constructors, consistent with the existing API-visibility pins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P15FjGQzyNmX9T6Qmyq8Dn
Bring the README in line with the D2/D3 2.0 API: the Quick Start and Vault
examples now use framework.worlds().main() and framework.bots().builder(), the
Core Features bullets reference the facet forms (worlds().fromTemplate(...),
server().stop()/start()/restart()/crash(), server().directory()/
pluginDataDirectory(...)), and a note flags the flat v1 names as
deprecated-for-removal in favour of the server()/worlds()/bots()/events() facets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P15FjGQzyNmX9T6Qmyq8Dn
Goal: fold the Opus review round into the facet pass. Collapses the
duplicated tick read — ServerControlFacade.currentTick() now delegates
to the framework's gateway-mandated currentServerTick(), restoring a
single source of truth — and rewrites the shared-server-down error
message (plus its test expectations) to steer users to server().crash()/
stop()/start()/restart() instead of the v1 names this branch deprecates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P15FjGQzyNmX9T6Qmyq8Dn
@PimvanderLoos

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@PimvanderLoos
PimvanderLoos requested a review from Copilot July 15, 2026 08:01
@PimvanderLoos

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The framework API is reorganized into server(), worlds(), bots(), and events() facets. Legacy flat methods now delegate to deprecated-for-removal defaults, internal operations move into facades, and unit, integration, assertion, diagnostic, and README usage is migrated.

Changes

Facet API and compatibility

Layer / File(s) Summary
Public facet contracts
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/*.java
Adds server, worlds, bots, and events interfaces and routes legacy framework methods through deprecated default delegates.
Facade implementations
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/*Facade.java, DefaultLightkeeperFramework.java
Moves server lifecycle, world creation, bot creation, and event capture into internal facades wired by DefaultLightkeeperFramework.
Consumers and validation
lightkeeper-framework-junit/src/main/java/.../assertions/*, lightkeeper-framework-junit/src/test/*
Updates assertions, diagnostics, compatibility tests, facade tests, lifecycle tests, and validation tests to use the facet APIs.
Integration usage and documentation
README.md, lightkeeper-integration-tests/src/test/java/...
Migrates examples and integration tests from flat framework methods to facet-based world, bot, server, and event operations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant IntegrationTest
  participant ILightkeeperFramework
  participant WorldsFacade
  participant BotsFacade
  participant ServerControlFacade
  participant EventsFacade
  IntegrationTest->>ILightkeeperFramework: access worlds(), bots(), server(), events()
  ILightkeeperFramework-->>IntegrationTest: return facet implementations
  IntegrationTest->>WorldsFacade: main() or create(WorldSpec)
  IntegrationTest->>BotsFacade: join(...) or builder()
  IntegrationTest->>ServerControlFacade: executeCommand(...) or currentTick()
  IntegrationTest->>EventsFacade: capture(eventClassName)
Loading

Possibly related PRs

Poem

A bunny hops through facets bright,
Worlds and bots join tests tonight.
Servers start, stop, crash, and sing,
Events flutter on a spring.
Old flat paths gently fade away—
New APIs lead the way! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: splitting the framework API into server, worlds, bots, and events facets.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/facet-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors LightKeeper’s JUnit framework API away from a large “god-interface” (ILightkeeperFramework) into four focused facet interfaces—IServerControl, IWorlds, IBots, and IEvents—while preserving source/binary compatibility for one release via deprecated default-method delegates. This aligns the framework module’s public API with the v2 design direction without changing the protocol layer.

Changes:

  • Introduces facet interfaces (server(), worlds(), bots(), events()) and package-private internal facade implementations as the single canonical codepaths.
  • Keeps all v1 flat methods as @Deprecated(forRemoval = true) default methods delegating to the facets, and migrates in-repo usage (tests + README examples) to the facet API.
  • Adds/updates unit tests to pin delegation correctness and ensure facade implementation visibility constraints.

Reviewed changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated no comments.

Show a summary per file
File Description
README.md Updates documentation/examples to use facet-based API and notes v1 deprecations.
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperWorldTemplateIT.java Migrates template-world interactions to server()/worlds() facets.
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperSharedLifecycleIT.java Migrates mainWorld() usage to worlds().main().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperServerLifecycleIT.java Migrates lifecycle + directory access to server() and bots to bots().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperServerErrorCaptureIT.java Migrates server error capture/commands to server().errors() + server().executeCommand(...).
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperPermissionsIT.java Migrates world/bot creation to worlds() and bots() facets.
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperMixedFreshLifecycleIT.java Migrates mainWorld() calls to worlds().main().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperMethodFreshServerIT.java Migrates mainWorld() call to worlds().main().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperFreshServerIT.java Migrates mainWorld() call to worlds().main().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperFrameworkIT.java Migrates world creation to worlds().create(...).
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperExtensionIT.java Migrates world creation to worlds().create() and main world to worlds().main().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperEntityQueryIT.java Migrates server commands/tick reads to server() and world creation to worlds().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperDiagnosticsIT.java Migrates to worlds().main().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperChatAndCancelIT.java Migrates bots, event capture, and tick reads to bots()/events()/server().
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperBotIT.java Migrates bot/world/server/event usage to facet API.
lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperBlockStateIT.java Migrates to worlds().create(...) / worlds().main().
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/WorldsFacadeTest.java Adds unit coverage for WorldsFacade behavior and validation.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/ServerControlFacadeTest.java Adds unit coverage for ServerControlFacade command/output/platform/errors.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/FailureDiagnosticsWriterTest.java Updates diagnostics tests to mock/use framework.server() facet.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/EventsFacadeTest.java Adds unit coverage for EventsFacade capture/validation.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkServerErrorsTest.java Migrates server error access to server().errors() and crash to server().crash().
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkLifecycleTest.java Migrates lifecycle/output calls to server() facet.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkGatewayTest.java Migrates directory/template/tick access to facets (server(), worlds()).
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/BotsFacadeTest.java Adds unit coverage for BotsFacade join/builder behavior and validation.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/FrameworkApiVisibilityTest.java Pins non-public visibility for internal facade implementations.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/DeprecatedDelegateTest.java Adds contract test ensuring every deprecated v1 method delegates to its facet equivalent.
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/assertions/HandleAssertionsTest.java Updates assertion tests to use framework.server() facet for errors/output.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IWorlds.java Introduces public worlds facet interface.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IServerControl.java Introduces public server-control facet interface.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/WorldsFacade.java Adds package-private canonical implementation for worlds facet.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/ServerControlFacade.java Adds package-private canonical implementation for server facet.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/FailureDiagnosticsWriter.java Routes diagnostics rendering through framework.server() facet.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/EventsFacade.java Adds package-private canonical implementation for events facet.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFramework.java Refactors framework to own shared internals and delegate public API to facet facades.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/BotsFacade.java Adds package-private canonical implementation for bots facet.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/ILightkeeperFramework.java Adds facet accessors and deprecates v1 flat methods with default delegates.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IEvents.java Introduces public events facet interface.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IBots.java Introduces public bots facet interface.
lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/assertions/LightkeeperFrameworkAssert.java Updates assertion helpers to use server() facet for output/platform/errors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 2a0e1cbb0f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkLifecycleTest.java (1)

72-90: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Test names still reference the deprecated v1 method names.

These test bodies now exercise server().output()/crash()/stop()/start()/restart() (e.g., Lines 86, 108, 133, 159, 188, 208, 229-232, 273-276, 300, 332, 357, 378-384, 402-403, 426-431), but the test method names (serverOutput_..., crashServer_..., stopServer_..., startServer_..., restartServer_...) still refer to the old, now-deprecated flat API. As per path instructions, **/src/test/java/**/*.java: "Test method names must follow methodToTest_whatWeTest".

Renaming to reflect the facet methods (e.g. output_shouldReturnServerProcessOutputSnapshot, crash_shouldInvalidatePlayersAndKillProcess) would keep names aligned with what's actually under test.

Also applies to: 93-114, 117-140, 143-165, 168-191, 194-211, 214-253, 256-281, 284-310, 313-338, 341-363, 366-386, 389-410, 413-433

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkLifecycleTest.java`
around lines 72 - 90, Rename the affected test methods in
DefaultLightkeeperFrameworkLifecycleTest to use the facet method under test
rather than the deprecated flat API prefixes. Update names such as
serverOutput_, crashServer_, stopServer_, startServer_, and restartServer_ to
output_, crash_, stop_, start_, and restart_, while preserving each test’s
existing behavior and descriptive suffix.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/BotsFacade.java`:
- Around line 86-107: Update createFromBuilder in BotsFacade to emit the same
INFO lifecycle log as join() after the player is successfully created, using the
created player details and existing logging conventions. Keep player
registration and wrapping behavior unchanged.

In
`@lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/ServerControlFacade.java`:
- Around line 92-180: Update the lifecycle log messages in crash(), doStop(),
start(), and restart() to include actionable server context, using available
runtimeManifest values such as the server directory identifier and runtime
protocol version. Preserve the existing lifecycle actions and log levels while
making each message identify the affected runtime.

In
`@lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/BotsFacadeTest.java`:
- Around line 102-106: Add unit tests in BotsFacadeTest for the validation paths
of BotsFacade.join: verify that passing a null uuid throws NullPointerException
mentioning "uuid", and passing a null world throws NullPointerException
mentioning "world". Use the existing framework setup and AssertJ exception
assertions, suppressing nullness warnings only where needed to intentionally
cross the non-null API boundary.

In
`@lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/WorldsFacadeTest.java`:
- Around line 97-101: Add a unit test alongside the existing WorldsFacade tests
covering WorldsFacade.create with a null WorldSpec. Intentionally bypass the
non-null API constraint, invoke framework.worlds().create(null), and assert that
it throws NullPointerException with a message containing “worldSpec”.

---

Outside diff comments:
In
`@lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkLifecycleTest.java`:
- Around line 72-90: Rename the affected test methods in
DefaultLightkeeperFrameworkLifecycleTest to use the facet method under test
rather than the deprecated flat API prefixes. Update names such as
serverOutput_, crashServer_, stopServer_, startServer_, and restartServer_ to
output_, crash_, stop_, start_, and restart_, while preserving each test’s
existing behavior and descriptive suffix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 777e8447-b65f-4e84-9db5-6e3004315645

📥 Commits

Reviewing files that changed from the base of the PR and between 624c843 and 2a0e1cb.

📒 Files selected for processing (39)
  • README.md
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IBots.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IEvents.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/ILightkeeperFramework.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IServerControl.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/IWorlds.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/assertions/LightkeeperFrameworkAssert.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/BotsFacade.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFramework.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/EventsFacade.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/FailureDiagnosticsWriter.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/ServerControlFacade.java
  • lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/WorldsFacade.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/DeprecatedDelegateTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/FrameworkApiVisibilityTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/assertions/HandleAssertionsTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/BotsFacadeTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkGatewayTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkLifecycleTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/DefaultLightkeeperFrameworkServerErrorsTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/EventsFacadeTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/FailureDiagnosticsWriterTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/ServerControlFacadeTest.java
  • lightkeeper-framework-junit/src/test/java/nl/pim16aap2/lightkeeper/framework/internal/WorldsFacadeTest.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperBlockStateIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperBotIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperChatAndCancelIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperDiagnosticsIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperEntityQueryIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperExtensionIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperFrameworkIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperFreshServerIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperMethodFreshServerIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperMixedFreshLifecycleIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperPermissionsIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperServerErrorCaptureIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperServerLifecycleIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperSharedLifecycleIT.java
  • lightkeeper-integration-tests/src/test/java/nl/pim16aap2/lightkeeper/maven/test/LightkeeperWorldTemplateIT.java

Comment on lines +92 to +180
@Override
public void crash()
{
framework.ensureOpen();
LOG.log(System.Logger.Level.INFO, "LK_FRAMEWORK: Crashing Minecraft server.");
playerScopeRegistry.invalidateAll();
agentClient.close();
minecraftServerProcess.kill();
framework.markServerDown();
}

@Override
public void stop()
{
framework.ensureOpen();
if (!minecraftServerProcess.isRunning())
throw new IllegalStateException("Cannot stop the server because it is not running.");
doStop();
}

/**
* Graceful-stop implementation without the running-state precondition.
*
* <p>Tolerates a server that died on its own after the caller's running check: player cleanup swallows
* per-player failures, the client close is idempotent, and the process stop handles dead processes. This is
* what lets {@link #restart()} avoid a check-then-act race on the running state.
*/
private void doStop()
{
LOG.log(System.Logger.Level.INFO, "LK_FRAMEWORK: Stopping Minecraft server gracefully.");
try
{
// Remove synthetic players through the live agent first so they quit cleanly instead of being
// persisted as offline players in the world's playerdata by the server's shutdown save.
playerScopeRegistry.cleanupAll(agentClient::removePlayer);
agentClient.close();
}
finally
{
framework.markServerDown();
minecraftServerProcess.stop(DefaultLightkeeperFramework.SHUTDOWN_TIMEOUT);
}
}

@Override
public void start()
{
framework.ensureOpen();
if (minecraftServerProcess.isRunning())
throw new IllegalStateException("Cannot start the server because it is already running.");

LOG.log(System.Logger.Level.INFO, "LK_FRAMEWORK: Starting Minecraft server.");
minecraftServerProcess.start(DefaultLightkeeperFramework.STARTUP_TIMEOUT);
try
{
agentClient.rehandshake(
DefaultLightkeeperFramework.AGENT_CONNECT_TIMEOUT,
runtimeManifest.agentAuthToken(),
runtimeManifest.runtimeProtocolVersion(),
Objects.requireNonNullElse(runtimeManifest.agentJarSha256(), "")
);
framework.preloadConfiguredWorlds();
}
catch (Exception exception)
{
// Return to a clean 'down' state so a retry of start() remains possible; leaving the process running
// here would wedge the start path (running + down means only restart() could recover).
try
{
minecraftServerProcess.stop(DefaultLightkeeperFramework.SHUTDOWN_TIMEOUT);
}
catch (Exception stopException)
{
exception.addSuppressed(stopException);
}
throw exception;
}
framework.markServerUp();
}

@Override
public void restart()
{
framework.ensureOpen();
LOG.log(System.Logger.Level.INFO, "LK_FRAMEWORK: Restarting Minecraft server.");
if (minecraftServerProcess.isRunning())
doStop();
start();
}

@coderabbitai coderabbitai Bot Jul 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Lifecycle log messages lack actionable identifiers.

crash(), doStop(), start(), and restart() log generic messages (e.g., "Crashing Minecraft server.") without identifiers like the server directory or runtime protocol version, even though runtimeManifest is already a field on this class.

As per coding guidelines, **/src/main/java/**/*.java: "Log at lifecycle boundaries such as start, stop, major transitions, and failures... include actionable context such as actions, identifiers, paths, and protocol versions."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lightkeeper-framework-junit/src/main/java/nl/pim16aap2/lightkeeper/framework/internal/ServerControlFacade.java`
around lines 92 - 180, Update the lifecycle log messages in crash(), doStop(),
start(), and restart() to include actionable server context, using available
runtimeManifest values such as the server directory identifier and runtime
protocol version. Preserve the existing lifecycle actions and log levels while
making each message identify the affected runtime.

Source: Coding guidelines

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining for this PR for the same behavioral-equivalence reason — these messages moved verbatim from DefaultLightkeeperFramework. Enriching lifecycle logs with the server directory/protocol version is a good standalone follow-up.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PimvanderLoos, understood — makes sense to keep this PR's log messages behaviorally equivalent to the original and defer enrichment to a follow-up. Let me know if you'd like me to open a tracking issue for enriching the lifecycle log messages with server directory/protocol version, and I'll file it.

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.58537% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...amework/assertions/LightkeeperFrameworkAssert.java 33.33% 4 Missing ⚠️
...keeper/framework/internal/ServerControlFacade.java 95.89% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@PimvanderLoos

Copy link
Copy Markdown
Owner Author

@codex review

Goal: address CodeRabbit's round-one findings on the facet PR — the
join(uuid/world) and create(worldSpec) fail-fast paths were validated
in the facades but not pinned by tests. Adds the three missing
NullPointerException tests following the existing NullAway-suppressed
boundary-crossing pattern.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P15FjGQzyNmX9T6Qmyq8Dn
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 2a0e1cbb0f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@PimvanderLoos
PimvanderLoos merged commit 89ab371 into master Jul 15, 2026
5 checks passed
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.

2 participants