Fix Dynamics 365 Field Service Optimizer: Prevent Rescheduling of Manual Bookings
Is the Field Service scheduler overriding the work your dispatcher placed by hand? This troubleshooting guide explains why Resource Scheduling Optimization reschedules bookings and gives the definitive fix: booking locks, booking statuses, optimization scope and goal constraints, and the technical steps to protect manual adjustments, drawn from our Field Service implementation and remediation work.
If Dynamics 365 Field Service keeps moving bookings your dispatcher placed by hand, Resource Scheduling Optimization is doing exactly what it was configured to do: every booking inside its scope is treated as movable unless something tells it otherwise. The definitive fix has three layers. Lock the booking, so the optimizer cannot change the resource, the time, or both. Keep manual work out of the optimization scope, using a booking status the scope does not optimize and a date range that cannot reach committed work. Then make both of those automatic, because a protection a dispatcher has to remember is a protection you will lose.
Two notes before the detail. First, the scheduling stack in Field Service is versioned and Microsoft moves things: the exact name of a lock option, where it appears on the booking form, and which settings live on the optimization scope rather than the optimization goal have all changed across releases, and they differ again between Resource Scheduling Optimization and the newer scheduling experiences. Treat the names below as the shape of the problem and confirm each one against your own environment and the current Microsoft documentation before you change it. Second, we do not guess which layer is missing on your system. Four different mechanisms can each stop a booking being moved, they are enforced at different moments, and the reason a dispatcher is angry is usually that one of them was configured and the other three were not. The order of work below is written to find out which.
The answer in three lines
Prove the optimizer moved it before you change any setting
Open the booking, read its audit history, and look at who made the change. Resource Scheduling Optimization writes as its own application user, so a run it performed is named in the record, and the optimization request that did it can be opened alongside. A meaningful share of the bookings people believe the optimizer moved were moved by a flow, by a plugin, by a requirement change that rebuilt the booking, or by another dispatcher on the schedule board. Those have completely different fixes, and locking bookings will not stop any of them.
A locked booking is the direct answer, and the lock has a shape
A booking can be locked to the resource, to the time, or to both. Locked to the resource means the optimizer may still move when the job happens but not who does it. Locked to the time means it may swap the person but not the slot. Locked to both pins it completely, which is what a dispatcher usually means when they say they scheduled it deliberately. Choosing the narrowest lock that protects the promise leaves the optimizer free to do useful work around it.
Scope is the layer people forget, and it is the stronger one
A lock protects one booking at a time. The optimization scope decides which bookings a run is allowed to consider at all, through its date range, its resource set, and the booking statuses it may optimize. Give manual bookings a status the scope excludes and they are invisible to every run, with nothing for anybody to remember. Locks then become the exception rather than the mechanism, which is the configuration that survives a busy Friday afternoon.
Why the booking moved, and why it is not always the optimizer
Resource Scheduling Optimization is usually involved, and on most systems we look at it is not the only thing rescheduling work. Locking bookings fixes the first cause below and none of the others. These are the ones worth checking, in the order they tend to matter.
The booking is inside the optimization scope and carries no lock
The direct cause and the one everybody arrives with. Resource Scheduling Optimization does not distinguish between a booking a human placed with a reason and one it created itself. Anything inside the scope, in a status the scope is allowed to optimize, with no lock on it, is raw material for the next run. There is no warning, and from the dispatcher side the job simply appears somewhere else the next morning.
The lock exists but the goal does not enforce it
An optimization goal separates constraints, which are rules a run cannot break, from objectives, which are preferences it trades off against each other. If the behaviour you are relying on is expressed as an objective rather than a constraint, the engine is allowed to give it up in exchange for a better score elsewhere, and it will. Check that the goal treats locked bookings and promised time windows as constraints rather than assuming the lock is honoured everywhere by definition.
The scope range reaches further forward than anyone intended
A scope defined as the next fourteen days will happily rebuild tomorrow morning, including the emergency job a dispatcher placed an hour ago and the visit somebody promised a customer by phone. Most teams want the optimizer working on the far end of the window and leaving the near end alone. That is a range setting, and it is usually the single change that ends the argument between dispatch and the schedule.
Every booking sits in one status, so the scope cannot tell them apart
If manual bookings and optimizer bookings both sit in the same scheduled status, no scope filter can separate them and no rule can be written about them. This is a data modelling gap rather than a settings problem, and it is why a dedicated committed or confirmed booking status is the backbone of most working configurations. Without it, the only protection available is a lock applied one booking at a time.
The lock is applied by hand, so it is applied inconsistently
A dispatcher placing a job during a busy hour is not thinking about the optimization run tonight. Even teams that agree to lock every manual booking lock most of them, and the ones they miss are the urgent ones placed under pressure, which are exactly the ones that hurt when they move. If the protection depends on somebody remembering it, the honest description is that it is unprotected.
The optimizer moved it for a reason the data made unavoidable
Sometimes it is right. A missing characteristic on the resource, a service address that does not geocode, working hours that do not match the shift the person actually works, or a travel time the engine calculates as impossible will all push a run to relocate a booking. Locking that booking stops the symptom and leaves the cause, so the next unlocked one moves for the same reason. Read the optimization result before you decide the engine was wrong.
Something other than the optimizer is doing the rescheduling
A Power Automate flow reacting to a work order update, a plugin that reschedules on a requirement change, an agreement generating bookings on a schedule, an auto scheduling rule on work order creation, or another dispatcher dragging on the board. Each of these produces the same complaint. The audit history on the booking names the author of the change, which takes minutes to check and prevents a week of configuration work on the wrong record.
Nobody moved it and the schedule board is showing another time zone
Worth ruling out early because it costs nothing. A schedule board tab has its own time zone setting, and a dispatcher looking at a board configured for one region while working in another sees bookings at hours nobody scheduled them for. The booking is untouched, the audit history shows no change, and the fix is a board setting rather than anything to do with the optimizer.
The layers that protect a booking, and where each one is enforced
Each of these is documented on its own, inside the record it belongs to, which is why teams commonly configure one of them and assume they are covered. They are enforced at different moments and they protect different things.
The lock on the booking
Applied per booking, either from the booking record or from the schedule board where a dispatcher already works. It is the most precise instrument available and the one to reach for when a specific job has been promised to a specific customer for a specific reason. Its weakness is that it protects exactly one booking and somebody has to apply it, which is why the automation section further down exists.
The booking status the scope is allowed to optimize
The optimization scope names which booking statuses a run may consider. Bookings sitting in any other status are not candidates at all, so a dedicated status for committed work protects every booking that reaches it without anything being applied per record. This is a configuration decision worth making early, because retrofitting a new booking status onto a live system means touching the board, the mobile flow, the reports, and any automation that reads status.
The reach of the optimization scope itself
A scope carries a date range, a set of resources, and the statuses above. Narrow any of the three and the run cannot touch what is outside it. A scope that starts tomorrow rather than today protects everything a dispatcher placed for the current shift, and a resource filter protects a crew whose week is planned by hand. This is the layer that scales, because it applies to work nobody has thought about yet.
The constraints on the optimization goal
The goal decides what the engine is not permitted to break, as opposed to what it prefers. Required characteristics, territory, working hours, promised time windows, and locked bookings belong on the constraint side. Travel time, utilisation, and job counts belong on the objective side, where they are traded off. Putting something on the wrong side is how a system that appears configured still produces a schedule the dispatcher does not recognise.
Excluding the resource entirely
Blunt, and sometimes correct. A crew whose schedule is genuinely planned by hand, a subcontractor, or a specialist with commitments the system does not model can be left out of the scope resource set altogether. Their bookings still occupy their calendar, so the engine plans other people around them, but it never proposes anything for them. Use it deliberately rather than as a way of avoiding a configuration conversation.
What a lock does not do
A locked booking is not hidden. It still consumes the capacity of the resource it is booked against, and a run will plan the rest of that day around it, which is the behaviour you want. It also does not protect the work order underneath it from being edited, and it does not stop a flow, a plugin, or a person from rescheduling the booking directly. It constrains the optimizer, and it constrains nothing else.
Which protection to use, and what each one costs you
Organised by what you are trying to protect rather than by which record the setting lives on, with the cost stated in every row, because the cost is what decides which of these a dispatch team can actually operate.
| Method | What it protects | What it costs |
|---|---|---|
| Lock the booking to resource and time | One booking, completely. The optimizer may not change who does it or when, and it plans the rest of the day around it. | Somebody has to apply it, per booking. Applied by hand it will be missed under pressure, so treat it as the exception mechanism rather than the policy, or automate it. |
| Lock to the resource only | The person. The named technician keeps the job, and the optimizer may still move it to a better time in their day. | The customer may be told a different time than the dispatcher agreed. Right where the promise was about who turns up, wrong where the promise was about when. |
| Lock to the time only | The slot. The appointment window holds, and the optimizer may put a different qualified resource into it. | A named technician the customer expected can be swapped out. Suits a large workforce with interchangeable skills, and does not suit relationship based service. |
| A dedicated committed booking status excluded from the scope | Every booking that reaches that status, without anything being applied per record. The strongest routine protection available. | A real configuration change. The status has to be created, mapped to the right field service status, added to the board, taught to dispatchers, and reflected in reporting and any automation that reads status. |
| Narrow the optimization scope date range | All work inside the near window, including bookings nobody has made yet. A scope that begins tomorrow leaves the current shift untouched. | The optimizer stops improving the near term schedule, which is where the largest travel savings often are. This is a genuine trade rather than a free win. |
| Restrict the scope resource set | Named crews, subcontractors, and specialists whose schedules are planned by hand. | Those resources get no optimization at all, and the exclusion list quietly grows until nobody remembers why anyone is on it. Review it on a schedule. |
| Constraints on the optimization goal | Promises the business cannot break, such as required characteristics, territory, working hours, and the arrival window agreed with the customer. | Over constraining produces runs that fail to schedule work at all, and leave requirements unplaced with no obvious reason. Add constraints one at a time and read the result of each run. |
| A flow or plugin that locks manual bookings automatically | Everything a human places, without the human doing anything. This is what turns a policy into a mechanism. | Code or a flow that you now own, test, and version. It belongs in a solution and under source control, not as something somebody built in production on an afternoon. |
The fix, step by step
Steps 1 to 3 establish what actually moved the booking. Steps 4 to 8 protect the work that carries a promise. Steps 9 to 12 make the protection survive contact with a real dispatch team and remove the reason the engine wanted to move the booking in the first place. The order matters, because changing an optimization scope before reading an audit history is configuring a record that may not be responsible.
Read the audit history on a booking that actually moved
Pick a specific booking the dispatcher complained about and open its audit history rather than reasoning from the general behaviour. You are looking for the field that changed, the timestamp, and the user who made the change. Resource Scheduling Optimization writes as its own application user, so a run it performed is identifiable, and a change made by a flow, a plugin, or a person is equally identifiable. Confirm auditing is enabled on the bookable resource booking table before you need it, because the history you did not turn on is the one you will want.
Open the optimization request that ran at that time
Every run leaves a record of what it considered and what it changed, with the scope and goal it used. Match the timestamp from the audit history to the run, then read what the run did to that booking and why. This is also where you find out whether the run was the scheduled one everybody knows about or a second scope somebody created during testing and never turned off, which is a common and entirely undramatic cause.
Rule out the changes that are not the optimizer
Check the flows on the bookable resource booking and work order tables, any registered plugin steps on those tables, agreement based booking generation, and whether auto scheduling runs on work order creation. Then check the time zone on the schedule board tab the dispatcher uses, because a booking that appears at the wrong hour and has no audit entry never moved at all. Only continue into the optimizer settings once the audit history has actually named it.
Lock the bookings that carry a promise, and lock them to the right thing
For the specific jobs under discussion, apply a lock now so the argument stops while you configure the rest properly. Choose the narrowest lock that protects what was promised: resource and time where a named person was promised at a stated hour, resource only where the customer cares who arrives, time only where the customer cares when. Locking everything to both is the reflex and it removes most of the value of running an optimizer at all.
Confirm the optimization goal enforces the lock as a constraint
Open the goal the scope uses and check the constraint list rather than assuming. Locked bookings, required characteristics, territory, working hours, and the promised arrival window belong on the constraint side, where the engine may not break them. Anything sitting on the objective side is a preference the engine will trade away for a better overall score, which produces the situation where a booking was locked, the setting looks correct, and the job still moved.
Create a booking status that means committed, and keep it out of the scope
Add a booking status such as Committed or Confirmed, mapped to the correct underlying field service status so the mobile app and the board still behave, and configure the optimization scope so that runs may optimize the scheduled status but not this one. This converts your policy into a mechanism: anything a dispatcher marks as committed is invisible to every run from that moment, without a lock being applied and without anybody remembering to apply one.
Pull the scope date range back off the near term
Decide how far ahead the optimizer is allowed to start rebuilding, and set the scope range to begin there. For most service operations the answer is that today is untouchable, tomorrow is negotiable, and everything past that is fair game. This one setting protects every booking a dispatcher places during the current shift, including the ones that do not exist yet, which is protection no per booking mechanism can offer.
Restrict the resource set where a crew is planned by hand
Where a specific crew, a subcontractor, or a specialist is scheduled manually as a matter of policy, take them out of the scope resource set rather than locking every booking they receive. Their bookings still consume their calendar, so the engine plans everyone else around them correctly. Write down why each resource is excluded and review the list periodically, because exclusion lists outlive the reasons that created them.
Automate the protection so nobody has to remember it
Build a flow or a plugin on the bookable resource booking table that applies the lock and the committed status when a booking is created or updated by a person rather than by the optimizer, keyed on the modifying user. This is the step that decides whether the fix holds. Every manual protection degrades over a few weeks of real dispatch work, and the bookings that get missed are the urgent ones placed under pressure, which are the ones that matter most.
Fix the data that made the optimizer want to move the booking
Read the run result and find out what the engine was solving for. Service addresses that do not geocode, resource start locations that are wrong or missing, characteristics and proficiencies that were set once and never maintained, and working hours that do not match the shift the person works will all produce relocations that look arbitrary and are not. Locking bookings hides this. Fixing it is what makes the optimizer produce a schedule dispatch stops overriding.
Ask whether the optimizer should be doing this job at all
If dispatchers have to lock nearly every booking, the configuration is telling you something. A narrower remit is often the right answer: let the optimizer place unscheduled requirements and leave existing bookings alone, or let it work only on the far end of the window while humans own the next two days. An optimizer running against work humans have already decided is not an optimizer, it is a source of rework.
Test it in a sandbox at real volume, then ship it as a solution
Reproduce the scenario in a non production environment with a realistic number of resources and bookings, run the optimization, and confirm the protected bookings are exactly where you left them. Check the unprotected ones still move, because a configuration that protects everything has quietly switched the feature off. Then promote the scope, the goal, the booking status, and any flow or plugin through managed solutions rather than repeating the changes by hand in production.
If the schedule board itself is also slow while you are doing this, that is a separate diagnostic and we cover it, along with resource counts, date ranges and plugin impact, on our Dynamics 365 health check page.
Making the protection automatic
This is the section that decides whether the fix holds for more than a fortnight. Asking dispatchers to lock every manual booking works until the first genuinely busy afternoon, and the bookings that get missed are the urgent ones, which are the ones that hurt when they move.
Key the automation on who made the change
The distinction you need is between a booking the optimizer created and a booking a person created. Resource Scheduling Optimization operates as its own application user, so the modifying user on the record is the cleanest signal available. A flow or plugin that applies the lock and the committed status when the author is anyone other than that user turns dispatcher intent into protection without asking dispatchers to do anything differently.
A flow is the fastest route and a plugin is the durable one
A Power Automate flow on create and update of the bookable resource booking is quick to build, easy for the client to read afterwards, and adequate at ordinary dispatch volumes. A plugin registered on the same messages runs synchronously and inside the transaction, which matters when the optimization run and the dispatcher are working at the same time. Choose the flow when volume is low and the team wants to maintain it themselves, and the plugin when the timing has to be exact.
Give the dispatcher an explicit way to release a booking
Automatic protection with no way out produces a schedule nobody can improve. A button, a status change, or a clearly labelled field that returns a booking to the optimizable pool is part of the design, not an afterthought. If dispatchers cannot hand work back to the engine easily, they will stop marking anything as committed and the mechanism dies quietly.
Make what is protected visible on the board
A dispatcher should be able to see at a glance which bookings the next run may move. Booking status colours on the schedule board, or a filtered view of unlocked bookings inside the protected window, turn an invisible rule into something the team can check before they go home. Most of the trust problem with an optimizer is that its intentions are not visible until the morning after.
Write down the rule, because the next person will not guess it
Which statuses are optimizable, what the scope range is, what the flow does and on what condition, and who is excluded from the resource set. This is four paragraphs of documentation that prevents somebody widening a scope range next year to fix a different complaint and silently undoing all of it. It belongs with the solution rather than in a message thread.
Before you lock everything
The instinct after a bad week is to protect every booking, and it works, in the sense that the optimizer stops changing anything at all. These are the things worth weighing before you get there one lock at a time.
Locking everything switches the feature off
If every booking is locked and every status is excluded, the optimizer runs, finds nothing it may touch, and reports success. The licence is still being paid for and the travel time it was bought to remove is still being driven. That is a legitimate outcome only if somebody decided it deliberately, and it is worth naming out loud rather than arriving at one lock at a time.
The engine is often right and the data is often wrong
A run that keeps relocating the same bookings is usually reacting to something real: an address that will not geocode, a start location set to the office for someone who leaves from home, a characteristic nobody maintained after the person was trained. Dispatchers experience this as the system being wrong. Fixing the inputs is slower than locking the booking and it is the change that stops the argument recurring.
Dispatcher overrides are data worth reading
A list of the bookings humans moved back after each run is one of the most useful reports in a Field Service deployment, and almost nobody builds it. Repeated overrides in the same territory, for the same customer, or against the same resource are telling you which constraint is missing from the goal. Treat them as defect reports about the configuration rather than as noise.
The narrow remit is a legitimate destination
Plenty of well run operations use the optimizer only to place unscheduled requirements and never to rearrange existing bookings, with humans owning the near window. That is a smaller benefit than the product brochure implies and a real one, and it is far better than a wide remit everybody spends their mornings undoing.
Some of this is a process problem wearing a settings problem
When dispatch and the schedule fight continuously, the cause is sometimes that two people are allowed to promise the same slot, or that customer commitments are made by phone and never recorded anywhere the system can see. No lock configuration fixes that. It is worth saying before a team spends a month tuning an optimization goal.
If you are still deciding whether the whole scheduling stack is the right fit, rather than tuning one that is already live, the trade between an integrated platform and a dedicated dispatch product is set out in our Field Service dispatch software comparison. And if the optimizer fighting dispatch is one symptom among several after a rollout that did not land, the recurring causes are named in why mid market companies fail at D365 Field Service implementation.
How Solzet fixes a schedule like this
Scheduling remediation is part of our Field Service delivery rather than something we sell separately, so this is what it looks like when we do it.
We start from the audit history, not from the settings
The first hour goes on a booking that actually moved: what changed, when, and who changed it. It is common enough to find that at least some of the complaints were a flow, a plugin, or a second optimization scope left over from testing. Changing scope settings before that reading is how a team spends a week configuring the record that was never responsible.
We separate the promise from the preference
Before touching a goal we get the business to say which commitments cannot be broken and which are preferences. Those two lists map directly onto constraints and objectives, and most badly behaved optimization configurations are a preference somebody put on the constraint side or a promise somebody left on the objective side.
We build the automation rather than issuing an instruction
A flow or a plugin that locks and re-statuses what a human placed, keyed on the modifying user, with a clear way for a dispatcher to release a booking back. Asking a dispatch team to remember a step during their busiest hour is not a fix, and we have picked up enough systems where that was the documented answer to be blunt about it.
We fix the scheduling data the engine is reacting to
Geocoding on service addresses, real start locations per resource, characteristics and proficiencies that are maintained, working hours that match the shift. This is the same work that decides whether the schedule board is trusted in week one, and it is where most Field Service remediation time honestly goes.
We ship it through proper solution lifecycle management
Separate development, test and production environments, changes made in unmanaged solutions and promoted as managed ones, with the scope, the goal, the booking status and any code moving together. A scheduling fix that exists only as edits somebody made in production is a fix you will lose, usually while trying to diagnose the next one.
Certified engineers in one time zone
We deliver Dynamics 365 Customer Engagement and the Power Platform from a single hub in Yerevan, Armenia, at GMT+4, which overlaps Western European hours and reaches into the US morning. Our engineers hold Microsoft certifications including PL-200, PL-400 and PL-600.
For a worked example of the same stack in production, including asset modelling, scheduling optimization and a custom control on the dispatch board, see our field service digitization case study for a European manufacturer. The engagement models, certifications and what a Dynamics 365 developer actually covers are on our Dynamics 365 developer page, and if the scheduling problem is one part of a rollout that has already stalled, the Field Service implementation partner page describes how we pick that up.
Frequently Asked Questions
How do I prevent the Dynamics 365 Field Service optimizer from rescheduling manual bookings?
Use three layers rather than one. Lock the booking, choosing whether it is locked to the resource, to the time, or to both, so Resource Scheduling Optimization may not change what you locked. Give manually placed work a dedicated booking status, such as Committed, and configure the optimization scope so that runs may optimize the ordinary scheduled status but not that one, which protects every booking that reaches it without anyone applying anything per record. Then pull the scope date range back so runs cannot reach into the current shift at all. Finally, automate the first two with a flow or plugin on the bookable resource booking that applies the lock and the status when the modifying user is a person rather than the optimizer application user, because a protection a dispatcher has to remember during a busy hour is one you will lose on the days it matters most.
Why does Resource Scheduling Optimization move bookings my dispatcher created?
Because it has no way of knowing they were deliberate. The optimizer treats every booking inside its scope, in a status the scope is allowed to optimize, without a lock on it, as material it may rearrange to score better against its goal. It does not distinguish between a booking it created and one a human placed with a customer on the phone. That is the design rather than a defect, and the fix is to tell it which bookings are off limits using locks, booking statuses, scope range, and the resource set. Before you change any of those, read the audit history on a booking that actually moved, because bookings are also rescheduled by flows, plugins, agreement generation, auto scheduling on work order creation, and other dispatchers on the board, and each of those needs a different fix.
What does locking a booking actually stop?
It constrains the optimizer and nothing else. A locked booking is not moved by an optimization run in whatever dimension you locked, and it still consumes the capacity of the resource it is booked against, so runs plan the rest of that day around it rather than ignoring it. What it does not do is prevent a person from dragging it on the schedule board, prevent a Power Automate flow or a plugin from rescheduling it, or protect the underlying work order from being edited. It is also worth confirming that the optimization goal treats locked bookings as a constraint rather than an objective, because a preference the engine is allowed to trade away produces the case where the lock is set, the configuration looks correct, and the booking still moves.
Should I lock to the resource, to the time, or to both?
Lock the narrowest thing that protects what was actually promised, because every extra dimension you lock is optimization you gave up. Lock to both where a named technician was promised at a stated hour, which is the usual case for an appointment a customer confirmed. Lock to the resource where the promise was about who turns up, for instance the engineer who knows that site, and let the optimizer still improve when they arrive. Lock to the time where the promise was the arrival window and any qualified person satisfies it, which suits larger workforces with interchangeable skills and does not suit relationship based service. Teams that lock everything to both by reflex end up with a schedule the optimizer cannot improve at all, at which point they are paying for a feature that is switched off in practice.
Is a booking status better than locking each booking?
For routine protection, yes, and it is the layer most teams have not configured. A lock is per booking and somebody has to apply it. A booking status that the optimization scope is not permitted to optimize protects every booking that reaches that status automatically, including all the ones nobody has created yet. The cost is that it is a real configuration change rather than a setting: the status has to be created, mapped to the correct underlying field service status so the mobile app and the board keep behaving, added to the schedule board, explained to dispatchers, and reflected in reporting and any automation that reads status. Locks then become the exception for individual jobs rather than the mechanism the whole operation depends on.
Can I stop the optimizer touching anything in the next two days?
Yes, and it is usually the single most effective change available. The optimization scope carries a date range, and setting that range to begin after the near window means no run can consider anything inside it, whether or not those bookings are locked and whatever status they sit in. For most service operations the shape people actually want is that today is untouchable, tomorrow is negotiable, and everything beyond that is fair game for the engine. The trade is real and worth stating: the near term is often where the largest travel savings are, so you are choosing dispatcher control over some optimization benefit. That is usually the right choice, because a schedule dispatchers trust is worth more than a marginally shorter route they will override anyway.
How do I tell whether the optimizer or a flow moved a booking?
Read the audit history on the booking. It shows which field changed, when, and which user made the change. Resource Scheduling Optimization runs under its own application user, so its work is identifiable, and you can then open the optimization request from the same timestamp and read what that run did and why. A change made by a flow or a plugin shows the user the automation runs as, and a change made by a person shows the person. Make sure auditing is enabled on the bookable resource booking table before you need it. This check takes minutes and it regularly redirects the entire investigation, because a surprising share of bookings people believe the optimizer moved were moved by an agreement generating bookings, a rule auto scheduling on work order creation, or a second optimization scope somebody set up while testing and never disabled.
Will locked bookings break the rest of the schedule?
No. A locked booking is still visible to the engine as occupied time on that resource, so runs schedule other work around it rather than double booking or pretending it is not there. What locks do change is how much room the engine has to work with, and that effect compounds. A day with two locked bookings still optimizes well. A day where every booking is locked cannot be optimized at all, and the run will complete successfully having changed nothing, which is a failure mode that is easy to miss because nothing reports an error. If you find yourself locking most bookings, the useful conclusion is not that locking is wrong but that the optimizer has been given a remit the operation does not actually want it to have.
The optimizer keeps moving the same bookings back. What now?
Stop treating it as a settings problem and read what the run was solving for. Repeated relocation of the same work is almost always the engine reacting to something real in the data: a service address that does not geocode, so travel is guessed rather than calculated; a resource start location left as the office for somebody who leaves from home; characteristics and proficiencies set during go live and never maintained; or working hours that do not match the shift the person actually works. Locking those bookings hides the symptom and the next unlocked booking moves for the same reason. It is also worth building a report of the bookings dispatchers moved back after each run, because a pattern by territory, customer, or resource usually names the constraint missing from your optimization goal.
Send us the booking that keeps moving
Tell us what the audit history on that booking says, what your optimization scope covers, and which booking statuses it is allowed to optimize, and we will tell you whether this is a lock, a status, a scope range, a goal constraint, or something that was never the optimizer at all. Solzet is a Dynamics 365 Customer Engagement and Power Platform consultancy in Yerevan, Armenia, working with clients and Microsoft partners across Europe and the US.