Contracts

charter-read-authority.md

Contract: Charter Read/Path Authority

Owning FRs: FR-001, FR-002, FR-003, FR-004, FR-006, FR-016 Landed by: WP01, WP02, WP03, WP04, WP11

The contract

There is exactly one door for a "does a charter exist / where is it" decision: charter/bundle.py's CHARTER_YAML / CHARTER_MD constants, read through charter/charter_yaml_io.load_charter_yaml.

schema-guarded resolution authority. Every authority-presence surface — dashboard (resolve_project_charter_presence), analysis-report staleness, retrospective policy resolution — keys on this file and survives charter.md deletion.

readable, free-form prose/rationale companion. It is never a resolving override. One legitimate exception class survives by design (C-003): the charter/context.py gate at if not charter_yaml_path.exists() and not charter_path.exists(): (line 270 as of this writing — non-authoritative, jump-to only, per this same mission's line-number convention in tests/architectural/charter_path_literal_allowlist.yaml), which renders prose if either file exists (an operator-facing "is there anything to show" gate, not an authority-presence check) — pinned, not retired, by WP01.

pre-consolidation charter.md-only shape, explicitly scoped and regression-pinned.

  • charter.yaml (.kittify/charter/charter.yaml) is the deterministic,
  • charter.md (.kittify/charter/charter.md) is a secondary,
  • One legitimate migration-compat exception (FR-006): _status_collectors.py's

Non-vacuous durability guard

tests/architectural/test_charter_path_literal_authority.py (WP11) AST-walks for inline .kittify/charter/charter.{yaml,md} path-literal construction outside charter/bundle.py, and for new charter.md-keyed .exists() presence gates. A frozen, shrink-only, per-site-justified allowlist (38 entries at mission close) captures the sanctioned residue — migration historical-determinism sites, the C-003 prose class, and the layering-forced src/doctrine/** sites that cannot import charter.bundle at all.

Evidence

  • tests/charter/test_context_prose_presence_pin.py (WP01)
  • tests/specify_cli/dashboard/test_charter_path_presence_probe.py (WP02)
  • tests/specify_cli/test_analysis_report_charter_yaml_staleness.py (WP03)
  • tests/specify_cli/cli/commands/charter/test_status_collectors_legacy_md_shape.py (WP04)
  • tests/architectural/test_charter_path_literal_authority.py + charter_path_literal_allowlist.yaml (WP11)

meta-json-fail-closed.md

Contract: meta.json Fail-Closed Authority

Owning FR: FR-007 Landed by: WP07, WP08, WP09 Tracker: #3140

The contract

A corrupt or non-dict meta.json always fails closed — a typed MissionMetaReadError (a RuntimeError subclass) or None, never a raw ValueError — through exactly one public reader: specify_cli.core.paths.load_meta_fail_closed.

home, no competing second authority. Its load_meta import stays function-local to avoid re-forming the core.paths ↔ mission_metadata import cycle.

(specify_cli/mission_metadata.py:275 feature_dir — note: NOT under core/, despite sitting next to the specify_cli.core.paths reference above — vs specify_cli/task_utils/support.py:599 meta_path) — every routed call site is disambiguated against the correct one.

are preserved untouched; only raise-default/unwrapped and divergent-wrapper callers route through the authority.

  • The reader promotes the pre-existing _load_meta_fail_closed in-place — one
  • Two distinct load_meta signatures exist in the tree
  • Deliberately-silent callers (load_meta_or_empty, on_malformed="none")

Non-vacuous durability guard

tests/specify_cli/test_meta_fail_closed_full_census_contract.py (WP09) independently AST-discovers every load_meta(-shaped call site in the tree (resolving import aliases, not a text grep) and cross-references it against a frozen, reasoned ledger of accounted-for sites. It fails if a new, unaccounted site appears, or if any accounted site regresses to a raw ValueError. This closed a real gap the original WP07 grep-count census missed (an aliased load_meta as _x import invisible to text grep).

Evidence

census (WP07)

(the two pre-existing reds this contract turns green)

  • notes/meta-load-census.md — the classified, grep-count-reconciled caller
  • tests/specify_cli/core/test_load_meta_fail_closed_authority.py (WP07)
  • tests/specify_cli/test_meta_fail_closed_batch_a.py (WP08)
  • tests/specify_cli/test_meta_fail_closed_full_census_contract.py (WP09)
  • tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed