Skip to content

Replace bonsai-ui with logseq/lui - #10

Merged
RCmerci merged 40 commits into
mainfrom
devin/lui-migration
Sep 24, 2026
Merged

RCmerci merged 40 commits into
mainfrom
devin/lui-migration

Conversation

@RCmerci

@RCmerci RCmerci commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Replaces the bonsai-ui stack (Jane Street Bonsai, bonsai_swiftui*, bonsai_flutter, and the BonsaiSwiftUI host) with logseq/lui end to end: OCaml app layer, worker service, native bridge, Apple host, Flutter host, build configuration, and tests. Application logic and user-facing behavior are intended to remain unchanged; this is a rendering/runtime-architecture swap.

OCaml app layer

  • app/application.ml{,i} now runs as a Lui_app reducer app. Bonsai primitives are mapped structurally: edge callbacks, clock/effect scheduling, platform request/response tracking, and serialized dispatch.
  • app/journal_view.ml{,i} provides the compatibility shim over Lui_elements/Lui_ui used by the existing screen code.
  • New runtime modules cover the C bridge, worker pump, environment snapshots, native extension registry/fingerprints, and IDs previously supplied by bonsai_swiftui_spec.

Platform hosts

  • swift/ hosts the app through LUIAppleBackend; the root is wrapped in NavigationStack so toolbar nodes with explicit placement hoist into native iOS/macOS chrome. The iOS detail and timeline bars now use system toolbar items and fused capsules matching the previous app.
  • flutter/ hosts the app through lui_flutter_backend with journal extension renderers, native asset linking, environment push, and notices.
  • Build scripts produce macOS and iOS simulator apps directly; iOS simulator builds embed __TEXT,__entitlements so keychain-backed auth works with ad-hoc signing.

Compatibility fixes verified on iOS simulator

  • Startup reaches real timeline data on ocaml-sync-test: download, E2EE unlock, list rendering, detail navigation, menus, and capture surfaces were exercised.
  • Fixed worker→UI wakeups, mount echo/remount loops, schema violations previously swallowed by the bridge, visible-range feedback storms, icon-only control labels, toolbar placement, and native toolbar capsule rendering.
  • dune build and dune runtest are green on the 5.5.0 switch.

The journal pin currently tracks logseq/lui@9181a9f2fada60af325a200be0dc94b6241fe85a, pending logseq/lui#24.

Link to Devin session: https://app.devin.ai/sessions/5e3c7830582348419f3eedb3d505df6e
Open in Devin Desktop: https://app.devin.ai/desktop/session/5e3c7830582348419f3eedb3d505df6e?variant=devin
Requested by: @RCmerci

RCmerci and others added 16 commits September 22, 2026 18:39
… registry, native bridge)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Mechanical port of bonsai-ui ocaml/runtime worker stack:
- journal_bounded_mailbox / journal_worker_eio_backend: verbatim copies
- journal_worker_runtime: Worker.Private -> Journal_worker.Private,
  Worker_eio_backend -> Journal_worker_eio_backend, ID = Journal_worker_ids
- journal_worker: same renames; subscribers are plain event -> unit
  callbacks; drain_to_effects ~schedule -> deliver (invokes subscribers
  directly on the app thread)
- journal_worker_ids: add Int64_id/Int_id/String_id module types
  required by the existing .mli

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- journal_view: Bonsai_swiftui_ui-shaped shim over Lui_elements
- journal_ids/journal_environment: Id and Environment replacements
- journal_platform: LJP2 codec + env-push (24) + notice (25/26/27) envelopes
- journal_bridge/journal_lui_bridge.c: lui_ocaml bridge + startup payload
- journal_lui_native/journal_pump: extension registry + cross-thread pump
- Rename Ui/ID/Environment/Graph_service references across app modules
- Drop logseq_db_worker/bonsai in favor of logseq_db_worker/lui

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- pubspec: drop bonsai_flutter/bonsai_flutter_native for lui_flutter_backend
  (git dep pinned to the opam pin) + vendored journal_lui_native hook
  package that links the OCaml complete object (lui_ocaml_* +
  journal_ocaml_* exports from journal_lui_bridge.c)
- main.dart: JournalRuntimeOwner owns JournalOcamlBridge + LUIFlutterBackend;
  patch callback applies LUI batches, LUIEvents forward to lui_ocaml_*
  entries, extension events to journal_ocaml_extension_event, wakeup
  schedules journal_ocaml_pump on the UI isolate, LJP2 platform channel
  bridged both directions, environment pushed as tag-24 envelopes, and
  notices resolve through a ScaffoldMessenger sink (tags 25/26/27)
- extension registry: journal-chrome/-asset-import/-media/-asset-settings/
  -list registered with fingerprints matching journal_lui_native.ml;
  renderers ported (grouped list with scroll requests, visible-range
  tracking, swipe + context-menu rows, disclosure expansion)
- adapter: bonsai interfaces replaced with JournalPlatformServices/
  JournalHostAdapter; LJP2 codec unchanged, tags 24-27 added
- Runner configs renamed off bonsai artifacts; bonsai-flutter.sexp and
  bonsai-bound renderers/tests removed

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- test_bonsai_service.ml renamed to test_lui_service.ml and re-pointed to
  Logseq_db_worker_lui.Logseq_db_worker_lui_service, Journal_worker,
  Journal_worker_runtime, Journal_worker_ids
- test_managed_sync_e2e.ml re-pointed to the same lui modules
- dune: drop bonsai_swiftui.driver, bonsai_swiftui_test, logseq_db_worker.bonsai;
  add logseq_db_worker.lui

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Re-point service imports to Logseq_db_worker_lui service in startup_test,
  application_view_test, journal_media*_test, journal_uploads_test
- journal_adaptive_test: assert symbol identity via Journal_symbols.name and
  Journal_view.View.For_testing.key; decode Style.Color channels through
  ordered public rgb probes (shim has no to_argb32/view introspection)
- journal_semantics_test: keep only test_timeline_media_targets (pure
  Journal_row.view); the remaining cases drove the removed
  bonsai_swiftui_test mounted-tree harness and cannot port
- journal_routes_test, journal_timeline_state_test: Journal_ids/Journal_view
  renames; drop Hidden_target (no such lui outcome)
- macos_mutation_input_diagnostics_pure_reducer_test: same renames (unwired)
- source_boundary_test: lui service paths, lui/ocaml-signal opam pins,
  Journal_platform.show_notice_request; drop sexp manifest assertions
- test/dune: drop all bonsai_swiftui* library entries and the
  bonsai-swiftui.sexp dep
- Remove bonsai-swiftui.sexp and bonsai-flutter.sexp manifests
- Delete test/macos_application_dispatch_test.ml: every case depended on
  the removed Bonsai test handle/mounted-tree harness
- Finish test_lui_service.ml renames left unstaged

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Allow the new flutter/lib files landed by the lui_flutter_backend port,
permit showModalBottomSheet/Image.file used by the new host, and stop
requiring the removed flutter integration test

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ol test env names

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- swift/: JournalRuntime owns the LUIAppleBackend + OCaml runtime (5-arg
  lui_ocaml_start with the LDB1 startup payload), patch callback applies
  backend.apply, wakeup pumps on MainActor, platform requests marshal off
  the OCaml worker thread and return via journal_ocaml_platform_response.
- JournalRuntimeHost is the shared SwiftUI host view (app scene + apple-tests
  harnesses): LUISwiftUIRoot + tag-24 environment pushes + tag-25/26/27
  notice presentation through JournalApplicationPlatform.
- JournalExtensions: one LUIAppleExtension per journal identifier (chrome,
  asset-import, media, asset-settings, list) with reproduced schema
  fingerprints; JournalList implements the journal-list payload/event
  contract (grouped sections, disclosure rows, visible-range, scroll
  completion, swipe/context actions, expanded + row events).
- swift/Package.swift declares the JournalApp executable on
  LUIAppleBackendStatic + amplify-swift 2.61.0 with native link inputs from
  tool/build_journal_apple.sh; apple/Info.plist carries the sexp's bundle
  config; the script compiles journal_lui_bridge.c, links the complete OCaml
  object (or a link-validation stub), and assembles a signed .app.
- apple-tests: OCaml probes rewritten as Lui_app signal+update fixtures
  self-registering Journal_bridge.hooks; Swift acceptance sources use
  JournalRuntimeHost/JournalApplicationPlatform observation hooks instead
  of BonsaiApplicationView/Bridge/Events/NativeViews; probe harnesses now
  stage swift/ overlays through tool/lui_probe_host.py.
- Removed bonsai-swiftui.sexp and swift-packages/Package.resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The upstream app-test port removed macos_application_dispatch_test.ml and
the bonsai_swiftui_test support library; the remaining mutation cases now
load the lui package and use the Journal_view/Journal_ids shims. Also
removes swift-packages/Package.resolved, superseded by
swift/Package.swift.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Replace Bonsai.Cont/component with a Lui_app.reducer_app: state record +
  action variant (Update | Platform_response | Environment_changed),
  update reducer, and a view built via Lui_elements.dyn.
- Shim Bonsai.Effect as unit -> 'a thunks; send/set_state/set_state_and_effect
  route through Lui_app.send with a pending_actions queue because
  ocaml-signal updates are not reentrant.
- Replicate Edge.on_change edges (feed, timeline presentation, drains,
  upload/media, notice, delete timer, sync-error timer) as post-update
  key diffs; Clock.until/every become generation-guarded timer threads
  that enqueue through Journal_pump.
- Platform.request continuations become a pending_platform table keyed
  by LJP2 response tag; platform_event hook decodes tag-24 environment
  snapshots into Environment_changed.
- native_hooks : Journal_bridge.hooks wires init/dispatch/extension_event/
  pump/platform_event/platform_response/dispose/root_node; config arrives
  via init payload (unchanged C ABI).
- Add Journal_view.mount accessor so the reducer view can return
  Lui_elements.t.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ui_app host

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

RCmerci and others added 2 commits September 22, 2026 20:44
…link flags

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…p bundle layout/entitlements

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

iOS Simulator smoke test: app boots + renders via lui, but stalls at "Opening journal" — blocks sign-in

Tested dune build @ios-app output plus unsigned variants on iOS 27.0 sim, iOS 26.5 sim, and the native macOS app. The LUIAppleBackend patch pipeline works — the OCaml Graph_opening busy screen renders on all three — but the app never advances past it (0% CPU, indefinite). The OCaml worker domain parks in eio iomux_poll on internal fds only; instrumented LJP2 logging shows zero platform requests, zero wakeups, zero disk/network I/O — the stall is inside OCaml worker startup before the first platform request, and reproduces identically on macOS with the real object, so it's shared code, not a sim artifact.

Two build issues also found: (1) ANY codesign --entitlements blob makes the binary unlaunchable on the iOS 27.0 sim ("No such process") — only unsigned/plain-adhoc binaries exec, so the @ios-app artifact can't be launched as produced; (2) the macOS app was signed with literal $(VARS) keychain entitlements → killed at exec.

iOS 26.5 stall macOS stall

Golden path (sign-in → E2EE → timeline → capture) is unreachable until the stall is fixed. Recording: https://app.devin.ai/api/presigned_proxy?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOiJvcmctZjZmZDVmNzI0MzlkNDlmZmJmY2QxYWQ2NTMwNjdhZTMiLCJ1c2VyX2lkIjpudWxsLCJidWNrZXRfbmFtZSI6ImRldmluYXR0YWNobWVudHMiLCJidWNrZXRfa2V5IjoiYXR0YWNobWVudHNfcHJpdmF0ZS9vcmctZjZmZDVmNzI0MzlkNDlmZmJmY2QxYWQ2NTMwNjdhZTMvN2U3ZjhjNTEtZDBhNS00NDAzLTk2ZDItNDM3MTdiNWVmNDExIiwiaWF0IjoxNzkwMTM3ODM5LCJleHAiOjE3OTA3NDI2MzksImZpbGVuYW1lIjoiam91cm5hbC1sdWktaW9zLXNpbS1zdGFsbC1lZGl0ZWQubXA0In0.ET2OWFhUxoB9QQKg5xRLpyffbeMBquChT5GLYYMyqPE

RCmerci and others added 4 commits September 22, 2026 21:31
…dhoc sign on iOS sim (iOS 27 rejects any entitlements blob)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The app parked on 'Opening journal' because mount-time exceptions raised
inside the C bridge's patch emission were dropped silently. Fixes:

- Wrap composed control labels in leaf properties: Button, Toggle,
  NavigationLink, Picker options, and Menu items are leaf host kinds that
  only accept ContextMenu children; their title/icon now travel as
  TextValue/InlineIconName props (label_content side-channel on the view
  record preserves the existing ~child/~label APIs and test ids).
- Rewrite Menu to the lui dropdown model (menu_item + dropdown_menu
  children) with a title/icon API instead of composed label elements.
- Mount toolbar items under a plain row (Toolbar kind accepts only fixed
  control children and no extensions) and guard placement/spacing hint
  props by node kind.
- Register journal SF Symbol names as app:<slug> icons via
  LUIAppleBackend appIcons (swift/JournalIcons.swift).
- Guard standard props on non-standard nodes: extension and placeholder
  nodes skip accessibility/frame/padding/semantics props via a shared
  node_is_standard check.
- Declare journal extension child schemas on both OCaml and Swift sides
  so extensions can nest.
- Surface startup exceptions on stderr instead of letting the bridge
  swallow them.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The old bridge surfaced platform request failures to OCaml; the ported
path returned nil from JournalApplicationPlatform.request and dropped it
in deliverPlatformRequest, leaving the pending continuation parked
indefinitely. On the iOS simulator the startup localAccount keychain read
fails (errSecMissingEntitlement on unentitled sim builds) and the app sat
on a blank screen forever; any keychain failure on a real device would
hit the same silent hang.

- journal_lui_bridge.c: new journal_ocaml_platform_failure entry that
  delivers the original request envelope back to OCaml.
- journal_bridge: platform_failure hook (OCaml resolves the pending
  continuation with Error via Platform_response under the response tag).
- application.ml: hoist response_tag to top level for the failure hook.
- JournalRuntime.deliverPlatformRequest: nil response now reports the
  request as failed instead of being silently dropped.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ead-end signature

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Startup stall fixed + platform failure delivery restored (b957534, 5676639)

The app previously parked forever on "Opening journal": mount-time lui schema violations raised inside the C bridge's emit_patch, which silently dropped the exception and emitted a zero-length patch. Fixed by bringing the journal view into schema compliance (control labels as properties, Menu → menu_item+dropdown_menu, toolbar items under a row, app:-slug icons via JournalIcons.swift, extension child schemas declared on both sides, standard props skipped on extension nodes). Startup exceptions are now surfaced on stderr instead of being swallowed.

Second defect: JournalApplicationPlatform.request returned nil on any failure and deliverPlatformRequest dropped it — a migrated regression vs the old bridge, which surfaced request errors to OCaml. Any platform request failure (e.g. keychain -34018) left the OCaml continuation parked → blank screen forever. journal_ocaml_platform_failure now round-trips the request envelope so OCaml resolves the continuation with Error, matching the old semantics.

iOS Simulator verification (iOS 27.0 + 26.5, adhoc builds)

  • Failure delivery verified: localAccount + authenticatedUser errors resolve OCaml continuations; app settles idle — no hang.
  • The sim still lands on a blank dead-end on the all-failures path — but this is parity, not a regression: JournalChrome on main has the same strict child-count guards (count == 3/4 → EmptyView), and OCaml ignores request Error results the same way, so the old stack dead-ends identically on an unentitled sim.
  • With a (reverted) test-only keychain patch the full auth UI proved functional on iOS: sign-in sheet auto-presents, typing/submit/error-surfacing/sheet-nav all work.
  • Real sign-in can't complete on this machine: unentitled sim binaries get -34018 on every keychain read and no entitled binary can exec there; macOS adhoc hits the same Amplify wall. Needs a signing identity or a device.

Two non-blocking observations: ~25–30k wakeup callbacks in the first ~40s of launch (MainActor task flood delays the first platform request ~25s, then settles to 0% CPU); iOS 27 sims reject any codesign --entitlements blob at exec (build now uses plain-adhoc).

Written by Devin

RCmerci and others added 3 commits September 22, 2026 23:44
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…a compliance

Worker->UI wakeup: replace the OCaml Condition waiter thread with a
set_output_wakeup hook fired on the producing domain. The waiter deadlocked
on iOS: while holding the shared output mutex it blocked re-acquiring its
domain lock, which the UI thread holds inside CFRunLoop — download appeared
stuck.

Render loop: Lui_elements.dyn remounts the whole tree on every publish.
Gate republish behind Signal.cutoff (==) and stop feeding mount-time echoes
back into the model — Editor.apply_text_edit returns None for identical
documents, the e2ee field and asset-settings refresh bail out when the new
value is physically/equal to the old.

Schema compliance (violations were swallowed by the C emit bridge and left
blank screens):
- Navigation_link list-item mounts its label as a child (schema requires
  text or children) and sets press-enabled so rows actually dispatch
- toolbar role/variant hints limited to schema-representable values
- back-button variant 'plain' -> 'ghost'
- journal-media/journal-list declare standard children + extension children
  whitelists (OCaml/Swift/Flutter fingerprints in sync); JournalMedia now
  renders context.content
- journal-chrome positional slots mount placeholder columns so the native
  child-index contract (feedback:3, journal:4) holds when a slot is empty

iOS sim: embed entitlements via __TEXT,__entitlements at link time (the
sim reads entitlements from the section, not the signature) so keychain
works under adhoc signing.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
RCmerci and others added 15 commits September 23, 2026 03:55
…ime gotchas

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Every caml_callback*_exn result that failed with Is_exception_result was
silently dropped: emit_patch returned 0, lui_ocaml_root_node returned 0,
and deliver_platform ignored the result value entirely. When OCaml threw
(e.g. schema validation errors on unsupported property values or child
kinds) the patch stream truncated silently and the host rendered a blank
or half-blank screen with zero diagnostic output.

Add report_ocaml_exception(), which formats the exception with
caml_format_exception(Extract_exception(result)) and fprintf()s it to
stderr tagged with the callback name, so the message reaches the app's
stderr/simctl launch --console-pty log. Return contracts are unchanged:
callers still get the same failure code; the exception is no longer
swallowed.
Parity pass against the recorded bonsai build, confined to the shim and
host Swift:

- Section.create emits a heading + plain column card as direct list
  children so LUIListView groups them natively (panel/card kinds overlay
  children in a ZStack, which stacked the unlock texts).
- Menu/toolbar/dock and capsule rows pin cross=center + measured widths
  so rows center instead of stretching half the bounded column.
- content_unavailable centers deterministically (growing column +
  spacers + centered label/description/actions).
- Navigation_link rows carry a trailing chevron icon to match
  NavigationLink's disclosure accessory.
- Icon-only mounts get a uniform 40pt control width; icon-only
  button/menu-item labels stay on the a11y channel.
- SectionDate uses an explicit label color: .primary inside a List
  section header resolves to adaptive gray on iOS 26.
- Asset-import button shows icon-only; asset-settings root column fills
  the viewport and anchors top; new SF Symbol slugs registered.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Drop the emulated '‹ Logseq Journal' back-link row: the system nav bar
  renders nothing for an empty title, so the shim's extra row had no old
  counterpart and pushed the nav row down.
- Emit size="sm" on icon-only menu triggers (person icon, overflow …) so
  the glyph matches the old 16pt menu-item icon.
- Replace .scrollPosition (two-way binding) with a ScrollViewReader +
  scrollTo for one-shot scroll requests.
- Defer onAppear/onDisappear @State writes off the layout pass and
  debounce visible_range emits (80ms): a boundary row flickering during
  layout previously emitted a range oscillation that fed patches back and
  pinned the main thread at 100% CPU.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
mount_icon_only recorded one boolean and then pinned the item's top
mounted node to 40pt, which mis-measured two cases: a Toolbar.group
mounts a row of controls (the row itself got the icon width while its
leaves stayed unsized), and a text button ("Save", "Close") is not
collapsed at all yet still inherits a fixed-width capsule.

set_leaf_label now collects each leaf that actually fell back to its
icon (icon_only_collapsed_nodes), mount_icon_only applies width=40 to
just those leaves, and capsule drops its pinned
width = 12 + 56*children_count so the pill hugs its content like the
bonsai chrome bar did.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…tem size)

The previous pin at 38096c4 only covered PR #9; the icon-size wire
property (logseq/lui#11) and the UIActivityIndicatorView spinner
(logseq/lui#10) merged after it, and the icon trigger cells rely on
menu-item size.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Latest lui maps a variantless button to .bordered (standard iOS
chrome), which drew accent-colored button chrome inside the chrome
capsules. Icon-collapsed bar controls and the back circle button now
opt into variant=ghost + secondary foreground so they stay plain dark
glyphs inside the pill.
Bottom-bar items that contain only controls now mount inside a lui
toolbar node (the schema semantic for a control bar), wrapped in a box
carrying the pill chrome. A row wrapper would auto-append a trailing
spacer and stretch the capsule full width; a box hugs its content, so
the pills stay compact. Groups mount their children flat into the
enclosing toolbar since a wrapper row is not a legal toolbar child and
a button-group would likewise stretch.
Fixes the timeline scroll regression: dyn branches previously dropped
and recreated their whole subtree on every publish, which destroyed the
journal-list UICollectionView and snapped scroll position to the top
continuously. With reconcile, same-kind nodes keep their ids so the
list survives patches.
Replaces the pre-merge pin 271fe33 with the squash-merged main commit.
Same fix: dyn branches reconcile instead of drop+create, so the
journal-list collection view survives publishes and timeline scrolling
works.
@RCmerci
RCmerci merged commit b0931d2 into main Sep 24, 2026
1 check 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.

1 participant