Decisions
0003. Pin Kyo 1.0.0-RC7 and JDK 25
Kyo and kyo-ui stay at 1.0.0-RC7 for the first release, on JDK 25 and Scala 3.9.0, and a tasty-query surface guard pins the kyo-ui members that the runner reads.
Status
Accepted
Date
2026-09-30 (the toolchain, second round); 2026-10-11 (the pin, D-19, gate 0).
Context
- Kyo 1.0.0-RC7 needs JDK 25 to compile and to run: its macros load Kyo classes (class file version 69). An sbt on JDK 21 fails with
UnsupportedClassVersionError. - Scala 3.9.0 is the LTS line, and Kyo RC7 is built with it.
- The runner copies rules that kyo-ui keeps private: the key dispatch and the region walk (ADR 0004). A change of these rules in a new kyo-ui version changes the behaviour without a compile error.
- Spike S3 (W0, 2026-10-09) compared RC5, RC6 and RC7. RC5 to RC6 changed a dispatch rule (
stopPropagation,keepBubbling; opt-in). RC6 to RC7 changed a region rule (walkStatic: a bound element at the root of aReactiveorForeachbecomes its own region; a new default). 11 and 16 names changed on the guard surface; all were additions. - By the gate words this was NO-GO for "bump freely": rules change between release candidates.
- The guard of S3 (a shape hash of the TASTy, not a raw hash: the raw hash gave 8 false alarms) found both rule changes, 27 of 27 names and 14 of 14 mutants, with 0 false alarms.
Decision
- Kyo, kyo-ui and the Kyo modules stay at 1.0.0-RC7 for the first release (
project/Versions.scala). D-19 (b). - JDK 25, Scala 3.9.0 and sbt 1.13.0 are the toolchain. The change of one of them happens in all modules at once.
- A tasty-query surface guard (
KyoUiSurfaceTest,kyo-ui-surface.txt) pins each kyo-ui member and rule that the runner reads. A Kyo bump is its own change, with the guard diff andCompatibility.None. - The JMH jars that kyo-kernel RC7 lists in compile scope are excluded from every module (3.0 MB that no run loads).
Alternatives considered
- Bump Kyo freely, with the guard as the only check (D-19 a). It was the recommendation if G3 was GO or SOFT. It lost because G3 was NO-GO: a release candidate can change a default rule.
- Wait for Kyo 1.0 final. Not recorded as an option. The release of tui4s is an RC while Kyo is an RC (ADR 0014).
- JDK 21. Not possible: Kyo RC7 does not run on it.
- Keep the JMH dependency. It lost: no class of the seven jars loads in a class-load log of two apps. An upstream draft asks Kyo to fix the POM (ADR 0019).
Consequences
- Good: the copied rules match one known kyo-ui. The guard fails when a pinned name or rule changes, so a bump is a visible, reviewed step.
- Good: kyo-ui adds 7 jars and 15.0 MB, and the first frame stays under 1 s (S4: 866 to 919 ms median).
- Bad: every user of tui4s needs JDK 25. The README and the start scripts say so.
- Bad: tui4s inherits the RC7 bugs: the
Signal.observeleak and the lost wakeup (ADR 0005), and the web bugs of ADR 0019. - Bad: a Kyo bump changes the binary API of all modules (
project/marks all modules unreleased).
References
- Decision log: second round; eighth round (D-19 yes).
- Plan: D-18, D-19; gates.md G3 (S3), G4 (S4).
- Upstream draft: kyo-kernel JMH in compile scope.
- CONTRIBUTING.md: "Toolchain", "Dependencies and versions"; the rule on
private[kyo](RR N9).
0002. jatatui renders the cells
jatatui 0.31.0 (a Java port of ratatui) with its crossterm JNI library is the terminal backend; tui-scala never goes on the classpath.
0004. Public Kyo APIs only
The runner calls no private[kyo] member and uses no reflection; where kyo-ui keeps a rule private, the runner copies its semantics and the surface guard pins what it reads.