This guide captures the repo-specific rules and conventions for working effectively in the Replicant codebase.
-
When asked to perform a task, ask clarifying questions one at a time until you have enough context to proceed. Make reasonable assumptions when the codebase makes the answer clear, and ask the user to confirm when there are meaningful alternatives.
-
Keep
AGENTS.mdaligned with the codebase.- Update this file in the same change whenever build steps, module structure, generated-code paths, runtime flags, or architectural concepts change.
- Remove stale references to deleted classes, endpoints, workflows, or dependencies instead of preserving compatibility lore.
- Prefer concise, accurate guidance over exhaustive historical notes.
-
Prefer direct API evolution over compatibility shims.
- Treat this repo as greenfield unless the user says otherwise.
- When changing constructors, methods, or internal interfaces, update all production code and tests directly instead of adding overloads, chained constructors, default interface methods, or adapter layers solely to reduce churn.
- Keep multiple constructors or overloads only when they are justified by the final design, not to preserve compatibility inside this repo.
-
When the user reports a bug, start by writing or updating a test that reproduces it. Then fix the bug and prove the fix with a passing test.
- Java modules:
client/contains the GWT-enabled client runtime and JS interop code.server/contains the CDI/WebSocket server transport and replication logic.shared/contains constants and types shared by client and server.
- Build configuration:
buildfiledefines the Buildr build.build.yamldefines artifact coordinates and dependency versions.tasks/*.rakecontains GWT, release, packaging, and diagnostic helper tasks.Gemfileconfigures the Ruby/Buildr toolchain.
- Source layout:
- Production code lives under
*/src/main/java/.... - Tests live under
*/src/test/java/....
- Production code lives under
- Generated sources:
- Annotation processor outputs checked in for GWT compatibility live under
client/generated/processors/main/java/.... - Do not hand-edit generated sources.
- Annotation processor outputs checked in for GWT compatibility live under
- Documentation:
- Keep
README.md,CHANGELOG.md, andAGENTS.mdaligned with user-visible or workflow-relevant changes.
- Keep
shared/- Keep transport path fragments, shared constants, and message keys centralized here.
- Example files:
shared/src/main/java/replicant/shared/SharedConstants.java,shared/src/main/java/replicant/shared/Messages.java.
client/- GWT modules live under
client/src/main/java/replicant/*.gwt.xml. - JVM-only code must use the package-local
replicant.GwtIncompatibleannotation, orreplicant.messages.GwtIncompatibleinside the messages package. - Client and shared code must avoid
var; use explicit local types.
- GWT modules live under
server/- The active transport is CDI + WebSocket + JSON-P (
javax.json). - The WebSocket endpoint lives at
"/api" + SharedConstants.REPLICANT_URL_FRAGMENT. - Session mutation is guarded by
ReplicantSession.getLock(); follow the locking patterns inserver/src/main/java/replicant/server/transport/ReplicantSessionManagerImpl.javaandserver/src/main/java/replicant/server/transport/ReplicantMessageBrokerImpl.java.
- The active transport is CDI + WebSocket + JSON-P (
- Channel descriptor grammar:
channelId[.rootId][#filterInstanceId].#is reserved; the filter instance id is the substring after the first#and may be empty.- No escaping is supported; JSON transport handles encoding.
- Instanced filter types:
DYNAMIC_INSTANCEDrequires#on subscribe, update, and unsubscribe, and allows filter updates.STATIC_INSTANCEDrequires#on subscribe and unsubscribe, and rejects filter updates.
- Bulk subscribe and unsubscribe uses a shared filter for all addresses; the instance id lives on each
ChannelAddress.
Implementation hotspots:
- Channel descriptor parsing and formatting:
client/src/main/java/replicant/ChannelAddress.javaserver/src/main/java/replicant/server/ChannelAddress.java
- Client validation and AOI flow:
client/src/main/java/replicant/Connector.javaclient/src/main/java/replicant/Converger.javaclient/src/main/java/replicant/SubscriptionService.java
- Server validation and routing:
server/src/main/java/replicant/server/ee/ReplicantEndpoint.javaserver/src/main/java/replicant/server/transport/ReplicantSessionManagerImpl.javaserver/src/main/java/replicant/server/transport/ReplicantSession.java
- Change encoding:
server/src/main/java/replicant/server/json/JsonEncoder.javaserver/src/main/java/replicant/server/Change.javaserver/src/main/java/replicant/server/ChangeSet.java
- Write for readability first. Prefer simple, direct code over clever abstractions.
- Keep naming, formatting, and architecture consistent with nearby code.
- Use the narrowest practical visibility. Helpers are typically
finaland package-private unless they are part of the public API. - Use comments sparingly and explain why, not what, when the code is otherwise hard to understand.
- The build targets Java 17 and compiles with
-Xlint:all,-processing,-serialand-Werror. Fix warnings or suppress them narrowly with justification. - Use
@Nonnulland@Nullablefromjavax.annotationfor nullability. - On JAX-RS-style validation boundaries, prefer
@NotNullfromjavax.validationwhen that style is already in use. Do not add new REST-specific guidance to this file unless the codebase adds REST resources again. - Use
finalwhere practical. - Use
final varfor local variables inserver/code and under*/src/test/java/...unless Java requires an explicit type or the explicit type materially improves clarity. - Never use
varinclient/orshared/; use explicit local types there. - Public API changes should include matching Javadoc updates. Keep package documentation in
package-info.javaaligned with the code.
- Do not hand-edit files under
client/generated/processors/main/java/.... - If annotation processor output changes, regenerate or update the generated sources consistently with the source change that required it.
Prerequisites: JDK 17+, Ruby 2.7.x, and Bundler.
- Bootstrap once:
bundle install - Build all modules:
bundle exec buildr clean package - Run all tests:
bundle exec buildr test
Additional build notes:
- The build is managed via Buildr; update
build.yamlwhen adding or upgrading dependencies. - GWT support is wired via
tasks/gwt.rakeandgwt_enhance(project)inbuildfile. - Test JVM properties default to development settings for Braincheck, Arez, and Replicant.
- Test framework: TestNG across modules.
- Place tests under
*/src/test/java/.... - Name tests with the
Testsuffix. - Run
bundle exec buildr testbefore submitting changes unless the user explicitly asks you not to.
Diagnostics fixtures and invariants:
- Client tests validate diagnostic messages via
MessageCollectorand fixtures inclient/src/test/java/replicant/diagnostic_messages.json. - Relevant properties:
replicant.check_diagnostic_messagesverifies emitted diagnostics against the fixture file.replicant.output_fixture_datarewrites fixture data when expected outputs intentionally change.replicant.diagnostic_messages_filepoints at the fixture JSON file.
- In IntelliJ, use the generated TestNG configurations such as
client - update invariant messageswhen fixture updates are intentional.
- Runtime and GWT properties are defined in
client/src/main/java/replicant/ReplicantConfig.javaandclient/src/main/java/replicant/Replicant.gwt.xml. - Key properties include:
replicant.environmentreplicant.check_invariantsreplicant.check_api_invariantsreplicant.enable_namesreplicant.enable_zonesreplicant.enable_spiesreplicant.validateChangeSetOnReadreplicant.validateEntitiesOnLoadreplicant.logger
- Keep transport routes and message formats in sync with shared constants and message keys.
- Prefer JSON-P builders and generators for message encoding rather than ad-hoc string concatenation.
- Follow
CONTRIBUTING.mdandCODE_OF_CONDUCT.md. - Keep commits small, focused, and imperative.
- Update
CHANGELOG.mdfor user-visible changes. - Update
README.mdwhen public APIs, workflows, or integration expectations change. - Release-related environment variables include
PRODUCT_VERSIONandPREVIOUS_PRODUCT_VERSION. - Publishing to Maven Central uses
tasks/package_for_maven_central.rakeand requires.netrccredentials forcentral.sonatype.complus GPG configured via Buildr.