Contracts

mission_runtime_api.md

Contract — mission_runtime public API

The canonical execution-state surface. Consumers import only from the package root.

Public surface (mission_runtime/__init__.py __all__)

__all__ = ["ExecutionContext", "ExecutionMode", "resolve_action_context", "ActionContextError"]

resolve_action_context

resolve_action_context(
    repo_root: Path,
    *,
    action: ActionName,
    feature: str | None = None,          # mission_id | mid8 | mission_slug (never mission_number)
    wp_id: str | None = None,
    agent: str | None = None,
    cwd: Path | None = None,
    env: Mapping[str, str] | None = None,
) -> ExecutionContext

Guarantees

  • CWD-invariant: identical result regardless of the caller's working directory (gated by the parity ratchet).
  • Topology-aware: feature_dir/read_dir/write_dir resolved via mission topology, never raw-constructed.
  • Mode-correct target_branch (FR-012); refuses to resolve mainline as a write target without explicit operator authorization (C-001).
  • Raises ActionContextError on unresolvable context — no silent fallback.

Forbidden for consumers

  • Importing relocated internals (mission_runtime.resolution, mission_runtime.context) directly — enforced by tests/architectural/test_mission_runtime_surface.py (FR-005).
  • Constructing main_repo_root / "kitty-specs" / mission_slug independently (FR-009).

Migration contract (Stage C)

  • The façade delegates to today's resolver during migration; behavior is preserved (NFR-001).
  • core/execution_context.py is a thin re-export shim during migration, removed when unreferenced (FR-003).
  • Stage B (commit-owning operation service / CommitTarget) is out of scope (C-008) and not part of this contract.

parity_ratchet.md

Contract — full-sequence e2e parity ratchet

Extends tests/architectural/test_execution_context_parity.py from the status read+write slice to the full command sequence across all execution modes.

Sequence under test

next → implement → move-task → review → status

Modes (fixtures)

1. repository-root-checkout CWD — sequence driven from the repository root. 2. lane-worktree CWD — sequence driven from .worktrees/<mission>-<mid8>-lane-a/. 3. direct-to-target — mission run with no worktree, target branch used directly.

Assertions

For each adjacent pair of modes, the following must be identical:

  • resolved WP identity (from resolve_action_context)
  • lane transitions emitted (event identity / ordering)
  • agent tasks status --json output

Plus:

  • Mode-correct branch: direct-to-target resolves the declared target branch; a resolved mainline write without explicit authorization is refused (C-001, FR-012).

Negative control (non-vacuity — FR-022)

A deliberately reverted surface that re-derives context independently MUST make the ratchet fail. Mirror the existing test_ratchet_catches_divergence / test_write_ratchet_catches_divergence injection proofs for the full sequence.

Docstring (FR-023)

The module docstring states the actual coverage (full sequence × 3 modes). It must not imply coverage the test lacks.

CI gate (FR-024)

Required for PRs touching: mission_runtime/, src/specify_cli/status/, src/runtime/next/, src/specify_cli/cli/commands/agent/.

status_boundary.md

Contract — repo-wide status/ import boundary

Extends tests/architectural/test_status_module_boundary.py from the 6 WP03 packages to all of src/specify_cli.

Rule

No module under src/specify_cli/ outside src/specify_cli/status/ may import a status.* submodule directly. Only from specify_cli.status import <symbol> (the facade) or MissionStatus usage is permitted.

DISALLOWED:  from specify_cli.status.emit import build_status_event
             from specify_cli.status.lane_reader import get_wp_lane
             import specify_cli.status.reducer as _reducer
ALLOWED:     from specify_cli.status import build_status_event, MissionStatus

Exemptions (documented plumbing — C-004)

  • src/specify_cli/coordination/status_transition.py
  • src/specify_cli/coordination/transaction.py
  • src/specify_cli/workspace/context.py

These are internal Mission-Management plumbing and legitimately reach status/ internals; the test must identify and exempt them (not "fix" them). workspace/context.py is a permanent import-time cycle breaker: status/__init__ imports status.emit, which imports workspace context before the status facade has finished initializing.

Pass condition

  • grep -rn "from specify_cli\.status\.\|import specify_cli\.status\." src/ --include=*.py | grep -v "src/specify_cli/status/" returns only the exempted lines (target: 0 non-exempt).
  • The AST-scan + pytestarch rule is green over all of src/specify_cli.
  • A synthetic injected violation is caught (non-vacuous), mirroring the existing SR-3 injection proof.
  • Scan completes ≤15 s (NFR-005).

Symbol disposition (set during IC-05; see occurrence_map.yaml)

Each promoted symbol is added to status/__init__.py __all__ (C-007 charter convention); each demoted symbol gets a _ prefix and loses external import sites.