{"record":{"id":"2796a6fc908a82fc","repo":"Hmbown/CodeWhale","slug":"first-party-catalog-drift-run-python3-scripts-sync","errorCode":null,"errorMessage":"First-party catalog drift: run python3 scripts/sync-marketplace.py, review, and rebuild.","messagePattern":"First-party catalog drift: run python3 scripts/sync-marketplace\\.py, review, and rebuild\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/sync-marketplace.py","lineNumber":40,"sourceCode":"for candidate in catalog[\"plugins\"]:\n    spec = candidate[\"source\"]\n    if not spec.startswith(\"path:\"):\n        raise SystemExit(f\"unexpected first-party source: {spec}\")\n    relative = spec[5:]\n    if any(part in (\"\", \".\", \"..\") or not all(c.isascii() and (c.isalnum() or c in \"-_.\") for c in part) for part in relative.split(\"/\")):\n        raise SystemExit(f\"unsafe bundle path: {relative}\")\n    # Pin every install source to the reviewed marketplace revision so the\n    # bytes a user installs are the bytes this snapshot describes. Freshness\n    # comes from bumping the pin (the marketplace-sync workflow reports drift\n    # against `main` weekly); `/plugin update` re-downloads the same archive\n    # and reports no change until the pin moves.\n    candidate[\"source\"] = f\"https://codeload.github.com/Hmbown/codewhale-plugin-marketplace/tar.gz/{revision}#path={relative}\"\nsnapshot = {\"repository\": REPOSITORY, \"revision\": revision, \"catalog\": catalog}\nrendered = json.dumps(snapshot, indent=2, ensure_ascii=False) + \"\\n\"\noutput = ROOT / \"crates/tui/assets/first-party-marketplace.json\"\nif args.check:\n    if not output.exists() or output.read_text() != rendered:\n        raise SystemExit(\"First-party catalog drift: run python3 scripts/sync-marketplace.py, review, and rebuild.\")\n    print(f\"First-party catalog matches marketplace {revision}\")\nelse:\n    output.write_text(rendered)\n    print(f\"Updated {output} from marketplace {revision}\")\n","sourceCodeStart":22,"sourceCodeEnd":45,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/sync-marketplace.py#L22-L45","documentation":"sync-marketplace.py regenerates crates/tui/assets/first-party-marketplace.json from marketplace.json plus the pinned git revision. With --check (CI mode), it compares the rendered snapshot to the committed file and exits with this drift message if the file is absent or differs, instructing the developer to regenerate, review, and rebuild.","triggerScenarios":"Committing a marketplace.json change without re-running the script; editing first-party-marketplace.json by hand; a CI check running after someone bumped marketplace.json but not the asset.","commonSituations":"Forgetting the sync step during a plugin release; manual tweaks to the generated asset; rebase that took marketplace.json from one side and the asset from another.","solutions":["Run `python3 scripts/sync-marketplace.py` to regenerate the asset.","Review the diff of crates/tui/assets/first-party-marketplace.json.","Rebuild/re-run tests that embed the asset.","Commit both marketplace.json and the regenerated asset together, then re-run with --check."],"exampleFix":"// before (hand-edited asset or stale)\ncrates/tui/assets/first-party-marketplace.json (revision abc123)\n// after\n$ python3 scripts/sync-marketplace.py  # regenerates asset at current HEAD revision","handlingStrategy":"validation","validationCode":"subprocess.run(['python3','scripts/sync-marketplace.py','--check'], check=True)","typeGuard":null,"tryCatchPattern":"import subprocess\ntry:\n    subprocess.run(['python3','scripts/sync-marketplace.py','--check'], check=True)\nexcept subprocess.CalledProcessError:\n    subprocess.run(['python3','scripts/sync-marketplace.py'], check=True)  # regenerate, then review diff","preventionTips":["Run the --check mode locally before committing marketplace changes","Never hand-edit generated assets under crates/tui/assets/","Commit marketplace.json and the generated asset in the same change"],"tags":["ci","drift","marketplace","generated-files"],"backgroundTag":"checksum-mismatch","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}