619 Commits

Author SHA1 Message Date
Miguel de Benito Delgado
6db7bceec9 ✨ Add retained renderer benchmark builds and host
Add prepared build artifacts, browser host and the build and
purge commands for the CLJS renderer benchmarks.

Each preparation attempt gets a build ID and a retained directory with
its manifest, log, Node case catalog, browser bundle, renderer files
and host page. Ready builds load their matching catalog in process and
serve only their own directory through an owned loopback host.

Own Chromium through a bounded process group, verify the compiled build
identity before execution and retain failed preparations for diagnosis.
Wire the diagnostic pilot to the same build, catalog, server and
browser APIs.

Add real boundary tests for artifacts, processes, servers, browsers and
CLI parsing, and register them with the performance test runner. Rename
the benchmark lint and test scripts to match the suite.

AI-assisted-by: deepseek-flash
2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
1720d6ecbc 🚧 WIP 24 Relocate all code, delete old benchmarks 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
2faeedea03 🚧 WIP 23 Results and reporting. Cleanup 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
a2d79fcbd5 🚧 WIP Step 22 nicer macros 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
76d16b639d 🚧 WIP Step 21.2 Cosmetic simplifications 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
366cf4f63e 🚧 WIP Step 21.2 Docstrings 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
0e5f136a58 🚧 WIP Step 21.2 Docstrings 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
b1c2926091 🚧 WIP Step 21 Refactor namespaces 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
e3f6e1d1a3 🚧 WIP Step 20 test last round of features 2026-11-11 15:27:06 +01:00
Miguel de Benito Delgado
5cfdc0e9f7 🚧 WIP Step 19.2 Missing browser utils 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
210c667f73 🚧 WIP Step 19.1 Allow selecting cases in pilot 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
be6349b66e 🚧 WIP Step 19 New scenes, use camera 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
907fa02032 🚧 WIP Step 18 Camera ops 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
5d68549da1 🚧 WIP Step 17 Support path construction 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
98a487b28d 🚧 WIP Step 16.4 Refactor failures, remove legacy code, cleanup 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
3e6f38b8f3 🚧 WIP Step 16.3 Cleanup pilot 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
fb9b9047cf 🚧 WIP Step 16.2 Renames and fixes 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
70956c7b9f 🚧 WIP Step 16.1 Relax scene macro constraints 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
5ad3b2f77f 🚧 WIP Step 16 Introduce hooks for the browser and load-scene 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
d102555547 🚧 WIP Step 15.1, cosmetic 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
048ab736e9 🚧 WIP Step 15, Use transit to simplify validation 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
df8436264a 🚧 WIP Step 14, Grab correct w/h attrs from context 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
5c60778578 🚧 WIP Step 13, Track failure causes
AI-assisted-by: muse-spark, GLM-5.3
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
43ae0f0206 🚧 WIP Step 12.4, Comments
AI-assisted-by: gpt6-astra
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
a89a570dd2 🚧 WIP Step 12.3, Test cleanup + missing coverage
AI-assisted-by: muse-spark, deepseek-flash
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
5cd68946fe 🚧 WIP Step 12.2, Fix browser bridge, lifecycle
AI-assisted-by: muse-spark, glm-5.3
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
eda6a6f539 🚧 WIP Step 12.1, Improve case validation
AI-assisted-by: muse-spark, glm-5.3
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
57e87722c0 🚧 WIP Step 12, temporary pilot
- pilot runner for testing
- will be entirely removed later

AI-assisted-by: muse-spark-1.3, deepseek-flash, glm-5.3
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
42ac1ee290 🚧 WIP Step 11, browser bridge
- New schema:viewport
- Browser bridge (with some temp code)
- Move prepare-scene out measured regions
-
AI-assisted-by: muse-spark-1.3, deepseek-flash, glm-5.3
2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
fe3b116031 🚧 WIP Step 10, scene upload 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
d996056ef7 🚧 WIP Step 10, defcase body validation, docs 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
6d621784f4 🚧 WIP Step 9, fix naming conventions 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
2c6fb4d961 🚧 WIP Step 8, simplify and clean up tests 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
f2d4db6471 🚧 WIP Step 7, scene and case declarations 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
551b40a28d 🚧 WIP Step 6, ellipses 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
d44ea9e134 🚧 WIP Step 5, bools 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
21ae97e6b7 🚧 WIP Step 4, frames and groups 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
08e00e1b59 🚧 WIP Step 3, fixture macros, prng, defaults, placeholder scene 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
8badcbe909 🚧 WIP Step 2, common scene code, validation 2026-11-11 15:27:05 +01:00
Miguel de Benito Delgado
a213b46f9b 🚧 WIP Step 1, scaffold cljs benchmark runner 2026-11-11 15:27:05 +01:00
Andrey Antukh
671ff4a05f Merge remote-tracking branch 'origin/staging' into develop 2026-11-10 20:06:46 +01:00
Andrey Antukh
e4fcc663c0 Merge remote-tracking branch 'origin/staging-2.19.x' into staging 2026-11-10 18:09:07 +01:00
Andrey Antukh
1db1487c7f
🐛 Require thread access when marking threads as read (#12894)
* 🐛 Require thread access when marking threads as read

mark-all-threads-as-read took any list of thread ids and wrote the read
status of the caller on each of them, without checking that the caller
can access the file that owns the thread. It was the only comment
mutation that did not check permissions, and it took the ids as an
unbounded array, so a single request could keep a database connection
and a transaction open for a long time.

The rpc now resolves the threads in one query and checks the comment
permissions of every distinct file, answering not-found when a thread
does not exist or is not accessible. Both cases answer the same error
on purpose, so the response cannot be used to tell existing threads
apart.

The status rows are now written with a single insert, keeping the
modified-at date one second in the future that makes the thread count
as read. Repeated ids are deduped, the command returns nil again like
the sibling commands with no result, and the schema limits the number
of threads per call to 500 while the dashboard sends the ids in batches
of that size.

Tests cover access rejection, unknown threads, mixed batches that write
nothing, repeated ids, empty lists, marking twice, and the frontend
batch split.

Relates to GHSA-j4vc-cmf6-jhr7

AI-assisted-by: minimax-m3.1-flash

* 🐛 Refresh the unread list when a batch fails

The dashboard sends the thread ids in batches of 500 and each batch
commits on the server. A failure in a later batch left the unread list
stale: the re-read only ran when every batch succeeded, so the threads
already marked as read stayed visible as unread.

The re-read now runs in both paths. On failure the event is emitted
before the error is propagated, so the error toast still shows and the
success toast stays limited to a full success.

The backend also answers an empty list without opening a transaction,
since there is nothing to check and nothing to write.

Relates to GHSA-j4vc-cmf6-jhr7

AI-assisted-by: deepseek-v4.1-flash
2026-11-10 15:54:11 +01:00
Andrey Antukh
8510daef52
🐛 Restrict the team invitation token and list to admins (#12892)
* 🐛 Restrict the team invitation token and list to admins

The token of a team invitation is a bearer credential: whoever holds it
accepts the invitation with the role of the invitation row. The RPC that
mints it only required edition permissions, while the rest of the
invitation commands require admin, so a team editor could get the token of
any pending invitation, including the ones that grant the owner role.

The token now requires admin, and the token of an owner invitation is
restricted to the team owner: an admin cannot create nor promote an owner
invitation, so it cannot keep its token either. It reuses the error code
already used for that rule.

Minting the token now leaves an audit event named as an action, carrying
the granted role and the id of the invitation, so the extraction does not
go unnoticed.

The list of pending invitations is admin only as well: it carries the
email of the invited person and the role offered, and the dashboard was
painting those emails to any member. The frontend catches the permission
error and shows the permission notice instead, and the copy action is not
offered for an owner invitation, which the backend rejects for an admin.

The five invitation commands now answer with the same permission error,
so they speak one language.

Relates to GHSA-4mmc-j8rh-74pf

AI-assisted-by: minimax-m3.1-flash

* 🐛 Clear the cached invitations and gate the list on team admin

The pending invitations are a team admin only list. The dashboard still
offered the entry to every member and keyed the section on the invite
policy of the organization, so a team admin blocked by that policy saw
the no-permission notice although the backend lets them list.

- `fetch-invitations` answers a denied refetch with an
  `invitations-fetched` event carrying an empty list, so a demoted admin
  does not keep the cached emails and the header no longer paints the
  invite button from a stale list.
- The header tabs and the team options dropdown hide the invitations
  entry without `:is-admin`, which already includes the team owner.
- `invitations-section-content` keys the section on `:is-admin`, and the
  invite policy only gates the invite actions: resending keeps the
  `can-invite?` check, deleting and row selection only need team admin.

AI-assisted-by: deepseek-v4.1-flash
2026-11-10 15:53:43 +01:00
Filip Sajdak
90d98b1989
🐛 Call the team hook on every render of the team container (#12920)
team-container* called mf/deref only after returning early for a team id
that is not a uuid. When the same component rendered once without a team
id and then with one, the number of hooks changed between the two renders
and React threw "Rendered more hooks than during the previous render"
(error #310), which sent the user to the internal error page. The reverse
order throws "Rendered fewer hooks than expected".

Call the hook on every render and keep the uuid check in the condition
that builds the providers.

Two tests mount the component in jsdom and render it with a team id that
arrives and with one that leaves; both fail without this change.

Closes #12728

AI-assisted-by: claude-opus-5-5
AI-assisted-by: claude-sonnet-5-5

Signed-off-by: Filip Sajdak <filip.sajdak@siili.com>
2026-11-10 11:32:58 +01:00
Alonso Torres
4fb0ea9eee
🐛 Give unique values to same-name components combined as variants (#12881)
When components whose name matches the variant container are moved into
it, removing the container name leaves an empty value. Combining several
components named the same produced "Value 1" for the first variant and
empty values for the rest, so variants shared the same combination.

Assign the first unused "Value N" to the last property when all computed
values are blank, tracking values given within the same batch.

Combine moves the remaining mains into the container one at a time, in
the combine order, so the generated values follow that order instead of
the layer order.

Closes #12878
2026-11-10 09:16:08 +01:00
Luke Lau
cd1ece4beb
⚡ Keep the translation flag on undo and redo of a move (#12870)
* ⚡ Keep the translation flag on undo and redo of a move

Previously undos and redos always forced a component sync + thumbnail
rerender for every component touched even if the underlying commits were just
translations. This propagates the translation flag to undos and redos and
propagates it to commit-changes. An entry merged from several undos/redos is
a translation only if all of its undos/redos are translations.

This reduces a UI freeze when undoing a move of a board with 453 components
from 2.42s -> 0.22s.

AI-assisted-by: claude-sonnet-5-5

* :translation? -> :translation

---------

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-11-09 20:47:42 +01:00
Luke Lau
6846afd08c
⚡ Send objects-map pages to the worker without a second encode (#12811)
* ⚡ Send objects-map pages to the worker without a second encode

When switching between pages on a large file e.g Material Design Icons, there's
some UI freeze from :index/initialize encoding object map shapes to send to the
worker. An objects map already stores the encoded JSON for each shape, and
`encode-str` was wrapping those strings in a second layer of JSON on the main
thread.

We can just transmit the already encoded JSON in a js/Map alongisde the
payload, similar to :blob, so structured clone just copies the strings verbaitm
without re-encoding. To do this this PR adds two functions to ObjectsMap that
converts to and from a js/Map.

The "Main components" page of the Material Design Icons has ~30k objects, so
this reduces the freeze when switching pages from 306ms -> 189ms (1.63x) on a
release build.

AI-assisted-by: claude-sonnet-5-5

* Split property tests out into new deftest

---------

Signed-off-by: Luke Lau <luke_lau@icloud.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-11-09 17:35:20 +01:00
Luke Lau
943e63a99e
⚡ Group color updates in selections (#12875) 2026-11-09 12:08:36 +01:00
Andrey Antukh
1df2941576 Merge remote-tracking branch 'origin/staging' into develop 2026-11-09 10:42:28 +01:00