Record a history rewrite on the repository [IFC-3284]

Merged
GM
14d ago
+1954-149

Why

When content at an earlier commit can no longer be re-derived, today only the worker logs and the orchestrator tell why. This PR stores the answer on the repository itself. IFC-3284, phase 6 of the IFC-3210 spec.

What changed

  • Four LOCAL, optional attributes on CoreGenericRepository: last_rewrite_previous_commit, last_rewrite_commit, last_rewrite_at and rewrite_count. CoreRepository and CoreReadOnlyRepository inherit them and override nothing.
  • HistoryRewriteRecorder writes them only when the graph comparison classifies a branch as REWRITE. Its store is a port. The SDK adapter reads the repository node through the generic and saves it, so the SDK builds the mutation of the node's own kind with only the changed fields.
  • collect_pending_imports records each rewrite right after the branch commit is written, inside the collection lock. A failed record fails that branch alone, and its import stays queued.

What to look at

  • InfrahubRepository._queue_import: one place for the new-branch, updated-branch and staging paths.
  • A failed record has a step of its own, record. On the default branch it is logged at error level and fails the run, but it does not write error-import: the import still runs and writes in-sync (FR-013).
  • A failed record is logged once where it is caught, the way a failed import is: the store chains the SDK error, so the reason is the API's own message for a known failure, and the traceback is kept only for an error that is not recognised.
  • The RewriteEventEmitter port is not here. It comes with the trunk signal (IFC-3285), because there is no event yet. The spec now says so.
  • The SDK protocols gain the four attributes in https://github.com/opsmill/infrahub-sdk-python/pull/1401, now merged. The python_sdk pointer names its merge commit on infrahub-develop.

How to test

uv run pytest backend/tests/unit/git/divergence/ backend/tests/unit/git/test_branch_reconciliation.py
uv run pytest backend/tests/component/git/test_repository_rewrite_branch_safety.py --neo4j
uv run pytest "backend/tests/integration/git/test_git_live_remote.py::TestRewrittenBranchSynchronisation" --neo4j

I broke each guard and watched its test fail, for example: classify against the worktree head instead of the graph commit, make the four attributes AWARE, or drop the catch around the record.

Checklist

  • Tests added/updated
  • Changelog entry added. This PR also carries +failed-branch-blocks-other-branches.fixed.md, which IFC-3282 moved to the top of the stack.
  • External docs updated: IFC-3287 documents the reconciliation
  • Internal .md docs updated
  • I have reviewed AI generated content