<feed xmlns='http://www.w3.org/2005/Atom'>
<title>LunaticChat.git/platform-velocity/src/test, branch main</title>
<subtitle>A next-generation chat plugin for Paper, Folia and Velocity.
</subtitle>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/'/>
<entry>
<title>feat: carry the sender's world in cross-server direct messages</title>
<updated>2026-09-28T14:43:14+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T14:43:14+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=388ae4ef14ec620e6f1fe2ce8a8ea8e3a816d10d'/>
<id>388ae4ef14ec620e6f1fe2ce8a8ea8e3a816d10d</id>
<content type='text'>
{world} rendered empty for a direct message from another server, which
left formats like "({world})" showing a bare pair of brackets. The relay
now carries the sender's world as an optional field, so this is a PATCH
bump (protocol 1.0.2) and either side can be updated first; an older
sender or proxy still yields an empty value.

The world is read once per message, so the sender, the spies and the
relayed copy can no longer disagree if the sender changes worlds mid-way.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
{world} rendered empty for a direct message from another server, which
left formats like "({world})" showing a bare pair of brackets. The relay
now carries the sender's world as an optional field, so this is a PATCH
bump (protocol 1.0.2) and either side can be updated first; an older
sender or proxy still yields an empty value.

The world is read once per message, so the sender, the spies and the
relayed copy can no longer disagree if the sender changes worlds mid-way.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(velocity): let the proxy be debugged without a config file</title>
<updated>2026-08-30T11:43:45+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-30T11:43:45+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=3aecb1374913d585c789c0c0f27295aa6be43fc4'/>
<id>3aecb1374913d585c789c0c0f27295aa6be43fc4</id>
<content type='text'>
The proxy had three slf4j debug calls and no way to turn them on, so the
handshake internals were either missing or mixed into INFO for every backend.

The switch is read from the `lunaticchat.debug` system property, falling back to
the `LUNATICCHAT_DEBUG` environment variable, rather than from a new config file:
a file means a parser and a parser means a dependency, and platform-velocity
deliberately ships without so much as Ktor. The property wins so a proxy started
from a compose file can still be overridden for one run without editing it.

Paper's `debug` is deliberately not carried over the handshake. The proxy is
shared by every backend, so one Paper server's setting must not decide how much
the proxy logs for everyone else.

The compatibility check now reports both halves of the rule with their measured
values. "Protocol version incompatible" left the operator comparing two version
strings against a rule they could not see, and which half failed is the whole
answer when a rolling upgrade stops relaying. For the same reason the relay names
the servers it skipped and why: from the receiving server's log, "the message
never arrived" and "the message was never sent" look identical.

The lines that were unconditionally at INFO drop to their category, leaving only
the failure an operator has to act on.

Refs #228

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The proxy had three slf4j debug calls and no way to turn them on, so the
handshake internals were either missing or mixed into INFO for every backend.

The switch is read from the `lunaticchat.debug` system property, falling back to
the `LUNATICCHAT_DEBUG` environment variable, rather than from a new config file:
a file means a parser and a parser means a dependency, and platform-velocity
deliberately ships without so much as Ktor. The property wins so a proxy started
from a compose file can still be overridden for one run without editing it.

Paper's `debug` is deliberately not carried over the handshake. The proxy is
shared by every backend, so one Paper server's setting must not decide how much
the proxy logs for everyone else.

The compatibility check now reports both halves of the rule with their measured
values. "Protocol version incompatible" left the operator comparing two version
strings against a rule they could not see, and which half failed is the whole
answer when a rolling upgrade stops relaying. For the same reason the relay names
the servers it skipped and why: from the receiving server's log, "the message
never arrived" and "the message was never sent" look identical.

The lines that were unconditionally at INFO drop to their category, leaving only
the failure an operator has to act on.

Refs #228

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(engine): give both platforms one debug switch to read</title>
<updated>2026-08-30T11:43:18+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-30T11:43:18+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=64197733346bbcabc3daa65f6648c1a21e26b328'/>
<id>64197733346bbcabc3daa65f6648c1a21e26b328</id>
<content type='text'>
"Debug" had grown into three unconnected mechanisms: a boolean injected into
RomanjiConverter, a one-off configuration dump at startup, and KtorSimpleLogger
calls that Paper's stock log4j configuration never printed. Turning `debug: true`
on told an operator nothing about the Velocity handshake, which is what #228 is
actually about.

The vocabulary goes in engine because it is a contract before it is an
implementation: config.yml and the proxy's system property have to agree on what
`velocity,protocol` means, and a category added on one side must exist on the
other. Only the writing is left to the platforms.

The message is a lambda so that the chat path - instrumented once per message -
costs nothing while debugging is off. The `if (debugMode) logger.info("... $word")`
guards this replaces built their strings either way.

Both platform loggers write at INFO rather than at the level the content
deserves, because neither Paper's nor Velocity's stock logging configuration
prints anything below it, and asking operators to edit log4j before they can
answer a bug report is the friction this exists to remove.

Refs #228

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
"Debug" had grown into three unconnected mechanisms: a boolean injected into
RomanjiConverter, a one-off configuration dump at startup, and KtorSimpleLogger
calls that Paper's stock log4j configuration never printed. Turning `debug: true`
on told an operator nothing about the Velocity handshake, which is what #228 is
actually about.

The vocabulary goes in engine because it is a contract before it is an
implementation: config.yml and the proxy's system property have to agree on what
`velocity,protocol` means, and a category added on one side must exist on the
other. Only the writing is left to the platforms.

The message is a lambda so that the chat path - instrumented once per message -
costs nothing while debugging is off. The `if (debugMode) logger.info("... $word")`
guards this replaces built their strings either way.

Both platform loggers write at INFO rather than at the level the content
deserves, because neither Paper's nor Velocity's stock logging configuration
prints anything below it, and asking operators to edit log4j before they can
answer a bug report is the friction this exists to remove.

Refs #228

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>perf: take per-message logging off the chat path</title>
<updated>2026-08-04T15:42:23+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-02T15:40:30+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=2d8b613a3ad48acafd683f5286e29c3f1c167275'/>
<id>2d8b613a3ad48acafd683f5286e29c3f1c167275</id>
<content type='text'>
Every channel message wrote a fully interpolated INFO line, duplicating
what the dedicated async ChannelMessageLogger already persists. Every
cross-server message produced one INFO on the sending Paper server, two on
Velocity, and one on each receiving Paper server - so a single global chat
message cost up to four synchronous console and latest.log writes across
the network, on the message path, with JUL and Logback appenders being
synchronous.

These are now debug, and phrased so the string is not built unless debug
is on: the JUL sites take a supplier, the slf4j sites take a format plus
arguments.

Handshake, registration and delivery-failure lines stay at info - they
fire once per server or once per failed message, and they explain
something an operator needs to see.

Two relay tests asserted on the text of a log line. One of them was
verifying "0 servers" where the same test already verifies zero sends;
the other was really checking that the payload reaches the target, so it
now decodes the relayed bytes and compares them to the original message.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Every channel message wrote a fully interpolated INFO line, duplicating
what the dedicated async ChannelMessageLogger already persists. Every
cross-server message produced one INFO on the sending Paper server, two on
Velocity, and one on each receiving Paper server - so a single global chat
message cost up to four synchronous console and latest.log writes across
the network, on the message path, with JUL and Logback appenders being
synchronous.

These are now debug, and phrased so the string is not built unless debug
is on: the JUL sites take a supplier, the slf4j sites take a format plus
arguments.

Handshake, registration and delivery-failure lines stay at info - they
fire once per server or once per failed message, and they explain
something an operator needs to see.

Two relay tests asserted on the text of a log line. One of them was
verifying "0 servers" where the same test already verifies zero sends;
the other was really checking that the payload reaches the target, so it
now decodes the relayed bytes and compares them to the original message.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat: add cross-server direct messaging via Velocity</title>
<updated>2026-06-17T07:15:40+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-06-17T07:15:40+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=c678bd15324dad0519cb1d9a4c58202a981ee8e2'/>
<id>c678bd15324dad0519cb1d9a4c58202a981ee8e2</id>
<content type='text'>
Allow /tell and /reply to reach players on other Paper servers behind a
Velocity proxy using the "&lt;player&gt;@&lt;server&gt;" target syntax.

Engine (protocol bumped 1.0.0 -&gt; 1.0.1, optional sub-channels):
- Add DirectMessageRelay, DirectMessageError, PresenceSnapshot/PresenceEntry
  and PresenceRequest messages plus codec branches.

Velocity:
- CrossServerDirectMessageRelay routes a DM to the target server (or returns
  a delivery error to the source).
- PresenceTracker broadcasts proxy-wide presence snapshots on join/quit/switch
  and on request.

Paper:
- RemotePlayerRegistry caches proxy presence for completion and remote target
  resolution.
- CrossServerDirectMessageManager handles send/receive/error and dedup.
- DirectMessageHandler reply state generalized to ReplyTarget (Local/Remote)
  so /reply works across servers.
- TellCommand parses "name@server", completes local names and remote
  name@server targets, and uses exact local name matching.
- New crossServerDirectMessage config flag and i18n keys (en/ja).

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Allow /tell and /reply to reach players on other Paper servers behind a
Velocity proxy using the "&lt;player&gt;@&lt;server&gt;" target syntax.

Engine (protocol bumped 1.0.0 -&gt; 1.0.1, optional sub-channels):
- Add DirectMessageRelay, DirectMessageError, PresenceSnapshot/PresenceEntry
  and PresenceRequest messages plus codec branches.

Velocity:
- CrossServerDirectMessageRelay routes a DM to the target server (or returns
  a delivery error to the source).
- PresenceTracker broadcasts proxy-wide presence snapshots on join/quit/switch
  and on request.

Paper:
- RemotePlayerRegistry caches proxy presence for completion and remote target
  resolution.
- CrossServerDirectMessageManager handles send/receive/error and dedup.
- DirectMessageHandler reply state generalized to ReplyTarget (Local/Remote)
  so /reply works across servers.
- TellCommand parses "name@server", completes local names and remote
  name@server targets, and uses exact local name matching.
- New crossServerDirectMessage config flag and i18n keys (en/ja).

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat: Improving Velocity's Cycling Compatibility</title>
<updated>2026-04-04T11:26:37+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-04-04T11:26:37+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=2b0829856c9a24b90a9248d28c7de84101b83232'/>
<id>2b0829856c9a24b90a9248d28c7de84101b83232</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>test: expand test coverage across all modules</title>
<updated>2026-02-25T15:17:21+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-02-25T15:17:21+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=70c785eee4c61601ba7fffa17cc8b992b4793491'/>
<id>70c785eee4c61601ba7fffa17cc8b992b4793491</id>
<content type='text'>
- Add 23 new test files covering exceptions, data classes, permissions,
  setting handlers, commands, and cross-server relay
- Change command execute methods from private to internal visibility
  to enable unit testing (16 command files)
- Engine coverage: 65.5% → 92.4%
- Platform-paper coverage: 16.8% → 40.0%
- Platform-velocity coverage: 62.4% → 76.8%

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
- Add 23 new test files covering exceptions, data classes, permissions,
  setting handlers, commands, and cross-server relay
- Change command execute methods from private to internal visibility
  to enable unit testing (16 command files)
- Engine coverage: 65.5% → 92.4%
- Platform-paper coverage: 16.8% → 40.0%
- Platform-velocity coverage: 62.4% → 76.8%

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat: add Codecov/Jacoco integration and expand test coverage</title>
<updated>2026-02-25T13:38:44+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-02-25T13:38:19+00:00</published>
<link rel='alternate' type='text/html' href='https://www.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=f4bf20791f4470d3e9b865a53b610b5f277ebb82'/>
<id>f4bf20791f4470d3e9b865a53b610b5f277ebb82</id>
<content type='text'>
- Add Jacoco plugin to all subprojects with XML report generation
- Replace post-test-results.sh with Codecov upload in CI workflow
- Add codecov.yml configuration
- Add 140 new tests across engine, platform-paper, and platform-velocity

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
- Add Jacoco plugin to all subprojects with XML report generation
- Replace post-test-results.sh with Codecov upload in CI workflow
- Add codecov.yml configuration
- Add 140 new tests across engine, platform-paper, and platform-velocity

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
