Implementation Plan — Charter UX & Org-Pack Vocabulary

Branch: mainmain (planning/base = merge target) Date: 2026-05-23 Mission slug: charter-ux-and-org-pack-vocabulary-01KSAF14 Mission ID: 01KSAF14K8FZ56MHYT45EGWHHC Spec: spec.md Research brief: research/mission-brief.md Linked issues: #1099, #1100, #1101, #1104, #1291 (parent epic #1111)

Summary

Bundle epic #1111 Slice A (charter freshness UX) and Slice F (pack-authoring vocabulary) into a single mission with a cross-cutting shipped → built-in rename. The work splits along the same two code surfaces (charter CLI + doctrine schema/validator pipeline), so a single mission with carefully sequenced waves avoids the merge conflicts that would arise from parallel missions.

Technical approach: 1. Instrument charter status/lint/synthesize with explicit graph-state and freshness reporting (Wave 1). 2. Add a new charter preflight command and a callable session-start hook (Wave 2). 3. Add overrides and enhances as first-class declarative fields across five doctrine artifact kinds; extend the Relation enum; reconcile the pack-validator advisory wording with the field-merge ADR (Wave 3). 4. Cutover vocabulary shipped → built-in across code, tests, JSON, docs (Wave 4 — last, because it touches the broadest surface).

Technical Context

Language/Version: Python 3.11+ (existing spec-kitty toolchain) Primary Dependencies: typer (CLI), ruamel.yaml (YAML), pydantic (schema models), rich (console rendering); existing doctrine.drg and charter.synthesizer packages Storage: Filesystem only — kitty-specs/<mission>/, .kittify/charter/, .kittify/doctrine/graph.yaml, src/doctrine//built-in/.yaml Testing: pytest (unit + integration + architectural); existing test patterns under tests/specify_cli/charter_lint/, tests/specify_cli/doctrine/, tests/integration/test_charter_, tests/architectural/ Target Platform: Linux/macOS/Windows 10+ (DIR-001 cross-platform) Project Type: single (Python CLI tool with library packages); follows existing src/ layout Performance Goals: Charter preflight <300 ms warm / <1.0 s cold (NFR-001); lint/status response unchanged for repos with existing DRG Constraints: mypy --strict passes; ruff check passes; no regression in existing test suite (NFR-003); no fixture YAML must fail to load after the new overrides/enhances fields land (NFR-004); ASCII-only identifiers (DIR-010 / DIR-011); HiC must be assigned to each linked GitHub issue when a WP for that issue begins implementing (DIR-012) Scale/Scope: ~63 Python files touch shipped vocabulary; ~459 source-line occurrences; ~90 test files; ~48 docs/YAML files. 8 issues closed by this mission (5 primary + 3 derived from epic body)

Charter Check

The project charter .kittify/charter/charter.md is present, SYNCED, and synthesized. Action-scoped context for plan was loaded via spec-kitty charter context --action plan --json. Relevant gates applied to this plan:

Charter ruleCompliance plan
DIR-001 Cross-platform (Linux/macOS/Windows)All new code is pure Python; no shell-specific dependencies. Preflight command uses pathlib and subprocess portably.
DIR-005 / DIR-006 / DIR-007 Tests, types, docstringsEvery new function lands with pytest coverage, mypy-strict annotations, docstrings for public APIs.
DIR-008 No security issuesNo credential/secret handling in new code; preflight does not touch git remotes.
DIR-009 Breaking changes documentedFR-017 requires a CHANGELOG entry for the shipped → built-in JSON rename.
DIR-010 / DIR-011 ASCII identifier safetyNew URN strings for Relation.ENHANCES, Relation.OVERRIDES are ASCII-only.
DIR-012 HiC issue assignmentFirst WP for each linked issue assigns the GitHub issue to the HiC before implementation begins.
DIR-013 Pre-existing failure reportingIf implementation surfaces pre-existing pytest failures, open a GitHub issue per the directive before proceeding.
ADR 2026-05-16-1-doctrine-layer-merge-semantics.mdField-merge behaviour is locked (Constraint C-001). New fields are declarative only; they do not change merge code paths.
__all__ convention (binding C-007)New public symbols added to package __init__.py exports.
ATDD-First (binding C-011)Tests for FR-001..FR-017 written before or alongside production code (matched by WP structure).

Charter-Check verdict: PASS. No violations require justification; the Complexity Tracking table at the end of this plan is empty.

Project Structure

Documentation (this mission)

kitty-specs/charter-ux-and-org-pack-vocabulary-01KSAF14/
├── spec.md                  # /spec-kitty.specify output (committed)
├── plan.md                  # this file (/spec-kitty.plan output)
├── research.md              # Phase 0 — consolidated decisions
├── data-model.md            # Phase 1 — new model fields & freshness state object
├── quickstart.md            # Phase 1 — operator-facing smoke flow
├── contracts/
│   ├── charter-status-json.md       # JSON contract for `charter status --json`
│   ├── charter-lint-json.md         # JSON contract for `charter lint --json`
│   ├── charter-preflight-json.md    # JSON contract for new `charter preflight`
│   └── pack-validator-advisory.md   # Validator wording / suppression rules
├── occurrence_map.yaml      # bulk-edit gate (shipped → built-in)
├── research/
│   └── mission-brief.md     # Researcher Robbie pre-research (already committed)
├── checklists/
│   └── requirements.md      # Spec quality checklist
├── tasks/                   # /spec-kitty.tasks output (not yet)
└── meta.json                # mission identity (change_mode: bulk_edit)

Source code (repository root)

The mission touches these existing trees and adds a new charter_preflight package:

src/
├── charter/
│   ├── drg.py                       # Wave 3 — `_warn_project_override` vocabulary; new `enhances`/`overrides` edge handling
│   ├── synthesizer/
│   │   └── project_drg.py           # Wave 1 — synthesize bootstrap post-condition (FR-009)
│   └── … (other charter modules unchanged)
├── doctrine/
│   ├── schemas/
│   │   ├── tactic.schema.yaml       # Wave 3 — add `overrides` / `enhances`
│   │   ├── styleguide.schema.yaml   #     ditto
│   │   ├── paradigm.schema.yaml     #     ditto
│   │   ├── procedure.schema.yaml    #     ditto
│   │   └── agent-profile.schema.yaml #    ditto
│   ├── tactics/models.py            # Wave 3 — Pydantic model fields + cross-field validator
│   ├── styleguides/models.py        #     ditto
│   ├── paradigms/models.py          #     ditto
│   ├── procedures/models.py         #     ditto
│   ├── agent_profiles/profile.py    #     ditto
│   ├── drg/
│   │   ├── models.py                # Wave 3 — extend `Relation` enum
│   │   └── org_pack_loader.py       # Wave 3 — auto-emit ENHANCES / OVERRIDES edges
│   └── base.py                      # Wave 4 — rename `shipped` identifiers / comments
└── specify_cli/
    ├── charter_lint/
    │   ├── _drg.py                  # Wave 1 — built-in fallback loader
    │   ├── engine.py                # Wave 1 — `DecayReport.graph_state` field
    │   └── findings.py              # Wave 1 — extend DecayReport schema
    ├── charter_preflight/           # NEW package (Wave 2)
    │   ├── __init__.py
    │   ├── runner.py                # `run_charter_preflight(...)`
    │   ├── result.py                # `CharterPreflightResult` dataclass
    │   └── cli.py                   # `spec-kitty charter preflight` command surface
    ├── cli/commands/
    │   ├── charter.py               # Wave 1 + 2 — wire preflight, freshness, graph-state
    │   └── profiles_cmd.py          # Wave 4 — rename "shipped" → "built-in" in JSON
    └── doctrine/
        └── pack_validator.py        # Wave 3 — branch advisory on enhances/overrides

tests/
├── specify_cli/charter_lint/
│   └── test_engine.py               # FR-001..FR-004 coverage
├── specify_cli/doctrine/
│   └── test_pack_validator.py       # FR-013 coverage
├── specify_cli/charter_preflight/   # NEW
│   ├── test_runner.py               # FR-006..FR-008 coverage
│   └── test_cli.py
├── integration/
│   ├── test_charter_lint_lints_all_layers.py   # extend for FR-002
│   ├── test_charter_status_reports_three_layers.py # extend for FR-005
│   └── test_charter_synthesize_fresh.py        # extend for FR-009
└── architectural/
    └── test_no_shipped_layer_label.py # NEW — FR-016 surface scan

architecture/3.x/adr/
├── 2026-05-DD-1-charter-freshness-ux-contract.md         # Wave 1+2 ADR
├── 2026-05-DD-2-pack-augmentation-vocabulary.md          # Wave 3 ADR
└── 2026-05-DD-3-shipped-to-built-in-cutover.md           # Wave 4 ADR (follow-up to 2026-05-16-1)

Structure decision: Single-project layout. New charter_preflight package follows the existing pattern of charter_lint (sibling package with engine.py / result.py / cli.py triad). Vocabulary rename touches existing modules in place; no new top-level packages introduced for the rename.

Phase 0 — Research findings

See research.md for the full version. Summary of decisions:

DecisionChoiceRationale
Field nameenhances (not augments)Matches canonical text in issue #1291; consistent with future-glossary entry.
Relation enum policyAdd ENHANCES = "enhances" and OVERRIDES = "overrides" as new values; keep REPLACES = "replaces" for backward compatibilityZero migration cost for existing DRG fragments; explicit alias on OVERRIDES is unnecessary because the new declarative field is what drives auto-emit.
Vocabulary cutover styleStraight cutover with CHANGELOG breaking-change notePre-3.2.0 stable; deprecation window adds maintenance overhead without consumer benefit.
Preflight invocation scopeManual spec-kitty charter preflight command + opt-in hook from next, implement, dashboard launchAvoids overhead on every CLI invocation while still catching the launch-blocker scenarios.
Bulk-edit gate formatStandard occurrence_map.yaml with all 8 categoriesThe skill is binding for change_mode: bulk_edit.

Phase 1 — Design outputs

See:

  • data-model.md for new model fields, freshness state shape, and DRG enum extension.
  • contracts/charter-status-json.md, contracts/charter-lint-json.md, contracts/charter-preflight-json.md, contracts/pack-validator-advisory.md.
  • quickstart.md for the operator-facing smoke flow.
  • occurrence_map.yaml for the shipped → built-in rename classification.

Implementation waves (dependency-ordered)

These waves map to dependency clusters in the work-package graph. Tasks within a wave can be parallelised; waves themselves are sequential because of shared file ownership.

Wave 1 — Charter freshness instrumentation (FR-001..FR-005, FR-009)

Shared file: src/specify_cli/cli/commands/charter.py, src/specify_cli/charter_lint/. Outputs: DecayReport.graph_state, built_in_only synthesizer marker, status freshness payload.

Wave 2 — Preflight (FR-006..FR-008)

Adds new src/specify_cli/charter_preflight/ package; consumes Wave 1 freshness payload. Wires hooks into next/implement/dashboard entry points.

Wave 3 — Pack-authoring vocabulary (FR-010..FR-014)

Schema additions across 5 artifact kinds; Pydantic model changes + cross-field validator; Relation enum extension; pack validator advisory branch logic; DRG auto-emit. Shares the doctrine package — no overlap with Wave 1/2 file set, so can begin in parallel with Wave 2 once Wave 1 lands.

Wave 4 — Vocabulary cutover (FR-015..FR-017)

Last wave because it touches the broadest file set. Driven by occurrence_map.yaml from Phase 1. Includes the architectural regression test FR-016 and the CHANGELOG entry FR-017. Sequencing after Wave 3 ensures the validator advisory text changes from Wave 3 land in the new vocabulary.

Cross-cutting (every wave)

ConcernBindingConcrete WP placement
ADR 2026-05-DD-1-charter-freshness-ux-contract.mdDIR-003First WP of Wave 1. Outline: problem (#1099/#1100/#1101/#1104), decision (introduce graph_state enum + freshness payload + preflight surface), alternatives (eager auto-refresh on every command), consequences (NFR-001 budget).
ADR 2026-05-DD-2-pack-augmentation-vocabulary.mdDIR-003First WP of Wave 3. Outline: problem (issue #1291 + extra="forbid" block), decision (declarative overrides/enhances + mutually-exclusive validator + DRG auto-emit), alternatives (drop extra="forbid"; magic precedence), consequences (cross-references 2026-05-16-1-doctrine-layer-merge-semantics.md).
ADR 2026-05-DD-3-shipped-to-built-in-cutover.mdDIR-003, DIR-009First WP of Wave 4. Outline: problem (vocabulary asymmetry between disk and code/JSON), decision (straight cutover with CHANGELOG entry), alternatives (deprecation window), consequences (external tooling impact). Treated as a follow-up to 2026-05-16-1-..., not a fresh design.
Glossary entries for enhances / overridesDIR-032Wave 3 first WP — add canonical-term entries to .kittify/glossaries/spec_kitty_core.yaml (or the doctrine-pack-vocabulary scope file if one exists). Lists augments as a synonym to-avoid for enhances; lists replaces as a synonym to-avoid for overrides.
HiC issue assignmentDIR-012First WP of any wave that touches one of #1099, #1100, #1101, #1104, #1291. The WP description MUST include a step that runs gh issue edit <#> --add-assignee @<HiC> before implementation begins.
Pre-existing test failure baselineDIR-013Wave 1 first WP — run pytest tests/ once at HEAD, capture the failure list, and open a GitHub issue per DIR-013 IF the baseline is non-zero. The issue link MUST be recorded in the WP's notes; subsequent WPs may then treat that baseline as accepted.
Bulk-edit gateC-002Wave 4 — every commit must trace to an occurrence_map.yaml row; meta.json already declares change_mode: bulk_edit.
Architectural test FR-016 scopeFR-016Wave 4 final WP — tests/architectural/test_no_shipped_layer_label.py MUST scan the JSON output of: (a) spec-kitty charter status --json, (b) spec-kitty charter lint --json, (c) spec-kitty charter preflight --json, (d) spec-kitty agent profile list --json, (e) spec-kitty doctrine pack validate --json on a fixture pack. For each, assert no "shipped" string appears as a JSON value. Excluded surfaces (preserved-historical per occurrence_map): CHANGELOG.md, architecture/3.x/adr/ files predating this mission, frozen kitty-specs//spec.md files.

Complexity Tracking

No charter violations require justification. The Complexity Tracking table is intentionally empty.

ViolationWhy NeededSimpler Alternative Rejected Because

Branch contract (final restatement)

This mission lands on main. There is no intermediate integration branch.

Next step

Run /spec-kitty.tasks to decompose this plan into work packages.

⚠️ DO NOT proceed to tasks generation inside this command. The user invokes /spec-kitty.tasks separately.