Skip to content

Merge 3.0.34 into 4.0 - #26

Closed
antobinary wants to merge 160 commits into
v4.0.x-developfrom
merge-3.0.34-into-4.0
Closed

antobinary wants to merge 160 commits into
v4.0.x-developfrom
merge-3.0.34-into-4.0

Conversation

@antobinary

@antobinary antobinary commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Merging BBB 3.0.34 into v4.0.x-develop — report

Branch

antobinary/merge-3.0.34-into-4.0https://github.com/antobinary/bigbluebutton/pull/new/merge-3.0.34-into-4.0

12b399c8fb  fix(test): drop duplicate symbols the 3.0 merge appended to the playwright suite
406288d2e5  revert(plugins): drop the 3.0 use-timer data-consumption hook on 4.0
119e7baa03  fix(webcam): adapt 3.0 camera-dock grid snapping to the 4.0 layout set
16c50a0367  Merge tag 'v3.0.34' into v4.0.x-develop

Scope: 86 commits / 15 PRs since the 3.0.33 merge base, 92 files. 68 of those 92 files had also been changed on 4.0 — 74% genuine divergence.

The 21 conflicts

# File Resolution
1 bigbluebutton-release 4.0 (kept 4.0.0-beta.5-wip)
2 .gitlab-ci.yml 4.0 build image
3–4 akka-*/Dependencies.scala 4.0 — comment-only reword, versions auto-merged
5 bbb-recording-imex/pom.xml stays deleted — module removed in 4.0; 3.0 side was a dependabot bump
6 bigbluebutton.properties 4.0 — html5PluginSdkVersion 0.1.24 (4.0 is on the 0.1.x SDK line, 3.0 on 0.0.x)
7 VoiceApp.scala both — 3.0's orphaned-voice-join fencing + 4.0's userRole lookup, which the merged call still consumes
8 ApiController.groovy both — 4.0's XML/URL validation gate on top of 3.0's async upload pipeline
9 external-video component 3.0 wholesale — 4.0 had no autoplay-mute recovery
10–11 html5 package.json + lock regenerated
12–14 it_IT/ja/zh_TW per-key three-way merge
15–16 playwright sharednotes .ts/.spec.ts 4.0 — superset; differences are 4.0 selector renames
17–20 4 docs files mixed, see below
21 docs/package-lock.json regenerated

Lockfiles. Taking either side wholesale was wrong in both directions: 4.0's lock silently dropped seven 3.0 security bumps, while 3.0's lock regressed 287 docs packages. I started from 4.0's and npm update'd only the affected transitive packages — fast-uri (html5) and body-parser, fast-uri, js-yaml, nanoid, postcss, shell-quote (docs). Both locks are now >= each side on every package, and neither package.json was modified.

Locales. The obvious rule ("changed on both sides → keep 4.0") was wrong: 22 keys per file were keys new in both, where 4.0 seeds the English source string and 3.0 carries the real translation. Using en.json as the reference, those 22 took the translation.

Docs. new-features.md is a curated 4.0 rewrite (335 lines vs 3.0's 589), and the 3.0 topics are already covered elsewhere in the 4.0 tree — so 4.0 for the structural hunks. But I ported the two 3.0.33 feature sections (BlockNote Markdown import/export, Panopto) that 4.0 documents nowhere, with the defaults corrected: 3.0 says "disabled by default", 4.0 ships both toggles true.

Re-implementations (separate commits)

CUSTOM_LAYOUT — 3.0's grid-snapping references LAYOUT_TYPE.CUSTOM_LAYOUT, which 4.0 deleted. Kept the intent: of the layouts 4.0 still has, UNIFIED_LAYOUT is the grid one.

use-timer plugin hook — merges textually but needs TimerData and DataConsumptionHooks.TIMER, which exist only on the 0.0.x SDK line. I checked the published SDK: neither 0.1.24 nor 0.1.25 (latest 0.1.x) declares TIMER. There is no version to bump to, and 0.0.104 would drag 4.0's plugin API back to 3.0. Removed the client half rather than leave 4.0 unbuildable — it needs a real SDK-side port.

Build from source — everything compiles

Component Result
bbb-common-message (sbt) PASS
bbb-common-web (sbt) PASS
akka-bbb-apps (sbt compile) PASS — validates VoiceApp.scala
bigbluebutton-web (gradle compileGroovy) PASS — validates ApiController.groovy
html5 client (webpack) PASS → deployed as b7b77b67fe9b485f5967
tsc --noEmit clean

I installed sbt in the container and published the SNAPSHOT artifacts via publishM2 (gradle uses mavenLocal(); publishLocal writes to Ivy, which is why the first attempt failed). Pre-merge client backup kept at /root/html5-client.backup-merge3034.

Playwright: 315 passed / 29 failed / 17 skipped — 0 regressions

I ran the project's own CI gate (--grep @ci --grep-invert '@flaky|@need-update|...'), then built the exact pre-merge client (e1e3f4d8...) in a worktree, deployed it, and re-ran the failing areas to attribute every failure:

Fail on both merged and pre-merge 25 — pre-existing in this environment
Fail only after the merge 4 (chat) — flaky: all pass in isolation, and the full chat spec re-runs 27/27
Fail only pre-merge 1fixed by the merge: "No blank presentation area on slide change with a cold cache", i.e. 3.0's decode-gate work landing correctly

Two caveats on the numbers: an early run showed 23/24 shared-notes failures purely because bbb-shared-notes-server was inactive (started it → 24/24). And this container's .env secret is stale — the live one is YvuMwv...; I overrode it per-run rather than edit the file.

The thing that actually worries me

The conflict list was not the risk surface. All 21 conflicts were resolvable and none of them broke anything. What broke the build were two files git merged cleanly:

  • sharednotes/blocknote/util.ts — 3.0's backport appended its own startSharedNotesBlockNote and getBlockNoteReadOnlyLocator to a file that already had both. The 3.0 copies call e.sharedNotes, which doesn't exist in 4.0's elements.ts at all.
  • whiteboard.spec.tsimport { linkIssue } landed twice.

Duplicate top-level declarations are a hard SyntaxError for the Playwright loader: the entire suite collected 0 tests in 0 files. Not "the shared-notes tests failed" — every spec failed to import. Nothing in git's output hinted at it, because the additions were textually far apart.

This is the same failure mode as 5840bc2984 ("restore BlockNote shared-notes helpers dropped in 3.0->4.0 merge") from the previous 3.0 merge. It has now happened twice.

Merge vs. replay — recommendation

Keep merging, but change what happens after the merge.

The decisive argument is ancestry. A merge advances the merge base, so the next 3.0→4.0 merge only considers genuinely new commits. Replaying doesn't record that: git would re-present the same 86 commits forever, and the usual escape hatch (git cherry / patch-id) breaks precisely on the commits you had to adapt — the adaptation changes the patch-id, so the tool stops recognising them as applied. Given 74% file-level divergence, you'd be adapting a lot, so you'd be poisoning the detector on exactly the commits that matter. That cost compounds every release; the merge's cost does not.

Replay's real advantage is reviewability, and you can have that without giving up ancestry — which is what I did here: mechanical resolution in the merge commit, every judgement call in its own follow-up commit with the reasoning in the message. A reviewer can read three small commits instead of auditing a 57-file merge blob.

Replay only wins where a 3.0 PR shouldn't exist on 4.0 at all. The use-timer hook is the case in point: replay would simply skip it, whereas merging forced me to merge-then-revert. That's one PR out of fifteen — not enough to change the strategy, and the revert commit documents the decision better than a silent omission would.

So, two concrete process changes:

1. A post-merge gate, because the conflict list lies. Cheapest first: npx playwright test --list takes seconds and would have caught both fatal duplicates immediately. Then tsc --noEmit on the client and the playwright project (that's what caught CUSTOM_LAYOUT and the SDK mismatch), sbt compile + gradle compileGroovy, and a lockfile diff against both parents. None of these are in CI for merge commits today, as far as I can tell.

2. Fix the upstream cause of the duplicates. Both incidents come from the same pattern: a 4.0-originated test file backported to 3.0 with renamed selectors, then merged forward. Either keep backports symbol-identical to the 4.0 original, or put 3.0-specific adaptations in a 3.0-only file that has no forward-merge counterpart. Otherwise this recurs every release, and it's a silent, total test-suite outage each time.

One caveat worth flagging rather than burying: new-features.md is release-line-specific prose, and I made editorial calls a mechanical merge can't justify. That file deserves a docs-team pass before this merges.

Tainan404 and others added 30 commits June 15, 2026 18:40
When cameraSortingModes.showAudioOnlyOnFirstPage is enabled, audio-only tiles
(camera-less users that have taken the floor) were displayed to moderators but
not to attendees. Moderators are unpaginated by default
(pagination.desktopPageSizes.moderator = 0) and add audio-only tiles via the
non-paginated path; attendees are paginated (viewer = 5) and, when
partitionPrivilegedStreams is false, ran the !partitionPrivilegedStreams branch
of useVideoStreams, which paginated camera streams but never added audio-only
tiles.

Add audio-only tile handling to that branch, mirroring the partitioned and the
non-paginated paths (reserve first-page slots, shift later pages, keep
off-page local cameras rendered), so audio-only tiles surface on the first
page for viewers too. Adds a Playwright regression test asserting audio-only
tile parity between a moderator and an attendee.

Refs: bigbluebutton#25242

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion modes

Addresses PR review feedback for bigbluebutton#25242:

- Extract reserveAudioOnlyTiles() and use it from both the partitionPrivilegedStreams
  true and false branches, removing the duplicated (and previously divergent) audio-only
  reservation logic and the dead `|| []` after Array.prototype.slice. The two pagination
  modes now share a single implementation, parameterized by reservedCount (pinned + local
  cameras), so they can no longer drift apart.
- Share the audio-only tile locator between the audio-only e2e tests via a new
  audioOnlyTilesLocator() helper in user/util.ts.
- Correct the audioOnlyTileVisibleForAttendee comment so it no longer overstates coverage:
  the regression lives in the partitionPrivilegedStreams=false branch, which is config-only
  (no per-meeting/userdata override), so the test asserts the moderator/attendee parity
  invariant and exercises the regression when the server runs partitionPrivilegedStreams=false.

Validated: audio-only e2e tests green under both partitionPrivilegedStreams=true (default,
no regression) and =false (the fixed branch).

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…verride

Addresses review on bigbluebutton#25284. The audio-only-tile parity test passed on the
default config regardless of the fix, since partitionPrivilegedStreams is
config-only with no per-meeting/userdata override.

Add a reusable `clientSettingsOverrides` option to page init that patches
`window.meetingClientSettings` before the client reads it (addInitScript +
accessor + deep-merge), and use it to force `partitionPrivilegedStreams: false`
and `showAudioOnlyOnFirstPage: true` so the test deterministically reproduces
the regression. Annotate the test with linkIssue(25242).
…-grid-audio-only-tiles-attendees

# Conflicts:
#	bigbluebutton-html5/imports/ui/components/video-provider/hooks/index.ts
The apps gallery drifted from the latest design proposal and broke at
minimum sidebar width: the two fixed grid columns left tiles too
narrow, so the NEW label overlapped the app icon and titles truncated,
and the search input refused to shrink.

Align the panel with the latest mocks and make it responsive:
- restyle the NEW label as a small semibold pill anchored to the tile's
  top-left corner (RTL-aware) instead of rendering it inline in the
  card flow
- use a rounded-square (8px) app icon container instead of a circle
- update tile geometry to the spec (1rem border radius, 2rem 1rem
  padding, 1rem gaps)
- let the grid adapt its column count (auto-fill, minmax 10rem) and
  allow the search input to shrink, fixing the min-width overflow
- stretch the section separator to the full content width
…#25165)

Backport of bigbluebutton#25165 (merged on v4.0.x-develop) to v3.0.x-develop, bringing the
BlockNote shared-notes e2e coverage to the 3.0 line.

Cherry-picked a9c0cd5 with two conflicts resolved:
- core/elements.ts: added the BlockNote selectors block at the shared-notes
  export insertion point.
- sharednotes/blocknote/util.ts (add/add): merged the new 4.0 helpers
  (startSharedNotesBlockNote, getBlockNoteReadOnlyLocator) with the existing 3.0
  helpers already present from bigbluebutton#25225, keeping a single getBlockNoteEditorLocator.

3.0 adaptations in sharednotes.ts for element renames that only exist on 4.0:
- sharedNotesSidebarButton to sharedNotes
- messagesSidebarButton to chatButton
- lock flow uses manageUsers + lockViewersButton (the 3.0 lock modal has no
  participant permissions tab)
- make-presenter uses userListItem instead of usersListSidebarButton +
  moreOptionsUserItemButton

The "Pin and unpin notes onto whiteboard" scenario is marked fixme on 3.0: a
viewer whiteboard does not re-sync to the presenter presentation state after the
presenter unpins shared notes (the canvas is not restored). That sync behavior
only exists on 4.0.
…ton#25448)

Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.24.9 to 7.29.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.6/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 7.29.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bump the pinned tomcat-embed override from 10.1.55 to 10.1.56.
Bump the managed Spring Boot version from 3.5.14 to 3.5.16.
bbb-apps-akka and bbb-fsesl-akka:
- jackson 2.13.5 -> 2.18.9, aligned across the suite via dependencyOverrides
- pin netty to 4.1.135.Final via dependencyOverrides (transitive)
- logback 1.2.13 -> 1.5.38, with slf4j-api pinned to 2.0.17
- commons-lang3 3.12.0 -> 3.18.0
- postgresql 42.5.0 -> 42.7.13 (bbb-apps-akka only)
Updated versions of Netty, PostgreSQL, Spring Framework, Jackson BOM, Logback, and Spring Data BOM.
…165-to-v3.0

test: add BlockNote shared notes e2e tests (backport of bigbluebutton#25165)
Bumps [axios](https://github.com/axios/axios) from 1.16.0 to 1.18.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.16.0...v1.18.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.18.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
A two-column grid needs room for two legible tiles. On a narrow sidebar
the columns get too tight — the NEW label overlaps the app icon and
titles truncate — so grid view is not usable there.

Switch the gallery to the list view whenever the sidebar-content panel
is narrower than the grid's minimum width, following the design team's
narrow-width mock:
- derive the panel width from the layout context and force the list
  view below the threshold, while preserving the user's grid/list
  preference so grid returns once the panel is widened again
- keep the grid a fixed two columns, dropping the adaptive column count
  that still produced cramped tiles
- disable the grid toggle while the fallback is active: it stays greyed
  and non-interactive (aria-disabled, so its tooltip still shows) with a
  tooltip explaining why — "Not enough space for grid view — expand the
  panel to use it"
…npm_and_yarn/bbb-export-annotations/axios-1.18.0

build(deps): bump axios from 1.16.0 to 1.18.0 in /bbb-export-annotations
…igbluebutton#25465)

`bolder` is a relative keyword that is only valid on the font-weight
*property*, not the @font-face *descriptor*. Browsers discard the
invalid descriptor, so the SemiBold and SemiBoldItalic faces fell back
to weight 400/normal and collided with the Regular faces. Register them
at their correct absolute weight (600) instead.

Fixes SonarQube css:S8775 (At-rule descriptor values should be valid).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

Bumps [axios](https://github.com/axios/axios) from 1.16.1 to 1.18.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.16.1...v1.18.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.18.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
See docs of the package used to create random numbers (https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/RandomStringUtils.html#randomNumeric(int)) Each pos. in the created numeric string can be any valid digit (0-9) The result can be: 00000, 00001,..., 99999
When navigating between slides, the presentation area flashed white until
the new slide's background SVG loaded. The root cause was in the
[curPageId] effect in whiteboard/component.jsx, which ran the visible
page swap (cleanupStore + updateStore(bgShape) + setCurrentPage)
synchronously, mounting the new slide's tldraw background image-shape
before its SVG had been fetched/decoded. CSS does not paint a
background-image whose resource has not loaded, so the area went blank
until the asset arrived.

Defer the swap behind an Image.decode() gate (bounded by a 1500ms
timeout) so the previous slide stays painted until the new one is
paintable. The decode reuses the HTTP cache the forward prefetch already
warms (Auth.authenticateURL is idempotent, so the same URL hits the same
cache entry). A broken/401/malformed asset swallows the decode rejection
and degrades to applying the swap anyway - never worse than before.

Rapid navigation is protected by a staleness/unmount guard: a late decode
for an abandoned page cannot clobber the current one. The
getEditingShape().complete() guard from issue 25332 now runs at swap
moment, adjacent to the mutation it protects, preserving the crash fix.

Two e2e specs added: no-blank-on-slide-change (RED before the fix,
GREEN after) and broken-asset-degrades-without-hanging.

Closes bigbluebutton#25397

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
- Drop the !isMountedRef.current guard from applyPageSwap. isMountedRef is not
  a mount flag: it is set true only late, inside adjustCameraOnMount after
  camera calibration, and stays false if calibration rethrows on an invalid
  viewbox. Gating the swap on it permanently stranded a viewer whose slide
  changed during the calibration window (the effect never re-fires for that
  curPageId). The cancelled flag already covers unmount fully; also re-check
  tlEditorRef, which can be torn down between the decode starting and resolving.
- Add a .catch to the deferred swap so a throw in the store mutation is logged
  instead of escaping as an unhandled rejection (synchronously it reached
  ErrorBoundaryWithReload; inside the async .then there is no boundary).
- Clear the fallback timer on the decode-wins path (.finally) and release the
  detached decode Image on cleanup so rapid navigation does not pin in-flight
  SVGs.
- Make the decode timeout configurable via
  meetingClientSettings.public.whiteboard.slideSwapDecodeTimeoutMs (default 1500).
- Correct the comments: the no-asset branch is the missing-svgUrl case (not
  infinite whiteboard), and pin the assets/curPageId lock-step invariant.

Known limitation: on latency above the timeout the fallback fires before the
asset is paintable and the original flash still shows.
AtilaU19 and others added 28 commits August 3, 2026 16:16
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mobile early-return branch of useVideoStreams omitted overflowUsers,
making its inferred type GridItem[] | undefined and failing tsc where
VideoProviderProps requires GridItem[].
The html5 .eslintrc.js declares env: { es6: true }, which does not define
the globalThis global (it lands with es2020), and no-undef is only turned
off in the .ts/.tsx override. The same call in video-list/component.tsx
lints clean for that reason, this .jsx one did not.

Kept globalThis instead of switching back to window: SonarCloud flagged
the opposite on this line (Prefer globalThis over window).
…opyright-25431

refactor: remove deprecated copyright create parameter
The webVoice create parameter has been dead weight: its value was only
ever copied into UserSession.webvoiceconf (write-only, never read) and
used as a voice-conference collision key that duplicated the telVoice
check. When absent it silently fell back to telVoice, so it never
selected a distinct voice conference in practice.

Remove webVoice end to end:
- ApiParams.WEB_VOICE constant and its copy-param entry
- ParamsProcessorUtil read + telVoice fallback + Meeting.withWebVoice()
- Meeting.webVoice field, getter and builder support
- MeetingService.getNotEndedMeetingWithWebVoice and its create collision use
- UserSession.webvoiceconf write-only field and getter
- ApiController existingWebVoice collision branch and webvoiceconf writes
- orphan api2 VoiceProp2/Meeting2 (Meeting2 was never constructed)

Voice conference selection is unchanged: it continues to derive solely
from voiceBridge via telVoice, and the nonUniqueVoiceBridge collision
check remains intact through telVoice.

Closes bigbluebutton#25460

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
Cover the two behaviours the webVoice removal must preserve, against a
live server:
- a create that still passes a webVoice distinct from voiceBridge
  succeeds and ignores webVoice, so the returned voiceBridge (voiceConf)
  equals the requested voiceBridge (backward compatibility);
- two live meetings sharing a voiceBridge are still rejected with
  nonUniqueVoiceBridge (the collision check runs through telVoice, which
  is untouched).

The BBB API is XML based, so the helper requests application/xml
explicitly.

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
Document the create parameter removal alongside the other 4.0 removed
parameters in the API reference, following the existing entry style.

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
The webVoiceConf join parameter set a custom Asterisk voice extension
for the old Flash client. It has no code path reading it anywhere in
the codebase, and Asterisk was replaced by FreeSWITCH, so the parameter
has been inert for a long time. Remove its entry from the join API
reference and record the removal in the 4.0 changelog alongside the
create-side webVoice removal.

Co-authored-by: Tainan Felipe <tainanfelipe214@gmail.com>
…ue/275

fix(data-consumption): prevent hook usage counter from going negative
…oice-param-4.0

Remove obsolete webVoice create parameter
feat(mobile): mobile layout overhaul — paginated webcams, compact bars and responsive dialogs
…bluebutton#25571)

* docs: iteration doc sync for 3.0.33 (bigbluebutton#25568)

* docs: iteration doc sync for 3.0.33

Covers documentation-worthy changes on v3.0.x-release since the v3.0.32
tag that were not yet reflected in the docs:

- new-features.md: Panopto external video player; the new
  public.whiteboard.slideSwapDecodeTimeoutMs client setting; corrected the
  html5PluginSdkVersion line to 0.0.104; tagged
  maxSharedNotesInitialContentUrlPayloadSize with 3.0.33 and added
  numPresentationDownloadThreads to the bbb-web properties ledger.
- create.tsx: "(added 3.0.33)" on sharedNotesInitialContentMarkdown and
  sharedNotesInitialContentMarkdownUrl.
- api.md: the three shared-notes initial-content create parameters added to
  the "Updated in 3.0" list, tagged with the point release that shipped them.
- plugins.md: useTimer hook (plugin SDK 0.0.104) and the new senderRole
  field on useLoadedChatMessages.
- faq.md: external video line now mentions Panopto.
…speed (bigbluebutton#25546)

* fix(whiteboard): prevent stale self-updates from dropping frame name characters

* compare versions before preserving frame names

* fix frame rename
Every module pins sbt.version=1.10.7; the setup steps still said 1.6.2.
…-to-talk

chore: Enable push-to-talk feature in settings.yml
Mechanical merge of the 3.0 line (86 commits since the 3.0.33 merge base) into
4.0. 21 files conflicted; resolutions:

Version/build markers — kept 4.0
  bigbluebutton-config/bigbluebutton-release, .gitlab-ci.yml,
  bigbluebutton.properties + package.json (html5PluginSdkVersion: 4.0 is on the
  0.1.x SDK line, 3.0 on 0.0.x), akka Dependencies.scala (comment-only reword).

Removed in 4.0
  bbb-recording-imex/pom.xml — the module is gone from 4.0; the 3.0 side was
  only a dependabot logback bump, so it stays deleted.

Kept both sides
  VoiceApp.scala — 3.0's orphaned-voice-join fencing plus 4.0's userRole lookup,
    which the merged handleUserJoinedVoiceConfEvtMsg call still consumes.
  ApiController.groovy — 4.0's XML/URL validation gate
    (processValidatedRequestXmlModules) on top of 3.0's async upload pipeline
    (resolvePresentationFilename + submitPresentationTask + the
    "invalid_filename" insertDocument result).
  external-video component — took 3.0's autoplay-mute recovery wholesale; 4.0
    had none of it.
  docs/plugins.md — 4.0's Apps Gallery badge and 3.0's configurable button
    styles are independent additions at the same spot.

Lockfiles regenerated rather than hand-merged
  Started from 4.0's lock and reconciled against the merged manifests, then
  restored the 3.0 security bumps that taking 4.0's lock wholesale would have
  dropped: fast-uri (html5) and body-parser, fast-uri, js-yaml, nanoid, postcss,
  shell-quote (docs). Both locks are now >= each side on every package, and
  neither package.json was modified.

Locales (it_IT, ja, zh_TW) — per-key three-way merge
  4.0 seeds new keys with the English source string while 3.0 carries the real
  translations; 22 keys per file were English placeholders and took the 3.0
  translation.

Tests/docs — kept 4.0
  playwright sharednotes helpers (4.0 is a superset; the differences are 4.0
  selector renames), the 3.0-only test.fixme whose own comment says 4.0 passes,
  and new-features.md structural hunks (4.0's file is a curated rewrite and the
  3.0 topics are covered elsewhere in the 4.0 docs tree). Ported the two 3.0.33
  feature sections that 4.0 documents nowhere, with the defaults corrected —
  4.0 ships the Markdown toggles enabled.

Two 3.0 changes do not compile against 4.0 and are handled in follow-up
commits: the camera-dock grid snapping references LAYOUT_TYPE.CUSTOM_LAYOUT,
and the use-timer plugin hook needs SDK APIs the 0.1.x line does not have.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.0's "grid-aware resize snapping in camera dock" (919ff6a) snaps the camera
dock to the grid in the two layouts where the cameras are laid out as a grid:

    const snapToCameraGrid = selectedLayout === LAYOUT_TYPE.CUSTOM_LAYOUT
      || selectedLayout === LAYOUT_TYPE.UNIFIED_LAYOUT;

4.0 removed CUSTOM_LAYOUT from LAYOUT_TYPE (layout/enums.js now has
UNIFIED_LAYOUT plus the CAMERAS_ONLY / PRESENTATION_ONLY /
PARTICIPANTS_AND_CHAT_ONLY / PLUGINS_ONLY / MEDIA_ONLY hybrids), so the merged
file referenced a member that no longer exists and failed tsc with TS2339.

Dropping the CUSTOM_LAYOUT arm keeps the intent: of the layouts 4.0 still has,
UNIFIED_LAYOUT is the grid one. This was the only CUSTOM_LAYOUT reference left
in the client.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.0's plugin-sdk-use-timer work (bigbluebutton#25335, commits bc4e822 / 172d67d /
388960c) adds a TIMER data-consumption hook and pairs it with plugin SDK
0.0.104. It merges cleanly on file level but does not compile on 4.0, because
it depends on SDK APIs that exist only on the 0.0.x line:

  - `TimerData` is not exported (TS2694)
  - `DataConsumptionHooks.TIMER` does not exist (TS2339)
  - `useTimer(...)` takes a boolean, not `{ enableNotifications, isIndicator }`
    (TS2345)

4.0 tracks the 0.1.x SDK line (html5PluginSdkVersion=0.1.24). I checked the
published SDK: neither 0.1.24 nor 0.1.25, the latest on that line, declares
TIMER in DataConsumptionHooks — the enum ends at CUSTOM_QUERY. So there is no
0.1.x version to bump to that would make this compile, and bumping to 0.0.104
would drag 4.0's plugin API back to the 3.0 line.

Removing the client half here rather than leaving 4.0 unbuildable. The feature
needs a real port once the 0.1.x SDK exposes the timer types, which is an SDK
change, not a merge conflict resolution. Nothing else references the hook: the
two files were added whole by the merge and the only other reference was the
registration in data-consumption/manager.tsx, removed here too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…right suite

Both files auto-merged without a conflict but ended up with duplicate top-level
declarations, which is a hard SyntaxError for the playwright loader. The whole
suite collected 0 tests in 0 files — every spec failed to import, not just the
shared-notes ones.

sharednotes/blocknote/util.ts
  3.0's backport of bigbluebutton#25165 appended its own startSharedNotesBlockNote and
  getBlockNoteReadOnlyLocator to a file that already defined both. The 3.0
  copies open the panel via e.sharedNotes, which does not exist in 4.0's
  elements.ts at all (renamed to sharedNotesSidebarButton), so they were dead
  on arrival as well as duplicated. Removed them; the 4.0 definitions at the top
  of the file already do the same job with the right selectors.

whiteboard/whiteboard.spec.ts
  `import { linkIssue } from '../core/helpers';` landed twice, once from each
  side, at different points in the import block.

This is the same failure mode as 5840bc2 ("restore BlockNote shared-notes
helpers dropped in 3.0->4.0 merge") from the previous 3.0 merge: git resolves
these files happily because the additions are textually far apart, and nothing
in the merge output hints that the result does not parse.

Not fixed here, because they predate this merge and are identical on
v4.0.x-develop (verified by running tsc against a worktree at 5fa28d6):
e.userListToggleBtn in accessibility/document-title.spec.ts,
ELEMENT_WAIT_EXTRA_LONG_TIME in presentation/presentation.ts, and e.sharedNotes
in sharednotes/blocknote/blocknote.ts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two things the merge pulled forward that should not cross a version line.

Translated locales are not merged. bigbluebutton-html5/public/locales/* comes
straight from Transifex via the integration, so carrying 3.0's translation sync
(ac21de5) into 4.0 fights that integration and would be overwritten by the
next pull anyway. Reverted it_IT.json, ja.json and zh_TW.json to their 4.0
state; they are now byte-identical to 5fa28d6.

en.json is the exception -- it is a source file, not a Transifex artifact, and
its changes DO get merged. Nothing to do here: 3.0 made no en.json change in
this range, and the merge left the file untouched.

new-features.md is scoped to what is new in its own major/minor. The two 3.0.33
feature sections I ported (BlockNote Markdown import/export, Panopto external
video) were new in 3.0, so they do not belong in "what's new in BBB 4.0" even
though both features exist here. Same for the two `... added in BBB 3.0.33`
property lines that auto-merged into the bbb-web "Added" list. Removed all four;
the file is back to 4.0's curated content.

Note the `#### Added` list already carried `added in BBB 3.0.27` and
`added in BBB 3.0.30` entries before this merge. Those predate it, so I left
them alone rather than widening the diff, but they look like the same
carry-over and are worth a separate cleanup.

Kept deliberately: the customize.md rows for maxSharedNotesInitialContentUrlPayloadSize
and numPresentationDownloadThreads. That file is a reference of settings a 4.0
admin can actually set, not a per-version changelog, and both properties are
live in the merged bigbluebutton.properties.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

🚨 Automated tests failed

@antobinary antobinary closed this Aug 12, 2026
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.