A settings save reported the fork pointers left resolving to nothing only
for the names in `deleted_datatables`, which `wmill sync push` never sends.
The save now works out what it removed from the locked entries, and the
CLI prints the stranded pointers it returns.
Also correct the replication helper's contract: no role or admin check
makes a replication connection safe, so a data table under roles is
refused outright rather than gated as an admin operation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjfMkJyKzodxkobqGZ6Lqb
* fix(cli): keep the workspace color when settings are synced from git
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs(cli): name the sync direction consistently in the identity-field comments
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(cli): apply the workspace color from settings.yaml only when the file sets one
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* fix(cli): keep permissioned_as on single-item push, as sync push does
* fix(cli): resolve syncBehavior from the target workspace, not the branch alone
* refactor(cli): share the workspace-name resolution between sync and single-item push
* test(cli): import the moved workspace-name helper from its new home
* 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
* 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>
* 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>
* 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