Gravity Migration

08 · Proof

Every difference gets a name and a decision.

Rule tests prove that the build does what the spec says. Only production can show that the spec covers what the business does. A parallel run puts the two side by side, and each mismatch teaches you something.

A captured production case, a late payment of 1,234.70 dollars, goes to both Anchor Core and the new build. Anchor Core produces 61.73 dollars and the new build produces 61.74 dollars. The comparison finds the mismatch and opens difference DIFF-007, which needs a named decision. CAPTURED CASEDue: $1,234.7030 days past due SOURCEAnchor CoreACLP210 SHADOW BUILDPaymentscomputes, posts nothing $61.73$61.74 COMPARE Mismatch: 1 centopens DIFF-007 Kept quirkdecided: Payments owner
The build runs in a shadow environment with no route to Anchor Core, a bank or a borrower, so comparing it can't affect anyone.

Four classifications · at Tidewater

The method's real output is decisions.

"Match the old system" isn't always right, and neither is "the new one is correct". Tidewater's late-payment slice produced one of each, and they all look alike until a person reads them.

IDCaseOldNewClassification and outcomeDecider
DIFF-007Fee on $1,234.70$61.73$61.74Kept quirk. Banks were always billed this way, so LPF-003 now says so.Payments owner
DIFF-009Due date 99999999No follow-upFollow-up openedRegression. Conversion treated it as a date. The build is fixed.Technical lead
DIFF-012Grace period across FebruaryStarts 2 days earlyStarts on timeFixed defect. The old code counted 30-day months. 214 past fees are reviewed.Payments owner
DIFF-015Due date on a bank holidayNo follow-up yetFollow-up openedDiscovered rule. The job read a bank calendar nobody remembered. LPF-006 is added.Payments owner

Coverage

June can't prove December.

Many behaviors only run at particular times: month-end, quarter-end, year-end, a leap day, the first run after a holiday. DIFF-012 could only appear after a February. Some cases are too rare to wait for, so build those from captured data, and say which were constructed.

Comparison also needs filters, since timestamps and generated IDs will always differ. Each filter is a recorded decision, because a filter is the easiest place to hide a real difference.

Where the run happens

A captured case holds real names, balances and account numbers, so it runs in a shadow environment under a Production permit that names only that environment. All the Standard's production evidence applies.

Shadow holds no credentials or route to Anchor Core, a bank or a person. "Posts nothing" is enforced by the environment, not promised by a flag. Earlier rungs use constructed or irreversibly masked cases.

Rules

MIG-029 to MIG-033, MIG-038

  1. MIG-029

    Every rule has a rule test that cites its ID, and rules in moved capabilities are also checked against captured production cases.

  2. MIG-030

    A parallel run covers at least one complete business cycle, including the period-ends that matter to the business.

  3. MIG-031

    Every difference gets exactly one classification and a named decider.

  4. MIG-032

    An unexplained difference blocks cutover of the slice it belongs to.

  5. MIG-033

    Captured production data keeps its classification and production-grade protection wherever it is used.

  1. MIG-038

    A parallel run on real data happens only in a shadow environment, which holds a Production permit naming only that environment and can't reach any real system, partner, or person.

difference-report.md
# DIFF-nnn — <short description>

- **Slice:** <name>
- **Found:** YYYY-MM-DD, in run <run ID>
- **Case:** <input, using identifiers and no classified values>
- **Old outcome:** <what the source did>
- **New outcome:** <what the build did>
- **Scope:** <how many cases, and which banks or periods>

## Classification (exactly one, MIG-031)
- [ ] Regression — the rule was clear and the build is wrong → fix the build
- [ ] Kept quirk — the old behavior stays → sharpen rule <ID>
- [ ] Fixed defect — the old behavior was wrong → change rule <ID>; remediate past results
- [ ] Discovered rule — right, but unwritten → add rule <ID>, its evidence and its test

## Decision
- **Decider:** <one named person> — YYYY-MM-DD
- **Reason:** <one or two sentences>
- **Past results affected:** none | <count and what happens to them>
- **Closed by:** <commit, rule test or run ID>

While this is unexplained, the slice can't cut over (MIG-032).