Implementation Plan: Charter Activation Catalog Coherence

Branch: issue-4785-charter-catalog-coherence | Date: 2026-09-19 | Spec: spec.md Input: Feature specification from kitty-specs/charter-catalog-coherence-01M2XQQF/spec.md

Summary

Close four charter-activation tooling gaps (issue #4785) so activating a built-in directive keeps the derived catalog.references coherent, worktree-safe, and complete by construction. The unifying insight: catalog.references has exactly ONE compiler authority — compile_charter / write_compiled_charter in src/charter/activation/compiler.py — and charter activate is the one activation surface that never calls it. The fix is disciplined routing through that single authority (never a second/minimal writer), plus a worktree-safety boundary that reuses the kernel git_topology probe, a corrected fresh-project gate, corrected remediation guidance, and a loader-parity fix so recompiled summaries are complete and deterministic.

Technical Context

Language/Version: Python 3.11+ Primary Dependencies: typer, rich, ruamel.yaml (existing) — no new dependency added or upgraded (supply-chain review N/A this mission) Storage: YAML charter store — .kittify/charter/charter.yaml (derived catalog.references + authored sections) Testing: pytest — tests/charter/, tests/doctrine/, tests/specify_cli/cli/commands/charter/, tests/specify_cli/charter_runtime/ Target Platform: Cross-platform CLI (Linux / macOS / Windows 10+) Project Type: single (CLI + library) Performance Goals: recompile-on-activate within the CLI budget; the measured end-to-end recompile time is recorded (target < 2 s) — NFR-001 Constraints: single catalog authority (C-001); do NOT change shared find_repo_root/get_main_repo_root (C-002); reuse kernel git_topology, no 4th root-resolution authority (C-003); reject minimal-writer design (C-004); authored sections + charter.md byte-identical (NFR-002); deterministic catalog ordering (NFR-005) Scale/Scope: ~254 catalog.references entries; 37 directives across built-in + project/org DRG layers; 5 charter write commands (activate/deactivate/generate/synthesize/resynthesize)

Charter Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

every catalog write through the one compile_charter/write_compiled_charter authority and explicitly forbids a second/minimal writer (C-001/C-004). It also deletes the dead parallel _build_references_from_yaml.

rather than adding a fourth root-resolution seam; the worktree policy lives at the charter command boundary, leaving the shared find_repo_root untouched (respects module seams).

@pytest.mark.regression repro that is RED through the pre-existing entry point before the fix (NFR-004); transitional repros become focused unit tests after.

next to (domain-matched, behavior-preserving).

is a bug-fix mission touching no __init__.py public surface version.

  • Single canonical authority (Governing Principle; DIRECTIVE_044). ✅ The plan routes
  • Architectural alignment (DIRECTIVE_001). ✅ Reuses the kernel git_topology probe
  • ATDD-first / red-first (C-011, DIRECTIVE_041/034). ✅ Each WP lands an issue-pinned
  • Campsite cleaning (DIRECTIVE_025). ✅ WP04 removes the dead reference-builder it sits
  • Terminology canon (Mission not Feature). ✅ No user-facing feature* identifiers added.
  • No version numbers in scope (DIRECTIVE_045). ✅ No pyproject.toml version bump; this

No violations. Complexity Tracking table not required.

Project Structure

Documentation (this mission)

kitty-specs/charter-catalog-coherence-01M2XQQF/
├── plan.md              # This file
├── research.md          # Phase 0 output (grounding-squad synthesis + decisions)
├── data-model.md        # Phase 1 output (charter store entities + derived/authored boundary)
├── quickstart.md        # Phase 1 output (how to reproduce + verify each finding)
├── contracts/           # Phase 1 output (behavior contracts per finding)
├── tracer-*.md          # Mission tracer files (tooling-friction / approach / design-decisions)
└── tasks.md             # Phase 2 output (/spec-kitty.tasks — NOT created here)

Source Code (repository root)

src/charter/activation/
├── compiler.py                 # SOLE catalog authority: compile_charter / write_compiled_charter
│                               #   _build_references_from_service / _render_kind_references
│                               #   (WP04: loader-parity + determinism; delete dead _build_references_from_yaml)
├── consistency_check.py        # coherence guard producing reference_id_divergences + suggestion string (WP01)
├── pack_manager.py             # activate()/deactivate() config-only writes (called by CLI)
└── charter_yaml_io.py          # single charter.yaml section writer (leave intact)

src/specify_cli/cli/commands/charter/
├── activate.py                 # activate_cmd + run_full_synthesize + RESYNTHESIZE_HELP (WP01, WP02)
├── deactivate.py               # deactivate_cmd (WP01, WP02)
├── generate.py                 # find_repo_root call site + _is_inside_git_worktree (WP02)
├── synthesize.py               # fresh-project short-circuit predicate (WP03); find_repo_root call site (WP02)
├── _synthesis.py               # _has_generated_artifacts signal (WP03)
├── resynthesize.py             # find_repo_root call site (WP02)
└── _charter_write_root.py      # NEW shared worktree-safe root resolver via kernel/git_topology (WP02)

src/kernel/
└── git_topology.py             # canonical git probe (REUSE; not modified)

tests/
├── charter/                    # test_compiler*, test_consistency_check (WP01, WP04)
├── doctrine/                   # test_activation_parity_guard (WP01)
├── specify_cli/cli/commands/charter/  # activate/synthesize/resynthesize CLI tests (WP01, WP02, WP03)
└── specify_cli/charter_runtime/       # test_references_parity_refresh, test_boundary_heal (WP01, WP04)

Structure Decision: Single-project layout. Changes are confined to the charter activation library (src/charter/activation/) and the charter CLI command surface (src/specify_cli/cli/commands/charter/), plus a new small worktree-safe root helper that delegates to the existing kernel git_topology. No new top-level modules or packages.

Parallel Work Analysis

Dependency Graph

WP04 (compiler: completeness + determinism + campsite)   ── foundation ──┐
                                                                          ▼
WP01 (activate/deactivate recompile-by-default + remediation strings)  ← depends on WP04
                                                                          │  (activate's DEFAULT recompile must be
                                                                          │   complete + stable, or it re-introduces
                                                                          │   placeholders / churn)
WP03 (synthesize fresh-project gate)  ── independent, small ──
WP02 (worktree-safe charter-write boundary)  ── independent, cross-cutting ──

placeholders) and diff-stable, which WP01's recompile-by-default depends on.

  • WP04 is the foundation and lands first: it makes a full recompile complete (no silent
  • WP01 depends on WP04 (semantic dependency, not merely file overlap).
  • WP02 and WP03 are independent of the catalog-content work; they can proceed in parallel.

Lane / write-scope expectation

Lanes collapse by owned-file overlap (finalize-tasks). Expected:

implemented sequentially (WP01 → WP03 → WP02 order within the lane is fine).

before implementing WP01's default recompile, merge the WP04 lane branch into the CLI lane (dependent-lane reconciliation). This will be validated against lanes_preview at finalize-tasks --validate-only.

  • WP04 owns compiler.py (disjoint) → its own lane.
  • WP01 / WP02 / WP03 overlap on activate.py / synthesize.py → likely one shared lane,
  • Because WP01 (CLI lane) depends on WP04 (compiler lane), the compiler lane merges first;

Implementation Concern Map

WPFindingConcernOwned filesRed-first repro (RED before fix)
WP04F4b + F4a + campsiteRecompiled catalog resolves real summaries for every directive in the authoritative bundled enumeration; genuine misses → diagnostics not silent placeholders; deterministic entry order; delete dead _build_references_from_yamlsrc/charter/activation/compiler.pyactivating/compiling a store leaves ≥1 directive as Definition unavailable though it has a bundled definition; a second recompile reorders/churns the catalog.references section
WP01F1 + F2-stringsactivate/deactivate recompile the catalog by default via compile_charter(from_interview=False); --no-compile opt-out; coherence-guard suggestion + RESYNTHESIZE_HELP name generate, never synthesizesrc/specify_cli/cli/commands/charter/activate.py, deactivate.py, src/charter/activation/consistency_check.pycharter activate <built-in directive> reds test_this_project_charter_pack_is_coherent; the guard suggestion string names synthesize
WP03F2-coresynthesize classifies an established store (compiled catalog present) as non-fresh; no fresh-project short-circuit that skips real worksrc/specify_cli/cli/commands/charter/synthesize.py, _synthesis.pycharter synthesize on a store with charter.yaml but no generated/ prints "fresh project" and short-circuits
WP02F3Every charter write command fails closed (non-zero + "use a repository-root checkout or dedicated clone") when invoked from a linked worktree; retire the chdir hack + split-brain; reuse kernel git_topologyNEW src/specify_cli/cli/commands/charter/_charter_write_root.py, generate.py, synthesize.py, resynthesize.py, activate.pya charter write command run from a linked worktree modifies the PRIMARY checkout's .kittify/charter/

Complexity Tracking

No Charter Check violations — table intentionally empty.

Phase 0 / Phase 1 Outputs

design decisions, adversarial-evidence dispositions).

contracts/ (one behavior contract per finding), quickstart.md (repro + verify).

  • Phase 0 → research.md (grounding-squad synthesis, the four root causes, the settled
  • Phase 1 → data-model.md (charter store entities + derived/authored boundary),

Branch Contract (restated)

  • Current branch at plan start: issue-4785-charter-catalog-coherence
  • Planning/base branch: issue-4785-charter-catalog-coherence
  • Final merge target for completed changes: main (via a non-draft PR; the operator merges)
  • branch_matches_target: true (planning base = current branch)