Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .agents/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,15 @@ and GitHub Packages.
- `codegen/plugins/`: **separate Gradle project** with ProtoData plugins that
generate Kotlin extensions for Protobuf messages. Requires JDK 17,
Gradle 9.4.x, and Kotlin 2.3.20, unlike the root project (JDK 11,
Gradle 6.9.4, Kotlin 1.8.20). Applied to consuming projects through the
Gradle 6.9.4, Kotlin Gradle plugin 1.8.22). It is applied to consuming
projects through the
[Chords Gradle plugin](https://github.com/SpineEventEngine/Chords-Gradle-plugin).
- `pom.xml`, `dependencies.md`: generated dependency/license reports; must be
regenerated (not hand-edited) when the version or dependencies change.
- `.github/workflows/`: CI for Ubuntu/Windows builds, license-report and
version-increment guards, Gradle wrapper validation, and publishing.
- `.agents/workflows/`: local agent workflow drivers and their regression
suites.

Gradle group: `io.spine.chords`. Artifact prefix: `spine-chords-`. Preserve
package roots such as `io.spine.chords` and `io.spine.money` where already
Expand Down Expand Up @@ -106,6 +109,8 @@ or Spine versions; such upgrades are dedicated tasks with wide impact.
- `AGENTS.md`: repository operating policy for agents.
- `.agents/project.md`: project map, architecture notes, documentation
ownership, and CI notes.
- `PAIR_AGENTS_RUN_GUIDE.md`: operator guide for the paired-agent issue
workflow.
- `core/README.md`: application shell, component model, and core components.
- `proto/README.md`: Protobuf-aware components and message forms.
- `proto-values/README.md`: supplementary Protobuf messages and extensions.
Expand Down
7 changes: 4 additions & 3 deletions .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ routing source of truth.

- `engineer`: routing skill for mixed or unclear implementation work, and
the home of the shared design-restraint policy.
- `kotlin-engineer`: the Kotlin language itself — the 1.8.20 ceiling,
null-safety, `lateinit`, coroutine scoping, and public-type rules. Pairs
with whichever area skill owns the code being changed.
- `kotlin-engineer`: the Kotlin language itself — the root/compiler/library
version split, the separate codegen-plugin toolchain, null-safety,
`lateinit`, coroutine scoping, and public-type rules. Pairs with whichever
area skill owns the code being changed.
- `component-engineer`: class-based Compose UI components across `core`,
`proto`, and `client` — the component model, input components, message
forms, and server-connected components.
Expand Down
18 changes: 10 additions & 8 deletions .agents/skills/build-engineer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ For workflow YAML under `.github/workflows`, use

## Policy

- Two toolchains coexist: the root project uses JDK 11 / Gradle 6.9.4 /
Kotlin 1.8.20; `codegen/plugins` uses JDK 17 / Gradle 9.4.x / Kotlin 2.3.20.
Keep build logic compatible with the owning toolchain.
- Two toolchains coexist: the root project uses JDK 11 / Gradle 6.9.4 and the
compiler/library version split documented in `kotlin-engineer`;
`codegen/plugins` uses JDK 17 / Gradle 9.4.x / Kotlin 2.3.20. Keep build
logic compatible with the owning toolchain.
- Dependency coordinates belong in
`buildSrc/src/main/kotlin/io/spine/internal/dependency/`, one object per
library, following the existing pattern. Do not inline version strings into
Expand All @@ -41,8 +42,9 @@ For workflow YAML under `.github/workflows`, use
- Every PR increments `chordsVersion` in `version.gradle.kts`
(`2.0.0-SNAPSHOT.<N>`); CI enforces this with `checkVersionIncrement`.
- `pom.xml` and `dependencies.md` are generated by the build (PomGenerator and
LicenseReporter); regenerate them via `./gradlew build` rather than editing,
and include the regenerated files in version-bump changesets.
LicenseReporter); regenerate them with the focused command in `AGENTS.md`,
"Versioning and Reports", rather than editing, and include the regenerated
files in version-bump changesets.
- The `config/` submodule is owned by `SpineEventEngine/config`; do not edit
its contents here. If shared build logic must change, describe the upstream
change instead.
Expand All @@ -60,9 +62,9 @@ For workflow YAML under `.github/workflows`, use
Root build (repository root, JDK 11):

```bash
./gradlew clean build
./gradlew publishToMavenLocal
./gradlew checkVersionIncrement
.agents/workflows/gradle-root.sh clean build
.agents/workflows/gradle-root.sh publishToMavenLocal
.agents/workflows/gradle-root.sh checkVersionIncrement
```

Codegen plugins build (from `codegen/plugins/`, JDK 17):
Expand Down
6 changes: 5 additions & 1 deletion .agents/skills/code-reviewer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ duplicate its steps.
get wrong, including which toolchain ceiling governs the file and the
sanctioned exceptions to otherwise-standard bans.
- Missing or weak tests for changed logic, extensions, or codegen behavior.
For whether an added suite follows local conventions, apply
`.agents/skills/kotlin-jvm-tester/SKILL.md`.
- Version-policy misses: `chordsVersion` not incremented, or `pom.xml` /
`dependencies.md` not regenerated when required.
- Module-ownership violations, leaked state, unjustified reflection, and
Expand All @@ -110,7 +112,9 @@ duplicate its steps.
security-specific analysis.
- Documentation and comment findings go to
`.agents/skills/docs-reviewer/SKILL.md`.
- Test design or coverage authoring goes to `.agents/skills/tester/SKILL.md`.
- Test design or coverage authoring goes to `.agents/skills/tester/SKILL.md`;
test-suite conventions go to
`.agents/skills/kotlin-jvm-tester/SKILL.md`.

## Skip

Expand Down
16 changes: 8 additions & 8 deletions .agents/skills/codegen-engineer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ For components that merely consume generated metadata, prefer

## Policy

- `codegen/plugins` targets JDK 17, Gradle 9.4.x, and Kotlin 2.3.20; the rest
of the repository targets JDK 11, Gradle 6.9.4, and Kotlin 1.8.20. Never mix
the two toolchains in one command or assume APIs from one are available in
the other.
- `codegen/plugins` targets JDK 17, Gradle 9.4.x, and Kotlin 2.3.20; the root
build targets JDK 11 and Gradle 6.9.4, with the Kotlin version split described
in `.agents/skills/kotlin-engineer/SKILL.md`. Never mix the two toolchains in
one command or assume APIs from one are available in the other.
- The generated-code contract is consumed by `proto` and `client` and by
external projects: changes to `MessageField`/`MessageOneof`/`MessageDef`
shapes are public API changes on both the generator and runtime sides and
Expand Down Expand Up @@ -62,10 +62,10 @@ Codegen plugin changes (from `codegen/plugins/`, JDK 17):
Runtime and end-to-end verification (from the repository root, JDK 11):

```bash
./gradlew :runtime:test
./gradlew :codegen-tests:test
./gradlew :proto-values:test
./gradlew clean build
.agents/workflows/gradle-root.sh :runtime:test
.agents/workflows/gradle-root.sh :codegen-tests:test
.agents/workflows/gradle-root.sh :proto-values:test
.agents/workflows/gradle-root.sh clean build
```

The root build republishes codegen plugins to Maven local automatically before
Expand Down
10 changes: 5 additions & 5 deletions .agents/skills/component-engineer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ build logic, use `.agents/skills/build-engineer/SKILL.md`.
Compose APIs in use are experimental
(`@OptIn(ExperimentalComposeUiApi::class)`); keep such opt-ins localized
and documented.
- For the Kotlin language itself — the 1.8.20 ceiling, explicit API mode,
null-safety, `lateinit` in `Props`, and coroutine scoping — follow
- For the Kotlin language itself — the root compiler/library split, explicit
API mode, null-safety, `lateinit` in `Props`, and coroutine scoping — follow
`.agents/skills/kotlin-engineer/SKILL.md`.
- Match existing KDoc style: `@param` tags for type parameters and
constructor-like parameters, backticked identifiers, and wrapped lines
Expand All @@ -74,9 +74,9 @@ build logic, use `.agents/skills/build-engineer/SKILL.md`.
Run the narrowest relevant command first (repository root, JDK 11):

```bash
./gradlew :<module>:test
./gradlew :<module>:check
./gradlew clean build
.agents/workflows/gradle-root.sh :<module>:test
.agents/workflows/gradle-root.sh :<module>:check
.agents/workflows/gradle-root.sh clean build
```

UI rendering and interaction cannot be covered by automated tests here. For
Expand Down
7 changes: 4 additions & 3 deletions .agents/skills/engineer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ description: >
# Engineering Router

`.agents/skills/kotlin-engineer/SKILL.md` applies to *all* of the areas
below — it owns the Kotlin language baseline (the pinned 1.8.20 ceiling,
null-safety, coroutine scoping, public types under explicit API mode). Pair
it with the area skill that owns the code being changed:
below — it owns the Kotlin language baseline (the root compiler/library split,
the separate codegen-plugin toolchain, null-safety, coroutine scoping, and
public types under explicit API mode). Pair it with the area skill that owns
the code being changed:

- `.agents/skills/component-engineer/SKILL.md` for class-based Compose UI
components in `core`, `proto`, and `client`: the component model,
Expand Down
59 changes: 38 additions & 21 deletions .agents/skills/kotlin-engineer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
name: kotlin-engineer
description: >
Chords Kotlin implementation policy and the pitfalls that recur in review:
the pinned 1.8.20 language ceiling, null-safety and `!!`, `lateinit` in
`Props`, coroutine scoping and cancellation in `client`, and read-only
public types under explicit API mode. Use whenever writing, changing,
the root compiler/library version split and separate codegen-plugin
toolchain, null-safety and `!!`, `lateinit` in `Props`, coroutine scoping
and cancellation in `client`, and read-only public types under explicit API
mode. Use whenever writing, changing,
refactoring, or reviewing Kotlin in any module: `.kt`/`.kts` edits,
turning Java-style Kotlin idiomatic, anything touching coroutines,
cancellation, or `Flow` (concentrated in `client`), and designing a public
Expand Down Expand Up @@ -42,39 +43,52 @@ Each of these owns its area; this skill stays out of them:
## Toolchain Ceiling

**Two ceilings, and which one applies depends on the file you are editing.**
The root build compiles with **Kotlin 1.8.20** — the version of the
`kotlin("jvm")` plugin declared in `buildSrc/build.gradle.kts` — on JVM
target 11. It covers every module in
The root build compiles with the Kotlin Gradle plugin dependency declared as
`kotlinVersion` in `buildSrc/build.gradle.kts` — currently **1.8.22** — on JVM
target 11. The `kotlin("jvm")` declaration earlier in that file is the plugin
used to compile `buildSrc` itself, not the version applied to root modules. The
root toolchain covers every module in
`settings.gradle.kts`: `core`, `proto`, `proto-values`, `client`, `runtime`
(at `codegen/runtime`), and `codegen-tests` (at `codegen/tests`) — note that
both `codegen/` subprojects belong to the *root* build. Only
`codegen/plugins` is separate, using **Kotlin 2.3.20** on JDK 17 (its own
`kotlinVersion` in `codegen/plugins/buildSrc/build.gradle.kts`).

Everything below about the 1.8.20 ceiling applies to the root build; in
`codegen/plugins` the 2.x language is available. Never carry a construct
from one across to the other because it compiled where you first wrote it.
Both builds enable explicit API mode.
Everything below about the Kotlin 1.8 language ceiling applies to the root
build; in `codegen/plugins` the 2.x language is available. Never carry a
construct from one across to the other because it compiled where you first
wrote it. Both builds enable explicit API mode.

Within the root modules:

- **The stdlib on the classpath is newer than the compiler.**
`forceProductionDependencies()` in
`buildSrc/src/main/kotlin/DependencyResolution.kt` pins `kotlin-stdlib` to
the `Kotlin.version` coordinate — currently 1.9.23 — while the compiler
stays at 1.8.20. A 1.9 stdlib *function* can therefore resolve and compile,
stays at 1.8.22. A 1.9 stdlib *function* can therefore resolve and compile,
even though a 1.9 *language feature* cannot. **"It compiles" is not
evidence that a construct is within the baseline** — check when the API
was introduced, and prefer one that predates 1.8.20.
- Not available at 1.8.20: `data object`, `enumEntries`, the stable `..<`
was introduced, and prefer one that predates Kotlin 1.8.20.
- Not available under the root's 1.8 language ceiling: `data object`,
`enumEntries`, the stable `..<`
operator (use `until`), and stable context receivers.
- Available and preferred where they fit: sealed interfaces, `@JvmInline
value class`, `buildList` / `buildMap`, and `kotlin.time.Duration`.
- **Context receivers, not context parameters.** The root build passes
`-Xcontext-receivers` from `KotlinConfig.setFreeCompilerArgs()`. That enables
the experimental context-receiver syntax under Kotlin 1.8; it does not
enable the later context-parameter syntax. `codegen/plugins` enables
neither feature.
- Coroutines are **1.7.3** (`KotlinX.Coroutines.version`), forced across
every configuration by the `resolutionStrategy` block in the root
`build.gradle.kts`. 1.7 APIs are available. Ignore the unused
`Coroutines` object in the same dependency package — nothing imports it,
and its version is not what resolves.
- **`failOnVersionConflict()` is enabled.** Adding a dependency that brings a
different version of an already-forced library fails resolution rather than
silently choosing one. Adjust the coordinate in
`buildSrc/src/main/kotlin/io/spine/internal/dependency/` and the force list
when the conflict is real; do not work around it in a module build file.
- **Explicit API mode is on in both builds** — each calls `explicitApi()`
in its Kotlin block. The compiler enforces exactly two
things: an explicit visibility modifier and an explicit return type on
Expand Down Expand Up @@ -124,9 +138,9 @@ Within the root modules:
- **Confine `runBlocking` to a bridge** from a non-suspend API into suspend
code. Inside a `suspend` function it is always a bug.
- **Expose read-only types from public API** — `List` over `MutableList`,
`StateFlow` over `MutableStateFlow`, and never the mutable backing
property itself. Explicit API mode makes each of these a published
contract.
`StateFlow` over `MutableStateFlow`, `State` over `MutableState`, and never
the mutable backing property itself. Explicit API mode makes each of these a
published contract.
- **Immutability first**: `val` over `var`, and `copy()` on a data class
rather than mutation.
- **Named arguments once a Kotlin call takes three or more parameters**,
Expand Down Expand Up @@ -164,20 +178,23 @@ Within the root modules:
- **No platform-type leak in public API.** A value crossing from Java
arrives as `String!`; give the public declaration an explicit nullable or
non-null type rather than letting the platform type propagate.
- **No language feature newer than 1.8.20**, and no stdlib API added after
it without a deliberate decision — see "Toolchain Ceiling".
- **No language feature newer than Kotlin 1.8**, and no stdlib API added after
1.8.20 without a deliberate decision — see "Toolchain Ceiling".
- **No new deprecated-API call** without that explicit instruction; use the
replacement named in the `@Deprecated` or `ReplaceWith` message.
- **No blanket Detekt suppression.** Suppress the narrowest rule at the
narrowest declaration, matching existing style, and only when that rule is
genuinely wrong about the site.

## Verification

Compile the narrowest module first; the full command set and the JDK
constraints live in `AGENTS.md`, "Verification and Quality".

```bash
./gradlew :<module>:compileKotlin
./gradlew :<module>:test
./gradlew detekt
.agents/workflows/gradle-root.sh :<module>:compileKotlin
.agents/workflows/gradle-root.sh :<module>:test
.agents/workflows/gradle-root.sh detekt
```

Detekt runs over these modules — do not introduce new violations, and keep
Expand Down
Loading
Loading