Skip to content

Fix #4850: stop auto-creating ghost l10n bundles in wrong module#4867

Merged
shai-almog merged 1 commit into
masterfrom
fix/4850-l10n-cross-module-lookup
May 5, 2026
Merged

Fix #4850: stop auto-creating ghost l10n bundles in wrong module#4867
shai-almog merged 1 commit into
masterfrom
fix/4850-l10n-cross-module-lookup

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Fixes the respawn loop reported on issue #4850 by ThomasH99 and Ngosti2000 -- the "simulator doesn't crash but the same CSS> ... stack trace keeps spamming the log" state they hit even after applying liannacasper's manual workaround.

Root cause (the part the previous fixes missed)

The CN1CSSCLI subprocess that CSSWatcher forks inherits cwd = javase/ from the simulator. JavaSEPort.findLocalizationDirectory looked only at cwd and -- when nothing was found -- mkdirs()'d a throwaway javase/src/main/l10n/Bundle.properties. Older CN1 versions (< 7.0.237) poisoned that ghost bundle with @im=@im via the AutoLocalizationBundle wormhole.

After users cleaned the real bundle in common/src/main/l10n per liannacasper's instructions, every CN1CSSCLI respawn still loaded the ghost bundle in javase/, crashed inside parseTextFieldInputMode("@im-@im"), and CSSWatcher.start() (Ports/JavaSE/.../CSSWatcher.java:376-379, 415-418) respawned the dead subprocess with no backoff. Hence the looping CSS> stack trace seen in Ngosti2000's video.

Fix

findLocalizationDirectory now:

  1. Checks the current module first (cwd/src/main/{l10n,i18n}).
  2. Walks up to the sibling common/ module (matches the CN1 maven layout and CSSWatcher.addLocalizationCandidates, which already does this).
  3. Never auto-creates the directory. If the developer hasn't set up localization, the auto-bundle is a no-op -- project-level opt-in, addressing ThomasH99's "maybe it should be an opt-in thing?" feedback.

findDefaultLocalizationBundleFile no longer returns a non-existent Bundle.properties path as a fallback. Combined with rule 3, no l10n files on disk = enableAutoLocalizationBundle returns early at bundleFile == null and there's no surprise bundle materialising.

Both methods get static overloads taking an explicit projectDir so the regression tests can drive them without mutating user.dir. The instance methods become thin wrappers.

Test plan

  • AutoLocalizationBundleTest gains three regression tests:
    • verifyFindLocalizationDirectoryDoesNotAutoCreate -- no l10n dir => returns null AND src/main/l10n is not created on disk.
    • verifyFindLocalizationDirectoryWalksToCommonSibling -- cwd=javase with sibling common/src/main/l10n => returns common's dir; once javase/src/main/l10n exists, local wins.
    • verifyFindDefaultBundleReturnsNullWhenNoBundleFile -- l10n dir present but empty => returns null and Bundle.properties is not created.
  • Manual end-to-end verification with a standalone driver against the rebuilt 8.0-SNAPSHOT JavaSE jar -- all five behavioural cases pass (no auto-create, walks to common, local wins, empty dir => null, real bundle => returned).
  • mvn -pl javase install -Plocal-dev-javase builds clean.
  • CI: existing archetype-smoke.yml job already exercises the auto-bundle code path with the pref forced on -- this PR doesn't change that surface.

Migration note for affected users

After upgrading, javase/src/main/l10n (and the poisoned Bundle.properties inside) is no longer touched, but the directory created by previous versions still exists. Users can rm -rf <module>/javase/src/main/l10n to clean up the ghost bundle. The 5de1898d1 self-heal already handles legacy poisoned files in real l10n dirs going forward.

🤖 Generated with Claude Code

The CSS subprocess (CN1CSSCLI forked by CSSWatcher) inherits cwd =
`javase/` from the simulator. JavaSEPort.findLocalizationDirectory was
looking only at cwd and -- when nothing was found -- mkdirs()'d a
throwaway `javase/src/main/l10n/Bundle.properties`. Older CN1 versions
poisoned that ghost bundle with `@im=@im` via the AutoLocalizationBundle
wormhole. After users cleaned the *real* bundle in `common/src/main/l10n`
per liannacasper's workaround, every CN1CSSCLI respawn still loaded the
ghost bundle from `javase/`, crashed inside parseTextFieldInputMode, and
CSSWatcher.start() respawned the dead subprocess in an infinite loop --
hence "fix worked, simulator doesn't crash, but `CSS> ...` stack trace
keeps spamming the log" (Ngosti2000 + ThomasH99).

New rules for findLocalizationDirectory:
1. Check the current module first (cwd/src/main/{l10n,i18n}).
2. Walk up to the sibling `common/` module (matches CN1 maven layout
   and CSSWatcher.addLocalizationCandidates which already does this).
3. Never auto-create the directory. If the developer hasn't set up
   localization, the auto-bundle is a no-op -- project-level opt-in.

findDefaultLocalizationBundleFile no longer falls back to a non-existent
`Bundle.properties` path either. Combined with rule 3 above, no l10n
files on disk = enableAutoLocalizationBundle returns early at
`bundleFile == null`, and ThomasH99's "the auto-bundle fills up by
itself" complaint goes away for projects that didn't ask for it.

Both methods get static overloads taking an explicit projectDir so
unit tests can drive them without mutating user.dir. The instance
methods become thin wrappers around the static versions.

AutoLocalizationBundleTest gains three regression tests:
- verifyFindLocalizationDirectoryDoesNotAutoCreate: no l10n dir =>
  returns null AND src/main/l10n is not created on disk.
- verifyFindLocalizationDirectoryWalksToCommonSibling: cwd=javase
  with sibling common/src/main/l10n => returns common's dir; once
  javase/src/main/l10n exists, local wins.
- verifyFindDefaultBundleReturnsNullWhenNoBundleFile: empty l10n
  dir => returns null and Bundle.properties is not created.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

Compared 7 screenshots: 7 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

iOS screenshot updates

Compared 75 screenshots: 74 matched, 1 updated.

  • graphics-fill-rect — updated screenshot. Screenshot differs (1x1 px, bit depth 8).

    graphics-fill-rect
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as graphics-fill-rect.png in workflow artifacts.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 224 seconds

Build and Run Timing

Metric Duration
Simulator Boot 67000 ms
Simulator Boot (Run) 1000 ms
App Install 25000 ms
App Launch 9000 ms
Test Execution 303000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

Compared 86 screenshots: 86 matched.

Native Android coverage

  • 📊 Line coverage: 9.87% (5369/54372 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 7.75% (26328/339651), branch 3.59% (1169/32602), complexity 4.54% (1417/31210), method 7.96% (1160/14574), class 13.02% (254/1951)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 9.87% (5369/54372 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 7.75% (26328/339651), branch 3.59% (1169/32602), complexity 4.54% (1417/31210), method 7.96% (1160/14574), class 13.02% (254/1951)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 866.000 ms
Base64 CN1 encode 173.000 ms
Base64 encode ratio (CN1/native) 0.200x (80.0% faster)
Base64 native decode 965.000 ms
Base64 CN1 decode 262.000 ms
Base64 decode ratio (CN1/native) 0.272x (72.8% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog shai-almog merged commit 4975f11 into master May 5, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unable to launch simulator because of Java.lang.StringIndexOutOfBoundsException in latest as of reporting (7.0.236)

1 participant