Fix the rollout checker for a column rename
Your task
An agent renamed users.fullname to full_name with one migration and the matching code change in the same PR. During the rolling deploy, old and new app versions served traffic side by side, and the old ones failed on the missing column. Your team now checks every schema plan, step by step, before it runs.
An assistant wrote first_unsafe_step(initial_columns, initial_code, steps). It is in the editor. It has a bug. Find it and fix it.
Input and output:
initial_columns: the columns the table has now.initial_code: the columns the running code reads, comma separated.steps: the plan, in order, such asmigrate:+full_name,migrate:-fullname,migrate:fullname>full_nameordeploy:id,full_name.- Return the number of the first unsafe step, counting from 1, or 0 when every step is safe.
Rules the tests check:
- Track the schema, the set of existing columns, which starts as
initial_columnsexactly as given, and the running code's columns. A comma separated list of columns, likeinitial_codeor a deploy payload, is split on,, each name trimmed, empty names ignored. Names inmigratesteps are used exactly as written, with no trimming. - Split each step at its first
:into a kind and a payload. A step with no:, or with a kind other thanmigrateordeploy, does nothing. migrate:+coladds the column, if the name is not empty. It is always safe.migrate:-coldrops the column. It is unsafe when the running code reads it.migrate:old>new, split at the first>, renames a column. It is unsafe when the running code readsold. Otherwiseoldis removed andnewis added, if not empty. Any othermigratepayload does nothing.deploy:colsrolls out code that readscols. During the rollout the old and new code both serve traffic, so it is unsafe when any column read by the running code or by the new code is missing from the schema. Afterwards the running code readscols.
Examples
first_unsafe_step(initial_columns: list[str], initial_code: str, steps: list[str]) -> intExample 1
Input
first_unsafe_step(["id", "fullname"], "id,fullname", ["migrate:fullname>full_name", "deploy:id,full_name"])Output
1Example 2
Input
first_unsafe_step(["id", "fullname"], "id,fullname", ["migrate:+full_name", "deploy:id,fullname,full_name", "deploy:id,full_name", "migrate:-fullname"])Output
0Example 3
Input
first_unsafe_step(["id", "fullname"], "id,fullname", ["deploy:id,full_name"])Output
1