Commit Graph
174 Commits
Author SHA1 Message Date
Ruben Fiszelandrubenfiszel 74c1813f98 chore(main): release 1.801.0 (#10921)
* chore(main): release 1.801.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-09-02 01:01:01 +02:00
Ruben Fiszelandrubenfiszel 870f67121d chore(main): release 1.800.1 (#10910)
* chore(main): release 1.800.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-09-01 11:34:32 +02:00
Ruben Fiszelandrubenfiszel 412eb90c0d chore(main): release 1.800.0 (#10888)
* chore(main): release 1.800.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-31 20:29:23 +02:00
Ruben Fiszelandrubenfiszel 7a0c81d722 chore(main): release 1.799.0 (#10874)
* chore(main): release 1.799.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-28 17:26:18 +02:00
Ruben Fiszelandrubenfiszel 90b40fffc3 chore(main): release 1.798.1 (#10870)
* chore(main): release 1.798.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-27 12:00:45 +02:00
Ruben Fiszelandrubenfiszel 2302e58c24 chore(main): release 1.798.0 (#10868)
* chore(main): release 1.798.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-27 11:07:15 +02:00
Ruben Fiszelandrubenfiszel 52ca19e9ae chore(main): release 1.797.0 (#10848)
* chore(main): release 1.797.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-27 10:15:23 +02:00
Ruben Fiszelandrubenfiszel 0f3d884c6f chore(main): release 1.796.0 (#10810)
* chore(main): release 1.796.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-24 22:42:33 +02:00
Ruben Fiszelandrubenfiszel 74af4ed939 chore(main): release 1.795.0 (#10807)
* chore(main): release 1.795.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-22 12:11:36 +02:00
Ruben Fiszelandrubenfiszel 1a506b8f22 chore(main): release 1.794.1 (#10801)
* chore(main): release 1.794.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-21 13:45:56 +00:00
Ruben Fiszelandrubenfiszel 55b6279058 chore(main): release 1.794.0 (#10782)
* chore(main): release 1.794.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-21 12:27:44 +02:00
Ruben Fiszelandrubenfiszel 2439a610be chore(main): release 1.793.0 (#10764)
* chore(main): release 1.793.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-20 22:18:01 +02:00
Ruben Fiszel 05abf6d5aa feat(cli): deduplicate identical script lockfiles (dedupeLockfiles) (#10769)
* feat(cli): deduplicate identical script lockfiles into one per language

* test: pin shared lockfile path classification

* fix(cli): never delete a lockfile the dedup plan also writes

* fix(cli): plan lockfile dedup from the whole tree, not the sync scope

* fix(cli): keep dedup out of dry runs and stop hiding scripts from its scan

* test: pin which files the shared-lock scan counts as readers

* fix(cli): validate shared-lock refs and let the majority keep its file

* fix(cli): snapshot shared-lock ownership before regeneration moves it

* fix(cli): address dedup review nits (dry-run push, json shape, scan scope)

* refactor(cli): put shared lockfiles in a top-level locks/ directory

* fix(cli): claim only the shared lock names windmill writes, and only when on

* fix(cli): read the lock field itself, and count only scripts sync reads

* fix(cli): parse metadata by its real format and lint from the sync root

* fix(cli): never re-hash a script whose generation failed

* fix(cli): share sync's walk exclusions and fail closed on unreadable dirs

* fix(cli): keep a lockfile the metadata on disk still references

* fix(cli): decide a lock is unread from the metadata field sync reads

* refactor(cli): name shared lockfiles after the dependency file they resolve

* fix(cli): carry shared lockfiles a narrowed sync cannot speak for

* fix(cli): move a shared lockfile when its dependency file moved, not on a head count

* fix(cli): let the many correct a shared lockfile a lone variant planted

* fix(cli): read why a lock differs from the stamp the worker writes into it

* fix(cli): let an agreeing majority speak whatever the stamps say

* docs(cli): count the disjuncts the comment introduces

* fix(cli): keep a private lock for any script the worker locks differently

* fix(cli): match annotations by the worker's own names, not by shape

* fix(cli): recognize the py: interpreter pin the macro does not cover

* fix(cli): let the map speak for dependency-file deletions

* perf(cli): group lock entries without rebuilding the group per insert

* fix(cli): defer shared-lock deletions until the metadata has settled

* fix(cli): decide shared-lock readers by the lock field, failing closed

* fix(cli): read folded lock refs and keep locks read by unparseable metadata

* refactor(cli): one shared-lock reader scan, shared by the pull and push paths

* fix(cli): keep nested dependency set names out of shared lockfiles

* fix(cli): drop a shared-lock scan gate that no real repo took
2026-08-20 15:08:13 +02:00
Ruben Fiszelandrubenfiszel a7637aca31 chore(main): release 1.792.2 (#10753)
* chore(main): release 1.792.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-19 14:15:59 +02:00
Ruben Fiszelandrubenfiszel 9f517d5a40 chore(main): release 1.792.1 (#10750)
* chore(main): release 1.792.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-18 17:10:42 +02:00
Ruben Fiszelandrubenfiszel 8efede55d6 chore(main): release 1.792.0 (#10745)
* chore(main): release 1.792.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-18 12:32:35 +02:00
Ruben Fiszelandrubenfiszel ce71756c89 chore(main): release 1.791.0 (#10718)
* chore(main): release 1.791.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-18 01:55:42 +02:00
Ruben Fiszelandrubenfiszel 010d67e07f chore(main): release 1.790.1 (#10712)
* chore(main): release 1.790.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-17 11:08:47 +02:00
Ruben Fiszelandrubenfiszel 944ad1083a chore(main): release 1.790.0 (#10699)
* chore(main): release 1.790.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-15 14:54:31 +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 Fiszelandrubenfiszel 80a18ec284 chore(main): release 1.789.0 (#10670)
* chore(main): release 1.789.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-13 13:29:52 +02:00
Ruben Fiszelandrubenfiszel b39860235c chore(main): release 1.788.0 (#10664)
* chore(main): release 1.788.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-12 21:17:47 +02:00
Ruben Fiszelandrubenfiszel 2ac3e64fe2 chore(main): release 1.787.0 (#10657)
* chore(main): release 1.787.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-12 13:27:21 +02:00
Ruben Fiszelandrubenfiszel 20953a0c67 chore(main): release 1.786.1 (#10652)
* chore(main): release 1.786.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-12 09:40:03 +02:00
Ruben Fiszelandrubenfiszel 45a6e4932a chore(main): release 1.786.0 (#10649)
* chore(main): release 1.786.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-12 02:22:18 +02:00
Ruben Fiszelandrubenfiszel a65a184a80 chore(main): release 1.785.0 (#10626)
* chore(main): release 1.785.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-11 18:26:31 +00:00
hugocasaandClaude Fable 5 85134578b4 fix(cli): sync push crashed on edited fileset children; reject non-canonical fileset dirs (#10572)
* fix(cli): route fileset children to their parent resource on sync push

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

* fix(cli): scope fileset pointer validation to sync pushes

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

* fix(cli): error on script push of file/fileset resource content files

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

* fix(cli): enforce server-canonical fileset pointers and fail fast before apply

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

* fix(cli): resolve ws-specific fileset metadata and validate pointers before dry-run

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

* fix(cli): prefer workspace-specific fileset metadata over base file

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

* test(cli): make fileset metadata lookup assertions platform-separator safe

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

* fix(cli): stop dropping fileset children whose names look like typed metadata

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

* fix(cli): exempt fileset children from the current-workspace classifier too

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 13:16:45 +00:00
Ruben Fiszelandrubenfiszel cf3ddaa3cc chore(main): release 1.784.0 (#10603)
* chore(main): release 1.784.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-10 22:56:55 +02:00
Ruben Fiszel 9eef70ea8b fix(cli): attach the right job path to preview runs (#10606)
* fix(cli): attach the right job path to preview runs

* fix(cli): keep a deliberately-absent file in the directory it was named in

* fix(cli): resolve links for a path naming a file that is not there
2026-08-10 19:37:46 +02:00
Ruben Fiszelandrubenfiszel 099efa358a chore(main): release 1.783.0 (#10578)
* chore(main): release 1.783.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-07 12:41:05 +02:00
Ruben Fiszelandrubenfiszel d592fb75eb chore(main): release 1.782.0 (#10566)
* chore(main): release 1.782.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-06 12:55:48 +02:00
Ruben Fiszelandrubenfiszel c03bd34be9 chore(main): release 1.781.3 (#10563)
* chore(main): release 1.781.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-06 10:02:27 +02:00
Ruben Fiszelandrubenfiszel 74737d16dd chore(main): release 1.781.2 (#10561)
* chore(main): release 1.781.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-06 09:53:18 +02:00
Ruben Fiszelandrubenfiszel c7ea530e1f chore(main): release 1.781.1 (#10556)
* chore(main): release 1.781.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-06 02:17:57 +00:00
Ruben Fiszelandrubenfiszel 9cf307f3ad chore(main): release 1.781.0 (#10528)
* chore(main): release 1.781.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-06 00:04:25 +02:00
Ruben Fiszelandrubenfiszel 055a9c2690 chore(main): release 1.780.0 (#10527)
* chore(main): release 1.780.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-05 00:37:06 +02:00
Ruben Fiszelandrubenfiszel 59072a1273 chore(main): release 1.779.0 (#10496)
* chore(main): release 1.779.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-04 20:45:57 +02:00
Ruben Fiszelandrubenfiszel 4c4d6c98bf chore(main): release 1.778.0 (#10469)
* chore(main): release 1.778.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-04 01:49:00 +02:00
f365929eaa feat(fork): merge a fork deletion on evidence, not on the counters (#10484)
* feat(fork): merge a fork deletion on evidence, not on the counters

`workspace_diff.ahead`/`.behind` record that a write happened on a side,
not what it was or who made it. That leaves one row shape undecidable: an
item the parent has and the fork does not can mean the parent added it,
the fork deleted it, or a git-sync pull reverted a deploy that had just
brought it in. #10467 kept every such row out of the merge direction,
which killed the phantom but also dropped the only way to propagate a
fork-side deletion and left a rename's old path behind in the parent.

Record the evidence instead:

- `workspace_diff` gains, per side, the last event's kind (`write` /
  `delete` / `rename_from`) and origin (`authored` / `sync`). Rows
  written before the migration have neither and keep #10467's behavior.
- The kind is probed from whether the path still holds an item once the
  write has committed; an item kind the probe doesn't map records no
  evidence rather than a deletion. Create and update are not split —
  nothing at that point tells them apart for every kind, and the
  comparison already recomputes existence per side.
- The origin comes from an `X-Windmill-Deploy-Origin` header the API
  scopes into a task-local for the request. It is the load-bearing half:
  recording `delete` alone would read a git-sync revert as a fork
  deletion and reproduce the original bug. Two clients set it — `wmill
  sync push` (which the git-sync auto-pull runs inside a job) and the
  compare page's parent→fork "Update fork". Merging the other way stays
  authored so a deletion keeps propagating up a fork chain.
- The merge direction admits a parent-only row only when the fork's last
  event was an authored delete or rename-away. Such a row stays opt-in,
  never bulk-selected, and reads "Removes in <parent>"; the update
  direction keeps offering it back as "New".

A fork deletion and a rename now merge into the parent, a rename leaves
no duplicate behind, and a fork the parent also edited surfaces in both
directions instead of the parent silently winning.

Fixes WIN-2289

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

* fix(fork): address review — detached tallies, enum wire values, doc duplication

Codex P1: a dependency job tallies its deploy whenever it happens to finish,
and the event kind is probed from the state at that moment. If anything
removed the path in between (a git-sync revert), the stale tally read that
deletion as its own and filed it as authored — handing the merge exactly the
removal this is meant to withhold. `tally_deployed_object_changes` now takes
`Option<DeployOrigin>`; `None` bumps the counter and leaves the evidence
columns as the last vouching tally left them, and the worker path passes it.
Covered by extending the removal-origin test: a detached tally after the sync
archive must not disturb `(delete, sync)`.

Also from review:
- `fork_removed_it` compares through `DeployOrigin::as_str()` /
  `DeployEventKind::as_str()` rather than repeating their wire values, so a
  renamed variant can't silently make the predicate always false.
- `deploy_origin`'s module doc no longer claims `sync` is inert: it cannot
  make the merge propose a removal, but it does drop a row out of both sides
  of the `all_ahead_items_visible` comparison.
- `WorkspaceDiffRow` says why only the fork half of the evidence is consumed.
- The delete-vs-revert rationale is stated once (the migration) instead of
  restated in eight files.
- `PATH_KEYED_TABLES` is swept by a test: its query is built at runtime, so a
  wrong table name is not a compile error and would only surface as a failed
  tally for that trigger kind in a fork.

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

* fix(fork): let only a request task vouch for a deploy event

Round 2 found the first fix incomplete. Detaching only the failed/cancelled
dependency path left the common route untouched: a dependency job that
succeeds calls `handle_deployment_metadata` from the worker, where
`deploy_origin::current()` read as `Authored`. A sync archiving the script
while its lock generation was pending then had its deletion probed on
completion and refiled as authored — the same fabricated removal, on the
path most deploys actually take.

`current()` now returns `Option`, `Some` only inside the request scope the
API always enters. Having no scope means "not the task that served this
write", which is true of every worker-side call and needs no marking at the
call site. The integration test drives the real `handle_deployment_metadata`
off a request task instead of the tally directly, and fails without this.

Two more from the same round:

- The script dependency handler passed no `renamed_from`, unlike the flow
  and app handlers next to it. A lock-generating create has no earlier
  tally, so that was the only chance for the path a rename vacated to be
  recorded at all — renames of Python/TS scripts left the old path in the
  parent, which the bash-only manual check missed.
- The tally now drops a `renamed_from` equal to the path itself. Callers
  pass the previous path whether or not the deploy moved the item, so an
  unfiltered one both counted the path twice and stamped it `rename_from`
  when nothing was renamed.

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

* fix(fork): carry a deploy's origin into the dependency job it queues

Round 3 caught the previous fix cutting too deep. Refusing a detached tally
any claim also refused its rename evidence, and a lock-generating deploy has
no other tally — so the `renamed_from` added alongside it was inert, and a
renamed flow, app or Python script still left its old path in the parent
with nothing to merge. Flows and apps always generate, so renames worked
essentially nowhere.

The two capabilities are now separate. `TallyEvidence` says whether the
tallying task served the write (`Served`, may probe what the path holds now)
or is reporting one that committed earlier (`Deferred`, may not), and each
column is written only from a source that answers for it. The origin itself
is a fact of the deploy either way, so the request stamps it into the
dependency job's args and the worker re-enters the scope with it — the last
place that knows it handing it to the only tally that will run.

Also from round 3: `WorkspaceDiffRow`'s event fields skip serializing `None`
rather than emitting `null`, matching what the schema declares (OpenAPI
3.0.3 ignores a `description` sibling of `$ref`, so those moved onto the
shared schemas).

Verified against a live worker: renaming a flow in a fork records
`(rename_from, authored)` on the vacated path and the merge offers its
removal, while the deployed path claims nothing.

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

* fix(fork): mark the CLI's parent-to-fork merge as sync

`wmill workspace merge --direction to-fork` is the CLI's "Update fork" and
deletes items in the fork, but without the marker the compare page sets. Its
deletions were recorded as authored fork decisions, so once the parent
recreated such a path the merge would offer deleting it there.

Also from review: an unrecognized deploy-origin arg now reads as no evidence
rather than as authored — strict where a request header is lenient, since an
unmarked request really is authored but an unreadable stored value is skew.
Reading the arg moved next to `stamp_origin_arg`, the half that writes it, so
the round trip a lock-generating deploy depends on is covered by one test.

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

* fix: drop the imports the shared arg reader made unused

CI compiles with `-D warnings`, so this was four red Backend jobs rather
than a lint.

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

* fix(fork): stop a stale deferred rename from restating a removed path

Nothing orders these events. A tally that served the write made its claim
inside its own commit, but a deferred one reports a write that landed at an
unknown remove. So a lock-generating rename whose dependency job finished
after a sync had removed the vacated path could overwrite `(delete, sync)`
with `(rename_from, authored)` — the path is gone either way, so the merge
would then offer removing it from the parent on the strength of the older
event.

A deferred claim now only writes where the side has none, which is the case
it exists for: a vacated path that nothing else has spoken for. The
regression asserts the ordering directly, and fails without the guard.

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

* fix(fork): record a rename's vacated path from the request that made it

The deferred mechanism could not be made correct, as round 7 showed: its
guard protected an existing row, but that row is deleted as soon as the two
workspaces agree on the path — so a rename job finishing after the
reconciliation inserted fresh, and the stale claim reappeared against
whatever the parent later recreated there. Ordering cannot be recovered
outside the row, because the row is disposable.

So the vacated path is now recorded by the request, which is inside its own
commit and whose row shares the counter's lifetime. A deploy that hands its
metadata to a dependency job — every flow and app, and any script needing a
lock — calls `tally_rename_vacated_path` once its transaction has committed;
scripts reach it through the post-commit hook they already had, which grew a
second variant rather than new plumbing.

That lets the whole deferred apparatus go: `TallyEvidence`, the origin job
arg and its round trip. `deploy_origin::current` is `Some` only inside a
request scope again, and `handle_deployment_metadata` hands `renamed_from`
to the tally only when it can answer for it — git-sync still gets it either
way, so the rename keeps naming itself in the commit message.

The vacated path's kind now reads `delete` rather than `rename_from` for
these deploys, since it is probed rather than declared. The merge treats the
two alike; only the row's tooltip is less specific.

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

* fix(fork): cover raw-app renames, and stop firing CI before the lock exists

Two things the vacated-path call broke or missed:

- `create_script` reads its third return value as "no lock generation
  needed" to decide whether the script is runnable now, and the new
  `VacatedPath` variant made that true for renames that do generate. Those
  fired dependent CI tests from the API against a version with no lockfile,
  and again from the dependency job. The variant now decides it explicitly.
- Raw apps rename through `update_app_raw`, a separate route into
  `update_app_internal`, which the new call had not been attached to. Both
  routes now go through one helper.

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

* test(fork): assert the kind only an inline rename can record

`rename_from` is what a deploy says when it knows it moved the item, which
only the path that reports both halves from its own request can. Nothing
pinned it, and that is the side the vacated-path change touched.

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

* chore: update ee-repo-ref to a45bec03922d305aad5893ed354dc029c7f97bb4

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

Previous ee-repo-ref: 62f494b2a51de0dfc0cfa0c3530ff19a1d32667c

New ee-repo-ref: a45bec03922d305aad5893ed354dc029c7f97bb4

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-04 00:50:27 +02:00
6b9691df3a chore(main): release 1.777.1 (#10464)
* chore(main): release 1.777.1

* Apply automatic changes

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
Co-authored-by: windmill-internal-app[bot] <217088191+windmill-internal-app[bot]@users.noreply.github.com>
2026-08-03 13:18:26 +02:00
Ruben Fiszelandrubenfiszel 45b5c7a0c0 chore(main): release 1.777.0 (#10454)
* chore(main): release 1.777.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-03 12:32:57 +02:00
Ruben Fiszelandrubenfiszel b0a2c8ca44 chore(main): release 1.776.0 (#10406)
* chore(main): release 1.776.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-01 20:47:00 +02:00
Ruben Fiszelandwindmill-internal-app[bot] bfc3f5242a feat: sync data table migrations to git, gated by a new object type (#10436)
* fix: auto-sync data table migrations to the linked git repo

* fix: deploy data table migrations when a data table is renamed or deleted

* fix: hold new data table names to the git-sync-safe charset

* fix: reject leading-dot data table names and warn on unsyncable legacy names

* chore: update ee-repo-ref to 15c9eef2a4f867eb90d841aee1ce762f4b725589

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

Previous ee-repo-ref: e2fb073a3d0057683666424e463b2ce423664caa

New ee-repo-ref: 15c9eef2a4f867eb90d841aee1ce762f4b725589

Automated by sync-ee-ref workflow.

* feat: make data table migrations a git-sync object type with its own toggle

* fix: never let an untracked checkout delete data table migrations on push

* fix: confirm ambiguous data table migration deletions instead of dropping them

* fix: settle ambiguous migration deletions before the dry-run preview prints

* fix: restore the split shared-UI comment and count migration records in prompts

* chore: keep the deletion-safety doc block attached to its function

* fix: trust git history, not the working tree, for migration deletions

* fix: scope migration history to HEAD, detect shallow clones and subdir roots

* chore: give the unattested-history case a remedy that applies to it

* chore: pair each unattested-history cause with its own remedy

* fix: treat a sparse checkout as unattested history for migration deletions

* fix: normalize the sparse-checkout boolean and give it a remedy that works

* chore: describe both shapes of unattested migration history

* chore: update ee-repo-ref to a786cd42b5aaf0aa6789fbb723d956560f93b1b3

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

Previous ee-repo-ref: 4f312642b5d8fd37ab5e20473a011d6f1d299cf6

New ee-repo-ref: a786cd42b5aaf0aa6789fbb723d956560f93b1b3

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-07-31 23:33:47 +02:00
81b23a2ba0 feat: make the fork lineage the only deploy relationship (#10410)
* feat: make the fork lineage the only deploy relationship

`workspace_settings.deploy_to` (2023) and `workspace.parent_workspace_id` (2025)
both expressed "which workspace does this one deploy into". Fork creation and
dev-workspace attach seeded both, but nothing kept them in agreement, so every
reader picked one and they disagreed.

Drop `deploy_to`. A migration folds surviving pairs into the lineage: a sole
claimant on a target with no dev workspace becomes that target's dev workspace
and keeps its own job tags, while many-to-one pairs become plain forks. Pairs
that the lineage cannot express -- dangling target, self-reference, chain,
mutual -- are reported and left unlinked.

Job tags were never lineage-aware: `per_workspace_tag` mapped any parented
workspace to its parent while `$workspace` interpolated the raw id, so a fork
running a script tagged `<tag>-$workspace` produced a tag no worker serves and
the job queued forever. Both paths now resolve to the nearest ancestor whose id
an admin would provision workers for.

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

* fix: preserve unconvertible deploy links and sweep tag caches on reparent

Review findings on the deploy_to unification:

- convert chains instead of discarding them, and keep whatever the lineage
  cannot express in workspace_deploy_to_unmigrated so the down migration can
  restore it
- ignore soft-deleted workspaces when choosing between a dev workspace and a
  plain fork; an archived claimant was demoting live pairs
- mirror attach_dev_workspace's git-sync strip, which the migration skipped
- sweep the tag cache over whole subtrees on rename and delete: tag resolution
  now walks ancestors, so a nested fork kept a tag nothing serves
- call a dev workspace a dev workspace in the settings copy
- redirect a root away from ?tab=deploy_to instead of rendering an empty target

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

* fix: detect lineage cycles and record archived links in the deploy_to migration

Second review round on the unification:

- detect cycles over the lineage as it would exist after conversion, not over
  the deploy_to graph alone: a root whose target was one of its own forks
  closed a loop that no deploy_to edge revealed
- record an archived source's link instead of filtering it out entirely, which
  dropped it with the column
- treat a fork whose deploy_to merely repeats its parent as redundant rather
  than reporting every pre-existing fork as unmigrated
- read the row count from the lineage update rather than the git-sync one
- sweep the tag cache when archiving a dev workspace, the last site that
  mutates is_dev_workspace without one

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

* fix: resolve $workspace on preprocessed flow tags regardless of $args

Third review round on the unification:

- a flow tag containing only `$workspace` skipped interpolation entirely on the
  preprocessed path, because the branch that ran it keys on `$args`. The raw
  tag was written back and named a queue no worker serves. Resolve `$workspace`
  before the branch and leave `$args` to it.
- record the new table's foreign key in the schema summary
- describe what the archive tag sweep actually does: the dev flag is cleared for
  any archived workspace, which is why it is unconditional

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

* fix: keep the deploy_to leftovers table only when it holds something

* fix: sweep tag caches on archive only where the dev flag actually changes

* feat: broadcast lineage changes and walk ws_specific ancestors only

- propagate tag-cache invalidation across processes over notify_events: the
  cache is per-process, so replicas kept resolving stale lineage for the TTL.
  The listener clears the whole cache rather than tracking ids, since a single
  mutation invalidates an unbounded set of descendants and lineage changes are
  rare admin actions.
- narrow list_ws_specific_versions to ancestors: walking down as well made a
  root fan out over its entire live fork subtree, and each member costs an
  identity lookup plus an RLS switch and probe. Ancestors are bounded by the
  fork depth limit.
- probe the leftovers table unqualified so rollback restores on a PG_SCHEMA
  install, where search_path is not public
- drop the nativets client method for the removed edit_deploy_to endpoint

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

* fix: let a prod see its dev workspace in ws_specific, and stop the walk oscillating

Descending into plain forks made a root fan out over its whole live fork
subtree, but a dev workspace is the paired editable environment rather than a
throwaway copy, so a prod should still see it. There is at most one per parent
and attach rejects nested dev chains, so that edge stays bounded.

The edges run both ways, so the recursion never converged: it bounced
parent<->dev until the depth cap on every call, 33 rows for a two-member set.
A visited-path guard ends the walk when nothing new is reachable.

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

* fix: keep dev pairings unnested, gate the delete broadcast, cover the ws_specific walk

Fifth review round:

- a root that already owns a dev workspace no longer converts: linking it under
  its deploy target would leave that dev nested beneath a fork, the shape
  attach_dev_workspace refuses to create. The link is preserved instead.
- broadcast a lineage change on delete only when descendants are orphaned.
  Deleting a leaf, which ephemeral fork churn does constantly, changes nobody
  else's resolution and was making every replica drop its whole tag cache.
- call list_ws_specific_versions in a test. plpgsql defers everything past a raw
  parse to the first call, so replaying the migration only proved it parses.
- use unwrap_or_default for the descendant sweeps, which run after the
  transaction has committed; a transient failure must not fail the request
- trim the traversal comment to the four-line limit

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

* fix: cache the renamed tally query and clear instance alerts on conversion

The integration test's query was never cached: `cargo sqlx prepare` without
--all-targets skips test targets entirely, and renaming its fixture workspace
changed the query text. Regenerated with --all-targets --features
all_sqlx_features,private, which is what lets the EE-gated otel test compile.

Also from review:
- clear error_handler_fallback_to_instance_alerts on converted workspaces.
  Dispatch ignores it once a parent exists, but the settings page keeps
  submitting the stored true, which the API rejects on a fork.
- restore the schema summary row to the file's name: columns format and put it
  back in alphabetical order

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

* fix: never cache an unresolvable tag workspace, and unadvertise the removed endpoint

- lookup_tag_workspace cached a "no row" result as self-resolution. A rename
  resolves the new id before its row lands, so a fork could be pinned to its own
  wm-fork-* id -- which nothing serves -- for the whole TTL, and its schedules
  kept re-pushing onto that dead tag. Fall back for the call without caching,
  matching how the error path already behaved.
- change_workspace_id swept its children but never itself. Sweep the new and old
  ids and broadcast unconditionally, since a rename always changes lineage.
- openapi-deref.{json,yaml} are served to clients via include_str!, so they were
  advertising edit_deploy_to after it started 404ing. The audit-action enum
  keeps the entry: historical rows still carry it.

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

* fix: align the served YAML spec with the JSON one and correct two comments

- the YAML deref lost the removed path but kept deploy_to on get_settings,
  so the two served specs disagreed. Both are now identical.
- the rename-sweep comment blamed cached-unresolvable lookups, which the same
  commit stopped caching. The real reason is that workspace ids are
  reclaimable, so a new id can carry a previous occupant's resolution.
- the instance-alert comment claimed the settings page submits the stored true
  and gets a 400. It hides the option on a fork and sends false; the hazard is
  the value outliving the pairing and re-enabling alerts after a detach.

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

* chore: update ee-repo-ref to 82da6cb2bafeda18acd6b70c599013a12117ecb0

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

Previous ee-repo-ref: f9ddf6a75aa13d1c13a3d7216a361a96f75ca435

New ee-repo-ref: 82da6cb2bafeda18acd6b70c599013a12117ecb0

Automated by sync-ee-ref workflow.

* fix: grant the deploy_to preservation table to the windmill roles

* test: drop the one-shot migration tests, keep the ws_specific execution guard

The two conversion tests replayed the migration against the fully-migrated
schema, which is not how it runs -- in production it runs mid-sequence against
the schema as of that point. A later migration touching workspace or
workspace_settings would break them without breaking anything real, and sqlx
checksums already freeze a released migration. They earned their keep finding
the archived-claimant and nested-dev cases during development; there is nothing
left for them to guard.

list_ws_specific_versions is different: it is live, no caller exercises it, and
plpgsql only parses a function body until first call.

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

* fix: invalidate a reclaimed fork id cluster-wide without flushing every entry

Gating the delete broadcast on orphaned descendants stopped leaf churn flushing
every replica, but fork ids are reclaimable: the deleting process invalidated
locally while every other replica kept the old parent for the TTL, so a job
pushed in a recreated fork routed to the previous parent's tag.

The broadcast payload now carries meaning. A workspace id drops that one entry,
used for leaf deletion where exactly one id changed what it denotes. The `*`
sentinel drops everything, used for attach, detach, archive, rename and
deletions that orphan descendants -- reshaping a subtree no single id names.

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

* docs: name the right broadcast for each invalidation case

* docs: attach does invalidate the tag cache; the resolver walks the whole chain

---------

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-07-30 14:20:27 +00:00
Ruben Fiszelandrubenfiszel 64ec1aa490 chore(main): release 1.775.2 (#10397)
* chore(main): release 1.775.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-29 12:12:07 +02:00
Ruben Fiszelandrubenfiszel cfb8ca4391 chore(main): release 1.775.1 (#10394)
* chore(main): release 1.775.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-28 20:43:07 +02:00
Ruben Fiszelandrubenfiszel 0de18dc017 chore(main): release 1.775.0 (#10392)
* chore(main): release 1.775.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-28 18:59:14 +02:00
Ruben Fiszelandrubenfiszel 773a428ad0 chore(main): release 1.774.0 (#10365)
* chore(main): release 1.774.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-28 17:43:36 +02:00
Ruben Fiszelandrubenfiszel 3b4c648e4a chore(main): release 1.773.0 (#10363)
* chore(main): release 1.773.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-27 19:04:24 +02:00
Ruben Fiszelandrubenfiszel 86e7f18f09 chore(main): release 1.772.0 (#10346)
* chore(main): release 1.772.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-07-27 16:57:27 +02:00