Skip to content

feat(lifecycle-ownership): guarded operator recovery for lifecycle ownership #294

Closed

Description

@mashkovd

Split out of mctlhq/mctl-api#293 on 2026-09-12. #293 keeps the read-only
inspection surface and moves earlier — it is what makes the observe-mode
soak diagnosable. This issue keeps the mutating half, which cannot be
specified until the reconciler defines what a legitimate recovery is.

Parent roadmap: mctlhq/.github#57
Depends on: mctlhq/mctl-api#293, mctlhq/mctl-agents#352, mctlhq/mctl-agents#353

Goal

Expose narrowly-scoped, auditable operator recovery for lifecycle ownership —
the operations an operator needs when reconciliation has correctly refused to
act and a human must break the tie.

Why this is separate from #293

#293's read surface is needed during rollout: without it, the observe-mode
soak is diagnosed by grepping logs instead of asking the platform. Recovery is
the opposite — specifying it before mctlhq/mctl-agents#353 has defined what a
legitimate recovery looks like would mean inventing the semantics at the API
layer, which is exactly how a force_owner escape hatch gets built.

Scope

Operations equivalent to:

  • request ownership reconciliation for one entity;
  • request or retry an explicit handoff;
  • release/fence a claim that is provably stale;
  • inspect conflict evidence before intervening.

Requirements

  • Every recovery operation takes optimistic preconditions — expected owner,
    owner epoch, and entity version/head — and fails closed when any of them
    has moved. A stale client must never be able to overwrite fresh state.
  • Recovery is subject to normal mctl policy/authz and is audited. It does not
    imply GitHub merge authority, and it does not bypass CODEOWNERS, branch
    protection, NEVER_MERGE_SERVICES or repository merge policy.
  • A caller may not release or progress an ownership row it does not own, except
    through an explicit, audited recovery operation that records why.
  • No generic force_owner=<anything> mutation. Each operation names a
    specific, reviewable transition.
  • Every recovery records entity, phase, version/head, old and new owner epoch,
    claim state, the evidence relied on, the acting principal, reason and outcome.

Acceptance criteria

  • Each recovery operation requires preconditions and fails closed when owner
    epoch or entity version changed.
  • A stale client cannot overwrite fresh state; a test proves it.
  • No operation can transfer merge or approval authority.
  • Recovery is policy/authz controlled and appears in the audit trail.
  • Conflict evidence is inspectable before intervention.
  • MCP descriptors make mutating semantics explicit; read and recovery tools
    are not confusable.
  • No generic force/override endpoint exists.

Non-goals

  • A free-form admin endpoint for reassigning any lifecycle entity.
  • Making mctl-api the owner of Temporal/DevLoop lifecycle state.
  • Automatic recovery — that is mctlhq/mctl-agents#353. This is the human path.

Activity

  1. added
    agents:intakeFeed this issue to the mctl-agents Temporal pipeline
    on Sep 18, 2026
  2. removed
    agents:intakeFeed this issue to the mctl-agents Temporal pipeline
    on Sep 18, 2026
  3. mctl-agents commented on Sep 18, 2026

    @mctl-agents
    Contributor

    mctl-agents issue-investigator has analyzed this issue and created a proposal:

    https://github.com/mctlhq/mctl-gitops/tree/main/platform-gitops/agents-state/mctl-api/proposals/issue-294-feat-lifecycle-ownership-guarded-operato/

    Status: proposed — pending human approval. Review requirements.md, design.md and tasks.md, then approve: signal this issue's DevLoopWorkflow (mctl-api POST /api/v1/agents/dev-loop/dev-loop-mctlhq-mctl-api-294/approve, or python -m orchestrator.temporal.cli approve dev-loop-mctlhq-mctl-api-294 --approver <your-identity>) — the workflow flips .status.yaml to accepted via the mctl-agents-approve operation and runs the Tier 2 implementer. If no DevLoopWorkflow is running for this issue (pre-Temporal proposal), run the mctl-agents-approve operation directly with service=mctl-api slug=issue-294-feat-lifecycle-ownership-guarded-operato.

    The approver is recorded in .status.yaml and in the gitops commit, and the implementer refuses a proposal whose control.requires_human_approval carries no named approver — so prefer the mctl-api endpoint, which takes the approver from the authenticated caller rather than from what the caller types.

  4. added a commit that references this issue on Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions