<feed xmlns='http://www.w3.org/2005/Atom'>
<title>LunaticChat.git/website/src/docs/reference, branch main</title>
<subtitle>A next-generation chat plugin for Paper, Folia and Velocity.
</subtitle>
<link rel='alternate' type='text/html' href='https://openpgpkey.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://openpgpkey.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(paper): add world, display_name, channel_id and role chat placeholders</title>
<updated>2026-09-28T14:00:29+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-09-28T14:00:29+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=af2feee95e7f6ebaef5466402789917ae65c0796'/>
<id>af2feee95e7f6ebaef5466402789917ae65c0796</id>
<content type='text'>
Operators asked for more of the sender's context in chat formats than the
name alone. {world} covers direct messages and channel chat; the channel
details and the sender's display name and role only exist for channel
chat, so only that format accepts them.

A direct message from another server renders {world} empty: the relay does
not carry the sender's world, and adding it would need a protocol bump and
a coordinated Velocity release for one placeholder. The renderer now
accepts underscores so the snake_case names match as written.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Operators asked for more of the sender's context in chat formats than the
name alone. {world} covers direct messages and channel chat; the channel
details and the sender's display name and role only exist for channel
chat, so only that format accepts them.

A direct message from another server renders {world} empty: the relay does
not carry the sender's world, and adding it would need a protocol bump and
a coordinated Velocity release for one placeholder. The renderer now
accepts underscores so the snake_case names match as written.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: Add v1.4.0 doc</title>
<updated>2026-08-30T11:55:48+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-30T11:55:48+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=6eadc66f4ac9bf626e3649da9a3402dec35c7ba6'/>
<id>6eadc66f4ac9bf626e3649da9a3402dec35c7ba6</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(paper): add /lc reload to apply message formats without a restart</title>
<updated>2026-08-09T23:31:20+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-09T23:31:20+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=f08d4d8f0557581d93063cd9f6e750ab3ac9cc17'/>
<id>f08d4d8f0557581d93063cd9f6e750ab3ac9cc17</id>
<content type='text'>
Changing a message format meant taking the server down, because config.yml
was read once in onEnable and every consumer held the value it was built
with. Operators tune these formats far more often than anything else in the
file, and a restart is a disproportionate price for a colour code.

Only messageFormat is applied. The rest of config.yml settles things once,
at startup - which services exist, which commands and listeners are
registered, which files are opened - and none of that can be redone while
the server runs: Paper registers commands only through its COMMANDS
lifecycle event, Bukkit cannot unregister a listener, and the conversion
cache saver keeps no task handle to cancel. Rebuilding the services would
leave the old ones still wired up, so a changed setting the server cannot
pick up is reported back as needing a restart rather than silently ignored.

MessageFormatHolder is deliberately narrower than LunaticChatConfiguration:
taking it says the value is live, taking the configuration says it was
frozen at startup. A holder over the whole tree would hold a configuration
matching no version of the file, since only messageFormat is ever swapped.

Reload reads config.yml more strictly than startup does, because it has an
option startup does not - leaving the running configuration alone. Startup
falls a single unreadable setting back to its default so the server can come
up; reload refuses the file, names every unreadable setting at once, and
keeps what the server already had. A document holding no settings is refused
for the same reason: it cannot be told apart from a config.yml caught
halfway through being written, and resetting every format over that is worse
than doing nothing.

Closes #266

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Changing a message format meant taking the server down, because config.yml
was read once in onEnable and every consumer held the value it was built
with. Operators tune these formats far more often than anything else in the
file, and a restart is a disproportionate price for a colour code.

Only messageFormat is applied. The rest of config.yml settles things once,
at startup - which services exist, which commands and listeners are
registered, which files are opened - and none of that can be redone while
the server runs: Paper registers commands only through its COMMANDS
lifecycle event, Bukkit cannot unregister a listener, and the conversion
cache saver keeps no task handle to cancel. Rebuilding the services would
leave the old ones still wired up, so a changed setting the server cannot
pick up is reported back as needing a restart rather than silently ignored.

MessageFormatHolder is deliberately narrower than LunaticChatConfiguration:
taking it says the value is live, taking the configuration says it was
frozen at startup. A holder over the whole tree would hold a configuration
matching no version of the file, since only messageFormat is ever swapped.

Reload reads config.yml more strictly than startup does, because it has an
option startup does not - leaving the running configuration alone. Startup
falls a single unreadable setting back to its default so the server can come
up; reload refuses the file, names every unreadable setting at once, and
keeps what the server already had. A document holding no settings is refused
for the same reason: it cannot be told apart from a config.yml caught
halfway through being written, and resetting every format over that is worse
than doing nothing.

Closes #266

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>feat: warn where a pair connects but falls short of a feature</title>
<updated>2026-08-05T11:56:07+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-05T11:56:07+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=54c369939455bcfd7b66faa9d0a18aff901c05b0'/>
<id>54c369939455bcfd7b66faa9d0a18aff901c05b0</id>
<content type='text'>
The matrix marked every accepted pair with a plain tick, which reads as
"everything works". It does not. ProtocolVersion bumps PATCH for sub-channels a
peer can safely ignore, so Paper 1.3.0 (protocol 1.0.1) against Velocity 1.1.0
(1.0.0) completes the handshake and then silently drops cross-server direct
messages — the very feature that PATCH was bumped for. An operator reading the
tick had no way to learn that, and the pages around it repeated the claim.

The handshake is settled by MAJOR and MINOR alone, so any difference left once a
pair is accepted is a feature the newer end offers and the older will never
answer. Those pairs now carry a warning that says which end lags. Naming the
feature would take a protocol-version-to-feature table on the website, which
would drift from the protocol it describes, so the warning stays general and
leaves the reader one hop from the compatibility page.

The handshake verdict keeps the three checks that mirror Velocity's gate, with
the new one layered after them, so the mirror stays honest. isCompatible now
holds for a degraded pair, which does connect.

Cells are built once per pair in a computed instead of recomputing on each of the
template's reads, which a third state would otherwise have multiplied.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The matrix marked every accepted pair with a plain tick, which reads as
"everything works". It does not. ProtocolVersion bumps PATCH for sub-channels a
peer can safely ignore, so Paper 1.3.0 (protocol 1.0.1) against Velocity 1.1.0
(1.0.0) completes the handshake and then silently drops cross-server direct
messages — the very feature that PATCH was bumped for. An operator reading the
tick had no way to learn that, and the pages around it repeated the claim.

The handshake is settled by MAJOR and MINOR alone, so any difference left once a
pair is accepted is a feature the newer end offers and the older will never
answer. Those pairs now carry a warning that says which end lags. Naming the
feature would take a protocol-version-to-feature table on the website, which
would drift from the protocol it describes, so the warning stays general and
leaves the reader one hop from the compatibility page.

The handshake verdict keeps the three checks that mirror Velocity's gate, with
the new one layered after them, so the mirror stays honest. isCompatible now
holds for a degraded pair, which does connect.

Cells are built once per pair in a computed instead of recomputing on each of the
template's reads, which a third state would otherwise have multiplied.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: correct the website where it had drifted from the implementation</title>
<updated>2026-08-04T19:36:50+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-08-04T19:36:50+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=418be2d127ce2d6a3ed5e9c876deb9c2aafc089b'/>
<id>418be2d127ce2d6a3ed5e9c876deb9c2aafc089b</id>
<content type='text'>
Several statements were wrong rather than merely thin, and each would have set
the wrong expectation:

- the conversion example implied romaji replaces the input, when the result is
  appended in parentheses and both are sent
- the handshake was described as happening at startup, when it waits for the
  first player to join, so a DISCONNECTED status on an empty server read as a
  fault
- cache eviction was called oldest-first, which the unordered in-memory map
  cannot provide
- the Velocity settings table omitted crossServerDirectMessage
- ConfigManager was described as reading Bukkit's FileConfiguration, and the
  settings storage as recovering from a backup that does not exist

It also documents behaviour that had no mention anywhere: the `!` force-global
prefix, that spy sees channel messages and not only DMs, the nightly build
warnings, the overall 1000ms conversion budget that makes api.timeout above it
ineffective, and the data files the plugin writes.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Several statements were wrong rather than merely thin, and each would have set
the wrong expectation:

- the conversion example implied romaji replaces the input, when the result is
  appended in parentheses and both are sent
- the handshake was described as happening at startup, when it waits for the
  first player to join, so a DISCONNECTED status on an empty server read as a
  fault
- cache eviction was called oldest-first, which the unordered in-memory map
  cannot provide
- the Velocity settings table omitted crossServerDirectMessage
- ConfigManager was described as reading Bukkit's FileConfiguration, and the
  settings storage as recovering from a backup that does not exist

It also documents behaviour that had no mention anywhere: the `!` force-global
prefix, that spy sees channel messages and not only DMs, the nightly build
warnings, the overall 1000ms conversion budget that makes api.timeout above it
ineffective, and the data files the plugin writes.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: add developer design/architecture guide (EN/JA) (#251)</title>
<updated>2026-07-19T13:06:37+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-07-19T13:06:37+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=bee1a61b7e38b160d967a91dd06bc5f44e14d057'/>
<id>bee1a61b7e38b160d967a91dd06bc5f44e14d057</id>
<content type='text'>
* docs: add developer design/architecture guide (EN/JA)

The docs site covered features and reference but had no entry point for
the codebase's design. Add a Developer Guide section describing the
module structure (engine shared kernel, platform-paper, platform-velocity),
the protocol-version compatibility model, and the Service Container /
Feature Gating pattern, so contributors can understand the architecture
without reading the source first.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;

* docs: mirror cross-server DM docs into English (#231)

PR #231 added the cross-server direct messaging feature but updated only
the Japanese docs. Port the same additions to the English pages
(configuration, direct-message, velocity, commands) so both locales stay
in sync.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;

* style: apply biome formatting to ja.ts sidebar config

The developer-guide sidebar entries were not biome-formatted, failing the
build_docs CI check (format:check). Apply the formatter.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;

---------

Co-authored-by: Claude &lt;noreply@anthropic.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* docs: add developer design/architecture guide (EN/JA)

The docs site covered features and reference but had no entry point for
the codebase's design. Add a Developer Guide section describing the
module structure (engine shared kernel, platform-paper, platform-velocity),
the protocol-version compatibility model, and the Service Container /
Feature Gating pattern, so contributors can understand the architecture
without reading the source first.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;

* docs: mirror cross-server DM docs into English (#231)

PR #231 added the cross-server direct messaging feature but updated only
the Japanese docs. Port the same additions to the English pages
(configuration, direct-message, velocity, commands) so both locales stay
in sync.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;

* style: apply biome formatting to ja.ts sidebar config

The developer-guide sidebar entries were not biome-formatted, failing the
build_docs CI check (format:check). Apply the formatter.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;

---------

Co-authored-by: Claude &lt;noreply@anthropic.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>docs(website): make English the default locale</title>
<updated>2026-06-12T06:42:51+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-06-12T06:42:51+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=8326b6a7619fd9e4fb6a640d01c4bf0c6194dc81'/>
<id>8326b6a7619fd9e4fb6a640d01c4bf0c6194dc81</id>
<content type='text'>
Swap the website default locale from Japanese to English.
English now lives at the site root (/), and Japanese moves
under /ja/. Update locale config, nav/sidebar links, internal
doc links, and asset relative paths accordingly.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Swap the website default locale from Japanese to English.
English now lives at the site root (/), and Japanese moves
under /ja/. Update locale config, nav/sidebar links, internal
doc links, and asset relative paths accordingly.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>docs(compatibility): clarify protocol version validation is Velocity-only</title>
<updated>2026-06-01T04:58:03+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-06-01T04:58:03+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=04ab6c92a6849e3d2af7439c2f0092324bc8889b'/>
<id>04ab6c92a6849e3d2af7439c2f0092324bc8889b</id>
<content type='text'>
Update the compatibility matrix logic and documentation to reflect the actual
implementation: only Velocity performs the handshake validation, not Paper.

- Remove velocity-too-new and velocity-too-old from CompatibilityResult
- Simplify checkCompatibility() to check only if Velocity accepts Paper
- Update reason labels to clarify direction (Paper vs Velocity perspective)
- Add note distinguishing plugin version from protocol version
- Clarify Velocity-only validation in the protocol section
- Rewrite compatibility rules from Velocity's perspective

Paper only sends the handshake; it does not validate Velocity's version.
This aligns documentation with the actual behavior in
platform-velocity/.../PluginMessageHandler.kt.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Update the compatibility matrix logic and documentation to reflect the actual
implementation: only Velocity performs the handshake validation, not Paper.

- Remove velocity-too-new and velocity-too-old from CompatibilityResult
- Simplify checkCompatibility() to check only if Velocity accepts Paper
- Update reason labels to clarify direction (Paper vs Velocity perspective)
- Add note distinguishing plugin version from protocol version
- Clarify Velocity-only validation in the protocol section
- Rewrite compatibility rules from Velocity's perspective

Paper only sends the handshake; it does not validate Velocity's version.
This aligns documentation with the actual behavior in
platform-velocity/.../PluginMessageHandler.kt.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>docs: clarify paper/velocity compatibility</title>
<updated>2026-05-05T21:09:43+00:00</updated>
<author>
<name>Sho Sakuma</name>
<email>me@m1sk9.dev</email>
</author>
<published>2026-05-05T21:09:43+00:00</published>
<link rel='alternate' type='text/html' href='https://openpgpkey.dangofactory.net/cgit/cgit.cgi/LunaticChat.git/commit/?id=c092edbab0e8b516faaa459f6d0915c7df3cd06f'/>
<id>c092edbab0e8b516faaa459f6d0915c7df3cd06f</id>
<content type='text'>
Add a dynamic compatibility matrix (GitHub Releases + ProtocolVersion.kt at
each tag) shown on the home page, download page, and a new reference doc.
Split protocol theory and rolling-update rules out of the Velocity feature
guide into the new compatibility reference, and simplify the download notice.

Also set explicit GitHub release titles in the Paper / Velocity workflows so
the awkward paper/v* tag prefix is not the user-facing label.

Co-Authored-By: Claude &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add a dynamic compatibility matrix (GitHub Releases + ProtocolVersion.kt at
each tag) shown on the home page, download page, and a new reference doc.
Split protocol theory and rolling-update rules out of the Velocity feature
guide into the new compatibility reference, and simplify the download notice.

Also set explicit GitHub release titles in the Paper / Velocity workflows so
the awkward paper/v* tag prefix is not the user-facing label.

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