Data Model: recorded-pin classification (#4827)

This is an infrastructure/CLI fix; the "data model" is the derived classification state of the recorded planning_commit_sha, not a persisted schema change. lanes.json's LanesManifest.planning_commit_sha field is unchanged (str | None).

Entity: recorded-pin classification (derived, not persisted)

Computed against the planning target-branch tip with two git predicates.

FieldSource
recorded_shaLanesManifest.planning_commit_sha (read from lanes.json)
target_tip_capture_target_branch_tip(repo_root, target_branch) (may be None)
object_presentgit cat-file -e <recorded_sha>^{commit} → rc 0
reachablegit merge-base --is-ancestor <recorded_sha> <target_tip> → rc 0

States and transitions

execution not begun ............................ CAPTURED   (capture tip; today's behavior)
recorded reachable from tip (rc 0) ............. CURRENT/ADVANCED
recorded present, not reachable, tip capturable  ORPHANED   (the rebase shape)
recorded absent (cat-file rc != 0) ............. FOREIGN
tip uncapturable / not a git repo .............. (degrade → preserve, no classification abort)
FromActionTo
ORPHANEDfinalize --refresh-planning-commit --allow-orphanedCURRENT/ADVANCED (re-pinned to tip)
ORPHANEDplain finalize (no flag)fail closed (no write); state unchanged
ORPHANEDbare finalize --refresh-planning-commitrefused ("not an ancestor"); state unchanged
FOREIGNany re-pin attemptrefused; state unchanged
CURRENT/ADVANCEDfinalize --refresh-planning-commit (tip advanced)refreshed (existing #4141)

Consumers of the classification (read-only; C-001 — none writes the field)

ConsumerFile:lineOrphan behavior after fix
Recorded-planning mergeworktree_allocator.py :419/:482/:562 via shared _merge_recorded_planning_commitraise orphan-specific error naming the re-pin recovery (not generic conflict)
Reconcile mergeimplement_support.py:352 (same shared helper)same as above
Claim-ancestry gateimplement_support.py:497 check_claim_ancestryname orphan + recovery, not bare missing_refs
Owned-review basetasks_move_task.py:697 _mt_resolve_owned_review_basedetect orphan (object present ⇒ rev-parse --verify succeeds), fail closed instead of diffing a dead base

Report vocabulary (FR-009)

PlanningCommitResolution.action gains repinned alongside the existing captured / preserved / refreshed. The --json success payload's planning_commit object carries {action: "repinned", sha, previous_sha, branch_tip}. orchestrator_api/envelope.py CONTRACT_VERSION bumps 1.5.0 → 1.6.0 (additive).