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_dirresolved 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
ActionContextErroron unresolvable context — no silent fallback.
Forbidden for consumers
- Importing relocated internals (
mission_runtime.resolution,mission_runtime.context) directly — enforced bytests/architectural/test_mission_runtime_surface.py(FR-005). - Constructing
main_repo_root / "kitty-specs" / mission_slugindependently (FR-009).
Migration contract (Stage C)
- The façade delegates to today's resolver during migration; behavior is preserved (NFR-001).
core/execution_context.pyis 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 --jsonoutput
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.pysrc/specify_cli/coordination/transaction.pysrc/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.