Build one deployment plan preview from shared defaults and an application's overrides. The preview must apply the requested changes without quietly editing the next deployment's starting state.
Inputs are already validated. No type checks, parsing, loops, or comprehensions are needed. The supplied function shells establish the interface; fill their bodies with direct collection operations. The final shell already calls the prototype helper and constructs the output dictionary. Preserve signatures and return values. Printing is not a return value.
Inputs
defaults has exactly these fields:
workers: nonnegative integer worker count.enabled: boolean deployment switch.fallback: string naming a fallback/recovery policy, orNoneto inherit the environment's routing default.labels: list of strings; order and duplicates matter.regions: list of region names representing ordered routing attempts.
overrides contains any subset of those fields, with the same types. An override replaces the entire matching field; lists are replaced, not merged. An empty list is an intentional replacement. There are no unknown fields or deeper nested objects in this schema.
request has these required fields:
serviceandenvironment: strings identifying the target; preserve their spelling and case.primary_region: string to insert as the first routing attempt.extra_regions: list of strings to append as additional routing attempts.retired_region: string to remove from the routing attempts.required_permissionsandavailable_permissions: sets of strings.
For build_deployment_plan, the validator guarantees that the retired region occurs exactly once in the effective region list, and never occurs in the primary or extra additions. Other repeated regions are valid retry attempts. These guarantees keep removal a direct operation; invalid requests are outside this exercise's contract. The prototype helper also accepts empty region lists because it does not perform routing edits.
Prototype: effective settings
Implement effective_settings(defaults, overrides):
- Return a new dictionary with the same five fields. Overrides win, including
False,0,None, and empty lists. A missing override keeps the default. - Give the returned dictionary independent
labelsandregionslists, whether their values came from defaults or overrides. Changing a result must not change either input, and later input changes must not change an existing result.
This helper applies settings only; it does not insert or retire regions.
Final: the complete plan
Implement build_deployment_plan(defaults, overrides, request) using that helper:
- Identity and settings: return the target as
(service, environment)and the effective settings as a dictionary. - Routing: on the owned settings region list, insert the primary first, append all extra attempts, then remove the retired region. Preserve the order and duplicates of everything that remains. Return the first two final attempts as a separate
region_previewlist; fewer than two is valid. - Access: return
missing_permissionsas required permissions absent from the available set; returnallowed_permissionsas required permissions that are available. Do not grant unrelated available permissions. Both values are sets. - Ownership: leave every input unchanged. The result's settings, its two settings lists, its preview list, and its permission sets must be independent of input containers and of other returned plans. Editing
region_previewmust not edit the full routing list. Sharing immutable strings is fine.
The output has exactly these keys: target, settings, region_preview, missing_permissions, and allowed_permissions. settings has the same five keys as the prototype. The final checks include the prototype requirements.
Example
Here is one complete request. This code defines the inputs and calls your API; the implementation belongs in exercise.py:
defaults = {
"workers": 2,
"enabled": True,
"fallback": "manual",
"labels": ["stable"],
"regions": ["old-region", "singapore"],
}
overrides = {"workers": 0, "enabled": False, "fallback": None}
request = {
"service": "payments",
"environment": "staging",
"primary_region": "mumbai",
"extra_regions": ["tokyo", "singapore"],
"retired_region": "old-region",
"required_permissions": {"deploy", "read-logs"},
"available_permissions": {"deploy", "read-metrics"},
}
plan = build_deployment_plan(defaults, overrides, request)The resulting plan is shown below. Set display order is not part of the contract.
{
'target': ('payments', 'staging'),
'settings': {
'workers': 0,
'enabled': False,
'fallback': None,
'labels': ['stable'],
'regions': ['mumbai', 'singapore', 'tokyo', 'singapore']
},
'region_preview': ['mumbai', 'singapore'],
'missing_permissions': {'read-logs'},
'allowed_permissions': {'deploy'}
}Also check an empty override, empty labels and permissions, a region list containing only the retired entry, repeated fallback attempts, and two plans built from the same inputs. This is a fixed-schema ownership exercise, not a request to implement recursive deep copying.
If your saved draft still contains the older unique_words or group_words exercise, download it before using Reset starter code to load this exercise's new shell.
Complete the starter code, then run the checks.
Results and errors will appear here.