Skip to content

Decisions and manual work

Two schema snapshots show facts, not intent. If display_name disappears while full_name appears, that could be a rename, a replacement with different meaning, or two unrelated changes. onwardpg stops and prints a fingerprinted hint.

Terminal window
onwardpg plan rename-display-name \
--hint '{"kind":"rename","object":"column","from":["app","accounts","display_name"],"to":["app","accounts","full_name"]}'

For an eligible same-type rename, the planner can create a temporary second column and deterministic dual-write bridge. Existing rows still need an explicit strategy: reviewed manual SQL, an acknowledged single transaction for a known-small table, or a split plan.

The catalog proves the types differ. It cannot decide whether an empty string becomes NULL, fails, or maps to a product value.

ALTER TABLE app.accounts
ALTER COLUMN age TYPE integer
USING NULLIF(trim(age), '')::integer;

Choose manual_sql for a one-deployment bridge, then replace the generated ONWARDPG TODO in the relevant phase file. Add assertions for every data-dependent assumption:

-- onwardpg:assert account_age_is_convertible
SELECT NOT EXISTS (
SELECT 1
FROM app.accounts
WHERE age IS NOT NULL
AND trim(age) !~ '^[0-9]+$'
);

manual_sql hints never carry SQL. The editable file is the reviewed artifact, and its exact bytes become receipted only after clone verification succeeds.

Answers are bound to exact source and desired graph fingerprints. If a later edit changes the participating objects, stale or unused answers fail. This prevents a previous approval for one destructive shape from silently authorizing another.