Skip to content

PROD-2552: add agility verify to compare a synced target against its source - #235

Draft
5PK wants to merge 4 commits into
mainfrom
feature/PROD-2552-verify-command
Draft

5PK wants to merge 4 commits into
mainfrom
feature/PROD-2552-verify-command

Conversation

@5PK

@5PK 5PK commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

Problem

Brightstar has had migrations where the sync reported success but components on pages ended up in the wrong order, and they couldn't be sure the page and sitemap order was right. --preflight only says what a sync intends to do. Nothing checks what it actually did, so the only way to confirm a migration is a manual regression pass over 100+ pages, which took them about two weeks last time. For the SPL blue/green cutover on Nov 23 we need a step that proves the new instance matches before traffic switches.

Change

New command agility verify --sourceGuid X --targetGuid Y. It adds no new flags: it reuses --locales, --channel, --models, --pages, --containers and --jsonSummary. It never writes to either instance or to the mapping files.

Pull guard

  • Checks the Fetch API status for both instances, in both preview and fetch mode. If an update is in progress, it waits up to a fixed 10 minutes using its own bounded polling. The SDK's wait has no timeout.
  • Then it does a full pull of both instances and checks again. If an update ran during the pull, it pulls once more. If that happens again, it exits 2.
  • Exits 2 if a status check fails or times out. Standalone pull ignores a failed status check, but verify doesn't (see PROD-2754).

Comparison

  • It doesn't reuse the push transforms or change detection, which decides on version IDs. Both sides are converted into the same neutral form, with source IDs translated to target IDs through the mapping files, and compared there. Otherwise a bug in the transforms would produce the same wrong result on both sides and still pass.
  • Checks:
    • Mapping integrity: source items with no mapping, mappings that point at a missing target, and two sources mapped to one target.
    • Models, containers and templates.
    • Content: counts per model and per container, list order, and field values. Linked content, assets (including asset URLs in rich text) and companion fields are resolved through the mappings.
    • Components on pages: the order within each zone and which zone each component is in. Zones are matched by section ID, then by name, and never by position (the PROD-2350 bug class).
    • Sitemap: each page's parent and its order among its siblings, per locale and channel.
  • Severities:
    • Failures: mismatches, missing items, and order, zone or sitemap errors.
    • Warnings: target-only content and publish-state differences.
    • Source defects, listed but not failing the run: an item missing a required field (using validateContentItemAgainstModel) or an item in a deleted container.
  • Output: a console table per locale and the first 20 findings per category, plus a full JSON report. Exit codes: 0 match, 1 differences, 2 couldn't verify.
  • README: new "Verify" section.

Testing

  • npx jest: 126 suites / 2,389 tests pass (main: 116 / 2,252). tsc --noEmit is clean.
  • Unit tests cover:
    • the mapping index
    • each normalization rule
    • page zones: swapped components, a component in the wrong zone, a renamed zone matched by section ID, zones defined in a different order on the two templates, and an unmapped zone, which never falls back to position
    • sitemap reordering, reparenting and multi-channel
    • count mismatches, list order, and an item unpublished on one side
    • source-defect classification
    • the status guard: waiting, timeout and an update during the pull
    • exit codes and JSON output
  • End-to-end hermetic test: sync, then verify (exit 0). Reverse one zone in the target, and verify gives exit 1 with only a component-order failure. The mapping files are byte-identical afterwards.
  • Live, read-only, against the SPL clone pair 7a2c6fef-us2 → df079bec-us2 (en-us, pt-br). The full pull took 54s the first time, mostly downloading assets, and about 4s on the repeat run; the comparison took 0.2s. Exit 1: 15 failures, 15 warnings, 67 source defects. On 10-02 the sync for this pair reported 77 ok / 0 failed, but the failures are real target defects:
    • /scratchers (en-us) has empty zones on the target, missing 5 components. Three pt-br pages are missing 4 components between them.
    • Target page 39 (terms of service) has RichTextArea 547 twice, in both locales. Source page 53 has 11 components; target page 39 has the same 11 plus a trailing duplicate. I checked this by hand.
    • Three home_homebanner items lost mobileBackgroundImage, and one item links a list that only exists on the target.
  • Fully matching: 260 models, 2,170 containers, 6 templates, 1,306 assets, 7 galleries, 121 pages and 117 sitemap entries.
  • False positives found on the live data and fixed: Agility system containers, items in deleted containers, a duplicate component also being reported as a wrong order, empty or dangling list links, and missing page publish-state warnings.

Known limits / follow-ups

Closes PROD-2552. Covers PROD-2549.

🤖 Generated with Claude Code

5PK and others added 4 commits October 7, 2026 15:58
Shared interface (RequiredFieldIssue / FieldValidationResult) used by verify
to classify differences explained by a source item missing a required field.
Minimal faithful copy; the version on the validation branch wins at merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ecks, report)

- mapping-index: Map-backed bidirectional indices over every mapping type, read-only
- canonicalize: neutral comparison form (target IDs, linked refs, asset URL
  translation and host aliasing, null/empty/CRLF/case/numeric normalization);
  shares no code with the push transforms
- checks: mapping integrity, models/containers/templates, content (fields,
  counts, list order), page fields and zones (section-ID or exact-name pairing,
  never positional), sitemap (parent, sibling order, missing)
- verify-report: findings, tallies, exit codes, console table, JSON report
- writeJsonSummary accepts any report object

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Status guard (bounded 10-minute wait in preview and fetch mode, re-pull once
if an update lands during the pull), full pull of both instances, per-locale
checks, console + JSON report. Exit 0 pass, 1 differences, 2 could not verify.
Accepts only existing flags via a dedicated verifyArgs set; never writes to an
instance or to the mapping files. Also satisfies PROD-2549.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant