diff --git a/docs/work-record-uuid-derivation_v1.md b/docs/work-record-uuid-derivation_v1.md index a215dc5..28dcdca 100644 --- a/docs/work-record-uuid-derivation_v1.md +++ b/docs/work-record-uuid-derivation_v1.md @@ -80,7 +80,8 @@ the cutover: each replacement must resolve its current UUID with HTTP 200 and its derived target with HTTP 404 on every named projection, or the manifest is not ready for approval. Saved projection endpoints are rechecked by `migration-batch-verify`; omitting the option retains the offline source/Git-only -planning mode. +planning mode. A projection-aware batch containing UUID assignments fails +closed until an assignment-specific projection identity check is implemented. Activation and applying a bulk migration remain separate governed steps. Publishing or planning this function does not retroactively rewrite existing diff --git a/src/repo_manager/identifiers.py b/src/repo_manager/identifiers.py index 515d42f..1beb06e 100644 --- a/src/repo_manager/identifiers.py +++ b/src/repo_manager/identifiers.py @@ -365,7 +365,14 @@ def _projection_migration_preflight( ) -> dict[str, Any]: """Require every replacement source and no replacement target per projection.""" projections: list[dict[str, Any]] = [] - errors: list[dict[str, str]] = [] + errors: list[dict[str, str]] = [ + { + "scope": str(mapping.get("record_id") or "unknown"), + "reason": "projection-aware approval does not yet support UUID assignments", + } + for mapping in mappings + if mapping.get("action") == "assign" + ] for raw_base in api_bases: api_base = raw_base.strip().rstrip("/") try: diff --git a/tests/test_identifiers.py b/tests/test_identifiers.py index 47510e2..530f040 100644 --- a/tests/test_identifiers.py +++ b/tests/test_identifiers.py @@ -7,6 +7,7 @@ import httpx import pytest from repo_manager.identifiers import ( + _projection_migration_preflight, derive_work_record_uuid, load_fleet_namespace, migrate_repository_identifier_files, @@ -22,6 +23,21 @@ def test_declared_fleet_namespace_is_helixforge() -> None: assert load_fleet_namespace() == "helixforge" +def test_projection_preflight_rejects_unproven_assignment() -> None: + result = _projection_migration_preflight( + [{"action": "assign", "record_id": "ONE-WP-0001"}], + ["http://hub.test"], + ) + + assert result["ok"] is False + assert result["errors"] == [ + { + "scope": "ONE-WP-0001", + "reason": "projection-aware approval does not yet support UUID assignments", + } + ] + + def _workplan(path: Path, identifier: str, status: str, task_status: str = "todo") -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(