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, or None to 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:

  • service and environment: 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_permissions and available_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):

  1. Return a new dictionary with the same five fields. Overrides win, including False, 0, None, and empty lists. A missing override keeps the default.
  2. Give the returned dictionary independent labels and regions lists, 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:

  1. Identity and settings: return the target as (service, environment) and the effective settings as a dictionary.
  2. 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_preview list; fewer than two is valid.
  3. Access: return missing_permissions as required permissions absent from the available set; return allowed_permissions as required permissions that are available. Do not grant unrelated available permissions. Both values are sets.
  4. 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_preview must 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:

Python
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.

output
{
    '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.

Drag or use the arrow keys to resize. Home collapses the question; End collapses the editor. Enter or double-click resets the split.
Loading editor…
No results yet.

Complete the starter code, then run the checks.
Results and errors will appear here.