* fix(forks): clone only the current raw-app bundle, via server-side copy
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(forks): fall back to get+put when object-store copy is unsupported
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(s3_proxy): enforce CE 50MB upload cap on multipart uploads
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(s3): replace CE 50MB upload cap with 10GiB workspace storage quota
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): gate CE quota OSS stubs to not(enterprise) to match callers
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): delta-aware CE storage quota + guard usage-load retry loop
Account for the overwritten object's size in the quota check so valid
same-size overwrites near quota are not rejected (Codex review), and stop the
storage-usage $effect from re-firing on persistent API errors (Pi review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): count chunked PUTs; revert overreaching volume quota copy
Volumes write to workspace storage via a separate worker-side path with its own
50MB-per-file cap that this PR does not change, so revert the drawer copy that
claimed they count toward the 10GiB quota (Codex review). Bump ee-repo-ref for
the chunked-PUT accounting fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): add SQLx cache for CE usage-bump/quota queries; exclude volumes
Regenerate the missing offline SQLx cache for the not(enterprise) bump and
remaining-quota queries so the private CE offline build compiles, and bump
ee-repo-ref for the volumes/-prefix exclusion from the counted quota (Codex
review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): always HEAD for CE upload delta so overwrites don't inflate usage
Bump ee-repo-ref for the fast-path overwrite-accounting fix (Codex review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): reserve volumes/ prefix on CE write surfaces to close quota bypass
Reject direct writes to the reserved volume prefix on the app-upload surface and
add the OSS stub; bump ee-repo-ref (Codex review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): refuse new multipart work when CE workspace is at quota
Bump ee-repo-ref for the multipart-initiate/part quota gate (Codex review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(s3): reserve in-flight multipart bytes against CE storage quota
Add workspace_multipart_inflight table + grants, SQLx cache for the reservation
queries, and bump ee-repo-ref. Bounds abandoned multipart uploads that the
list-based recount can't see (Codex review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): clear multipart reservation only after a successful complete
Add exclude-upload arg to the OSS quota stub/caller and the SQLx cache for the
updated remaining-quota query; bump ee-repo-ref (Codex review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(s3): per-part multipart reservation; commit only on part success
Per-part workspace_multipart_inflight schema (upload_id, part_id) so retries
replace rather than double-count; SQLx cache for the reworked queries; bump
ee-repo-ref (Codex review).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* perf(s3): HEAD the multipart overwrite target once per upload, not per part
SQLx cache for the stored-credit lookup; bump ee-repo-ref.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: update ee-repo-ref to bea5a8b5120d6d69cab1ad4611ebe463559bd200
This commit updates the EE repository reference after PR #640 was merged in windmill-ee-private.
Previous ee-repo-ref: 6e6ff86f1939cf74736b7d435bf6851416437523
New ee-repo-ref: bea5a8b5120d6d69cab1ad4611ebe463559bd200
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat: support workspace forks on cloud using parent workspace limits
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: clarify count_paid_seats approximates rather than mirrors billing seats
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: non-admin fork UI, attach cap, and fork-count for cloud forks
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: cloud fork billing cache on rename, usage display, attach cap edge
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: fork count in cloud quotas + fork billing points to parent
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: invalidate billing/fork caches on fork deletion for id reuse
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: gate fork usage remap on CLOUD_HOSTED, not just the cloud feature
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: note cloud feature vs CLOUD_HOSTED gating in backend guide
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: reserve fork-cap slots for an attach candidate's whole subtree
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: invalidate team-plan cache on delete, raise fork depth cap
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: cap fork nesting depth (MAX_FORK_DEPTH, default 5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: fork count/height robust to cycles and deleted intermediates
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): reset fork button loading state on creation error
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: invalidate billing cache for attached fork subtree; helper auth docs
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: invalidate bun bundle cache on transitive relative-import changes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: do not memoize transient fetch errors in bundle-key import cache
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: use regular comment on lazy_static block (deny unused_doc_comments)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: align bundle-key import version selection with loader content endpoint
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): show inline workspace name editor on general settings
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): guard rename and support enter-to-save on workspace name
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(ai): add Azure AI Foundry as a native AI provider
Adds `azure_foundry` as a new AIProvider variant wired through the AI
chat (copilot) and AI agent flow steps. Foundry's chat completions API
is OpenAI-compatible and uses Azure conventions (api-key header, Azure
URL building), so it reuses the existing OpenAI-compatible query builder
and proxy path via the shared `is_azure` helper (renamed from
`is_azure_openai`).
Backend (windmill-ai):
- New `AzureFoundry` enum variant (serde `azure_foundry`)
- `get_base_url` requires a resource base URL (like Azure OpenAI / Custom)
- `is_azure()` covers Azure OpenAI + Foundry (api-key auth, Azure URL)
- Added to OpenAI-compatible proxy support and HttpForward proxy mode
- New proxy URL unit test
Frontend (copilot):
- New provider entry, completion config, model-token handling, streamed
usage tracking, and reasoning registry (all model-id-gated, so a no-op
for Foundry's non-OpenAI catalog)
- Treated as a chat-completions provider, not the OpenAI Responses API
OpenAPI:
- `azure_foundry` added to AIProvider (openapi.yaml) and AIProviderKind
(openflow.openapi.yaml); regenerated CLI guidance
Note: the `azure_foundry` resource type (base_url + optional api_key) is
hub-managed and must be published to the Windmill Hub separately.
Fixes WIN-2122
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(ai): add azure_foundry to copilot flow Zod provider enum
The tracked copilot flow schema (openFlowZod.gen.ts and its openFlow.json
source) still carried the old AIProvider enum, so validateFlowModules /
validateSpecialFlowModule rejected AI-generated flow edits that create or
update an aiagent module with provider kind "azure_foundry" before they
could be saved. Add the value to both (preserving the generated single-line
format) and a regression test over the flow-module validation path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(ai): lead provider list with OpenAI, Anthropic, Google AI
Reorder AI_PROVIDERS so the three primary direct providers come first. The
AIProviderPicker renders the first three entries as quick-access buttons, so
these become the defaults (previously OpenAI, Azure OpenAI, Azure Foundry);
Azure OpenAI / Azure Foundry stay adjacent right after. No logic depends on
provider order (only per-provider defaultModels[0] is read).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): home New submenus fall back below hugging the right edge
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): re-hug submenu on window resize even without a melt reposition
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: revalidate workspace items cache on context picker open
The chat context picker (and workspace drill pickers) read from a
module-level cache that was only invalidated from two editor save paths,
so items created or deleted anywhere else stayed stale until a full page
reload. Make the loader do real stale-while-revalidate: cached items
render instantly and each workspace+kind is re-fetched once per picker
mount, keeping the state reference stable when nothing changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: retry failed picker revalidation and handle its rejection
Mark a workspace+kind as revalidated only after the fetch succeeds, so a
failed revalidation is retried on the next ensureLoaded call instead of
stranding stale data for the rest of the mount. Catch the rejection
(callers fire-and-forget) and log it. Also dedupe the
stale-while-revalidate rationale to its canonical comment site in
workspacePicker.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
A websocket trigger is permanently disabled (with a critical alert) when a
single connect attempt in get_consumer fails. Gateway endpoints fronted by
edge proxies (e.g. Discord behind Cloudflare) sporadically answer the
upgrade handshake with a transient 502/520, so a long-lived trigger that
reconnects frequently eventually catches one and dies until a human
re-enables it.
Retry transient failures (HTTP 5xx/429 handshake responses and IO errors)
up to 5 attempts with exponential backoff before surfacing the error, and
report retry progress through the trigger's error status. Permanent-looking
errors (bad URL, other 4xx, protocol/TLS mismatch) still disable immediately.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(pipeline): backfill a range of partitions from the asset drawer (ee)
* feat(pipeline): cancel in-flight backfill job and show cancelling state
* refactor(pipeline): move backfill range logic behind private feature
* fix(pipeline): close backfill cancel-launch race and record dispatch intent
* docs(openapi): producer_path also covers SDK write-edge producers
* chore: update ee-repo-ref to c3852ecb36bd0be1a74c63169e513888f3347850
This commit updates the EE repository reference after PR #641 was merged in windmill-ee-private.
Previous ee-repo-ref: 7c1450ef89fbc9e844a121b39cafe0d7235d704b
New ee-repo-ref: c3852ecb36bd0be1a74c63169e513888f3347850
Automated by sync-ee-ref workflow.
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix: scope SCD2 built-in data tests to current rows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: add --partition to pipeline run and fix duckdb s3object upload binding
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: note filesystem storage type is dev-only in storage settings
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: use ISO week for weekly partition default in pipeline run
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): reserve fixed height for unsaved-changes banner to avoid content shift
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): remove border around reserved banner slot and shrink it
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): tighten top padding under the unsaved-changes banner
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): give unsaved-changes banner buttons minimal vertical breathing room
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(frontend): drop redundant Metadata section title in trigger and script editors
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): tuck schedule editor labels under summary to match convention
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* revert(frontend): keep Metadata section title in ScriptBuilder for a separate PR
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): drop leftover header-content margin on headless Section
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): drop top padding above resource editor first field
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* style(frontend): match variable editor bottom padding to resource
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): add Path label in new resource form to match edit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): reserve half the banner height to halve the idle gap
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): reserve a third of the banner height when idle
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): don't reserve banner slot or tighten top for new entities
Gate the reserved-height slot and the tight content top padding on the banner's baseline (bannerReserved) instead of merely on the banner snippet being present, so new-entity drawers keep normal top spacing and add no empty slot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(frontend): trim banner comments to the 4-line invariant limit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(frontend): describe partial-reserve banner behavior accurately
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(frontend): keep pipeline graph layered when lineage has cycles
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): fit pipeline graph to visible canvas on initial load
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): style pipeline minimap so it reads as a minimap
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(parser): don't infer s3 reads from bare string-literal mentions in sql
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(duckdb): render temporal values as ISO strings in job results
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): key pipeline viewport fit on the loaded graph's folder
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(parser): treat list/named read-fn arguments as definitive s3 reads
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(frontend): surface pipelines in sidebar nav, index page and sql editor hint
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(frontend): remove pipelines sidebar nav item
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(frontend): group compare & deploy items by folder
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): group folder items with their folder, fix disabled hint
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(duckdb): auto-declare the partition arg for // partitioned scripts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(cli): pipeline run --arg to pass plain run args to cascade scripts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The cron schedule row placed the input next to a shrink-0 button group, so
on narrow layouts the buttons kept their width and squeezed the input to
near-zero. Make the row wrap and give the input a min width so the buttons
drop below it, keeping both visible.
Fixes WIN-2121
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fetching options for a `dynselect`/`dynmultiselect` input was inconsistent
between deployed scripts and deployed flows:
- scripts ran through `push_script_job_by_path_into_queue` — a `script` job
with the script's path, tag, lock and codebase resolution;
- flows ran their schema dyn-select code as an anonymous `preview` with no
path and no tag (always the language default), and reported access
failures as a raw `SqlErr: no rows`.
Deployed scripts are left exactly as they were (that path already handles
tag/lock/codebase/on-behalf-of correctly). The flow branch now:
- carries the flow path on the preview job,
- reads the flow's `tag` under RLS and routes the job to it (falling back to
the language default when unset), matching the script's worker group, and
- runs `check_tag_available_for_workspace` on that tag — the same gate a
normal flow run and the script path apply — so a caller who can read the
flow but is not allowed to use its (custom/scoped) worker tag is rejected
consistently.
The flow's tag read runs on every request, so it also serves as the
per-request access check, replacing the raw error with a clean
`NotAuthorized` / `NotFound`. Entrypoint-name validation now covers all
branches (it is interpolated into the generated wrapper). Inline is
unchanged: a `preview` with no path on the language default, blocked for
operators.
Fixes WIN-2118
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(forks): let partial-visibility users deploy the visible subset
The fork Compare & Deploy page hid the deploy button entirely whenever the
comparison reported any item not visible to the user (all_ahead/all_behind
flags), telling them to hand the deploy to someone with full access. But the
non-visible items are already filtered out of the diff list, and the UI already
supports deploying an arbitrary subset via per-item selection — so blocking
everything was inconsistent and, for stale/phantom rows, blocked on items that
don't even exist.
Show the deploy footer regardless; the user acts on the visible/selected items
(the per-item disabled conditions are unchanged). The hidden-items notice is
kept but downgraded to a non-blocking, direction-scoped banner that explains the
excluded items instead of removing the action.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(forks): surface hidden-item counts by kind + admin path list
WIP: expose items dropped by the visibility filter (hidden_ahead/hidden_behind
in the compare response): by-kind counts for everyone, kind+path only for admins.
* fix(forks): don't close the deployment request on a partial (hidden-items) deploy
Making the deploy button reachable in the partial-visibility case exposed a bug:
a clean merge-into-parent deploy unconditionally closed any open fork deployment
request as "merged" — marking its comments obsolete and notifying the requester
and assignees of a merge — even when hidden ahead changes were excluded from the
list and left undeployed. Only close the request as merged when the full ahead
set was visible (all_ahead_items_visible); otherwise leave it open (with a toast)
so someone with full access can finish it.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): correct misleading delete-fork command description
The `wmill workspace delete-fork` description claimed it deletes "a
forked workspace and git branch", but the implementation only deletes
the Windmill workspace via the backend API and removes the local
workspace profile. No git operations are performed, so the remote
branch is left untouched. Drop the "and git branch" clause and
regenerate the derived guidance/system-prompt files.
Fixes WIN-2120
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(cli): permanently delete temp workspaces in folder test cleanup
The isolated-workspace test helper archived each temp workspace on
teardown. After #9865 added a CE cap of 1 archived workspace, the second
archive-cleanup is refused, so temp workspaces leak into the active set
and hit the 2-workspace CE cap — failing every subsequent create/fork
across the shared test backend.
Permanently delete the workspace instead (DELETE /api/workspaces/delete),
which frees the slot without occupying the archived quota.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
The blast-radius guard added in #9866 forced `all_ahead_items_visible` true for
any fork/target admin. But `filter_visible_diffs` keeps a modified/conflict row
(one that exists in the source AND the fork) only when the caller can see it on
both sides, so an ahead diff can be dropped for a source-side visibility gap even
when the caller is a fork admin. Forcing the flag on fork-admin alone then wrongly
reported "all ahead items visible", letting the UI enable deployment from an
incomplete comparison.
Gate the guard on admin of BOTH the source and the fork (superadmin satisfies
both), which is what actually guarantees full visibility of every item on every
side. Adds a regression test where a fork admin who is only a plain member of the
parent (no access to the item's folder) must still get `all_ahead_items_visible
= false`, plus the superadmin sanity path.
Also restores the SQLx offline cache entry for the phantom-trigger test INSERT
that #9866 landed without (CI/`SQLX_OFFLINE=true` builds failed on it), and adds
entries for the new test's all-literal queries.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deleting a trigger left a stale `workspace_diff` row: `delete_trigger` (the
generic TriggerCrud handler) was the only delete path that never called
`handle_deployment_metadata`, unlike every other kind. Because
`compare_workspaces` trusts a cached `has_changes=true` row for non-script/flow
kinds and the visibility filter then drops it (the trigger no longer exists), a
deleted trigger became a phantom "ahead" item that flipped
`all_ahead_items_visible` to false — hiding the deploy button and showing a
"changes not visible to your user" warning that even a superadmin could not
resolve (`reset_diff_tally` doesn't clear a `has_changes=true` row either).
- delete_trigger now re-tallies via handle_deployment_metadata, so the next
compare re-evaluates and corrects/removes the row (matches resource/variable/
folder/schedule deletes).
- compare_workspaces forces the visibility flags true per side for anyone who
sees that side in full: target/fork admin (or superadmin) for ahead items,
source/parent admin (or superadmin) for behind items. The flag is a pure
visibility guarantee — the deploy itself is authorized separately — so for
such users a dropped diff is provably a phantom, never a permission gap.
- Add a regression test asserting a phantom trigger diff row no longer blocks a
superadmin while still (conservatively) warning a partial-context user.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(workspaces): enforce CE workspace limit when unarchiving
Unarchiving a workspace re-activates a soft-deleted (deleted = true)
workspace, effectively bringing it back to the active set. On CE this
bypassed the 2-workspace cap that create_workspace enforces, letting a
user exceed the limit by archiving and re-unarchiving.
Run the same _check_nb_of_workspaces guard before flipping deleted back
to false. The workspace being restored is still deleted = true at that
point, so it is correctly excluded from the count.
Fixes WIN-2119
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(workspaces): cap CE archived workspaces at 1
Complements the unarchive-limit fix: without a cap on archived
workspaces, a CE user could stockpile many soft-deleted workspaces (each
of which still occupies its workspace id and can later be unarchived).
Refuse a new archive on CE when an archived workspace already exists,
mirroring the create/unarchive workspace-count guards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>