{"record":{"id":"c1502c20a5a4e31b","repo":"Hmbown/CodeWhale","slug":"publish-package-list-is-missing-workspace-crates","errorCode":null,"errorMessage":"publish package list is missing workspace crates: {missing}\npublish package list contains non-workspace crates: {extra}","messagePattern":"publish package list is missing workspace crates: (.+?)\npublish package list contains non-workspace crates: (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"scripts/release/validate-crate-publish-order.py","lineNumber":118,"sourceCode":"        rendered = \", \".join(str(version) for version in versions)\n        raise ValidationError(f\"workspace packages have mixed versions: {rendered}\")\n\n    workspace_by_name = {package[\"name\"]: package for package in packages}\n    release_names = sorted(\n        name for name in workspace_by_name if name.startswith(\"codewhale-\")\n    )\n    ordered_set = set(ordered_crates)\n    missing = sorted(set(release_names) - ordered_set)\n    extra = sorted(ordered_set - set(release_names))\n    if missing or extra:\n        messages = []\n        if missing:\n            messages.append(\"publish package list is missing workspace crates: \" + \" \".join(missing))\n        if extra:\n            messages.append(\n                \"publish package list contains non-workspace crates: \" + \" \".join(extra)\n            )\n        raise ValidationError(\"\\n\".join(messages))\n\n    positions = {name: index for index, name in enumerate(ordered_crates)}\n    has_workspace_dependencies = {name: False for name in release_names}\n    publish_edges: set[tuple[str, str, str]] = set()\n    for dependent in release_names:\n        dependencies = workspace_by_name[dependent].get(\"dependencies\", [])\n        if not isinstance(dependencies, list):\n            raise ValidationError(f\"Cargo metadata dependencies for {dependent} must be a list\")\n        for dependency in dependencies:\n            if not isinstance(dependency, dict) or dependency.get(\"path\") is None:\n                continue\n            dependency_name = dependency.get(\"name\")\n            if dependency_name not in workspace_by_name:\n                continue\n            has_workspace_dependencies[dependent] = True\n            kind = dependency.get(\"kind\") or \"normal\"\n            # Cargo does not compile dev-dependencies while verifying a publish.\n            # They may legitimately point back across the publication DAG.","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/release/validate-crate-publish-order.py#L100-L136","documentation":"The set of workspace crates named codewhale-* and the positional crate list passed on the command line (the maintained publication order from scripts/release/crates.sh) do not match: codewhale-* crates absent from the list are reported as 'missing', and list entries that are not codewhale-* workspace crates are reported as 'non-workspace'. One or both parts may appear, joined by a newline. The release inventory must exactly mirror the codewhale-* workspace members.","triggerScenarios":"A new crate codewhale-foo was added to the workspace but not to scripts/release/crates.sh; a crate was removed or renamed (e.g. codewhale-bar -> codewhale-bar2) without updating crates.sh; a typo in a crate name in the list; passing a manually typed crate list that omits or adds entries.","commonSituations":"Post-merge release validation after adding, renaming, or deleting workspace crates.","solutions":["Add each crate named under 'missing' to scripts/release/crates.sh, placed before any crate that depends on it","Remove each entry named under 'non-workspace' from the list, or fix its spelling to match the real package name","Re-run scripts/release/validate-crate-publish-order.py with the updated list until it passes"],"exampleFix":"# scripts/release/crates.sh: before\ncrates=(codewhale-protocol codewhale-tui codewhale-cli)\n# workspace gained codewhale-release -> error lists it as missing\n\n# after\ncrates=(codewhale-protocol codewhale-release codewhale-tui codewhale-cli)","handlingStrategy":"validation","validationCode":"# Keep the crate list in sync with codewhale-* workspace members\nexpected = sorted(p[\"name\"] for p in packages if p[\"name\"].startswith(\"codewhale-\"))\nif sorted(ordered_crates) != expected:\n    raise SystemExit(\n        f\"list drift: missing={set(expected) - set(ordered_crates)} \"\n        f\"extra={set(ordered_crates) - set(expected)}\"\n    )","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat scripts/release/crates.sh as release-critical: update it in the same commit that adds/removes/renames any codewhale-* crate","Run the validator in CI on every push so inventory drift is caught immediately"],"tags":["release","workspace","cargo","inventory","python"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}