Skip to content

feat(docs): In-app documentation browser with Jekyll site and Docusaurus sync#5445

Merged
jamesarich merged 68 commits into
mainfrom
feat/20260507-161858-app-docs-markdown
May 19, 2026
Merged

feat(docs): In-app documentation browser with Jekyll site and Docusaurus sync#5445
jamesarich merged 68 commits into
mainfrom
feat/20260507-161858-app-docs-markdown

Conversation

@jamesarich
Copy link
Copy Markdown
Collaborator

Summary

Adds a full in-app documentation browser to the Meshtastic Android & Desktop app, backed by a Jekyll site for standalone browsing and a Docusaurus sync pipeline for meshtastic.org.

What's included

In-app docs browser (feature/docs)

  • 17 user guide pages + 9 developer guide pages written against source code
  • Markdown rendering via multiplatform-markdown-renderer with M3 theming
  • Keyword search engine with aliases and weighted scoring
  • TOC with per-page icons via MeshtasticIcons
  • Inline screenshot rendering via Coil 3 + ComposeResourceImageTransformer
  • Deep link support (meshtastic://docs/{pageId})
  • Crowdin i18n for user-facing pages

Jekyll site (docs/)

  • just-the-docs v0.11.0 theme with Meshtastic M3 colors
  • Auto-deployed via GitHub Pages on push to main
  • Section index pages with What's New highlights

Docusaurus sync (Phase 10)

  • scripts/sync-android-docs.js — transforms Jekyll → Docusaurus format
  • WebP screenshot conversion via cwebp
  • Weekly sync workflow (lives in meshtastic/meshtastic#2405)

New content pages (Phase 10)

  • docs/user/translate.md — Crowdin contribution guide
  • docs/developer/measurement.md — MetricFormatter API guide

Screenshot testing

  • 8 @PreviewLightDark previews in DocsPreviews.kt
  • 8 screenshot tests in DocsScreenshotTests.kt

Verification

  • ./gradlew spotlessApply detekt assembleDebug test allTests passes
  • Sync script dry-run verified (27 pages + 37 screenshots)

Related

@github-actions github-actions Bot added build Build system changes enhancement New feature or request repo Repository maintenance labels May 13, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label May 13, 2026
@jamesarich jamesarich requested review from garthvh and rcarteraz May 13, 2026 20:05
@jamesarich jamesarich force-pushed the feat/20260507-161858-app-docs-markdown branch from 55776d0 to 9275da0 Compare May 13, 2026 21:24
@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2373 1 2372 0
View the top 1 failed test(s) by shortest run time
org.meshtastic.core.database.DatabaseManagerWithDbRetryTest::withDb retries against current database when previous pool closes during switch
Stack Traces | 20.3s run time
java.lang.AssertionError: expected:<42424242> but was:<null>
	at org.junit.Assert.fail(Assert.java:89)
	at org.junit.Assert.failNotEquals(Assert.java:835)
	at org.junit.Assert.assertEquals(Assert.java:120)
	at kotlin.test.junit.JUnitAsserter.assertEquals(JUnitSupport.kt:32)
	at kotlin.test.AssertionsKt__AssertionsKt.assertEquals(Assertions.kt:63)
	at kotlin.test.AssertionsKt.assertEquals(Unknown Source)
	at kotlin.test.AssertionsKt__AssertionsKt.assertEquals$default(Assertions.kt:62)
	at kotlin.test.AssertionsKt.assertEquals$default(Unknown Source)
	at org.meshtastic.core.database.DatabaseManagerWithDbRetryTest$withDb retries against current database when previous pool closes during switch$1.invokeSuspend(DatabaseManagerWithDbRetryTest.kt:99)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
	at kotlinx.coroutines.test.TestDispatcher.processEvent$kotlinx_coroutines_test(TestDispatcher.kt:24)
	at kotlinx.coroutines.test.TestCoroutineScheduler.tryRunNextTaskUnless$kotlinx_coroutines_test(TestCoroutineScheduler.kt:98)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$2$1$workRunner$1.invokeSuspend(TestBuilders.kt:326)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:256)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:54)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlockingImpl(Builders.kt:30)
	at kotlinx.coroutines.BuildersKt.runBlockingImpl(Unknown Source)
	at kotlinx.coroutines.BuildersKt__Builders_concurrentKt.runBlockingK(Builders.concurrent.kt:172)
	at kotlinx.coroutines.BuildersKt.runBlockingK(Unknown Source)
	at kotlinx.coroutines.BuildersKt__Builders_concurrentKt.runBlockingK$default(Builders.concurrent.kt:157)
	at kotlinx.coroutines.BuildersKt.runBlockingK$default(Unknown Source)
	at kotlinx.coroutines.test.TestBuildersJvmKt.createTestResult(TestBuildersJvm.kt:10)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:309)
	at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:1)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:167)
	at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:1)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:159)
	at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:1)
	at org.meshtastic.core.database.DatabaseManagerWithDbRetryTest.withDb retries against current database when previous pool closes during switch(DatabaseManagerWithDbRetryTest.kt:69)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:524)
	at org.robolectric.internal.SandboxTestRunner.executeInSandbox(SandboxTestRunner.java:494)
	at org.robolectric.internal.SandboxTestRunner.access$900(SandboxTestRunner.java:67)
	at org.robolectric.internal.SandboxTestRunner$7.evaluate(SandboxTestRunner.java:442)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.robolectric.internal.SandboxTestRunner.access$600(SandboxTestRunner.java:67)
	at org.robolectric.internal.SandboxTestRunner$6.evaluate(SandboxTestRunner.java:333)
	at org.robolectric.internal.SandboxTestRunner$3.evaluate(SandboxTestRunner.java:233)
	at org.robolectric.internal.SandboxTestRunner$5.lambda$evaluate$0(SandboxTestRunner.java:317)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:101)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@jamesarich jamesarich marked this pull request as ready for review May 14, 2026 11:16
@jamesarich jamesarich added this to the 2.8.0 milestone May 14, 2026
@jamesarich jamesarich marked this pull request as draft May 14, 2026 15:34
@jamesarich jamesarich force-pushed the feat/20260507-161858-app-docs-markdown branch 2 times, most recently from 70497d3 to 36cf06e Compare May 18, 2026 20:20
@jamesarich jamesarich marked this pull request as ready for review May 18, 2026 22:37
jamesarich and others added 15 commits May 18, 2026 17:58
- Create DocsPreviews.kt with 8 preview composables for docs UI screens
- Add screenshot test wrappers in DocsScreenshotTests.kt
- Generate 16 reference images (8 light + 8 dark mode)
- Replace placeholder screenshots with real Compose preview renders
- Inline screenshots into all 14 user guide markdown docs
- Sync updated docs to composeResources for in-app display
- Fix detekt issues: MagicNumber, LongMethod, ReturnCount,
  LoopWithTooManyJumpStatements, PreviewPublic, lambda tense
- Rename onPageSelected → onSelectPage (Compose naming convention)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update `DefaultDocBundleLoader` to explicitly bind to the `DocBundleLoader` interface in Koin
- Add `FeatureDocsModule` to `DesktopKoinModule` to enable documentation support in the desktop application
…tection

- Update `MeshtasticDatabaseTest` to use Room 3 `MigrationTestHelper` with `BundledSQLiteDriver` and `runBlocking` for KMP compatibility
- Update `DatabaseManagerLegacyCleanupTest` to use `DataStore` instead of `SharedPreferences`, matching the current `DatabaseManager` architecture
- Modify build-logic to recognize `src/androidDeviceTest` source sets when determining if instrumented tests should be enabled
- Add `compileAndroidDeviceTest` dependencies to the root convention plugin for `:core:database` and `:core:model` to catch compilation breakages early in the build process
… (FR-038)

- Create ComposeResourceImageTransformer using Res.getUri() + Coil 3
- Wire transformer into DocsPageRouteScreen Markdown composable
- Update syncDocsToComposeResources to include screenshots
- Add docs-screenshot-aliases.properties for CST-to-semantic renaming
- Refactor copyDocsScreenshots to read manifest at configuration time
- Fix markdown image paths to root-relative for Jekyll resolution
- Remove redirect_to from docs/index.md for local rendering
- Add coil dependency and synced assets to .gitignore
- Update spec artifacts and reference screenshots
Tasks: T061, T062, T083, T084
These files are generated by syncDocsToComposeResources and are
already listed in .gitignore.
- Add iconId field to DocPage model for per-page icons
- Add DocPageIconResolver composable mapping iconId to MeshtasticIcons
- Render leading icons in DocsBrowserScreen TOC list items
- Add signal-meter.md and units-and-locale.md user doc pages
- Update DocBundleLoader with new pages and icon mappings
- Update DocsPreviews with iconId and new sample pages
- onboarding.md: add CriticalAlerts permission, expand permissions section
- nodes.md: correct filters (6 toggles + search) and sorts (7 options)
- messages-and-channels.md: add reactions, message actions, expand quick chat
- desktop.md: add keyboard shortcuts table, structure system tray section
- map-and-waypoints.md: expand waypoint expiration and locked behavior
- tak.md: expand TAK/TAK_TRACKER roles, add CoT format
- mqtt.md: add message formats and encryption/privacy sections
- Upgrade to just-the-docs v0.11.0 with remote_theme for GitHub Pages
- Add Meshtastic M3 color scheme (Green 700 primary, Neutral palette)
- Add dynamic copyright footer
- Add user.md and developer.md section index pages with What's New
- Update index.md with Quick Links table
- Update Gemfile to Jekyll 4.3 with required gems
- Restructure versions.yml for nested format
Runs weekly to detect doc pages not updated since their source code changed.
Uses ubuntu-24.04-arm runner per CI conventions.
- Mark TOC icons, content validation, and Jekyll upgrade tasks complete
- Add Phase 9 tasks (T200-T206) for Apple alignment
- Update session context with current state
- Fix sidebar nav by overriding circular parent refs in user.md/developer.md
- Strip .md extensions from 10 internal links for Jekyll compatibility
- Add M3-aligned dark color scheme (meshtastic-dark.scss) from Color.kt
- Refresh light scheme with explicit $color-scheme and M3 tokens
- Add light/dark toggle with localStorage persistence and OS preference
- Add Inter + JetBrains Mono fonts, M3-style rounded corners, transitions
- Wire DocsLinkUriHandler for in-app markdown link navigation via
  CompositionLocalProvider + custom UriHandler
jamesarich and others added 11 commits May 18, 2026 17:58
- Add Mutex for cache concurrency safety
- Use atomic file writes (temp + atomicMove) to prevent partial reads
- Touch files on read to maintain proper access-time eviction order
- Move I/O off main thread with withContext(ioDispatcher)
- Key LaunchedEffect on locale so content refreshes on locale change
- Log segment translation failures instead of swallowing silently
- Replace generic Exception catches with IOException for detekt

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e tests

- Show 'Community translated' or 'Auto-translated' subtitle in TopAppBar
  when viewing non-English content
- Auto-download ML Kit models on first translation attempt instead of
  requiring separate download UX flow
- Show English content immediately while ML Kit translates in background
- Move TranslationSource enum to model package for reuse
- Add TranslationCascadeTest with 8 tests covering service contracts
- Update spec tasks.md with Phase 14 documenting all translation work

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rce off main thread

- Remove @single annotation from DocTranslationCache to prevent
  ComponentScan from attempting to instantiate it without Context
  (it's provided explicitly via GoogleAiModule factory)
- Wrap hasTranslatedResource() call in withContext(ioDispatcher)
  to avoid CMP resource I/O on the main thread

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- DocBundleLoader.readPageLocalized() loads Crowdin locale-qualified
  files directly (CMP Res.readBytes doesn't auto-resolve locale variants)
- DocsNavigation cascade now correctly: Crowdin → ML Kit → English
- MarkdownTranslationSegmenter translates link-only lines (TOC)
- Cache touchFile uses lightweight sidecar (.access) mtime instead of
  rewriting full cache entry (corruption risk eliminated)
- Detekt suppressions for LongMethod, TooManyFunctions, ReturnCount

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Jekyll config: locale-scoped defaults (nav_exclude, locale_page layout)
- Language switcher: globe dropdown in header, detects available pages
- locale_page layout: community translation banner, RTL support, lang attr
- DocsTasks: generateDocsBundle discovers docs/{locale}/user/ dirs,
  produces locale-qualified HTML + index entries + locales.json manifest
- translations.md landing page with Crowdin CTA
- crowdin.yml already maps docs/user/*.md → docs/{locale}/user/*.md

Same markdown source now serves both:
  - In-app: CMP composeResources via syncTranslatedDocs task
  - Web: Jekyll GH Pages with locale routing and language switcher

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- _data/locales.yml: all 38 Android locales with native names and dir
- _config.yml: scope defaults for all locale paths
- DocsTasks: regex accepts region-qualified codes (pt-BR, zh-CN)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Crowdin's %two_letters_code% only produces 2-letter codes (pt, zh),
losing regional distinctions. %locale% produces the full locale code
for regional variants (pt-BR, zh-CN, zh-TW) while keeping simple codes
for non-regional languages (fr, es, de).

This matches our Android resource structure which distinguishes
pt vs pt-BR and zh-CN vs zh-TW.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace brittle locale.replace("-", "-r") with proper bcp47ToCmpQualifier()
in build script and consolidate runtime locale resolution:

- Add currentLocaleQualifier() expect/actual that returns CMP-format
  qualifier (e.g. "pt-rBR", "fr") directly from system Locale
- DocBundleLoader tries qualifiers in specificity order: region-qualified
  first (files-pt-rBR/), then language-only (files-pt/), then English
- Build-side bcp47ToCmpQualifier() properly handles 2-letter regions,
  and falls back to BCP-47 b+ format for script tags (sr-Latn)
- CMP files/ resources don't support auto locale resolution (confirmed
  in official docs) so manual path construction is required

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
%android_code% outputs Android/CMP qualifier format directly (pt-rBR,
zh-rCN, fr), removing the need for bcp47ToCmpQualifier() conversion.

Pipeline is now zero-conversion:
  Crowdin → docs/pt-rBR/user/foo.md (already CMP format)
  Sync   → files-pt-rBR/docs/user/foo.md (just prepend files-)
  Runtime→ files-pt-rBR/docs/user/foo.md (direct match)

Updated Jekyll config and locales.yml to use Android qualifier format
for consistency across the entire docs pipeline.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Locale-qualified HTML pages (docs/pt-rBR/user/foo.html) need
  ../../styles/docs.css, not ../styles/docs.css (one extra level deep)
- Heading regex now requires space after # per CommonMark spec,
  preventing corruption of lines like ##hashtag or #noSpace

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich force-pushed the feat/20260507-161858-app-docs-markdown branch from 55acac8 to 6ce21af Compare May 18, 2026 22:58
jamesarich and others added 11 commits May 18, 2026 19:49
DocTranslationCache is constructed via a factory function that provides
the Path from Context.cacheDir, but Koin verify still introspects the
class constructor params. Adding these types to extraTypes suppresses the
false MissingKoinDefinitionException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updates spec to reflect the implemented translation system:
- FR-048: Three-tier translation cascade (Crowdin → ML Kit → English)
- FR-049: Zero-conversion locale pipeline via %android_code%
- FR-050: Jekyll i18n with Android qualifier paths
- FR-051: currentLocaleQualifier() expect/actual
- SC-022–025: Corresponding success criteria
- Updated Assumptions: translation now in scope for User Guide
- Added Session 2026-05-18 clarification notes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses quality gaps identified in cross-platform audit vs meshtastic-apple:

nodes.md:
- Added 'Choosing a Role' guidance with practical use cases
- Added Client Hidden role (was missing)
- Added encryption indicator icons section with PKI explanation
- Added mesh topology tip (Router:Client ratio guidance)

settings-radio-user.md:
- Expanded modem preset table with SNR limits and km range estimates
- Added 'Choosing a Modem Preset' section with scenario-based guidance
- Clarified TX Power 0 = region max (not 0 dBm)
- Added warning about preset mismatch between nodes

messages-and-channels.md:
- Added delivery error codes table (10 errors with cause and fix)
- Expanded channel security to 4-level icon table with AES bit info
- Added tip about error self-resolution

tak.md:
- Added TAK Identity section (team/role/callsign)
- Added wire format V1/V2 comparison table
- Added troubleshooting table (5 common issues with solutions)

map-and-waypoints.md:
- Simplified confusing 'Boundary' expiration language
- Clarified expiration countdown starts at creation time

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Upgrades the Chirpy AI assistant for significantly better helpfulness:

- Add systemInstruction with rich Meshtastic-knowledgeable persona
- Add cloud model with Tool.googleSearch() for web-grounded answers
  (accesses meshtastic.org and community content when online)
- Implement on-device → cloud fallback cascade:
  1. Try on-device first (fast, private, offline)
  2. If answer seems insufficient, fall back to cloud with grounding
- Update isSupported() to always return true on Google flavor
  (cloud model is always available even without AICore)
- Remove overly restrictive 'if not in docs, refuse' behavior
- System prompt now encourages using training knowledge about
  meshtastic.org when bundled docs don't cover the topic

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Upgrade model from gemini-2.5-flash-lite to gemini-3.1-flash-lite
  (latest stable, released 2026-05-07, free tier, improved quality)
- Add Tool.urlContext() alongside Google Search grounding so Chirpy
  can directly access meshtastic.org/docs when cloud inference is used
- Append meshtastic.org URL hint to cloud-grounded prompts for
  better URL context tool activation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace Tool.googleSearch() with Tool.urlContext() so Chirpy only
fetches content from explicitly-provided official URLs:
- meshtastic.org/docs
- github.com/meshtastic/Meshtastic-Android
- github.com/meshtastic/firmware

This prevents the model from pulling context from random forums,
blogs, or third-party sites that may contain outdated or incorrect
information. The system instruction also explicitly forbids citing
non-official sources.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use model.startChat() + chat.sendMessage() so Chirpy maintains full
conversation history across messages. This enables natural follow-up
questions like 'can you explain that more?' or 'what about X?'

Architecture:
- First message: try on-device for speed, seed cloud chat session
- Subsequent messages: use cloud chat (has full conversation context)
- resetSession() clears the chat when opening a fresh conversation

Also adds resetSession() to AIDocAssistant interface (no-op on
keyword fallback platforms).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The usedOnDeviceModel field was hardcoded to false even when the
on-device model successfully generated the answer. Refactored
generateWithChat() to return a ChatResult data class that tracks
which model produced the answer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
InferenceMode.PREFER_ON_DEVICE silently falls back to cloud when
on-device isn't available, causing:
1. usedOnDeviceModel incorrectly reporting true (it was cloud)
2. Redundant cloud chat seeding call (double API usage)

Switch to ONLY_ON_DEVICE so failures are explicit — the caught
exception routes cleanly to the cloud chat path instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The docs screenshots use a markdown renderer that produces slight
pixel differences between macOS (local) and Linux (CI). Increase
tolerance from 0.05% to 0.5% to accommodate platform font rendering
differences while still catching meaningful visual regressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich force-pushed the feat/20260507-161858-app-docs-markdown branch from 172fdc7 to 2897b8b Compare May 19, 2026 03:05
Reference images for Chirpy and DocsPageContent screenshots were
generated on macOS, which uses different font metrics than Linux CI.
This caused 62% pixel differences due to text wrapping at different
character positions despite identical layout constraints.

Replace references with the CI-rendered actual images (verified visually
correct) so that validation matches the Linux rendering environment.
Revert threshold from 0.02f back to 0.0005f since references now match
the CI platform.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich force-pushed the feat/20260507-161858-app-docs-markdown branch from 90d2366 to a460211 Compare May 19, 2026 03:41
@jamesarich jamesarich added this pull request to the merge queue May 19, 2026
Merged via the queue into main with commit fc0df1a May 19, 2026
16 checks passed
@jamesarich jamesarich deleted the feat/20260507-161858-app-docs-markdown branch May 19, 2026 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Build system changes documentation Improvements or additions to documentation enhancement New feature or request repo Repository maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant