Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
192 commits
Select commit Hold shift + click to select a range
652ba00
fix: keep styled rich text off foreground draw
bytemain Jun 18, 2026
a50018c
fix(compose): avoid redundant inline text layout
bytemain Jun 21, 2026
b612310
fix(compose): refresh native frame on placement offset changes
bytemain Jun 21, 2026
2ee7c82
fix(compose): guard profiler trace stack updates
bytemain Jun 21, 2026
b79a43f
fix(compose): keep profiler log output crash-safe
bytemain Jun 22, 2026
34efdcb
fix(compose): route profiler logs to platform logger
bytemain Jun 22, 2026
0989f41
fix(android): center odd line height leading
bytemain Jun 22, 2026
7b9503d
fix(android): center line height around glyph metrics
bytemain Jun 23, 2026
b992014
fix(android): center line height on glyph bounds
bytemain Jun 23, 2026
54120fa
fix(android): render slock inline code markers
bytemain Jun 24, 2026
1745a32
fix(android): draw inline code as chip rects
bytemain Jun 25, 2026
0fb5d8b
fix(android): restore inline code edge padding
bytemain Jun 25, 2026
2992785
fix(android): darken inline code border
bytemain Jun 25, 2026
25bf6ea
fix(android): draw crisp inline code borders
bytemain Jun 25, 2026
22eebd6
fix(android): match inline code tag border width
bytemain Jun 25, 2026
f0975f7
fix(android): reserve inline code side margin
bytemain Jun 25, 2026
60e8abe
fix(android): accept pull refresh list method
bytemain Jun 25, 2026
9b4d759
fix(android): let inline code wrap naturally
bytemain Jun 25, 2026
55b509e
fix(android): keep inline code path atoms together
bytemain Jun 25, 2026
dd491e1
fix(android): tighten inline code side padding
bytemain Jun 25, 2026
04aae11
fix(android): correct inline code edge margin
bytemain Jun 25, 2026
0f22838
fix(ohos): reduce LazyColumn scroll white-screen on HarmonyOS
Jun 26, 2026
df96ce2
fix(compose): suppress OHOS sub-pixel scroll remeasure storms
Jun 26, 2026
10a59ca
demo(compose): expand ComposeAllSample for OHOS LazyColumn scroll str…
Jun 26, 2026
da74e0a
fix(android): tighten inline code outer margin
bytemain Jun 26, 2026
c128546
feat: opt
Jun 29, 2026
6ab31be
fix(ohos): sync nested scroll boundary handling to compose scroll sync
Jun 29, 2026
31bd372
fix(ohos): dedup calculateContentSize during LazyColumn mid-scroll
Jun 30, 2026
6bbb4ca
perf(ohos): add LazyColumn scroll audit trace and state write gates
Jun 30, 2026
88eb73d
fix(ios): disable implicit border layer animations
bytemain Jun 30, 2026
f20bafb
fix(compose): schedule pull refresh bridge on kuikly thread
bytemain Jul 1, 2026
a63655b
fix(android): render rich text span backgrounds
bytemain Jul 1, 2026
5405fa9
fix(render): support rich text span backgrounds on apple and ohos
bytemain Jul 1, 2026
06db5e8
fix(compose): rename slock inline code annotation namespace
bytemain Jul 1, 2026
cc61d6f
fix(android): draw inline code border above text background
bytemain Jul 1, 2026
0ff3463
fix(android): let compose overlays capture native touch dispatch
Jul 1, 2026
21733ed
fix(android): restore native dispatch after compose touch
Jul 2, 2026
4ed2bb7
fix(compose): serialize rich text span font family
Jul 2, 2026
08986a6
Merge task42 rich text span font family
Jul 2, 2026
da3d65f
fix(android): fake bold rich text fallback glyphs
Jul 2, 2026
bacb648
fix(android): avoid double inline code background
Jul 2, 2026
9527520
fix(android): add explicit native dispatch capture
Jul 2, 2026
703408a
fix(android): tighten inline code horizontal padding
Jul 2, 2026
3509bee
fix(ohos): support native dispatch capture
Jul 2, 2026
1fd3fe2
fix(compose): add pager keep item alive
Jul 3, 2026
8002a07
Merge Slock Kuikly fork updates into staging2
Jul 3, 2026
3bd6a61
fix(richtext): support custom underline style
bytemain Jul 4, 2026
0e70080
fix(richtext): restore markdown tag chrome support
bytemain Jul 4, 2026
dd76e65
feat(android-render): sharp small-angle static rotation via canvas ma…
Jul 4, 2026
7ea6b09
fix(android-render): stable line centering for editable text fields
Jul 5, 2026
03ef5cf
revert(android): content-independent line height centering
Jul 5, 2026
f980261
fix(compose): dispatch key input events
Jul 5, 2026
ab96717
Merge KuiklyUI PR #1478 into staging2
Jul 5, 2026
c1d4192
fix(compose): address key event review
Jul 5, 2026
24c9a0a
Merge key input events into staging2
Jul 5, 2026
b1babee
fix(android): preserve inline code edge padding
Jul 5, 2026
3632479
Merge remote-tracking branch 'upstream/main' into cindy/staging2-inli…
Jul 6, 2026
d2954d5
fix(ohos-render): add textarea newline edit menu (#3)
bytemain Jul 6, 2026
306c336
fix(android): draw inline code trailing padding
bytemain Jul 6, 2026
bc678aa
fix(android): expand inline code end chrome
bytemain Jul 6, 2026
73dfcf5
Revert "fix(android): expand inline code end chrome"
bytemain Jul 6, 2026
deabf29
fix(android): keep inline code margin outside chrome
bytemain Jul 6, 2026
128fca3
Revert "fix(android): keep inline code margin outside chrome"
bytemain Jul 6, 2026
20f9c2a
fix(android): reserve inline code trailing margin outside chrome
bytemain Jul 6, 2026
8b9623e
Revert "fix(android): reserve inline code trailing margin outside chr…
bytemain Jul 6, 2026
1b14d8d
fix(android): measure inline code trailing margin
bytemain Jul 6, 2026
ba0811e
fix(android): pad trailing inline code separators
bytemain Jul 6, 2026
7ef8981
fix(android): narrow inline code trailing margin
bytemain Jul 6, 2026
10640bf
fix(android): soften inline code trailing margin
bytemain Jul 6, 2026
f6864c2
fix(compose): stop idle scroll boundary feedback (#4)
bytemain Jul 7, 2026
d65f724
fix(android): mirror inline-code trailing border (re-land on current …
Jul 7, 2026
dd7759a
fix(android): wrap over-long inline-code instead of overflowing (#58)
Jul 7, 2026
6a8ab47
fix(android): char-level auto-wrap for long inline-code (#58)
Jul 7, 2026
acc232d
fix(android): align inline-code fill to react brand yellow D440
Jul 7, 2026
661e6a3
revert(compose): drop lazy scroll white-screen patch set
Jul 7, 2026
4144d2b
fix(android): chip borders use display density, not Paint.density
Jul 7, 2026
9ba1179
fix(ios): harden text input runtime behavior
bytemain Jul 8, 2026
f9c951a
fix(ios): disable autocap for compose text areas (#6)
bytemain Jul 9, 2026
9bd3a44
fix(ios): forward textarea tab key events
bytemain Jul 9, 2026
1618b8b
ios(task #439): draw Slock rich-text chip chrome in core-render-ios
Jul 9, 2026
a910841
ios(task #439): tighten chip chrome vertical to font metrics + glyph-…
Jul 9, 2026
9110e97
fix(ios): apply font family to text inputs (#8)
bytemain Jul 9, 2026
539736b
fix(ios): preserve dynamic font loading for inputs
bytemain Jul 9, 2026
1cf8399
fix(ios): preserve ellipsis after soft wrap
Jul 9, 2026
7c6987c
ios(task #439): clamp chip fill to the token's glyphs per line (fix w…
Jul 9, 2026
b5e0767
ios(task #439): chip chrome no-underline + px-1 padding + leading-1.5…
Jul 9, 2026
067c6e0
fix(android): clamp pull refresh overscroll (#10)
bytemain Jul 9, 2026
bd2ad40
ios(task #448): model rich-text inline boxes atomically
bytemain Jul 9, 2026
1888e63
fix(render): bridge marshal never drops fields silently (mobile task …
bytemain Jul 9, 2026
33fa419
fix(android): keep ordinary mentions underlined (#14)
bytemain Jul 10, 2026
7602d0e
ohos(task #414): render markdown chips with native box geometry (#13)
bytemain Jul 10, 2026
9bb84eb
revert(android): remove pull refresh hard clamp (#15)
bytemain Jul 10, 2026
4b9b09a
fix(android): bound vertical overscroll resistance (#16)
bytemain Jul 10, 2026
5aea44f
fix(ohos): apply rich-text brush colors before attach (#17)
bytemain Jul 10, 2026
5909030
fix(compose): coalesce semantics updates per frame to prevent fling w…
bytemain Jul 10, 2026
9aae59f
fix(input): reject stale controlled callbacks by revision (#19)
bytemain Jul 10, 2026
af2c4d5
fix(render): marshal off-context native calls (#20)
bytemain Jul 11, 2026
fc57a0e
fix(android): align line-height with CSS font metrics (#22)
bytemain Jul 11, 2026
73fc777
feat(richtext): add generic inline box span style (#21)
bytemain Jul 12, 2026
37cf709
fix(compose): arbitrate native text focus (#23)
bytemain Jul 12, 2026
d7172e1
fix(ohos): publish complete text state first (#24)
bytemain Jul 12, 2026
8b546ce
fix(compose): blur detached text editors (#25)
bytemain Jul 12, 2026
bcacb66
sync: absorb Tencent 2.23.1 runtime fixes (#26)
bytemain Jul 12, 2026
45f45e4
fix(ios): align inline box fill and border clipping (#27)
bytemain Jul 12, 2026
41ad5a5
fix(ios): center inline box chrome in line (#28)
bytemain Jul 12, 2026
7ed15b7
fix(richtext): preserve inline box link typography (#30)
bytemain Jul 12, 2026
e845df5
fix(richtext): isolate inline box child paint (#32)
bytemain Jul 12, 2026
3099998
fix(richtext): preserve inline box link precedence (#33)
bytemain Jul 12, 2026
dd54e16
test(richtext): assert inline box font family precedence (#34)
bytemain Jul 12, 2026
61da1f6
fix(android): draw one inline box chrome (#35)
bytemain Jul 12, 2026
e30a26d
fix(richtext): remove migrated markdown tag chrome (#36)
bytemain Jul 12, 2026
d4da2a4
fix(input): preserve rapid controlled edit order (#37)
bytemain Jul 13, 2026
e50bcef
fix(android): keep single-run inline boxes atomic (#38)
bytemain Jul 13, 2026
c0cbd30
fix(android): pin atomic inline box chrome (#39)
bytemain Jul 13, 2026
71227e6
fix(android): harden render scheduler task queue (#41)
bytemain Jul 13, 2026
820e806
fix(ios): align numeric inline box chrome (#40)
bytemain Jul 13, 2026
d869f46
refactor(ios): generalize inline box edge anchoring (#43)
bytemain Jul 13, 2026
996a20f
fix(compose): clear stale lazy scroll offset guards (#42)
bytemain Jul 13, 2026
ba0f19f
fix(android): preserve text field line height on first input (#44)
bytemain Jul 14, 2026
35290a1
feat(compose): allow pull refresh without held inset (#45)
bytemain Jul 14, 2026
aec013d
fix(compose): refresh pull config without replacing state (#46)
bytemain Jul 15, 2026
14b3a14
fix(compose): defer lazy offset alignment during scroll (#47)
bytemain Jul 15, 2026
f31bf82
fix(ohos): surface image adapter failures (#48)
bytemain Jul 15, 2026
e2f6770
fix(compose): redraw reused native views (#49)
bytemain Jul 15, 2026
cc78123
fix(compose): propagate draw invalidation across reused dirty ancestors
bytemain Jul 16, 2026
b2a2eb0
fix(android): clear decoration before view reuse (#53)
bytemain Jul 16, 2026
2527b9e
fix(compose): never dispatch off-target programmatic scroll echoes
bytemain Jul 17, 2026
cea98d3
sync: absorb Tencent runtime fixes batch 1+3 (#55)
bytemain Jul 18, 2026
0ae8e9f
fix(android): pager will drag end not sync on android (#1546) (#56)
bytemain Jul 18, 2026
d9c8181
fix(iOS): touch event dispatch causing multiple views to respond (#15…
bytemain Jul 18, 2026
5755ac0
fix(compose): guard profiler frame events and marshal file IO onto Ku…
bytemain Jul 18, 2026
f12b025
sync: absorb Tencent demo/docs batch (#1518/#1542/#1544/#1420) (#59)
bytemain Jul 18, 2026
d91856d
docs: add AGENTS.md fork collaboration conventions (#60)
bytemain Jul 18, 2026
8412827
fix(compose): synchronize profiler StateIdentityRegistry and frame st…
bytemain Jul 18, 2026
a80c06d
feat(compose): add preemptible context idle lane (#61)
bytemain Jul 18, 2026
94b7924
fix(ios): preserve textarea IME composition (#64)
bytemain Jul 18, 2026
1a26a84
fix(scroll): enforce transactional native writes with OHOS active-axi…
bytemain Jul 18, 2026
f575d1b
fix(ohos): merge upstream touch handled-first dispatch with native di…
bytemain Jul 18, 2026
462f411
fix(compose): converge retained text focus state (#66)
bytemain Jul 18, 2026
f35eeb8
fix(ios): reject non-finite scroll event values (#67)
bytemain Jul 18, 2026
79d5a05
fix(compose): reshow keyboard for focused editor (#68)
bytemain Jul 18, 2026
824a0fd
fix(compose): keep retained native events fresh (#69)
bytemain Jul 18, 2026
fbe21d5
ci(ohos): prepare official runner metadata (#70)
bytemain Jul 18, 2026
0bd0d71
fix(android): guard recycler inset writes before content attach (#71)
bytemain Jul 18, 2026
d521169
revert(scroll): remove transactional native writes from release line …
bytemain Jul 19, 2026
86558d5
fix(compose): preserve styleless link typography (#73)
bytemain Jul 19, 2026
ad10ae8
feat(compose): expose cached async image bitmap (#74)
bytemain Jul 20, 2026
0e101b7
fix(drawer): wait for current native scroll binding (#76)
bytemain Jul 21, 2026
fdf43ad
feat(compose): gate moveable drawer user scroll (#77)
bytemain Jul 21, 2026
e58c787
fix(android): make custom underlines wrap-safe and single-source (#79)
bytemain Jul 23, 2026
969ac42
fix(android): let glyph ink occlude custom underlines (#80)
bytemain Jul 23, 2026
8d06798
fix(compose): isolate profiler scope observer state (#81)
bytemain Jul 24, 2026
e50633f
fix(profiler): preserve file output across pager lifecycle
bytemain Jul 24, 2026
d3fe2cb
fix(profiler): acknowledge report file commits (#83)
bytemain Jul 24, 2026
92245b3
fix(compose): commit initial lazy viewport before placement (#84)
bytemain Jul 24, 2026
60efe6c
fix(profiler): recover file queue across Pager loss (#85)
bytemain Jul 24, 2026
428b19f
fix(android): guard empty inline box rich text (#87)
bytemain Jul 26, 2026
588ecd3
fix(android): clip wrapped inline boxes to selection (#86)
bytemain Jul 26, 2026
f7eb31c
fix(ohos): scale text decoration thickness against the engine's 1/18 …
bytemain Jul 29, 2026
3951e17
fix(compose): clear removed native semantics (#90)
bytemain Jul 29, 2026
5a10be8
feat(ios): support interactive keyboard dismissal on scrollers (#89)
bytemain Jul 29, 2026
191d1b9
fix(compose): exclude hidden native subtrees (#92)
bytemain Jul 30, 2026
04fa0d1
fix(android): preserve hidden subtrees with test tags (#93)
bytemain Jul 30, 2026
e01902b
fix(ios): publish final IME state before legacy text (#94)
bytemain Jul 31, 2026
c319476
fix(compose): hide flattened semantics descendants (#95)
bytemain Jul 31, 2026
d794187
feat: add system-selectable plain text surface across three platforms…
bytemain Jul 31, 2026
a318e89
fix(ohos): decode Canvas images into SDR shared memory (#97)
bytemain Jul 31, 2026
5ea4bb3
fix(accessibility): hide flattened layout descendants (#98)
bytemain Jul 31, 2026
725ff18
fix(compose): measure selectable text in lazy layouts (#99)
bytemain Jul 31, 2026
b57fc34
fix(ohos): validate Canvas pixelmaps before caching (#100)
bytemain Jul 31, 2026
76d756c
fix: deliver native touch and truthful a11y to SelectableText (#101)
bytemain Jul 31, 2026
4b51659
fix(ohos): pull-to-refresh contentInset offset rests at 0 under margi…
bytemain Aug 1, 2026
51ddc75
fix(ohos): align horizontal content inset with margin model (#103)
bytemain Aug 1, 2026
04d5398
fix(ios): guard zero-width inline code atoms (#106)
bytemain Aug 2, 2026
cff8112
fix(compose): redraw reactivated lazy slots (#107)
bytemain Aug 2, 2026
6a531a5
fix(compose): wake activated precomposed slots (#108)
bytemain Aug 3, 2026
c5730e2
fix(compose): redraw restored lazy descendants (#110)
bytemain Aug 3, 2026
461bbe5
fix(compose): preserve draw dispatch semantics (#112)
bytemain Aug 3, 2026
1547d16
fix(compose): fence stale text input snapshots (#111)
bytemain Aug 3, 2026
8190595
fix(compose): synchronize offset after viewport changes (#113)
bytemain Aug 4, 2026
dbc3830
fix(android): replay IME height to replacement listeners (#114)
bytemain Aug 4, 2026
7404576
fix(ios): dismiss selectable text menu on detach (#115)
bytemain Aug 4, 2026
c7a0212
fix(android): enforce keyboard registry main thread (#116)
bytemain Aug 4, 2026
d691975
fix(compose): replay pending offset after viewport shrink (#117)
bytemain Aug 4, 2026
e75e8bc
feat(compose): generic switchable trace for lazy layout measure
Aug 5, 2026
dab45ac
feat(compose): deliver the lazy trace handle through a composition local
Aug 5, 2026
90dcdf4
fix(compose): enable the switch and require a real frame identity
Aug 5, 2026
39c5308
fix(compose): key the measure lambda on the trace handle
Aug 5, 2026
adda975
feat(compose): emit the placement stage
Aug 5, 2026
0fe6c08
fix(compose): emit placement only after every place() returns
Aug 5, 2026
04cb73b
feat(compose): record the viewport-shrink offset reconciliation
Aug 5, 2026
7271a4d
feat(compose): record install, consume and replay of the pending offset
Aug 5, 2026
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
119 changes: 119 additions & 0 deletions .github/workflows/android-render-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: Android Render PR

on:
pull_request:
branches:
- staging2
paths:
- "core-render-android/**"
- "buildSrc/**"
- "gradle/**"
- "build.gradle*"
- "settings.gradle*"
- "gradle.properties"
- ".github/workflows/android-render-pr.yml"

permissions:
contents: read

jobs:
android-render-jvm:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check out exact PR head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1

- name: Verify exact PR head
env:
EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
actual_head_sha="$(git rev-parse HEAD)"
echo "expected_head_sha=${EXPECTED_HEAD_SHA}"
echo "actual_head_sha=${actual_head_sha}"
test "${actual_head_sha}" = "${EXPECTED_HEAD_SHA}"

- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4

- name: Run Android render JVM tests
run: >-
./gradlew
:core-render-android:testDebugUnitTest
--no-daemon

- name: Report Android render JVM test count
run: |
python3 - <<'PY'
from pathlib import Path
import xml.etree.ElementTree as ET

reports = sorted(Path("core-render-android/build/test-results").glob("**/TEST-*.xml"))
if not reports:
raise SystemExit("No Android render JVM test result XML files found")

totals = {"tests": 0, "failures": 0, "errors": 0, "skipped": 0}
for report in reports:
suite = ET.parse(report).getroot()
for key in totals:
totals[key] += int(suite.attrib.get(key, "0"))

print(
"android_render_jvm_test_count "
+ " ".join(f"{key}={value}" for key, value in totals.items())
)
if totals["tests"] == 0 or totals["failures"] or totals["errors"]:
raise SystemExit(1)
PY

- name: Prove stale-radius regression catches old reset wiring
run: |
python3 - <<'PY'
from pathlib import Path

source = Path(
"core-render-android/src/main/java/com/tencent/kuikly/core/render/android/css/ktx/"
"KRCSSViewExtension.kt"
)
text = source.read_text()
fixed = "\n".join([
" KRCssConst.BORDER_RADIUS -> {",
" resetDecorationForReuse()",
" return true",
" }",
"",
])
old = "\n".join([
" KRCssConst.BORDER_RADIUS -> {",
" background = null",
" destroyViewDecorator()",
" return true",
" }",
"",
])
if text.count(fixed) != 1:
raise SystemExit("Expected exactly one fixed BORDER_RADIUS reset block")
source.write_text(text.replace(fixed, old))
PY

set +e
./gradlew \
:core-render-android:testDebugUnitTest \
--tests '*KRCSSDecorationReuseTest*' \
--rerun-tasks \
--no-daemon
mutation_status=$?
set -e

git checkout -- \
core-render-android/src/main/java/com/tencent/kuikly/core/render/android/css/ktx/KRCSSViewExtension.kt
test "${mutation_status}" -ne 0
272 changes: 272 additions & 0 deletions .github/workflows/compose-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
name: Compose PR Exact Matrix

on:
pull_request:
branches:
- staging2

permissions:
contents: read

env:
EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha }}

jobs:
identity-diff:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out exact PR head
uses: actions/checkout@v4
with:
ref: ${{ env.EXPECTED_HEAD_SHA }}
fetch-depth: 0

- name: Verify identity, DCO, diff and clean tree
shell: bash
run: |
set -euo pipefail
actual_head="$(git rev-parse HEAD)"
test "$actual_head" = "$EXPECTED_HEAD_SHA"
test -z "$(git status --porcelain)"
git diff --check "${{ github.event.pull_request.base.sha }}...HEAD"
# Single-commit exact: exactly one commit on top of the merge base,
# and the head's sole parent is that merge base.
base_sha="${{ github.event.pull_request.base.sha }}"
test "$(git rev-list --count "${base_sha}..HEAD")" = "1"
test "$(git rev-parse HEAD^)" = "$(git merge-base HEAD "${base_sha}")"
author_email="$(git show -s --format=%ae HEAD)"
committer_email="$(git show -s --format=%ce HEAD)"
author_name="$(git show -s --format=%an HEAD)"
# Generic DCO gate (owner-agnostic): author == committer, and the commit
# carries a Signed-off-by trailer matching that identity.
test -n "$author_email"
test "$author_email" = "$committer_email"
git show -s --format=%B HEAD | grep -Fx \
"Signed-off-by: ${author_name} <${author_email}>"
{
echo "head=$actual_head"
echo "tree=$(git rev-parse HEAD^{tree})"
echo "parent=$(git rev-parse HEAD^)"
echo "base=${{ github.event.pull_request.base.sha }}"
echo "merge_base=$(git merge-base HEAD '${{ github.event.pull_request.base.sha }}')"
echo "author=$(git show -s --format='%an <%ae>' HEAD)"
echo "committer=$(git show -s --format='%cn <%ce>' HEAD)"
echo "patch_id=$(git show --pretty=format: HEAD | git patch-id --stable | awk '{print $1}')"
} | tee exact-manifest.txt
git diff --binary "${{ github.event.pull_request.base.sha }}...HEAD" > candidate.patch
sha256sum candidate.patch | tee candidate.patch.sha256

- name: Upload exact identity evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: identity-diff-${{ env.EXPECTED_HEAD_SHA }}
path: |
exact-manifest.txt
candidate.patch.sha256

common-core-android:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.EXPECTED_HEAD_SHA }}
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- uses: gradle/actions/setup-gradle@v4
- name: Verify exact checkout
run: test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD_SHA"
- name: Compile metadata and run production JVM fixtures
run: |
./gradlew \
:core:compileCommonMainKotlinMetadata \
:compose:compileCommonMainKotlinMetadata \
:core:testDebugUnitTest \
:compose:testDebugUnitTest \
:core-render-android:testDebugUnitTest \
--no-build-cache --no-daemon
- name: Require successful JVM suites and report module counts
run: |
python3 - <<'PY'
from pathlib import Path
import xml.etree.ElementTree as ET

for module in ("core", "compose", "core-render-android"):
reports = sorted(Path(module, "build", "test-results").glob("**/TEST-*.xml"))
tests = failures = errors = 0
for report in reports:
suite = ET.parse(report).getroot()
tests += int(suite.attrib.get("tests", "0"))
failures += int(suite.attrib.get("failures", "0"))
errors += int(suite.attrib.get("errors", "0"))
print(f"{module}: tests={tests} failures={failures} errors={errors}")
# The safe pre-transaction core tree has no JVM test sources, so
# :core:testDebugUnitTest is intentionally NO-SOURCE. Compose and
# Android renderer both have real suites and must stay nonzero.
if module != "core" and tests == 0:
raise SystemExit(1)
if failures or errors:
raise SystemExit(1)
PY
- name: Upload JVM evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: common-core-android-${{ env.EXPECTED_HEAD_SHA }}
path: |
core/build/test-results
compose/build/test-results
core-render-android/build/test-results

ios-renderer:
runs-on: macos-14
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.EXPECTED_HEAD_SHA }}
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true
- uses: gradle/actions/setup-gradle@v4
- name: Select Xcode 16.2
run: sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
- name: Generate CocoaPods dummy framework
run: ./gradlew :demo:generateDummyFramework --no-build-cache --no-daemon
- name: Install locked Pods
run: bundle exec pod install --project-directory=iosApp --deployment
- name: Compile Kotlin Native main and tests
run: |
./gradlew \
:core:compileKotlinIosSimulatorArm64 \
:compose:compileKotlinIosSimulatorArm64 \
:compose:compileTestKotlinIosSimulatorArm64 \
--no-build-cache --no-daemon
- name: Run native text-input sequencing fixture
run: tools/ios-renderer-tests/run-text-input-event-sequencer-test.sh
- name: Build production renderer with warnings as errors
run: |
mkdir -p build
set -o pipefail
xcodebuild \
-workspace iosApp/iosApp.xcworkspace \
-scheme OpenKuiklyIOSRender \
-configuration Debug \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO \
GCC_TREAT_WARNINGS_AS_ERRORS=YES \
SWIFT_TREAT_WARNINGS_AS_ERRORS=YES \
-derivedDataPath build/ios-derived \
-resultBundlePath build/ios-renderer.xcresult \
build | tee build/ios-renderer.log
- name: Upload iOS evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: ios-renderer-${{ env.EXPECTED_HEAD_SHA }}
path: |
build/ios-renderer.log
build/ios-renderer.xcresult

ohos-native:
# KuiklyUI is a personal repository, so organization-scoped Blacksmith runners never pick up
# these jobs. Keep the existing pinned HarmonyOS container on the official hosted runner.
runs-on: ubuntu-latest
container:
image: ghcr.io/bytemain/harmony-next-pipeline-docker/harmonyos-ci-image:v6.1.1.280-android.1
timeout-minutes: 60
env:
OHOS_SDK_HOME: /opt/harmonyos-tools/command-line-tools/sdk/default/openharmony
DEVECO_SDK_HOME: /opt/harmonyos-tools/command-line-tools/sdk
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.EXPECTED_HEAD_SHA }}
fetch-depth: 0
- name: Trust the mounted workspace inside the job container
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global user.name "Kuikly CI"
git config --global user.email "kuikly-ci@users.noreply.github.com"
- name: Prepare OHOS native dependency metadata
working-directory: ohosApp
run: |
export PATH="$OHOS_SDK_HOME/native/build-tools/cmake/bin:$OHOS_SDK_HOME/native/llvm/bin:$PATH"
ohpm install --all
hvigorw --sync -p product=default --analyze=normal --parallel --no-daemon
hvigorw assembleHar \
--mode module \
-p module=render@default \
-p product=default \
-p buildMode=debug \
--analyze=normal \
--parallel \
--no-daemon
- name: Fresh arm64 production libkuikly compile and link
shell: bash
run: |
set -euo pipefail
export PATH="$OHOS_SDK_HOME/native/build-tools/cmake/bin:$OHOS_SDK_HOME/native/llvm/bin:$PATH"
tools/ohos-renderer-tests/run-arm64-direct-link.sh "$GITHUB_WORKSPACE/build/ohos-evidence"
- name: Upload OHOS native evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: ohos-native-${{ env.EXPECTED_HEAD_SHA }}
path: build/ohos-evidence

source-contracts:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.EXPECTED_HEAD_SHA }}
fetch-depth: 0
- name: Reject stale native callbacks retained by Compose node initialization
run: python3 tools/check-compose-node-event-freshness.py --self-test
- name: Preserve active user motion when RecyclerView enters dragging
run: python3 tools/check-android-drag-entry-preserves-physical-scroll.py --self-test
- name: Keep DrawModifierNode view-aware production dispatch
run: python3 tools/check-draw-modifier-view-dispatch.py --self-test
- name: Reject non-finite iOS scroll event values
run: python3 tools/check-ios-scroll-event-finiteness.py --self-test
- name: Preserve profiler observer composition and thread ownership
run: python3 tools/check-profiler-observer-state-partition.py --self-test
- name: Preserve profiler file output across Pager and session lifecycle
run: python3 tools/check-profiler-file-output-lifecycle.py --self-test
- name: Keep OHOS contentInset leading offsets aligned with the margin model
run: core-render-ohos/src/test/cpp/run_scroller_content_inset_offset_test.sh

exact-matrix:
if: always()
runs-on: ubuntu-latest
needs:
- identity-diff
- common-core-android
- ios-renderer
- ohos-native
- source-contracts
steps:
- name: Require every exact-bound gate
env:
RESULTS: ${{ toJSON(needs) }}
run: |
python3 - <<'PY'
import json, os
needs = json.loads(os.environ["RESULTS"])
failed = {name: value["result"] for name, value in needs.items() if value["result"] != "success"}
print(json.dumps(needs, indent=2, sort_keys=True))
if failed:
raise SystemExit(f"exact matrix failed: {failed}")
PY
Loading