Decisions
0007. Compiler flags from sbt-tpolecat
sbt-tpolecat sets the scalac options; warnings stay warnings on a developer machine, and CI (SBT_TPOLECAT_CI) turns them into errors.
Status
Accepted
Date
2026-10-11 (gate 0: D-8 changed by the user). The CI mode was ASSUMED on 2026-10-12 (the user did not answer) and is in ci.yml since.
Context
- The first build had hand-written flags:
-Yexplicit-nulls,-Wunused:all,-Wvalue-discard,-Wnonunit-statement, but no fatal-warning flag. A greensbt checkdid not prove that the code had no warnings (D-8 facts). - The plan recommended
-Werrorin every build (D-8 a). Its cost: an unused import in work-in-progress code stops the compile. - The user changed it: "warnings of unused and stuff are warnings, use sbt-tpolecat".
- Spike S6 found gaps of the strict flags at the Java boundary:
-Wnonunit-statementdoes not see a Java call in statement position, and-Yexplicit-nullsgives flexible types to Java results. -Ycheck-all-patmatreports a match on Kyo's opaqueMaybeas not exhaustive. That is a false alarm.
Decision
- sbt-tpolecat 0.5.7 sets the scalac options (
build.sbt, "Compiler options"). - The default mode is
DevMode: on a developer machine the warnings stay warnings. - GitHub Actions sets
SBT_TPOLECAT_CI=1, which adds-Werror. A localtpolecatCiModegives the CI behaviour. - The build adds
-Yexplicit-nullsand one-Wconfrule for the noise of inlined Kyo@nowarn, and excludes-Ycheck-all-patmat. - One exception stays fatal in every mode: a non-exhaustive match in
EventMapping.scalais an error, so a new crossterm event case stops the build on a developer machine too. - The code stays free of warnings. A null check is written by hand where a Java source or JNI contract allows null.
Alternatives considered
- Hand-written flags with
-Werroreverywhere (D-8 a, the plan's recommendation). The user rejected it: unused-code warnings must not stop local work. - Fatal only when the
CIvariable is set, with the hand-written flags (D-8 b). Close to the decision. The user named sbt-tpolecat instead of a hand-kept flag list; the notes give no other reason. - No fatal mode, a warning count in each PR body (D-8 c). Warnings can pile up while CI is green.
- Warnings everywhere, also in CI. The mode was ASSUMED (dev locally, fatal in CI) when the user did not answer; one build line flips it.
Consequences
- Good: CI holds the line at 0 warnings, and local work is not blocked by an unused import.
- Good: the flag set follows sbt-tpolecat upgrades, not a hand-kept list.
- Bad: a local
sbt checkis weaker than CI unless the developer runstpolecatCiMode. A warning can reach CI and fail there. - Bad: the flags do not see some Java-boundary mistakes (spike S6). Reviews must check for null at those calls.
References
- Decision log: eighth round (D-8 changed); handoff "Open items for the user" (the mode, assumed).
- Plan: D-8, D-26; gates.md G6 (S6).
- CONTRIBUTING.md: "Toolchain" (sbt-tpolecat), "Rules for code" (the Java boundary).
0006. Purity: edge files, lint and a pure painter
The functional rewrite (L0, phases P1 to P6) keeps impure code in nine edge files and a few marked KEEP sites, checked by scalafix DisableSyntax, with a pure painter, a synchronous release stack and one fiber gauge.
0008. The artifact split: runner, app, testkit and core
tui4s-core becomes a composite of three artifacts in this repository: tui4s-runner, tui4s-app and tui4s-testkit, each with its own version and tag, in the same packages, with tui4s.internal sealed.