Contracts
resolution-and-enforcement.md
Contracts — Mission-Type Doctrine Authority
Internal (in-process) contracts, not network APIs. Each is a behavioural contract a test asserts. Signatures are indicative; the WPs finalize them against live code.
C1 — resolve_mission_type_context (the seam)
resolve_mission_type_context(repo_root, *, mission_type=None, feature_dir=None) -> ResolvedMissionType
Behaviour
- Resolves the type key: explicit
mission_type→feature_dir/meta.json→ error. - *Unknown typed mission* (type present, unrecognised, no resolvable override) → raises a clear, remediable error (
UnknownMissionTypeError-class). Never returns software-dev. (FR-003) - Typeless / no
feature_dirand nomission_type→ neutral/degrade result, never software-dev. (FR-003a) - Known type, empty grain for a step → empty resolved set for that step, no error. (FR-004)
- Governance slot = type-grain ∪ action-grain, ordered, URN-deconflicted; double-declaration across grains → error. (FR-013, NFR-007)
- Preserves the two distinct hard-fail policies (action-sequence strict; governance tolerant when a project override exists) as explicit branches.
- Complexity ≤ 15 via extracted helpers.
Consumers converge: prompt_builder (Surface B) and the action-doctrine path both call this; no second resolution path remains.
C2 — Action-doctrine path (leak closure)
build_charter_context(...)andbuild_charter_context_json(...)accept the mission type (threaded fromscope_router/feature_dir);_load_action_doctrine_bundlekeys off it, nevertemplate_set or "software-dev-default".- Per-entry contract: prompt path has
feature_dir; planning-from-root requires explicit--mission-type; mission-less callers (executor.py,workflow.py) degrade neutrally. - Dead
_render_action_scoped/_append_action_doctrine_linesremoved. template_setretained only for template-file selection.
C3 — Per-type override overlay
- Project profile at
.kittify/doctrine/mission_types/<type>/governance-profile.yamlresolves throughdoctrine/base.py: builtin → org → project, field-merge, collision warning. - A project override of a field wins; absent fields fall through; a collision is reported (not silent).
C4 — Dossier gate reader (detachable swap)
ManifestRegistry.load_manifest(type)reads the doctrine tree viarepository.get_expected_artifactsthrough aConfigResult → ExpectedArtifactManifestadapter (cache preserved).- Ordering contract: reconcile doctrine upward → transitional parity green → flip → delete copies. Never delete before parity is green. Non-blocking for enforcement; final flip deferrable on deep drift (deferral recorded, not silent).
C5 — Enforcement (enduring, behavioural)
- Non-leakage: for each of documentation/research/plan, the resolved (type ⊕ action) URN set is disjoint from a curated, URN-normalized software-dev-only denylist.
- Non-vacuity twin: the same denylist is resolved by
software-dev, exercised through an action name shared across types (so it cannot pass vacuously). - Determinism: two resolutions of identical inputs are byte-identical.
- Hard-error: unknown typed mission errors on every governance path; typeless caller degrades.
- All enduring tests are doctrine-module or integration; no transitional parity scaffold survives merge; no code kept solely to avoid test churn.