Skip to main content

Workflow versions and deployments

See How workflows work.

Task walkthrough: Version and deploy a workflow. This page is the full configuration and troubleshooting reference.

A workflow is versioned as it's edited, and deployed to an environment to run there. These are separate ideas: a version is a saved snapshot of the design; a deployment decides which version runs in which environment.

Versions​

Each saved change creates a new version (an incrementing number) with an optional change description, linked to the version it came from. This gives a full history that can be reviewed and rolled back to.

Versioning tracks one workflow through its own lifecycle. To start a separate workflow from an existing one, see Copy a workflow; to move configuration between environments, see Automation export and import.

FieldNotes
versionIncrementing version number.
changeDescriptionA note describing the change, at most 500 characters and trimmed before storing. Accepted on the first version too — see Scripts and Service requests. The workflow editor's own dialog is stricter: it requires a note and caps it at 300 characters — see Draft, save, and version.
previousVersionThe version this one was based on (null for the first).
createdAt / createdByWhen and by whom the version was saved.

Draft, save, and version in the workflow editor​

Three different things were all called "saving". They now read differently:

What it isWhere you see it
A temporary draft — your edits, auto-saved in this browser. It is not on the server and no one else can see it.The Workflow Settings panel's footer says the workflow is auto-saving temporary drafts, and a notice appears the first time a draft is written in a session.
A committed version — the change persisted on the server, in the history.The filled save action in the editor toolbar, whose tooltip reads Commit changes to a version (Create workflow on one that has never been committed). It is the only filled action in that row, so it stands out from the ghost icons beside it.
Which version you are looking atThe version selector, which now states the save state in words.

The version selector reads:

LabelMeaning
v1 (draft)Never committed. The selector is not openable — there is nothing to choose yet.
v1Committed, with no local edits since.
v1 (auto saved draft)Committed, with local edits auto-saved in this browser and not yet committed.

The suffix is presentational; it never changes the version number. It appears only where a browser draft actually exists — a historical view or Forecast view, where auto-saving is off, shows the bare number.

Committing behaves differently for the first version and every one after it:

  • The first version commits with no dialog. There is no history to describe yet.
  • Every later version opens a Save to a New Version dialog with a required Notes field, capped at 300 characters and trimmed before it is stored. The dialog used to be titled Save Version followed by the workflow name, with an optional, uncapped Change Description — which produced a version history that mostly said nothing. The API's own limit is still 500 characters.
The manual Draft button is gone

The Workflow Settings panel used to carry Draft and Cancel buttons, and edits made in that panel did not reach the workflow until you pressed Draft. The panel now writes straight through: what you type is in the workflow immediately, and the auto-save persists it in the browser. Committing a version is what puts it on the server.

If the browser cannot store the draft — storage full or unavailable — the footer says so as an error rather than claiming the work is saved. Commit a version to keep it.

The Code View dialog reads and writes the same live configuration. It now states the find-and-replace shortcut (Ctrl+F / Cmd+F) under its title, and its own footer repeats the auto-save note.

When a commit is refused because someone else committed first​

A commit carries the version it was built on. If someone else committed in the meantime, yours is refused — and the message says exactly that:

This workflow was changed on the server since you started editing. Your changes are safe in this browser — reload to get the latest version, then re-apply and commit again.

Your edits are in the browser draft, so nothing is lost by reloading. What you cannot do is commit onto a version the server has already moved past.

Three other refusals are reported in their own words rather than as this one:

RefusalMeaning
A workflow with this name already exists. Please choose a different name.A genuine name collision. Reloading cannot help.
A duplicate job idThe server names the offending job, which is the only way to find it in a workflow with dozens.
No changes detected on a RestoreThe version you restored is identical to the current one.
Earlier builds reported a lost race as a duplicate name

Any refused commit that was not self-evidently a version clash was reported as A workflow with this name already exists — including a lost race, and including a Restore, which sends no name at all and has no name field on screen to change. Renaming cannot clear a stale version, so the advice led nowhere.

A version won't commit while the workflow has validation errors​

Create Version is blocked while anything in the workflow would produce a job that cannot dispatch. The button is disabled and its tooltip names the first problem, with a count of the rest — "Job 'EXTRACT' has no job type (and 2 more problems)".

The same check draws a red border and tooltip on the offending job on the canvas, so what blocks the commit is always visible on the node that causes it. Before this, the canvas badge and the commit gate were separate computations and could disagree.

Blocked on any of:

RuleDetail
The workflow has no nameApplies when updating, not only when creating.
A job has no name, a name over 255 characters, or a name that duplicates another job'sNames are compared ignoring case.
A job's agent assignment is internally inconsistent
A job has no job typeThe common case: a job added straight onto the canvas.
A job is missing a required task parameterTop-level parameters of the job type's schema.
A job is missing a required custom field
A job's job type is not available in this workspace, or its definition could not be loadedUsually the plugin providing the type is disabled or gone.
A job needs an agent assignment and has none

Two things follow from this that are worth knowing:

  • It blocks on pre-existing problems, not only on your current edit. A job stored before a rule applied — or before a plugin update marked one more parameter required — has to be opened and fixed before the workflow can be versioned again. The alternative is a version that cannot dispatch.
  • The gate validates the config, not the editor. Three routes put jobs into a workflow without opening the job editor — adding a node on the canvas, an undo/redo resync, and the Code tab — so the editor's own checks can't be the only defence.

Restoring an older version goes through the same check, and is refused with Cannot restore this version plus the reason. Rolling back to a version that predates a rule doesn't bypass it.

note

While the job-type and custom-field data the check needs is still loading, the button reports Checking workflow… and stays blocked, so a slow lookup can't race an invalid save through. If that data fails to load outright, the tooltip says so and asks you to retry rather than letting the commit proceed unchecked.

Deployments​

A deployment links a workflow to an environment with a version strategy and an optional date window.

FieldNotes
environmentIdThe environment the workflow is deployed to.
versionStrategyLATEST (always run the newest version) or PINNED (run a fixed version).
pinnedVersionThe version to run when the strategy is PINNED.
effectiveDate / expirationDateOptional window during which the deployment is active. Leave Effective Date empty for immediately effective, and Expiration Date empty for no expiration. Clearing either field on an existing deployment now removes the boundary — earlier builds silently kept the stored date.
isActiveWhether the deployment is currently active.

A workflow can be deployed to multiple environments — for example, PINNED to a tested version in production while running LATEST in a test environment.

Good to know
  • A change isn't showing up in an environment. Likely the deployment is PINNED to an older version, the new version hasn't been deployed, or the deployment's effective date is in the future. Check the environment's deployment, not just the workflow.
  • To roll an environment back, edit its deployment and pin it to the earlier version. The older version still exists in the workflow's history. There is no separate rollback action in the interface — see Deployment history.
  • Production vs test drift is expected when production is PINNED and test runs LATEST.
  • A date window you thought you removed may still be there. On earlier builds, clearing the Effective or Expiration Date field and saving left the stored date in place, so a deployment could keep an expiry nobody could see in the form. Clearing works now — but if a deployment behaves as though it has a window, open the dialog, clear the field, and save again to be certain.

Deployment history​

Each change to a deployment's settings is recorded in a deployment history, and a deployment can be rolled back to an earlier entry. Both are available through the API only — no screen shows the history or offers the rollback. Three things limit what that history tells you:

  • A rollback restores the deployment's settings, not its transform rules. The strategy, pinned version, dates and active flag return to the earlier entry; the transform rules stay as they are now.
  • An entry records the settings from before the change, not after it. Rolling back to the newest entry undoes the most recent edit.
  • For a LATEST deployment, the workflow version recorded is always 1, whatever version the environment was actually running. Only a PINNED entry records a meaningful version.

A sub-workflow must be deployed wherever its parent is​

A Workflow Container job embeds another workflow, so deploying the parent to an environment only means something if the embedded child is deployed there too — and deployed for as long as the parent is. The platform holds that invariant at the moment a deployment is written, in both directions.

What is checked, and when​

The writeWhat it asks
Set-up Deployment on a parentEvery container job's sub-workflow is deployed to this environment, with a window that covers the one you are creating.
Edit on a live parent deploymentThe same question, against the window as you are changing it.
Edit that narrows a child's windowEvery deployed parent using the child here stays covered.
Delete, or deactivating, a child's deploymentNo live parent deployment in that environment still uses it.
Rollback to an earlier deployment history entry (API only)The snapshot being restored is checked as though you had edited the deployment into that shape.
Renaming the child workflowNo deployed parent references it by name only — an embedding that stores the child's id survives a rename.
Deleting the child workflowNo deployed parent references it at all. This reaches a PINNED parent serving an older version, which a cross-reference check of current designs alone would miss.
Committing a new version of a parentEvery container job's sub-workflow is deployed to each environment holding a live LATEST deployment of this parent — see Committing a version is checked too.

A rejected write changes nothing — the check runs before the deployment's version snapshot is taken, so a refused edit leaves no half-written row behind. Every violation found across the rules is reported in one refusal rather than one per attempt.

How a window has to cover​

Effective Date is inclusive and Expiration Date is exclusive, and both compare as UTC calendar dates. A child covers a parent when:

  • the child's effective date is on or before the parent's — and a parent with no effective date (immediately effective) is covered only by a child that also has none;
  • the child's expiration date is on or after the parent's — and a parent with no expiration is covered only by a child that also has none.

A parent whose window has fully elapsed no longer constrains its children, so an expired deployment never blocks tidying up the child it used to use.

What the refusal tells you​

Each message names the sub-workflow and what is wrong with it — that it is not deployed here, that it is not deployed for a given date or earlier, that it is not deployed for a date or later, or that the reference cannot be resolved at all:

  • "Child" is not deployed to this environment. Deploy the child first.
  • "Child" is not deployed for 2026-10-01 or earlier in this environment. The child's effective date starts after the parent's.
  • "Child" is deployed with an expiration date, but this deployment has none. An open-ended parent needs an open-ended child.
  • Job "X" references a sub-workflow that no longer exists. Or, when the job stored an id that does not resolve, that you should re-select the sub-workflow.
  • Job "X" references "Child" by id only. Re-select the sub-workflow so its name is stored. The build resolves a container by name, so an id with no name beside it is unbuildable.
  • Job "X" has no sub-workflow selected.
  • Job "X" references this workflow as its own sub-workflow.

On the child's side the refusal states the boundary you would have to meet, and lists who is holding you to it — "Expiration Date must be on or after 2026-12-31 (or blank) — deployed workflows use this sub-workflow until then. Used by: Nightly Close, Payroll Run." The date quoted is the strictest across all dependents, so meeting it satisfies every one of them at once.

Workflows in a workspace you cannot see are counted, never named

A dependent in a workspace you have no access to is reported as "1 workflow in a workspace you cannot view" — it still blocks the write, and the required date still accounts for it, but nothing about it is disclosed. Names are shown three at a time with the rest as a count.

The deploy modal shows the answer before you act​

Open Deploy on a workflow and each environment card is checked in its own right, so the state is visible per environment rather than only in a refusal.

  • A workflow with container jobs gets a Sub-Workflows section on each card, one row per container job, reading the child's name and the version it serves — Version 4 (Pinned) or Version 6 (Latest). A row that fails swaps the version line for the warning, and failing rows sort to the top. Where two jobs embed the same child, the rows say which job each one is. The section is hidden once the platform confirms the workflow has no container jobs.
  • Set-up Deployment is disabled on a card whose sub-workflow is missing, with the reason on the card rather than in an error after the fact. It is also held disabled while the check is still running, so it never offers an action it is about to refuse.
  • A sub-workflow's deployed cards get a Used By section naming the parents that depend on that deployment, each with the version it serves and the job that embeds it, and Delete is disabled while any of them does. When nothing depends on it the section reads "Not used by any deployed workflow" — which is how you know removing the deployment is safe, rather than having to try it.
  • Edit and Delete stay available on a deployed parent whose child row is failing — the state already exists, and fixing it is exactly what those actions are for.
  • Each row's name is a link that opens that workflow in a new tab, where you can see it.
  • A workflow that is both a parent and a sub-workflow gets both sections.

If the check itself cannot be run the section says "Could not check sub-workflow deployments." and nothing is disabled — the card falls back to letting you try, and the write is still refused if it must be. An environment you have no view grant on is left out of the check entirely, and its card renders as though nothing was asked.

The Used By section and the Delete gate follow what the platform reports, not the workflow's Sub-Workflow flag: a workflow whose flag was never turned on is still protected while parents embed it.

Deactivating a deployment is not offered in this build

isActive is reachable only through the API. It is checked by the same rule as a delete — a child's deployment cannot be deactivated while a live parent uses it — but there is no control for it on the card.

Service requests share this modal and have no sub-workflow rules, so neither section appears on one.

The deploy form checks the window as you type it​

The environment card answers the question for the deployment as it stands. The New Deploy and Edit Deploy form answers it for the deployment you are about to write — so a window that would not cover a child is caught before you submit it, not after.

  • The form carries its own Sub-Workflows section, below the transform rules, with the same rows as the card: one per container job, the child's name and the version it serves, and the warning in place of the version line on a row that fails.
  • It re-checks as you change the environment, the strategy, the pinned version and the two dates — the dates after a brief pause, so a typed date is checked once you stop rather than per keystroke. The check describes exactly the write the button would make.
  • Deploy (or Save) is held inactive while the check is running or still settling, and while it reports a failure. Because the section sits at the bottom of a long form, the inactive button carries the reason: Checking sub-workflow deployments…, or A sub-workflow is not deployed or does not cover this window — see Sub-Workflows.
  • If the check itself cannot be run, the button stays active. The rule is enforced when the deployment is written either way, and refusing to let you try on the strength of a failed check would be worse than letting the write answer for itself.
  • A refusal that arrives on submit anyway — someone else changed a child's deployment in the meantime — is rendered as those same rows rather than as a bare error message, so you can see which sub-workflow and which side of the window was wrong. Changing anything on the form hands control back to the live check.
  • Reopening the form shows the rows it last held straight away, but Deploy waits for the check to confirm them before becoming active again.

The child side appears above the form. When the workflow you are deploying is itself a sub-workflow and the window you have typed would strand a deployed parent, the warning at the top of the form names each parent holding you to it, and each name opens that workflow in a new tab. A workflow that is both a parent and a sub-workflow can show both at once.

A reminder sits under the rows, because it is the question the section prompts: transform rules for a sub-workflow are set on that sub-workflow's own deployment. To change them, open the sub-workflow and redeploy it.

Committing a version is checked too​

A deployment set to LATEST re-points at whatever version is committed next, so committing is a write that can change what an environment runs — and until this build nothing checked it. Adding a container job for an undeployed sub-workflow committed cleanly and broke that environment at its next build, with no signal to the person who did it.

A commit is now refused when it would leave a live LATEST deployment holding an undeployable sub-workflow reference. The refusal carries the same per-environment failure lines the deployment writes use, and no version is committed — nothing is half-written.

What it covers, and what it deliberately does not:

Deployments consideredOnly this workflow's active LATEST deployments, and only those whose window has not fully elapsed. A PINNED deployment keeps serving its pinned version and cannot be changed by a commit, so it is not consulted.
Saves consideredOnly a save that changes the container reference set — which sub-workflows the workflow embeds. A save that leaves those references alone is not checked at all.
Undeployed sub-workflow you inheritedStays editable. A workflow whose existing sub-workflow was never deployed has to remain savable for every edit that leaves its references alone, or the check would trap exactly the people repairing it.
Deployments that already violate the ruleLeft as they are. Nothing is retro-corrected; the check applies from the next write onwards.

The Save dialog says so before you commit​

The Save to a New Version dialog asks the same question while it is open, so the answer arrives before you commit rather than after:

  • Blocked shows a warning above every other notice in the dialog — "This version cannot be saved while deployed as 'latest'." — with one line per failure grouped by environment, and Save is disabled. The advice under it is to deploy the sub-workflow to those environments, or pin this workflow's deployment there, then save again.
  • While the check is running the dialog reads Checking sub-workflow deployments… and Save is disabled with it. The answer is moments away and committing through it would race it.
  • A check that could not be reached does not block you. The dialog reads Could not check sub-workflow deployments; the save will be verified on submit. and Save stays live — the server re-checks on submit and is the authority, so an unreachable pre-check is not evidence of a problem.

The check only runs on a workflow that actually has a live LATEST deployment. A save on an undeployed or pinned-only workflow cannot change what anything runs, so it costs nothing and the dialog says nothing.

The dialog now stays open until the commit settles. A sub-workflow's deployment can be retired in the moment between the pre-check and your Save, so the refusal has to have somewhere to land: it renders in the dialog, in place, with the notes you typed still in it. A refusal reported that way raises no snackbar — it would say the same thing twice, and worse. Success, and every other kind of failure, closes the dialog exactly as before.

Restoring an older version goes through the same write with no dialog to catch the refusal, so it is reported as a message naming the environment, the job and the sub-workflow at fault, with any remaining problems counted — "Production: Job 'NIGHTLY' references 'CLOSE', which is not deployed to Production. (and 2 more problems)". Renaming a sub-workflow that a deployed parent still embeds by name is refused by the same write but is not a commit problem, so it is still reported on its own rather than inside the dialog's notice.

Transform rules​

A deployment can rewrite references as the workflow is served to its environment, so one design can run against a different environment's inventory without a second version of the workflow. The deploy dialog offers three kinds of rename, each authored as a from → to pair:

KindWhat it rewrites
AgentThe agent named in a job's agent slots (primary, secondary, tertiary, quaternary).
Property NameThe name of a property defined on a job or on one of the workflow's schedule instances. It does not change token text in a job's parameters, and it does not change which global property a token reads.
FrequencyThe frequency a job or an event is bound to.

Agent pools are deliberately not offered in the agent picker. A pool is a different kind of entity from an agent, so renaming across the two would leave a reference that resolves to nothing in the target environment.

Scoping a transform to one job​

Every row starts with a Job selector, which defaults to All jobs. Leave it there and the rename applies across the whole workflow, as it always has. Choose a job and the rename applies to that job only — so a single job can be retargeted without touching the rest of the schedule.

What a job-scoped row reaches is narrower than the all-jobs equivalent, and deliberately so:

KindAll jobsScoped to one job
AgentEvery job's agent slotsThat job's agent slots
Property NameJob properties and schedule-level propertiesThat job's own properties only
FrequencyThe schedule's frequency definitions, every job's frequency binding, event frequencies, and dependency predecessor frequenciesThat job's own frequency binding and its event frequencies

The exclusions matter. A workflow's frequency definitions and its schedule-level properties are shared by every job, so rewriting them because one job changed would leave every other job pointing at a name that no longer exists. Use an All jobs row when you mean to rename the shared definition; use a scoped row when you mean to move one job onto a different one.

Good to know

A name can be the source of one rename per scope. AGENT1 → AGENT_PROD on Job A and AGENT1 → AGENT_TEST on Job B are both valid and independent, because they touch different jobs. Two rows that overlap and share a source are not: the dialog stops offering a name that a row covering the same jobs has already claimed, because the second rename would silently do nothing. An All jobs row overlaps every scope.

You also can't rename a name to itself — the target list drops whatever the row's source is.

What the dialog blocks, and what it only warns about​

Blocking — Save is refused until you resolve the row:

ConditionWhy
Two transforms of the same kind share a source or a target, or one renames to a name another renames fromThe outcome would depend on the order the rules ran in.
A frequency rename collides with a frequency key a job already hasThe job would end up with two bindings under one name.
The scoped job's name can't be expressed as a rule pathSee below.
Scoping to that job makes the rule path longer than the platform allowsShorten the job name, or scope the row to all jobs.

A job name can't be used as a scope if it contains a line break, the sequence )] or )', or an @ followed by a space, ., ), [, or one of the words root, parent, property, path, or parentProperty. Ordinary names with an @ in them — svc@corp backup, a@b.com run — are fine. When a name can't be scoped, either rename the job or set the row back to All jobs.

Advisory — the row is flagged but Save still works:

  • "Job … is not in the workflow version this deployment serves, so this transform will not apply." The scoped job was renamed or deleted, or the deployment runs LATEST and the workflow has moved on. This is a warning rather than a block because a rule legitimately outliving a version is normal, and refusing Save would trap you in the dialog with unsaved work.

Because a scoped rule binds to the job's name, renaming a job breaks any transform scoped to it. The warning above is how you find out.

Renaming a frequency on deploy​

A frequency rename follows through to the per-job settings that reference it, so jobs keep the schedule they had instead of losing the binding. The dialog refuses a rename it cannot apply cleanly: two renames that collide on the same resulting name, a chain of renames (A to B while B becomes C), or a rename onto a frequency key that already exists. Resolve the conflict and deploy again.

Advanced rules — anything the typed sections can't express​

The three typed sections above cover renames. Anything else — deleting a field, appending or prepending to one, a pattern replacement, a hand-written path into a task parameter — is an Advanced rule, and the Advanced section is a full editor for them. Each row has:

FieldNotes
NameRequired, up to 255 characters. Rule names are unique per tenant, not per deployment, so two rows can't share one — and you can't reuse the name of a rule the same save is removing.
Target PathRequired. A JSONPath expression starting with $ or ., up to 500 characters.
Transform TypeREPLACE, REPLACE_PATTERN, APPEND, PREPEND, DELETE, or RENAME_KEY.
Source PatternA regular expression. Required for REPLACE_PATTERN and RENAME_KEY, and not offered for the others.
Target ValueThe value to write, or the new key for RENAME_KEY. Not offered for DELETE.

Use New Advanced Rule to add a row, and the row's remove control to drop one.

Changing the type clears the operands that type forbids, so a Target Value left over from a REPLACE can't ride along on a DELETE and be rejected when you save.

A rule the section can't recognise as one of the typed kinds still lands here, which means a rule authored through the API is now editable — you can fix a typo in one or remove it without going back to the API. Two things follow from that:

  • A saved rule keeps the settings this dialog doesn't edit. Saving compares each row against the server's copy and updates only what changed, so a rule's priority — which decides the order rules run in within a scope — and its active flag survive an edit made here.
  • The dialog's checks are authoring guidance, and they're stricter than the API. They aren't applied to a row that came from the server and hasn't been edited, because a rule the API accepted shouldn't be flagged as broken. REPLACE_PATTERN is exempt from needing a Target Value outright: replacing a match with nothing is how you strip a prefix, which is the commonest reason to reach for an Advanced rule at all.

A rule whose stored value can't be read still degrades to a plain entry rather than breaking the dialog. Earlier builds failed to load the whole Design module when a deployment carried transformation rules.

Good to know

When you save, rules are written before any are deleted, so a save that fails partway leaves every existing rule in place rather than removing one and failing to add its replacement.

An environment-wide rule needs an environment-wide grant

A rule scoped to a deployment is authorized against that workflow's own workspace. A rule scoped to an environment is different: it rewrites what is served to every workflow deployment and every service-request deployment in that environment, whichever workspace they belong to. So writing one requires workflow-deployments.edit and service-request-deployments.edit through grants that cover every workspace, in that environment.

A role scoped to particular workspaces is refused — otherwise the rule would reach deployments its author could not edit directly. See Where a grant has to be wider than one workspace.

Fields no rule may change​

A transformation rule takes an arbitrary path, so a few fields are protected: a rule that would add, remove, or rename one is refused.

Protected fieldWhy
Sub-Workflow flagThe Schedule Workflow dialog reads a workflow's stored setting while the build reads the transformed one, so a rule that changed it would make the two disagree about whether the workflow can be run directly.
A job's idIt is the job definition's persistent identity. A transformation applies per environment, so a rule reaching a job's id would give one definition a different identity in each environment while the stored definition kept another — and anything bound to that identity, such as a notification group member naming the job, would fire in some environments and silently not in others.
A dependency's predecessor job id (predecessorJob.schedule.job.id)The same argument one layer out: a rule here would aim a dependency at a different job identity in each environment. The name beside it stays transformable, which is the legitimate per-environment retarget — so leaving the id open would let the two disagree. The workflow id one level up (predecessorJob.schedule.id) also stays transformable: retargeting which workflow a dependency names per environment is supported.
A job's Batch User parameter (taskDefinition.parameters.batchUserId)It only displays the attached credential; dispatch reads the job's connection reference. A rule here would look active and change nothing, and the job would authenticate as the source environment's account on the target environment's machine, reporting success.
A container job's sub-workflow reference (taskDefinition.parameters.workflow, and the id and name beneath it)The sub-workflow deployment check runs against the reference as stored, and a transform rule is applied after it — so a rule that retargeted the reference would re-open exactly the failure the check exists to prevent, while the dialog still showed the target that passed.

Retargeting a machine name or a path per environment is what these rules are for. Retargeting an identity, or a reference to one, never is.

Use a different credential per environment — the right way

connectionRefs is deliberately not protected: pointing a job at a different connection per environment is a named, supported use of these rules. Target $.jobs[*].connectionRefs[0].id. The Batch User parameter beside it is re-synced to match the reference when the deployment is served, so the served configuration stays internally consistent.

A rule on a protected field is refused when you save it, not silently at deploy time. That check covers every rule type — replace, delete, append, and rename alike — and it catches every spelling that reaches the field, including an array wildcard or a recursive descent. For an environment-scoped rule only the path's own spelling can be checked, because such a rule applies to every deployment in the environment and there is no single configuration to resolve it against.

A refusal that happens at deploy time is not shown anywhere in the interface. That can happen to an environment-scoped rule whose path reaches a protected field by a spelling the save could not check, or to a broad wildcard rule that sweeps across a protected field along with others: the protected field is skipped and the rest of the rule applies. The rule still looks active in the deploy dialog, but the protected field keeps its stored value. The same is true of a rule whose path matches nothing in the version being served: apart from the dialog's warning for a job-scoped rule whose job is gone, nothing tells you it had no effect. If a per-environment change is not taking effect, check the rule's path against the fields above and against the version the deployment serves.

Environment-level rules​

Rules defined at the environment level apply to every deployment into that environment and are applied before a deployment's own rules. They're shown read-only in the deploy dialog, and job scoping doesn't apply to them — a job name only means something against one workflow.

Contact support when​

  • The active deployment points at a version that demonstrably differs from what's running in the environment.

Include the workflow, the environment, the deployment's version strategy/pinned version, and the effective/expiration dates.