Commit Graph
618 Commits
Author SHA1 Message Date
Ruben FiszelandClaude Opus 5.5 42851397fe perf: skip scope lookups for unrestricted jobs; list job token setting last
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-03 09:14:08 +02:00
Ruben FiszelandClaude Opus 5.5 319677e1fd fix: apply the step-scope worker gate to flow restarts
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 21:45:52 +02:00
Ruben FiszelandClaude Opus 5.5 6eaf26e546 fix: refuse flows with step or tool restrictions at push while an older worker is live
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 21:34:51 +02:00
Ruben FiszelandClaude Opus 5.5 87a1d7ea14 fix: validate step scopes in batch flows, fail closed on unvalidated step scopes
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 21:21:06 +02:00
Ruben FiszelandClaude Opus 5.5 f5912515ce Merge origin/main into restricted-job-tokens
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 21:05:49 +02:00
Ruben FiszelandClaude Opus 5.5 5db5cd61ef docs: correct the QueuedJobV2 completion comment
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 20:56:07 +02:00
Ruben FiszelandClaude Opus 5.5 b5bd70b2a5 fix: leave a zombie for the next sweep when its scopes cannot be read
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 20:46:37 +02:00
Ruben FiszelandClaude Opus 5.5 5ac15db691 fix: carry a job's scopes on its completion so a re-run keeps the caller's cap
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 20:21:42 +02:00
Ruben FiszelandClaude Opus 5.5 434e42b0ee fix: fail closed on perms read errors, refuse restricted queue imports, gate step scopes in previews
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL
2026-10-02 20:05:14 +02:00
Ruben FiszelandClaude Opus 5.5 fc9fec6e0b fix: store per-job scopes on job_perms instead of v2_job, pin inline runs to the checked version
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 19:24:43 +02:00
Ruben FiszelandClaude Opus 5.5 920771b598 keep tagged binary prebuilds off the dependency job tag (#11489)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 19:07:50 +02:00
Ruben Fiszel 2007cd3144 Merge origin/main into restricted-job-tokens 2026-10-02 18:50:59 +02:00
Ruben FiszelandClaude Opus 5.5 3d1d249556 feat: add an instance setting routing all dependency jobs to one tag (#11486)
* feat: add an instance setting routing all dependency jobs to one tag

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

* fix: keep bunnative locks on bun and explain the default dependency routing

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 18:40:32 +02:00
Ruben FiszelandClaude Opus 5.5 2ca3f56140 fix: keep restricted jobs off flow runners, preserve scopes on rename and promotion
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 17:55:03 +02:00
Ruben FiszelandClaude Opus 5.5 7646cb3281 fix: admit flow-run reads, skip dedicated workers, gate on worker version
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 17:30:37 +02:00
Ruben FiszelandClaude Opus 5.5 06a5d73bb8 feat: restricted job tokens (job_token_scopes on scripts and flows)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 17:14:26 +02:00
hugocasa 039f49ef12 feat: dispatch ai agent tools through the worker queue (#11227)
* feat: dispatch ai agent tools through the worker queue

* fix: respect worker tags when executing ai agent tools locally

* fix: cancel only direct-child tool jobs on agent failure

* fix: cancel queued descendant tool jobs on agent failure

* fix: route ai agent tools by the flow's tag rule
2026-09-29 22:30:50 +02:00
Ruben FiszelandClaude Opus 5.5 c5f59d6ccc fix: drop caller-supplied _MODULES at push for every job (#11418)
* fix: drop caller-supplied _MODULES at push for every job

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

* fix: never interpolate _MODULES into a tag and drop unused mut

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 20:17:32 +02:00
hugocasaandClaude Opus 5 cf5c49c3dc feat: restart perpetual runs on the version a deploy makes runnable (#11200)
* feat: opt-in move of perpetual runs to a newly deployed script version

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: keep the perpetual-run opt-in across relocks and check the new version's tag

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: pin the tag check on a perpetual version switch

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: count perpetual runs past the first queue page in the deploy prompt

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat: restart perpetual runs on the version a deploy makes runnable

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: claim a perpetual run and queue its replacement in one transaction

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: honour a cancel that lands after the worker last read its queue row

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: leave the lost-cancel fix to its own PR and match the scale down to 0 wording

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: run a preprocessor the deployed version adds over the arguments carried over

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* style: shorten the wording of the modal's argument warning

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: never preprocess a restarted perpetual run, as every other restart does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: preprocess for a replacement whose run had not been through one

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: push a perpetual replacement without the deployed debounce settings

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat: name the runs the deploy button restarts

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* perf: skip the perpetual restart lookups on a deploy that is not perpetual

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: move perpetual runs before anything that can fail after the deploy commits

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: report cancellation on the queue listing so the deploy prompt can skip it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: pass the tag workspace to the availability check after the merge

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* style: say which arguments are defined differently and which values are kept

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: resolve a dynamic tag before checking it for a restarted run

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: pin that a deployed dynamic tag is checked as it resolves

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-29 18:03:43 +02:00
bda00c6cad fix: run custom schedule handlers as the schedule (#11398)
* fix: run custom schedule handlers as the schedule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: correct handler identity comment and pin preset path check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: pin preset handler paths instead of matching their name

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: warn on unpinned preset-named schedule handlers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: update ee-repo-ref to 12a83524b81368043bc939caeb3764fd27a32523

This commit updates the EE repository reference after PR #833 was merged in windmill-ee-private.

Previous ee-repo-ref: bcfb0838f105d5bffbe49c6ed787116662ebe796

New ee-repo-ref: 12a83524b81368043bc939caeb3764fd27a32523

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-29 18:01:34 +02:00
Ruben Fiszel 3936191f46 Revert "feat: add pull_batch to claim jobs for many waiting workers at once (…" (#11412)
This reverts commit 9f40cdca62.
2026-09-29 15:25:35 +02:00
Ruben FiszelandClaude Opus 5.5 9f40cdca62 feat: add pull_batch to claim jobs for many waiting workers at once (#11350)
* feat: add pull_batch to claim jobs for many waiting workers at once

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

* fix: keep jobs admitted by earlier batch passes when a re-pull fails

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

* fix: keep suspended flows first on every batch re-pull pass

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 15:24:39 +02:00
hugocasaandClaude Opus 5.5 97fa55b719 feat: detect and alert when a schedule skips occurrences (#10917)
* docs: plan for detecting skipped schedule occurrences

Design plan only, no implementation. Records the scheduler's re-anchoring
behaviour, the measurements behind it, and the three-piece design that came
out of reviewing the alternatives.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* docs: state the user-facing outcome in the schedule plan

The plan described the mechanism but never what a user would see, which made it
hard to judge what the work is worth.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* docs: state which cause the schedule plan catches, and correct its scope

Records which of the two causes each piece covers, and corrects the overrun
scope: a script schedule carrying retry or dynamic_skip is pushed as a
SingleStepFlow, so it re-arms at step 0 entry and its occurrences overlap like
a flow's. Resolves the no_flow_overlap question, splits the read-time work into
bounded detection and editor-only counting behind measured croner costs, and
fixes the delivery order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* feat: count the occurrences a schedule skipped

A schedule that overruns its interval, or waits for a worker, silently loses
the occurrences in between: the scheduler keeps one queued occurrence and
re-anchors on the clock, so nothing records that a run was due and never
happened.

Recovers the sequence from rows that already exist rather than writing per
occurrence. `push_scheduled_job` anchors on `now_from_db` inside the
transaction that inserts the job, and `v2_job.created_at` defaults to that
same transaction timestamp, so `scheduled_for = find_next(created_at)` holds
exactly and the whole occurrence history is derivable.

The schedules list reports how many of the recent runs were followed by a lost
occurrence, and a new occurrences endpoint carries the per-run wait and
duration behind it. Detection is one `find_next` per gap, which stays bounded
on a full page; counting walks the gap and runs only for a single schedule.

The one write is `occurrence_baseline_at`, advanced at create, edit,
re-enable and re-arm. Gaps older than it span a pause, a cron change, a
re-enable or a reconciler re-arm, none of which mean runs were lost.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* feat: show the wait and run time behind a schedule's skipped occurrences

The list badge says a schedule is losing runs; this says which of the two
causes did it. A large wait means not enough workers, a long run means the job
outgrew its interval, and the pair is what tells them apart. Sits under the
existing upcoming-events panel, so due and overdue read together.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* feat: flag a schedule that is running late right now

Reconstruction is retrospective: a gap only appears once the next occurrence
has a row, which needs the current one to finish. A schedule wedged mid-run
shows nothing until it moves, which is the case an operator most wants to see.

An occurrence still in flight past the time its own successor was due will
cost that successor, so `now > find_next(scheduled_for)` is the signal, needing
no threshold and self-calibrating across a daily and a per-minute schedule. It
applies only where occurrences serialize; an overlapping schedule starts its
successor on time and would flag constantly while healthy.

The queue is read in one aggregating pass keyed on (trigger, runnable_path)
rather than a subquery per schedule, and an overlapping schedule holds more
than one root row, hence the aggregate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* feat: run the schedule overrun alert from the monitor pass

Wires `schedule_overrun_alerts` in next to `jobs_waiting_alerts`, every 30
iterations (~5 min). Its Enterprise implementation lives in
windmill-labs/windmill-ee-private#772; only the wiring and the OSS stub are
here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* chore: refresh the sqlx offline cache

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* feat: record and alert when a schedule skips occurrences

push_scheduled_job compares each chained occurrence with the slot after
the previous one. A gap is written to schedule.skipped_occurrences off the
push transaction, alerts once when a clean schedule starts skipping, and
recovers on the next clean chain. The schedules list shows a badge.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* feat: alert only on a streak of skipping runs, keep a recent skip visible

The skip state now describes the current streak and is written in the push
transaction, so it commits or rolls back with the push. The alert fires
once when 3 runs in a row skipped, and the list keeps a muted badge for 7
days after the latest skip. Editing or toggling a schedule resets it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* fix: name the missed-occurrence state after what it counts, alert only once committed

Renames the columns to late_run_streak, missed_occurrences and
last_missed_at, keeps the missed count after a streak ends so the muted
badge can show it, and rewords both badges. The alert task now reads the
streak FOR SHARE, which waits for the push transaction, so a push that
rolls back and retries alerts once. A failed slot count leaves the streak
untouched, and a schedule deleted mid-push no longer fails it. Adds an
integration test for the streak and its reset.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* fix: recover the late run alert, store the missed slot, name it missed throughout

The alert now recovers (and so acknowledges itself) when a streak that
alerted ends on a run on time, under the schedule:{path} resource used by
the other trigger alerts. last_missed_at records the last missed cron slot
rather than when the late run chained, and the counting helpers say
missed, since skipped already names occurrences queued and not run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* fix: scope the late run alert to its workspace, acknowledge it on edit, toggle and delete

Recovery acknowledges alerts by resource alone, so the resource now
carries the workspace. Editing, toggling or deleting a schedule clears
its streak and a disabled or deleted one never chains a run on time, so
those handlers acknowledge its open alert after committing. Past the
1000-slot cap, last_missed_at falls back to the detection time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

* refactor: raise the late run alert like the other critical alerts

Drops the recovery, the workspace-scoped resource and the acknowledgement
on edit, toggle and delete: the alert now fires once per streak with no
resource and is acknowledged from the alerts feed, as the trigger and job
failure alerts are. The FOR SHARE read stays, so a push that rolls back
across the flow path's retries still alerts once. Notes in openapi that
past 1000 misses in one late run the count is a floor and the time
approximate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ9wpjWp2YgLUSqt1Ai5d6

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-29 12:40:25 +02:00
17448c97d3 count trigger suspend, resume and discard (#11405)
* feat(telemetry): count trigger suspend, resume and discard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor: shorten the telemetry disclosure to one line per category

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: correct the resume branch comments and note the pre-commit fire count

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: name feature adoption in the telemetry disclosure

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: update ee-repo-ref to 9855e1b7a43a0a33e04f8accf1c497af3fd9b139

This commit updates the EE repository reference after PR #834 was merged in windmill-ee-private.

Previous ee-repo-ref: 1d5b128ec956c156fe549cf099ba0dbc1b6467bf

New ee-repo-ref: 9855e1b7a43a0a33e04f8accf1c497af3fd9b139

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-29 12:26:11 +02:00
Ruben FiszelandClaude Opus 5.5 893e64f630 fix: only restart a flow on a version of its own path and workspace (#11376)
* fix: only restart a flow on a version of its own path and workspace

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

* test: pin cross-workspace restart version rejection

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 14:10:21 +00:00
Ruben FiszelandClaude Opus 5.5 c2d8997549 fix: complete a canceled flow whose worker died between two steps (#11366)
* fix: complete a canceled flow whose worker died between two steps

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzGsxKey5g3kycKwGmpKNF

* fix: complete only the stranded canceled flow and let its parent process it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzGsxKey5g3kycKwGmpKNF

* fix: requeue a stranded canceled flow for a worker to complete its cancel

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzGsxKey5g3kycKwGmpKNF

* fix: keep a requeued canceled flow's start time

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzGsxKey5g3kycKwGmpKNF

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 14:40:01 +02:00
bebd762194 perf: complete a job in one statement on the common path (#11355)
* perf: complete a job in one statement on the common path

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

* fix: take completion locks in one order on every path

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

* fix: keep a losing zombie completion from touching its wac parent

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

* fix: leave a flow's ping alone when a step completes during its cancel

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

* test: probe only this test's completion for the lock wait

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

* fix: stamp a wac child's kept duration when its completed row exists

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJMJSJ2bDhYh7Shoh78Yyb

* perf: leave the parent ping out of completions with no flow to ping

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJMJSJ2bDhYh7Shoh78Yyb

* docs: note that the two completion statements must stay in step

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJMJSJ2bDhYh7Shoh78Yyb

* chore: update ee-repo-ref to 7a256cf353db7cf64a60a09fa0de7f3a8b27f626

This commit updates the EE repository reference after PR #830 was merged in windmill-ee-private.

Previous ee-repo-ref: 497137acb65e521568d46f3cbe1d66359f7f87ec

New ee-repo-ref: 7a256cf353db7cf64a60a09fa0de7f3a8b27f626

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-26 00:18:38 +02:00
hugocasaandClaude Opus 5.5 733c119fd9 feat: schedule hub scripts (#11330)
* feat: schedule hub scripts

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

* test: pin hub script schedule push

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

* feat: retry scheduled hub scripts natively

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

* chore: address review nits on hub schedules

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

* feat: open the hub picker from the script select

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

* chore: use a subtle button for the hub row

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:40:01 +00:00
Ruben FiszelandClaude Opus 5.5 245628210f perf: skip parent status write when a parallel loop iteration starts (#11348)
* perf: skip parent status write when a parallel loop iteration starts

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

* fix: keep the loop viewer off the parent job while a parallel loop runs

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

* docs: state what a parallel module's job would hold

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

* perf: test the parallel module with one containment check

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:41:27 +00:00
Ruben FiszelandClaude Opus 5.5 bc4f872f10 perf: skip the flow_env ancestor walk for sub-flows with nothing to inherit (#11349)
* perf: skip the flow_env ancestor walk for sub-flows with nothing to inherit

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

* fix: keep the flow_env mark out of sub-flow definitions replayed by restarts

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

* test: align the guest scopable-path test with app path validation

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:30:43 +00:00
hugocasaandClaude Opus 5 02006f364a fix: keep a cancel that lands after a worker last read its queue row (#11246)
* fix: keep a cancel that lands after a worker last read its queue row

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: take the cancellation from the queue row the completion deletes

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: wait for the completion to block on the row instead of a timer

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: settle a missed cancel from the deleted queue row alone

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 11:03:30 +00:00
Ruben FiszelandClaude Opus 5 69fafb9262 feat: check dynamic worker tags on the tag they resolve to (#11271)
* feat: check dynamic worker tags on the tag they resolve to

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

* test: pin the tag check after a flow preprocessor resolves the tag

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

* fix: keep tied tag placeholders exact and drop an unresolvable flow tag

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

* fix: describe tied tag placeholders in the custom tags editor

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

* fix: check workflow-as-code task tags on the tag they resolve to

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

* fix: judge a preprocessed flow's tag as written when it is run

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

* fix: check a preprocessed flow's own tag, as written only where it reads args

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

* feat: explain dynamic tags in the worker tag picker

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

* fix: look up worker availability for typed static tags

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

* fix: poll worker availability with the tag list as it is at each run

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

* feat: warn on custom tags with nothing fixed at their start or end

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

* fix: open the broad custom tag warning from the keyboard

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 07:30:48 +00:00
hugocasaandClaude Opus 5 48f00259c5 feat: support $flow_expr[...] dynamic tags on flow steps (#11170)
* feat: resolve $flow_expr[...] dynamic tags on flow steps

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: run an unresolvable $flow_expr tag on the default tag and give it the step input scope

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: resolve $flow_expr tags by path lookup instead of expression evaluation

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: say a $flow_expr tag fails to resolve, not to evaluate

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): word the $flow_expr help like the other dynamic tag lines

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reject a malformed $flow_expr placeholder instead of queueing its literal tag

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: render $flow_expr tag values through the $args path lookup

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: pin interpolate_args through the shared tag path rendering

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 14:37:50 +02:00
hugocasaandClaude Opus 5 381d4470ef fix: disable a schedule whose cron has no run left instead of panicking (#11195)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 11:40:00 +02:00
Ruben Fiszel 9a8a9c480c fix: stop reading an array job result as wm_failure or http response (#11154)
* fix: only read wm_failure and wm_labels from an object job result

* fix: serve an array sync result as json, not a composite response
2026-09-15 23:21:53 +02:00
Ruben FiszelandClaude Fable 5.1 0b1e9c0dda fix: wake a WAC parent from every path that completes its child (#11119)
* fix: wake a WAC parent from every path that completes its child

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2ibGNBxNd8oa3uQZLHsXn

* fix: park a WAC parent before writing its checkpoint so lock order matches child completion

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2ibGNBxNd8oa3uQZLHsXn

* fix: check the parent-child link before touching a WAC parent, wrap the fallback error, keep inline checkpoints in lock order

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2ibGNBxNd8oa3uQZLHsXn

* docs: say the zombie fallback keeps the WAC parent notification in its transaction

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 18:51:21 +00:00
Ruben FiszelandClaude Opus 5 c90d1d95c2 refactor: make the app policy's principal the authority for its identity (#10440)
* refactor: make the app policy's principal the authority for its identity

* fix: align the app backfill with the sibling migration and audit the uncached address

* chore: refresh the sqlx cache after rebasing onto the merged base

* fix: resolve the app execution address uncached, it decides the job's authorization

* chore: cache the EE queries at the ref this branch pins

* chore: cache the EE queries at the ref this branch pins

* fix: derive the app draft's on-behalf-of address on read

* chore: cache the query the draft derivation test added

* fix: derive the app identity on the draft-table and version reads too

* docs: state the draft resolver's authorization contract

* fix: resolve a draft's principal against workspace membership only

* chore: cache the membership lookup the draft resolver added

* fix: drop an unresolvable draft's address instead of leaving it stale

* perf: evict the address cache on change so app dispatch can read it

* fix: evict on superadmin role changes, not only address changes

* refactor: make the app policy's address optional instead of derived on read

* fix: follow an external superadmin's rename into the apps that name them

* docs: state the removal gate once, and correctly

* refactor: drop the app-policy version constant that gated nothing

* docs: drop the last reference to the removed constant

* perf: read the address cache everywhere now that eviction reaches every replica

* fix: keep persisted addresses off the cache the poller evicts asynchronously

* docs: state where the cached address is accepted and where it is not

* docs: keep the cache rule in one place and drop the stale premise

* docs: sort the two lookups by how long a wrong answer lives

* fix: resolve the schedule address uncached where it is written to the row

* docs: name the release this actually ships in

* perf: evict a superadmin's key per workspace instead of the whole cache

* fix: evict every alias a superadmin principal can be spelled as

* docs: describe the trigger as it is

* docs: cover the round-tripped read in the cache rule

* docs: record why a stale dispatch address cannot escalate

* fix: validate a dispatch address against the principal's live binding

* fix: carry the validated address through to the job row and token

* fix: record the validated address on the job row, not the one handed in

* test: run the substep tag check as the non-superadmin it means to test

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: rewrite a stored app address that disagrees with its principal

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: record the accepted staleness window of the cached dispatch address

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: record the validated address on the job's audit row

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: record the accepted rename race of pre-transaction identity resolution

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: separate the app's stored address from the derived one in the resolver doc

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: describe the job identity fast path the push comments skipped

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: backfill a legacy group-prefixed username as the group it names

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: resolve a schedule edit's identity before opening its transaction

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: never resolve a disabled member to a same-named superadmin

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: state what the email-change notify buys, and rewrap two comment lines

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: keep a group's runnables when offboarding a legacy group-prefixed member

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* fix: read the app author from the stored address, as execution does

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: record the rename race's full consequence as a known, accepted limitation

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

* docs: record the keep-target group address case as a known, accepted limitation

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JY4bBCR1q2c5XB8s2r7Ysc

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 09:10:15 +02:00
Ruben FiszelandClaude Opus 5 c6e0302d7c feat: let // materialize declare a dbt:// warehouse-relation write (#10978)
* feat: let `// materialize` declare a `dbt://` warehouse-relation write

`// materialize manual dbt://<warehouse>/<schema>/<name>` lets an ingestion
script in any language declare that it writes a warehouse relation, so it and
the dbt model reading that relation land on one asset node instead of two
disconnected pictures. `manual` is the only mode a warehouse target has —
nothing generates warehouse DDL — and the non-`manual` spelling is refused
rather than silently degraded. The `<warehouse>` segment is resolved against
the workspace's configured warehouses, like a descriptor's `profile.warehouse`.

The run records the same `materialized_partition` row a DuckLake target does,
from the generic job path rather than an executor: the DuckLake write engine is
DuckDB's, this declaration is anyone's.

With a non-dbt producer now possible, the blanket deploy-time refusal of
`# on dbt://<relation>` narrows to the shape that still cannot fire — every
writer of the relation being a dbt script, since a dbt run does not dispatch.
"Nothing produces it yet" stays accepted, as for every other asset kind, so
deploy order does not matter. A dbt script may not subscribe at all: its graph
ingest clears its own `dbt://` trigger rows. The one ordering the deploy cannot
catch — a subscription accepted before any producer, then claimed by a dbt
project — is named in that project's deploy log.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rw1WrKeRRzyYHjfkuB83ek

* fix: address review — preview stamping, stale producer set, public doc

Three findings from the local review round:

- Record the warehouse write only for a DEPLOYED script job. The annotation is
  a deploy-time contract (`manual`, three segments, a configured warehouse)
  checked where write access to the path is also required; honouring it in a
  preview, hub or inline-flow body let `jobs:run` alone restamp any relation's
  last writer from a script that never touched it.
- Exclude the deploying script's own rows from the producer set. Read
  committed, they describe the version being replaced, so a script dropping its
  `// materialize` while adding a subscription counted itself as the producer
  that would wake it and committed a dormant edge. It could not be that
  producer anyway — the dispatcher skips self-loops.
- `AssetKind::Dbt`'s doc no longer claims dbt is the exclusive producer of a
  warehouse relation, on both the types and the parser enum.

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

* fix: review round 1 — dbt-script materialize, set-form rule, doc

- Refuse `// materialize` on a dbt script, the producer half of the rule the
  trigger loop already applies to `// on`: the graph ingest republishes that
  path's asset rows wholesale, so a declared write is wiped by the deploy that
  accepted it while its runs keep stamping the relation.
- `dormant_dbt_subscriptions` now spells the same predicate its singular sibling
  does: the producer set has to be non-empty (nothing produces it yet is deploy
  order, not a dormant edge) and excludes the subscriber's own path (a script
  never wakes itself). Both divergences are pinned by tests.
- The docs no longer claim the dbt deploy log covers a native producer that drops
  its `// materialize`; it does not, and nothing else reports that case.
- An integration test over the deploy contract, since only a real deploy proves
  the handler feeds `sole_dbt_producer` the canonical key `asset.path` holds —
  the spelling that has to agree across the materialize target, the `// on` ref
  and the refusal that joins them.

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

* docs: qualify the any-language claim, and pin the dbt-script refusal

`AssetKind::Dbt`'s contract (both enums), the two runtime guides and the deploy
comment said a script of any language may declare a `dbt://` write, which the
dbt-script refusal added last round contradicts. They now say "any language but
dbt's own", with the reason: a project's writes are read from its manifest.

The deploy-contract integration test covers that refusal for both annotations.

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

* docs: teach the pipeline AI guidance the warehouse-relation target

The pipeline prompt (both sources, plus the regenerated bundle) told the model
`// materialize` is DuckDB-only and rejected on any other target, which now
steers users away from the very thing this PR adds. It distinguishes the managed
DuckLake write, still DuckDB-only, from the warehouse-relation declaration any
language but dbt's own may make.

`dbt_manifest.rs`'s module doc carried the same "the only thing that creates one"
overclaim the other four sites lost last commit.

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

* fix: draw an explicit dbt:// subscription on the canvas

The editor suppressed every `// on dbt://…` overlay, which was right while the
deploy refused all of them. It now refuses only a relation dbt alone builds, so
the suppression hid the author's own annotation for exactly the case this PR
adds — a subscription woken by a native `// materialize manual dbt://…`
producer. The deploy stays the gate.

Also the two stale claims round 4 named: the live pipeline prompt dropped the
dbt-script exception the base prompt carries, and the doc's e2e requirements
still said every `dbt://` subscription is refused.

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

* fix: refuse `// data_test` beside a `dbt://` materialize target

`// data_test` checks are verifier probes the DuckDB executor splices around a
managed write. A warehouse relation is written by the script itself, in any
language, so nothing would run them — and unlike the DuckLake `manual` case,
which at least fails loudly in that executor, a declarer in another language
deployed green with its data-quality assertions silently skipped.

Covered in the deploy-contract test and documented beside the annotation.

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

* fix: exclude a renamed producer from the sole-dbt producer set

The producer set already excluded the deploying script's own path, because its
committed rows describe the version being replaced. Under a rename the write
sits at the OLD path — still committed, and removed by the same uncommitted
transaction — so a producer renamed while it drops its `// materialize` and adds
`// on dbt://…` still counted as the producer that would wake it, and committed
a dormant edge.

The deploy-contract test covers it: without the exclusion the rename deploys
201 instead of being refused.

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

* test: take the rename test's parent hash from the create response

`format!("{:x}", …)` over the stored i64 drops leading zeros, while
`ScriptHash`'s deserializer hex-decodes and demands 8 bytes — so a hash below
2^60 would 422 the request instead of reaching the refusal it asserts on, on
roughly one in sixteen spellings of that script body. The create response
already carries the zero-padded form, as the rest of the suite uses.

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

* docs: state the concurrent-ingest interleaving honestly

`sole_dbt_producer`'s doc claimed the concurrent-deploy race only ever resolves
toward refusing. It does when the uncommitted producer is native; when it is the
dbt ingest, the check sees an empty producer set and accepts, and if that ingest
then commits and runs its warning query before the subscriber's trigger row
lands, neither side reports the dormant edge.

Not serialized: the two would have to share a per-relation lock, and the ingest
takes `script … FOR UPDATE` before its own advisory lock, so a deploy holding
relation locks first inverts that order into a cross-subsystem deadlock — a worse
failure than the cosmetic edge. Recorded beside the other orphaning the deploy
cannot catch, with the bound both share: the next deploy of that project warns.

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

* fix: refuse a `dbt://` subscription that is not a whole relation

`# on dbt://main/analytics` deployed and persisted a trigger row. Every producer
spells `<warehouse>/<schema>/<name>` — the manifest ingest derives it from
`relation_name`, a `// materialize` target is checked against it — so a partial
one is an edge nothing can ever wake, which is what the dbt-only refusal exists
to prevent.

The shape now has one definition (`is_full_relation_path`) that both halves of
the deploy ask, rather than a segment count spelled twice: a subscription and a
write that disagreed would refuse and accept the same string.

Also rewrites the canvas test's comment as a current constraint per AGENTS.md.

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

* fix: hold both halves of the deploy to one `dbt://` relation validator

A subscription checked the relation's shape but not its warehouse, so
`# on dbt://<unconfigured>/<schema>/<name>` deployed and persisted a trigger row
for something no producer can ever write: the write side refuses that exact
string, and a dbt project's `profile.warehouse` resolves against the same config,
so no later deploy fixes it and the dormant-edge warning cannot report it either.

The shape rule and the warehouse rule now live in one `validate_dbt_relation`
that both halves call, rather than being spelled per site — the previous two
rounds each closed one half of one rule, which is the drift that invites.

Also moves the parser test out from between a comment and the test it documents,
and names both refusals in the doc's list.

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

* fix: drop the subscription-only clause from the shared refusal message

"so nothing can produce it" reads backwards on the `// materialize` side, which
is the producer. The remaining sentence says what is wrong on both.

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

* fix: bound a `dbt://` relation by the asset-path column in the shared validator

`asset.path` is VARCHAR(255) and the manifest ingest drops a relation that
outgrows it rather than failing the whole graph, so past the column no producer
row can exist on either side. `script_trigger.trigger_ref` is unbounded text, so
an overlong subscription deployed and stayed dormant for good; an overlong write
reached Postgres and failed the deploy on a `value too long` instead of a message.

Both now refuse in the validator the two halves share, against the ingest's own
constant. The integration case computes the ref from that constant so it cannot
drift back under the bound.

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

* fix: report a warehouse-lookup failure as the failure it is, and correct the boundary

`dbt_warehouse_exists` fails three ways — no such warehouse, the query itself,
and a setting with no `resource_path` — and all three became a 400 blaming the
user's warehouse name. A pool timeout mid-deploy told a retrying sync that a
transient server error was a permanent client one. Only `NotFound` is the
annotation's fault now.

The known-boundary paragraph claimed a flow-runner run still cascades. It does
not: it is routed by `flow_step_id`, which `is_eligible_kind` rejects, as
`asset_trigger_dispatch.rs` pins. Recording and cascading are decided separately,
so the paragraph now names all three routes rather than merging two of them — and
the row it omitted, an ordinary flow step, which records and never cascades.

E2E item 7 said "deployable" where the rule is "wakeable": with only the dbt
project reading the relation the producer set is empty, which deploys fine.

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

* docs: correct two rationales the last commit got wrong

`Error::SqlErr` already maps to 400 in this codebase, so the query case's status
was never the thing at stake. What the `NotFound` match earns is that a query
failure and a malformed setting stop being described as an unconfigured warehouse
name, and that the malformed-setting `InternalErr` reaches its own 500 instead of
being flattened.

And a flow step is two shapes, not one: a step running a deployed script is a
`Script` job that records and never cascades, while a step with an inline body is
`FlowScript`, which the recording guard excludes along with previews.

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

* fix: warn about dormant subscriptions from the run that publishes ownership too

A run whose static descriptor finds its profile moved re-ingests the version's
graph and republishes path ownership, exactly as a deploy does — so it can be
what leaves a subscription accepted while the relation had no producer with dbt
as its only one. That path discarded `persist_ingest`'s result and emitted no
warning, which also made the doc's enumeration of unreported orphanings wrong.

Both ownership-publishing points warn now. An agent worker still cannot: it
reaches these tables only through the API and its ingest publishes without
reading back, which the doc now says.

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

* docs: an agent run publishes no ownership, and the warning has two callers

The agent-worker sentence called it an exception that publishes ownership without
warning. It publishes none: `Connection::Http` forces per-run models, and
`publishes_ownership()` is the negation of that, so an agent stores a job-pinned
snapshot and leaves workspace ownership with the deployed graph — it cannot orphan
a subscription at all.

`warn_dormant_subscribers`' own doc still named the deploy log as the only place
the warning shows, one commit after it gained its second caller.

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

* docs: stop the managed-write rule from contradicting the dbt:// target

The sentence after the warehouse-relation paragraph says `// materialize` means
the runtime writes the table for you and the body is a bare SELECT. That is the
managed DuckLake rule, written before a `dbt://` target existed, and unqualified
it tells the model the opposite of what the paragraph above it just said — a
model following the more prominent one emits a SELECT for a warehouse relation,
which deploys and then writes nothing.

Both prompt sources now scope it, and both name the `// data_test` refusal beside
a `dbt://` target, which the badge list advertised without the caveat.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 17:38:07 +02:00
Ruben FiszelandClaude Opus 5 f977f5bf8b fix: stand the WAC park down for a cancel that beat it to the row (#10990)
* fix: stand the WAC park down for a cancel that beat it to the row

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHfNFFJh3ozZYgyyoaEepu

* refactor: share the cancel result payload with canceled_job_to_result

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHfNFFJh3ozZYgyyoaEepu

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-05 09:41:15 +00:00
Ruben FiszelandClaude Opus 5 54287102b2 fix: meter WAC compute per segment, not the whole sleep (#10985)
* fix: clear started_at when a WAC parent suspends

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzS5d5Dc3GL49kWZPQAQCg

* fix: restore started_at on the WAC dispatch rollback, fail loudly on a no-op suspend

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzS5d5Dc3GL49kWZPQAQCg

* fix: restore the pulled segment start on the WAC dispatch rollback

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzS5d5Dc3GL49kWZPQAQCg

* feat: meter WAC execution per segment instead of only the last one

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzS5d5Dc3GL49kWZPQAQCg

* fix: make the cloud feature self-sufficient per crate

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzS5d5Dc3GL49kWZPQAQCg

* chore: name windmill-common/cloud directly in the worker cloud feature

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzS5d5Dc3GL49kWZPQAQCg

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-05 11:11:29 +02:00
Ruben FiszelandClaude Fable 5.1 11138284ac fix: deploy a relocked script version only when its lock changed (#10966)
* fix: deploy a relocked script version only when its lock changed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: write the unchanged relock hash under the row lock and skip the phantom tally

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: requeue a superseded relock and read the live head past the script cache

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: re-read the relock head after waiting on its lock and keep module locks

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* fix: bound the relock head re-read instead of reading once

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* chore: refresh the sqlx cache entry for the re-indented lock write

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

* test: pin the waiting-relock requeue and the multi-file importer no-op

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdEb6gzCZ2qXmAQJAeMf9W

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 01:01:36 +02:00
hugocasaandClaude Opus 5 8f349c032a fix: nested template literals in step inputs, and unresolvable $args tags (#10856)
* fix(frontend): keep nested template literals intact in template inputs

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: fail a flow step with an unresolvable $args tag instead of hanging

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): surface input expression errors when running a step test

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): treat an escaped \${ as literal text when escaping backticks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: accept the string "null" as a tag component, reject only JSON null

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: leave a same_worker step's inert tag alone, log an unresolved flow tag

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): escape every backtick when the template walk desynchronizes

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: leave a dedicated runnable's inert step tag alone

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reroute a step only when its own tag is what failed to resolve

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: name the inert-tag guard step_is_pulled_by_tag

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reject a tag only when it interpolates to nothing at all

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): validate the template walk instead of trusting a balanced stack

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: describe what an unresolvable tag actually interpolates to

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(frontend): decide template escaping with a real parser, not a hand-rolled scan

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: name is_flow_step on push now that it is load-bearing

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): heal an expression escaped before nested templates were handled

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reroute a step whose tag reads args that failed to evaluate

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: never hand a job that failed before running to a dedicated runner

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: reroute only a step whose args failed, leave other tags untouched

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: drop the post-preprocessor tag fallback, leaving tag resolution untouched

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: leave interpolate_args exactly as it was

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: use a generic example in the template literal tests

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): show an expression escaped by the old rule as it was authored

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): surface input expression errors from every step-run entry point

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: state what is_dedicated_worker actually reads

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): heal only text whose backticks were all escaped by the old rule

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): match the old rule textually so an authored backslash still heals

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(frontend): heal only expressions the old rule broke, never ones that parse

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 16:27:54 +02:00
Ruben FiszelandClaude Opus 5 4b406e37c0 fix: size the ephemeral job token to the job timeout it must serve (#10804)
* fix: size job token to the premium cloud job timeout

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

* fix: give the job token setup headroom and drop dead MAX_TIMEOUT_DURATION

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

* fix: cap job token setup slack so self-hosted tokens stay at 7d

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 09:30:08 +00:00
1f59841a67 feat: add WM_ROOT_WORKSPACE, the closest dev or prod workspace of a job (#10776)
* feat: add WM_ROOT_WORKSPACE, the closest dev or prod workspace of a job

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBMJwogo6jJ1P55uvB3YpF

* fix: do not cache a failed root-workspace lookup, and sweep on fork create

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBMJwogo6jJ1P55uvB3YpF

* fix: shorten the agent-worker root-workspace TTL and pin the sweep wiring

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBMJwogo6jJ1P55uvB3YpF

* chore: update ee-repo-ref to a2fa58e5301d3865dd06ad73519e20ba7a5af0f0

This commit updates the EE repository reference after PR #736 was merged in windmill-ee-private.

Previous ee-repo-ref: 07a9d26a79a403ae27c48abd508a6699f2c87c49

New ee-repo-ref: a2fa58e5301d3865dd06ad73519e20ba7a5af0f0

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-20 15:40:22 +02:00
c2deea13b7 fix(security): a WM_TOKEN job token can never be a global superadmin (GHSA-hfh4-cx4h-3fcr) (#10124)
* fix(security): a WM_TOKEN job token can never be a global superadmin (GHSA-hfh4-cx4h-3fcr)

Privilege escalation: an app/flow/schedule/trigger execution policy's `on_behalf_of`
(which a `wm_deployers` member can set) could point at a superadmin email. The
resulting job `WM_TOKEN` then passed the email-based superadmin checks, granting
instance superadmin. `forbid_superadmin_job_token` only guarded ~15 of ~75 routes.

Fix at the token layer: a WM_TOKEN must never satisfy a superadmin gate,
regardless of whose email it runs as (sentinel OR a real superadmin).

- `ApiAuthed` gains a `job_id` field, stamped once in `AuthCache::get_opt_job_authed`
  from the resolved token's job_id (correct even on cache hits).
- `require_super_admin(db, email)` -> `require_super_admin(db, &ApiAuthed)`, rejects
  `authed.job_id.is_some()`. `require_super_admin_email` kept for the few internal
  callers without an ApiAuthed.
- `is_super_admin_authed(db, &ApiAuthed)` for the boolean `is_super_admin_email`
  authorization branches on request handlers (workspace deletion, fork drops,
  dev-workspace attach/archive, object-storage SSRF exemption, custom dbname, EE GHES
  + connected repositories, ...). Migrate ~75 sites (OSS + EE).
- CUSTOM_INSTANCE_DB reads the *authenticated* job_id, not the caller-supplied
  `?job_id` query param. Worker-tag check takes a precomputed job-aware `is_super_admin`
  on the request path.

Execution-time on-behalf checks (scheduled/flow worker-tag, Cloud enqueue quota,
is_devops_email) are hardened in a follow-up — see
docs/followup-onbehalf-execution-privilege-hardening.md.

Regression tests: a superadmin-email WM_TOKEN is rejected on `require_super_admin`
routes, on `DELETE /workspaces/delete/{w}` (403, workspace preserved), and on the
CUSTOM_INSTANCE_DB lookup with no `?job_id` (401); real superadmin tokens still succeed.

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

* fix: cap devops role at workspace admin and reject reserved on_behalf_of identities

Extends the job-token cap with three pieces:

- `require_devops_role` takes `&ApiAuthed` and rejects job tokens.
  `is_devops_email` is true for superadmin emails, so every worker-management,
  instance-config and service-log route was reachable by the same superadmin
  `WM_TOKEN` that `require_super_admin` already rejects.
- A `job_id` claim that does not parse as a uuid rejects the token rather than
  resolving to `None`, which would clear the job provenance and uncap it. Applies
  to the internal JWT and the external `jwt_ext_` path.
- Defense in depth at store time: `validate_on_behalf_of` refuses the reserved
  internal sentinels as an `on_behalf_of` on apps/flows/scripts/schedules/triggers,
  and app execution refuses a policy carrying one — covering already-persisted and
  forked-app rows that predate the cap. Deploying on behalf of a real user,
  including a real superadmin, stays allowed; the cap handles that at execution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(mcp): preserve job-token provenance when minting the proxy JWT

The MCP endpoint-tool proxy re-mints a JWT from the caller's ApiAuthed to
forward the proxied request, but passed job_id: None. A job's WM_TOKEN is
capped at workspace admin (GHSA-hfh4-cx4h-3fcr); dropping the job_id here
re-minted an uncapped token that satisfies require_super_admin /
require_devops_role on the proxied route (e.g. listWorkers exposing worker
IPs, job/workspace IDs, and sensitive tags).

Carry api_authed.job_id into create_jwt_token. Adds an in-module regression
that decodes the forwarded JWT and asserts the job_id is preserved for a job
caller and absent for a non-job caller.

Reported by Codex CI review (P1) on #10124.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: cap the admin-or-devops gate at workspace admin for job tokens

require_admin_or_devops (the EE critical-alerts endpoints) grants when the
caller is a workspace admin OR an instance devops. is_devops_email is true
for superadmins, so a WM_TOKEN running on-behalf of a superadmin who is not a
member of the target workspace could clear the devops branch and read/ack that
workspace's critical alerts (GHSA-hfh4-cx4h-3fcr). This gate takes a bare
email, not an ApiAuthed, so the token-layer cap could not see it.

Thread the caller's job-token provenance and reject the devops branch for job
tokens, matching require_devops_role. The workspace-admin branch stays allowed
— that is the cap ceiling. Adds an enterprise-gated regression proving the
bypass is closed and a real superadmin token still clears the gate.

Found while auditing the PR for bare-email gates the choke-point cap misses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: cap instance-global is_admin gates at workspace admin for job tokens

Three instance-global routes gate on the caller's own `is_admin` claim, which
`ApiAuthed.is_admin` carries into a WM_TOKEN (it is a workspace-admin claim,
true for superadmins too). A job token is capped at workspace admin
(GHSA-hfh4-cx4h-3fcr), so its is_admin claim must not authorize instance
actions on a route with no workspace binding:

- `unarchive_workspace` — unarchive an arbitrary workspace by id
- `prune_concurrency_group` — delete a global concurrency group
- `list_worker_groups` — return unobfuscated `env_vars_static` (may hold secrets)

Add job-token-aware `is_instance_admin` / `require_instance_admin` helpers (the
same shape as `require_super_admin` / `require_devops_role`) and use them at
these three sites. Workspace-scoped `require_admin(authed.is_admin, ...)` gates
are intentionally left unchanged — a workspace-admin job token is within the
cap there. Regression added covering all three; verified it lets a WM_TOKEN
unarchive/leak without the fix and is blocked with it.

Reported by Codex CI review (P1) on #10124.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(mcp): drop orphaned path_field_renames from EndpointTool test helper

The merge with main adopted main's mcp path-substitution refactor (#10162),
which removed the `path_field_renames` field from `EndpointTool` and its
consumer (`substitute_path_params` no longer takes per-field path renames).
main's `runner.rs` `ep` test helper still constructed the struct with
`path_field_renames: None`, so the workspace test build (cargo test --all,
which compiles windmill-mcp's own #[cfg(test)] module under the `server`
feature) failed with E0560. A plain `cargo check` does not compile that test
module, so it only surfaced in CI's cargo_test.

Remove the orphaned field to match the struct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test: describe the sentinel-rejection policy the forged-identity test asserts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: complete ApiAuthed initializers in feature-gated tests after merge

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: stop job tokens minting credentials that shed their provenance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: cap the MCP OAuth approval mint at the same elevated-job-token gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: cap the self-service password reset at the elevated-job-token gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: cap app embed/SDK mints and scope widening at the elevated-job-token gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: keep job tokens from destroying the account they run on behalf of

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: deny job tokens a foreign-workspace admin claim and workspace ejection

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: keep the follow-up inventory in the PR instead of the repo

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: make the session workspace status gate job-token aware

session_workspace_status derived its superadmin branch from a bare email
check, so a job token carrying a superadmin identity resolved the existence
of workspaces it has no relationship with rather than seeing them as
deleted. Switch to is_super_admin_authed, matching every other instance
gate reached from a request ApiAuthed.

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

* revert: leave the global concurrency-group listing on the plain admin gate

The listing exposes concurrency keys across workspaces, which is metadata
rather than a capability, and it 401s rather than degrading. Keep the guard
on the prune route next to it, which is the destructive one.

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

* fix: keep the instance-admin gate on the global concurrency listing

The listing spans every workspace's concurrency keys, and the gate rejects
only job tokens: the !is_admin branch is the pre-existing check, so
workspaced tokens and interactive admins are unaffected.

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

* chore: update ee-repo-ref to d30af67d38954f9012f7bad08da23e347344b4c6

This commit updates the EE repository reference after PR #664 was merged in windmill-ee-private.

Previous ee-repo-ref: 7870573dbc3360f99bada143f094c67dce0d9e9c

New ee-repo-ref: d30af67d38954f9012f7bad08da23e347344b4c6

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: hugocasa <hugo@casademont.ch>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-19 22:33:46 +02:00
ed2ff6c5e7 fix: scope git-sync concurrency key per repository (#10767)
* [ee] fix: scope git-sync concurrency key per repository

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

* test: dedupe git repo resource helper, fail loudly on callback timeout

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

* fix: reserve the workspace prefix in the git-sync concurrency key cap

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

* test: cover the concurrency-key prefix reservation and the pull lane

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

* chore: update ee-repo-ref to dff61d6da80d15f8327af99d322c00cc91f784ff

This commit updates the EE repository reference after PR #734 was merged in windmill-ee-private.

Previous ee-repo-ref: e50a7eca7d7f8771979485f654831b15de59ec25

New ee-repo-ref: dff61d6da80d15f8327af99d322c00cc91f784ff

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-19 21:25:02 +02:00
53eb94659b feat(telemetry): extend feature-usage tracking beyond AI features (#10681)
* feat(telemetry): extend feature-usage tracking to long-tail features

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

* docs: describe telemetry as product feature usage rather than AI usage

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

* refactor(telemetry): trim disclosure copy and drop unused pick origin

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

* fix(telemetry): count trigger fires per run and key hub picks from hub data

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

* fix(telemetry): slugify hub keys and order both writers' upserts

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

* fix(telemetry): key native trigger adoption by service so it matches fires

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

* chore: update ee-repo-ref for native trigger adoption fix

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

* refactor(telemetry): move feature-usage collection into the ee crate

* docs: point feature-telemetry at the moved registry and rust writer

* docs: correct the trigger-fire gate comment to match measured step counts

* docs: put the private-build caveat on the verification step

* chore: update ee-repo-ref to f079db9e7962a413b349c4ff8036080894f30771

This commit updates the EE repository reference after PR #725 was merged in windmill-ee-private.

Previous ee-repo-ref: 055adb80416f9339c9a28ae7fbaeadad30d74959

New ee-repo-ref: f079db9e7962a413b349c4ff8036080894f30771

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-14 18:50:38 +02:00
Ruben FiszelandClaude Opus 5 633d7bcb2e feat: add trigger_history table with source tracking (#10696)
* feat: add trigger_history table with source tracking

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

* fix: gate trigger history reads on scopes and harden its writers

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

* fix: filter trigger history scopes in SQL and match the cleared-handler diff

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

* fix: record a trigger restore from the trashbin in its history

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

* fix: record bulk http trigger creates and document the recording boundary

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

* fix: lock the trigger row when capturing its history preimage

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

* fix: only record an auto-disable that actually flipped the schedule

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

* chore: state the auto-disable invariant once instead of at four call sites

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

* feat: render trigger history changes as a structured field diff

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

* fix: make a server-initiated disable atomic with its history row

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

* docs: note that the auto-disable savepoint takes no pool connection

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

* docs: note the flow fallback is the last chance to disable

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

* fix: never leave a trigger enabled because its history row failed

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

* fix: retry the disable history row instead of dropping it on first failure

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

* fix: use the design-system Button for the change-value expander

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

* fix: hold the trigger row lock across its disable history row

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

* fix: keep the history-loss alert out of the listener cancellation race

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

* fix: read the history workspace through the trigger-workspace seam

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:57:11 +02:00
Ruben FiszelandClaude Opus 5 71b9989daa feat: auto-build binaries to object storage on deployment (#10673)
* feat: auto-build binaries to object storage on deployment

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

* fix: queue the auto-build from pre-locked deploys and off the lock slot

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

* fix: materialize companion modules before a deploy-time build

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

* fix: keep a build job from stamping lock_error_logs on a healthy script

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

* test: de-flake test_flow_lock_all and surface the lock error it hides

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

* test: trim drafting history from the flow-lock fixture comments

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

* fix: stop a binary build from restarting dedicated workers

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

* fix: keep the build-job marker off the agent wire and out of user args

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:50:28 +02:00
fb82748296 fix: make on_behalf_of control permissions for scripts and flows (#10438)
* fix: make on_behalf_of control permissions for scripts and flows

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

* fix: inherit the recorded on-behalf-of identity when a preserving deploy omits it

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

* fix: keep an omitted permissioned_as from re-versioning an unchanged script

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

* fix: derive the on-behalf-of principal from the email and reject mismatched pairs

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

* fix: stop workspace deploys from carrying a source-workspace principal

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

* docs: correct the onBehalfOfPermissionedAs param doc

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

* test: pin that workspace deploys never carry a source-workspace principal

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

* docs: correct the omitted-principal contract and refresh generated prompts

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

* fix: keep external-superadmin principals on email-only redeploys

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

* fix: scope the recorded principal to its workspace and prefer real accounts

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

* fix: carry the recorded principal correctly through drafts and set-permissioned-as

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

* fix: sweep draft identity pairs on email change and offboarding

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

* fix: leave group identities alone when sweeping a user's email

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

* fix: treat only g/ without an email as a group, and match the offboard preview

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

* fix: stop the group guard from skipping rows with no recorded principal

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

* docs: state the group guard once instead of restating it

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

* refactor: make the permissioned_as the only stored on-behalf-of identity

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

* perf: skip resolving the on-behalf-of address for sync clients that discard it

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

* fix: address the local review of the identity refactor

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

* fix: resolve the on-behalf-of identity coherently across clones, offboarding and no-op deploys

* test: pin that a fork keeps only the on-behalf-of identities that resolve in it

* fix: decide a principal prefix-first everywhere and canonicalize bare addresses

* fix: prefix a slash-containing address so a reader cannot take it for a group

* fix: read an address as a username before the group- convention

* fix: rewrite the canonical principal when an account's address moves

* fix: keep the address form of a principal to accounts without a usr row

* fix: reject an identity a job row cannot carry and read it uncached at dispatch

* fix: count characters against the job identity width and cap the backfill

* refactor: name the script/flow principal on_behalf_of, as apps do

* docs: state the caller-must-authorize contract on the identity resolvers

* fix: keep writing on_behalf_of_email until every worker reads the principal

* fix: err high on the compatibility version and document the last resolver

* fix: keep the compatibility address current through identity mutations

* fix: carry the compatibility address with the principal on every copy path

* chore: re-pin the EE ref to the companion branch merged with EE main

* fix: key the dbt retry lookup on the stored principal

* fix: keep a mixed-version address recoverable through a fork

* fix: read a round-tripped address uncached so a redeploy is not rejected

* fix: refuse an email change that would make a principal unenqueueable

* chore: update ee-repo-ref to ac3d7d015296f041ae44ab6bc4953485f44d36e4

This commit updates the EE repository reference after PR #704 was merged in windmill-ee-private.

Previous ee-repo-ref: 219b0b03905a1a0028054b3a4985724e77d09036

New ee-repo-ref: ac3d7d015296f041ae44ab6bc4953485f44d36e4

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-01 20:37:21 +02:00