|
| 1 | +# Tao backend refactor — verification procedure |
| 2 | + |
| 3 | +Safety harness for the JetBrains-like reorganization of `decorated-window-tao` |
| 4 | +(FFI quarantine → subsystem packages → `explicitApi()`). The contract: **a |
| 5 | +framework user must observe zero change** — same Maven coordinates, same public |
| 6 | +FQNs, same binary API, same runtime behavior. |
| 7 | + |
| 8 | +Inspired by JetBrains practice: |
| 9 | +- **kotlinx binary-compatibility-validator** (`apiDump`/`apiCheck`) — same tool |
| 10 | + kotlinx / Compose use to freeze the public ABI. |
| 11 | +- **kotlin-desktop-toolkit**: generated/native bindings quarantined and never |
| 12 | + public; per-platform test harnesses; strict `explicitApi()`. |
| 13 | +- **compose-multiplatform** `tutorials/checker`: real consumer projects compiled |
| 14 | + as a regression gate — here the role is played by `nucleus-application`, |
| 15 | + `taskbar-progress-tao` and the example apps. |
| 16 | + |
| 17 | +## Invariants |
| 18 | + |
| 19 | +| # | Invariant | Verified by | |
| 20 | +|---|-----------|-------------| |
| 21 | +| I1 | Public ABI frozen: every public FQN, member and signature identical to the baseline | BCV `apiCheck` against `api/decorated-window-tao.api` (zero diff in phases 1–2; additive-only never allowed either) | |
| 22 | +| I2 | JNI linkage consistent: every `Java_*` symbol defined in native sources (`.rs`/`.c`/`.m`, vendor excluded) maps to a compiled Kotlin `external fun`, and every Kotlin `external fun` has a native definition; macOS dylibs in `src/main/resources` export no stale symbols | `scripts/check-tao-refactor-invariants.sh` (sections 1–2) | |
| 23 | +| I3 | Reflective FQNs resolve: `FindClass`/method-signature literals in native sources, `Class.forName` literals in Kotlin, `META-INF/services/*`, ProGuard `-keep` rules, GraalVM `reachability-metadata.json` (module **and** plugin `platform-metadata/*.json`) all point at classes that exist in the compiled output | `scripts/check-tao-refactor-invariants.sh` (sections 3–6) | |
| 24 | +| I4 | Consumers compile **without any source change**: `nucleus-application`, `taskbar-progress-tao`, `examples/tao-demo`, `examples/swing-tao-demo` | Gradle compile of the four modules; `git diff --stat` on them must be empty (exceptions must be listed in the phase commit message — e.g. a test doing reflection on an `internal` bridge) | |
| 25 | +| I5 | Runtime intact on the host OS: unit tests, dispatcher handoff tests, real-window smoke test, and a manual/scripted launch of `tao-demo` (window opens, first frame renders, popups & titlebar OK) | `:decorated-window-tao:test` + `:examples:tao-demo:run` | |
| 26 | +| I6 | Other OSes: natives rebuild from the renamed sources and the full matrix passes | CI on the PR branch: `build-natives.yaml` + `pre-merge.yaml` (Windows/Linux/macOS, x64+aarch64 verify arrays) | |
| 27 | + |
| 28 | +## One-time setup (baseline) |
| 29 | + |
| 30 | +```bash |
| 31 | +export JAVA_HOME=/Users/eliegambache/Library/Java/JavaVirtualMachines/jbr-21.0.10/Contents/Home |
| 32 | + |
| 33 | +# 1. Dump the public ABI baseline (BEFORE any refactor commit) |
| 34 | +./gradlew :decorated-window-tao:apiDump # writes decorated-window-tao/api/decorated-window-tao.api |
| 35 | +git add decorated-window-tao/api && git commit # baseline is part of the harness commit |
| 36 | + |
| 37 | +# 2. Sanity: harness must be green on the unmodified tree |
| 38 | +./scripts/check-tao-refactor-invariants.sh |
| 39 | +./gradlew :decorated-window-tao:test |
| 40 | +``` |
| 41 | + |
| 42 | +## Per-phase procedure |
| 43 | + |
| 44 | +Run **after every phase**, in this order (fail fast, cheapest first): |
| 45 | + |
| 46 | +```bash |
| 47 | +export JAVA_HOME=/Users/eliegambache/Library/Java/JavaVirtualMachines/jbr-21.0.10/Contents/Home |
| 48 | + |
| 49 | +# 0. If native sources changed (phase 1): rebuild macOS dylibs + clear loader cache |
| 50 | +(cd decorated-window-tao/src/main/native && ./build.sh) # or the module's native build task |
| 51 | +rm -rf ~/.cache/nucleus/native |
| 52 | + |
| 53 | +# 1. ABI freeze |
| 54 | +./gradlew :decorated-window-tao:apiCheck |
| 55 | + |
| 56 | +# 2. FQN / JNI / metadata consistency (compiles the module first) |
| 57 | +./scripts/check-tao-refactor-invariants.sh |
| 58 | + |
| 59 | +# 3. Unit + smoke tests |
| 60 | +./gradlew :decorated-window-tao:test |
| 61 | + |
| 62 | +# 4. Consumers compile, sources untouched |
| 63 | +./gradlew :nucleus-application:compileKotlin :taskbar-progress-tao:compileKotlin \ |
| 64 | + :examples:tao-demo:compileKotlin :examples:swing-tao-demo:compileKotlin |
| 65 | +git diff --stat nucleus-application taskbar-progress-tao examples # expected: empty |
| 66 | + |
| 67 | +# 5. Live run (host OS) — window must open, render, close cleanly |
| 68 | +./gradlew :examples:tao-demo:run --no-configuration-cache # inspect, then quit |
| 69 | + |
| 70 | +# 6. Commit the phase, push, let CI run the 3-OS matrix before the next phase |
| 71 | +``` |
| 72 | + |
| 73 | +### Phase-specific gates |
| 74 | + |
| 75 | +- **Phase 1 (FFI quarantine, `window.tao.ffi`)** — the only phase touching native |
| 76 | + sources. Extra gates: `nm -gU` on the freshly built `darwin-*` dylibs shows only |
| 77 | + `Java_dev_nucleusframework_window_tao_ffi_*` symbols (script section 2 enforces |
| 78 | + this); `tao-demo` must be exercised beyond startup: resize, fullscreen, popup, |
| 79 | + drag-and-drop, IME. Linux/Windows symbol renames are textual and cannot be |
| 80 | + linked locally — CI is the authority (I6): do not merge before `build-natives` |
| 81 | + + `pre-merge` are green. |
| 82 | +- **Phase 2 (subsystem packages)** — Kotlin-only moves of `internal` declarations. |
| 83 | + Extra gates: `apiCheck` diff must be **exactly zero** (if a move drags a public |
| 84 | + symbol along, the move is wrong — split the file instead); GraalVM/ProGuard/ |
| 85 | + services files updated in the same commit (script sections 3–6 catch misses). |
| 86 | +- **Phase 3 (`explicitApi()`)** — no declaration moves. Extra gates: `apiDump` |
| 87 | + after the change must be byte-identical to the baseline (adding explicit |
| 88 | + `public` modifiers must not alter the dump); Detekt/KtLint (`reformatAll`, |
| 89 | + `preMerge`) still pass. |
| 90 | + |
| 91 | +## Rollback |
| 92 | + |
| 93 | +Each phase is a single commit on `refactor/tao-jetbrains-layout`. Any red gate → |
| 94 | +`git revert` the phase commit; phases are independent enough that reverting one |
| 95 | +does not require reverting the following ones except phase 2 depends on phase 1 |
| 96 | +package names in metadata files. |
0 commit comments