6917 Commits

Author SHA1 Message Date
Claridtimo cedc0473a4 Revert "chore(ci): temporarily enable show_full_output on claude-review"
This reverts commit ec230e71c9.
2026-07-11 14:42:27 +12:00
Claridtimo ec230e71c9 chore(ci): temporarily enable show_full_output on claude-review
Debugging the instant SDK auth failure on this repo's review runs
(is_error, 1 turn, $0). REVERT once the root cause is captured.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JagA3ayqpJH4gC69qbLtgF
2026-07-11 14:41:13 +12:00
Claridtimo f12080af5b Instrument crowd data classes with generated streamers (Epic A1 Phase 5)
The presents transport layer got explicit streamers in 1.21/1.22, but crowd's
value classes (OccupantInfo, chat messages, BodyObject/PlaceObject fields)
still streamed reflectively — nondeterministic field order on Android/ART.
Generated with bang's genStreamableLibs task (ancestor-aware flatten mode).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
2026-07-06 22:55:44 +12:00
Claridtimo 67119d0be8 GenStreamableTask flatten: model the POST-regen hierarchy for super-call targets
Follow-up to 0f1626ece, found when 85 persisted .board files stopped
deserializing: the ancestor walk reflected on classes compiled from the
STRIPPED sources, but javac binds the emitted super.readObject to the nearest
declaration in the FINAL sources. CargoTank extends Counter extends Prop —
Counter regenerates a method covering `count`, so CargoTank's tail computed
against Prop streamed `count` twice and desynced the stream.

findStreamMethodAncestor now asks willDeclare(): an ancestor counts iff it
declares the method in current source (hand-written / substituted frame) OR
this run will generate one for it (concrete, in-fileset, nonempty own tail —
recursive, memoized; the filesets are pre-scanned so out-of-fileset ancestors
are never assumed generatable). Consequence: a subclass whose tail below the
NEAREST post-regen ancestor is empty generates nothing (CargoTank inherits
Counter's method).

The hand-written-custom skip is also per-SIDE now, not per-class: Prop has a
custom readObject but no writeObject, and its write side must regenerate both
for legacy parity and because subclasses emit super.writeObject against it
(the old whole-class skip left those uncompilable).

Verified: all 165 persisted .board files load with the regenerated streamers;
regen is idempotent (second run converts 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
2026-07-06 22:34:20 +12:00
Claridtimo 0f1626ecef GenStreamableTask flatten: nested classes, region scoping, ancestor-aware supers
Three structural fixes to flatten mode, found bringing up games on-device
(Epic A1 Phase 5):

1. Nested classes: processFlatten now recurses through getDeclaredClasses()
   (not gated on the outer class's eligibility), so nested Streamables like
   BangConfig.Round get deterministic methods too. All detection/substitution/
   insertion is scoped to each class's own body region (brace-matched,
   comment/string-aware, member-class bodies masked during detection) so an
   instrumented outer class can't hide — or poison — a nested one.

2. Ancestor-aware generation: a class whose ancestor declares read/writeObject
   now generates `super.readObject(ins)` + only the fields declared below that
   ancestor, instead of a self-contained full-set method. A self-contained
   subclass method silently dropped the ancestor's side effects for every
   subclass that previously inherited it: Prop.init() (server NPE cloning
   board props at startRound), Item's _nondb identity extras (itemId=0 on
   every wire-streamed item), InvocationMarshaller's _invdir rebind. Byte
   layout is unchanged: the ancestor's method streams exactly the flattened
   prefix. When the subclass adds no fields, nothing is generated — plain
   inheritance is already complete (the field-free marshaller/unit case).

3. Abstract classes: substitution-only. Their default*Object() pass-throughs
   are replaced in place with the class's own flattened prefix (making them
   safe super-call targets — the reflective pass-through reads the full
   dynamic-class set and would double-read the subclass tail), but whole
   methods are never generated for them. Requires every Streamable ancestor
   to be covered by the task's filesets; see findStreamMethodAncestor doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
2026-07-06 21:34:05 +12:00
Claridtimo 1cf16721d6 Add Claude Code review + @claude workflows
Ports the two Claude GitHub workflows from the bang repo (which narya lacked):
claude-code-review.yml auto-reviews PRs; claude.yml responds to @claude
mentions on issues/PRs. Review prompt tuned for narya (wire/streaming compat,
DObject/marshaller correctness, concurrency). Requires the
CLAUDE_CODE_OAUTH_TOKEN repo secret to authenticate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
2026-07-05 22:35:49 +12:00
Claridtimo 7cbac80172 Phase 5(b) fix: InvocationMarshaller explicit streaming preserves _invdir
The flatten-mode codegen gave each *Marshaller subclass a self-contained
read/writeObject, which overrode InvocationMarshaller.readObject and thus
skipped its side-effect of binding the transient _invdir from the stream's
client -> null _invdir -> NPE on the first invocation request (hit by ART
AND HotSpot clients). Fix: give InvocationMarshaller explicit read/writeObject
(GenStreamUtil, deterministic order, byte-identical to the old reflective
default) that keeps the _invdir binding; field-free subclasses inherit it.
narya 1.22.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
2026-07-05 22:10:13 +12:00
Claridtimo 9ea7ecf9ee WIP checkpoint: Phase 5(b) narya streamer codegen for ART field-order
Pre-crash safety checkpoint (box rebooted mid-implementation; NOT verified
complete). GenStreamableTask flatten-mode + GenStreamUtil runtime helper +
ObjectInputStream changes; explicit read/writeObject instrumentation across
presents net + dobj event classes so ART matches HotSpot's ClassUtil.getFields
order without the global sort flag (no data migration). narya 1.21.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
2026-07-05 19:56:40 +12:00
Claridtimo 12e65f059f Merge bang-tls: full-session TLS + narya 1.20
Merges the TLS transport work (PR #1). Conflict resolution note: master carried
an abandoned June-14 experiment pointing deps at local-stack SNAPSHOTs
(ooo-util 1.6-SNAPSHOT, depot 1.9-SNAPSHOT, jmustache 1.17-SNAPSHOT) plus the
upstream post-release 1.20-SNAPSHOT bump; the merge resolves all three poms to
the bang-tls state — released deps (ooo-util 1.5, depot 1.8, jmustache 1.16)
and version 1.20, which is exactly what was built, verified against Bang, and
published to GitHub Packages.
2026-07-02 22:00:33 +12:00
Claridtimo 3266a9c163 Bump narya to 1.20 for the Bang TLS work
A clean minor-version bump (retiring the Epic 2 -bangN patched-fork suffix —
that scheme is superseded; we now own these forks outright and version them
normally). GitHub Packages won't let us re-publish 1.19, and 1.20 makes the
TLS-capable build obvious in dependency listings.
2026-06-29 23:31:09 +12:00
Claridtimo a942d5d3dc TLS for inter-node peer connections
When the cluster's client port is TLS-enabled, peer connections (which connect to
that same port) must also speak TLS. PeerManager gains setPeerClientContext/
getPeerClientContext, and PeerNode installs that context on its client before
logon. Null (the default) leaves peering plaintext — a no-op, so non-TLS clusters
are unchanged.
2026-06-29 22:16:57 +12:00
Claridtimo ce4360f210 TLS transport wiring: full-session TLS over the Presents NIO stream
Wraps the entire client<->server TCP object stream in TLS, strictly opt-in via
an injected SSLContext (null = byte-for-byte the original plaintext behavior).

Connection: a ByteChannel _ioChannel indirection (defaults to the raw socket;
a TLS-wrapping channel when enabled). Selector registration, connection-pending
checks and close still use the raw SocketChannel.

Server (PresentsConnectionManager/PresentsConnection/ConnectionManager):
setSSLContext/isTlsEnabled; accepted sockets are wrapped in a non-blocking
ServerTlsChannel after init+registration; reads/writes route through the io
channel. tls-channel NeedsWrite/NeedsRead on write are treated as partial writes
(stashed in the existing per-connection overflow queue, retried each timed-select
tick — the server never needed OP_WRITE); on read, NeedsRead stays OP_READ and
NeedsWrite adds OP_WRITE so the re-dispatch pumps the handshake flush, cleared
after a clean read. processAuthedConnections carries the established io channel
from the authing connection to the running connection (init() would otherwise
revert it to the raw socket mid-session).

Client (Client/BlockingCommunicator): Client.setSSLContext; the connected
blocking socket is wrapped in a ClientTlsChannel (handshake driven transparently
in blocking mode); the Reader/Writer threads share it (one-unwrap + one-wrap, the
concurrency tls-channel allows).

DatagramChannelReader: fails closed — refuses to bind datagram ports while TLS is
enabled (we have no DTLS, so plaintext datagrams alongside TLS would be a footgun;
Bang binds zero datagram ports, so this never triggers today).
2026-06-29 22:02:52 +12:00
Claridtimo 93a2dc35d0 TLS foundation: tls-channel dep + TlsContextFactory
Adds the marianobarrios:tls-channel:1.0.0 dependency (thin ByteChannel-over-
SSLEngine wrapper, MIT, zero transitive deps, Java 8 bytecode) and a
TlsContextFactory that builds server (keystore) and client (pinned truststore)
SSLContexts, TLS 1.3 only. No transport wiring yet — this just compiles in the
building blocks for full-session encryption of the Presents NIO stream.
2026-06-29 21:52:48 +12:00
Claridtimo cbff83badd build: depend on local-stack SNAPSHOTs (ooo-util 1.6, depot 1.9, jmustache 1.17)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 11:39:45 +12:00
Michael Bayne cb6e321e5f [maven-release-plugin] prepare for next development iteration 2026-06-03 10:35:38 -07:00
Michael Bayne 34bd05060f [maven-release-plugin] prepare release narya-1.19 2026-06-03 10:35:34 -07:00
Ray J. Greenwell 3733ea02f5 Allow the default "warning size" for DSets to be set with a property. 2026-05-14 12:33:18 -07:00
Ray J. Greenwell 201e6bf766 Better documentation. 2026-05-13 14:53:19 -07:00
Ray J. Greenwell c781b86449 Allow the constraint for unstreaming size to be configured at startup...
int property com.threerings.io.maxContainerSize
2026-05-13 14:10:34 -07:00
Michael Bayne f1c1b730a1 [maven-release-plugin] prepare for next development iteration 2026-04-30 13:40:23 -07:00
Michael Bayne 9f4c3dbb54 [maven-release-plugin] prepare release narya-1.18 2026-04-30 13:40:19 -07:00
Ray J. Greenwell cc7193a4f4 Fix tests: add hamcrest jar, make them run headless/no dock icon. 2026-04-27 20:42:39 -07:00
Ray J. Greenwell 5e9f4d5a15 Stop using the old JSR250 annotation.
This will likely break a bunch of things because things further down the
line were depending on narya bringing in this jar.
2026-04-27 15:04:35 -07:00
Ray J. Greenwell 32809d2d79 Fix implicit cast warnings seen. 2026-04-27 15:04:21 -07:00
Ray J. Greenwell 71b30898c4 Show all the warnings! 2026-03-21 16:09:04 -07:00
Ray J. Greenwell d8c22a00f9 Fix more easy deprecation warnings: String constructors of boxed types. 2026-03-21 16:09:04 -07:00
Ray J. Greenwell 1fe0dc2f7f Remove some redundant casts. 2026-03-21 16:09:04 -07:00
Ray J. Greenwell 195562435b Fix Class.newInstance() deprecation warnings. 2026-03-21 16:09:04 -07:00
Ray J. Greenwell 4ddc4e2f8a Why does the compiler care about this one JComboBox and not others? 2026-03-21 15:48:40 -07:00
Ray J. Greenwell 2062371558 Specify UTF-8 file encoding to maven. 2026-03-21 15:34:56 -07:00
Ray J. Greenwell 99f797f66a Drive-by: a bit of modernization & warning cleanup, UTF-8 edition. 2026-03-21 15:27:14 -07:00
Ray J. Greenwell d7b4e10430 Only check for the "L" and ";" if we're in an array.
I can't help but over-optimize. We're parsing the result of class.getName(),
it will be a bare class name if not in the array.

Also: Stop going out of our way to not throw an exception if the input
is malformed, as that's the desired result for bad input.
2026-03-21 15:19:13 -07:00
Ray J. Greenwell 5e17d3ba67 Reformat: whitespace and comments, I'm not used to narya's 4-space indent. 2026-03-20 16:27:38 -07:00
Ray J. Greenwell c874221e62 Combine next char checks; class names may not have L! validate prims.
I think something else in narya must be stripping off the "L;" ..?
2026-03-20 16:20:10 -07:00
Ray Greenwell 6180dc265c Merge pull request #9 from fourbites/config-tooltip-support
Config tooltip support. Now as an annotation.
2026-03-20 14:35:49 -07:00
Ray J. Greenwell 93b9cd72c1 Inline the method so I don't have to correct the comment.
It's so small now anyway.
2026-03-20 14:34:14 -07:00
Ray J. Greenwell 4abbdc4c0a Use an annotation for tooltips rather than a separate static field. 2026-03-20 14:28:59 -07:00
Ray J. Greenwell 7e08d9fd48 All we're ever doing with the prefixes is iterating them. List. 2026-03-20 13:39:51 -07:00
Ray J. Greenwell d823feb674 Rayified: Delay chopping out a substring, check primitives?
I guess I could validate that the primitive code is the final character
in the string. start == end - 1...
2026-03-20 13:28:10 -07:00
Ray Greenwell 0e9b81404a Merge pull request #10 from fourbites/deserialization-fixes
Deserialization fixes
2026-03-20 13:16:06 -07:00
fourbites 84bed9e479 Class check cleanup 2026-03-20 20:53:26 +01:00
fourbites 1fd6240d09 Another class filtering fix 2026-03-20 15:41:04 +01:00
fourbites 35b8acb52a Allow L (array) types 2026-03-20 15:18:36 +01:00
fourbites c4ab0d13de Harden deserialization against malicious client input
Add three defenses to the Streamable deserialization system to prevent
exploitation by hacked clients:

- Class whitelist: ObjectInputStream.setAllowedClassPrefixes() validates
  class names before Class.forName(), blocking arbitrary class loading
  from crafted wire data. Callers configure at startup; unconfigured
  streams retain existing behavior for backward compatibility.

- Container size caps: BasicStreamers.validateSize() rejects arrays,
  collections, and maps with negative or >65536 element counts. Prevents
  OOM from a small frame declaring a massive allocation. Applied to all
  12 array/collection read paths and Streamer.ArrayStreamer.

- Recursion depth limit: ObjectInputStream.readObject() tracks nesting
  depth and throws at 32 levels, preventing stack overflow from
  maliciously nested structures (e.g., list-of-list-of-list).
2026-03-20 14:42:10 +01:00
fourbites 2a8db32013 Use keepalive and reduce ping interval
Some networks will kill connections sooner than 60s, especially if they are not using keepalive. This fix should reduce the random disconnects some players experience
2026-03-16 14:16:21 +01:00
Michael Bayne 91f1292ba4 Support Depot ByteEnum in Narya.
I don't think anything is directly streaming these over the wire, but it would
have worked before, so we'll try to keep it working now to avoid unpleasant
surprises.
2026-03-11 12:50:58 -07:00
Michael Bayne 283984464b [maven-release-plugin] prepare for next development iteration 2026-03-09 14:17:16 -07:00
Michael Bayne d930aacc8c [maven-release-plugin] prepare release narya-1.17.4 2026-03-09 14:17:13 -07:00
Ray J. Greenwell 3b0af94757 Drive-by: remove redundant null check. 2026-03-03 14:10:55 -08:00
Ray J. Greenwell fbf3238f80 Have FieldEditor update on ElementUpdatedEvents; Require match NamedEvent!
- It would update if an AttributeChangedEvent was received, but not an
  ElementUpdatedEvent!

- If you have 50 fields and 50 editors, then every one was updating
  whenever an event arrived? Filter by the field that actually changed?
  Does this break something?
2026-03-03 14:10:55 -08:00