Work Packages: Charter offering, activation presets and the doctrine-to-charter cutover

Inputs: kitty-specs/charter-pack-cutover-01M491G6/ — spec.md, plan.md, research.md, data-model.md, contracts/, quickstart.md, occurrence_map.yaml

Tests: required. C-006: WP01 writes every FR's acceptance test first as strict xfail naming the WP that turns it green; each later WP's first commit removes its own xfail markers (red), and the WP ends green (charter ATDD-first, C-011).

Organization: subtasks (Txxx) roll up into work packages (WPxx). Subtask rows are reference rows; record completion with spec-kitty agent tasks mark-status <Txxx> --status done.

Per-WP test policy (CLAUDE.md, NO_FULL_HEAVY_SUITES_IN_MISSION): make test-fast, the WP's own and touched-module tests, the owning subsystem directories (tests/charter/ and tests/doctrine/ whenever src/charter/offering/** changes), the acceptance tests the WP flips, and the specific architectural gate files it implicates. Never bare tests/architectural/ or make test-full. ruff check, ruff format --check --force-exclude <files>, mypy on touched sources, and pytest tests/architectural/test_no_legacy_terminology.py before every push.

Edits outside owned files: a WP may edit a file owned by another WP only when the two cannot run in parallel lanes, i.e. one is a (transitive) dependency of the other. Record each such file with a one-line rationale under "Mechanical edits outside owned_files" in the Activity Log. Never edit a file owned by a WP that can run in a parallel lane. Ownership guards parallel lanes; sequential follow-up edits are expected.

Generated files have no owner (no WP lists them in owned_files): packs/built-in/pack-manifest.yaml, src/specify_cli/_completion_manifest.json, docs/api/cli-commands.md, docs/development/docs-retrieval-index.yaml, regen fixtures and similar outputs are regenerated with their tool (spec-kitty charter pack regenerate-graph / spec-kitty doctrine regenerate-graph before WP15, the completion and docs generators) by whichever WP changes their inputs, and committed. Never hand-merge them; on a conflict, regenerate.

Version: no WP bumps pyproject.toml's version (unreleased rc; changelog entries go under Unreleased). The cutover migration targets the current version, 4.0.0rc6 (m_4_0_0rc6_charter_pack_cutover.py). The CLAUDE.md "__init__.py change needs a version bump" rule is satisfied by the WP24 changelog entry.

Subtask Index

IDDescriptionWPParallel
T001Acceptance suite scaffold: package, CLI/fixture helpers, pending_until(wp) strict-xfail helperWP01
T002Legacy fixture-project builders (NFR-001 list)WP01[P]
T003Golden "before" generator, run at base, frozen JSON + base SHAWP01
T004Preset acceptance tests (FR-001..FR-004, FR-019, US1, SC-001)WP01[P]
T005Upgrade acceptance tests (FR-012, NFR-001, NFR-004, US2, SC-002)WP01[P]
T006CLI-surface acceptance tests (FR-005..FR-007, FR-011, US3, SC-004)WP01[P]
T007Promotion acceptance tests (FR-015, US5)WP01[P]
T008Rename/skills/glossary acceptance tests (FR-008..FR-010, FR-013, FR-014, US4)WP01[P]
T009Gate, latency and messaging acceptance tests (FR-016..FR-018, NFR-002, NFR-003, SC-003, SC-005)WP01[P]
T010Traceability test: every spec id covered; every pending_until names a real WPWP01
T011kernel/charter_pack_paths.py replaces kernel/doctrine_root.pyWP02
T012Move _layer_roots to charter.activation.layer_roots; project root = pack rootWP02
T013Repoint READ sites in kernel, charter, runtimeWP02[P]
T014Repoint READ sites in specify_cliWP02[P]
T015Tests for the kernel module and moved layer rootsWP02
T016Repoint synthesizer WRITE sitesWP03
T017Repoint project registration, seeding, scaffold and applier WRITE sitesWP03[P]
T018State contract entry, repo .gitignore rules, ci-router.yml path filterWP03[P]
T019FR-016 path-authority gate with planted self-testsWP03
T020charter synthesize writes to the new root (CLI test) and flip WP01 FR-016 xfailsWP03
T021Prep: hash helpers and org_extends to offering; absorb_synthesis_manifest to activationWP04
T022Prep: OrgCharterPolicy steps behind hooks; pure manifest writer out of snapshotWP04
T023Move pack model/tooling to charter.offering.packsWP04
T024charter.packs facade; charter.drg exports; repoint specify_cli importersWP04
T025Move tests mirroring the moved modules; run gatesWP04
T026Move org charter composition to charter.activation (fold config.py)WP05
T027Move adapters to specify_cli.charter_packsWP05[P]
T028Delete specify_cli/doctrine/; boundary exemption deleted; census/roster/pyproject updatesWP05
T029Move tests; flip WP01 FR-010 package xfailsWP05
T030Public effective-set seam charter.activation.effective_setWP06
T031Fail-closed promotion in promote_activationsWP06
T032Repoint the four callers; interview stops importing a migration moduleWP06
T033Delete merge_defaults / _load_default_packWP06
T034Unit tests; flip FR-015 xfailsWP06
T035Preset JSON schema (kinds derived from ArtifactKind)WP07
T036Preset model + discovery across built-in, org chain, fetched packsWP07
T037Built-in presets/default.yaml and minimal.yaml (fixed kind gate)WP07
T038Validator: presets in charter pack validate / charter org validate; manifest hashes presetsWP07
T039charter org init scaffolds an example presetWP07[P]
T040Tests; regenerate pack manifest; flip FR-002/FR-019 xfailsWP07
T041Preset application engine (replace semantics, org union, diff, atomic write)WP08
T042charter activate --pack/--preset wiring and flag rulesWP08
T043charter pack list (packs + presets, project row) and charter pack path <pack>WP08[P]
T044Error codes PRESET_NOT_FOUND, PACK_NOT_FOUND, PRESET_ID_UNRESOLVED, PRESET_WOULD_OVERWRITEWP08
T045Tests incl. NFR-003 timing; flip FR-001/FR-004 xfailsWP08
T046Mission-type provisioning reads the default preset (init, charter generate, upgrade)WP09
T047DefaultPresetMissingError / DEFAULT_PRESET_MISSING replaces DefaultCharterPackMissingErrorWP09
T048Repoint remaining default.yaml readers from the research inventoryWP09
T049Tests with the positive control; flip FR-003 xfailsWP09
T050runs_first on BaseMigration, applied in get_applicableWP10
T051Neutralise rc35, normalizer and glossary-context skill migrationsWP10
T052Remove module-level imports of to-be-deleted modules from older migrationsWP10[P]
T053m_3_1_1_charter_rename and finalize migration fixesWP10[P]
T054Tests: ordering, chain integrity, neutralised migrations recorded as skippedWP10
T055Cutover migration skeleton: detect(), shared legacy predicate, result/summary plumbingWP11
T056Config-key rewrites (org packs incl. single-pack and organisation_packs, governance, tracker, answers)WP11
T057doctrine_pack_id → charter_pack_id in project activation entriesWP11[P]
T058Project-root move with collision preflight; path-reference rewrites; .gitignoreWP11
T059Run the migration on this repository (.kittify/doctrine/ → .kittify/charter-packs/)WP11
T060Tests per inventory row; flip FR-012 xfails for these rowsWP11
T061Frozen snapshot data module from research/default-yaml-snapshots.yamlWP12
T062Stale-list, kind-gate and [] resets with per-key report linesWP12
T063Installed-skill removal (manifested and hash-matched; edited copies kept)WP12
T064Upgrade summary rendering; dry-run parityWP12
T065NFR-001 / NFR-004 / pre-rc35 green; flip remaining FR-012 xfailsWP12
T066Delete charter_pack_registry, src/charter/activation/packs/, default_packWP13
T067Delete charter pack applyWP13
T068Retire accompanies_doctrine_pack; RETIRED_PACK_FIELD rejectionWP13
T069Tests; flip FR-005 xfailsWP13
T070Remove legacy key/path fallbacks and compat warningsWP14
T071Tracker CR-03 removal (doctrine key, --doctrine-mode, doctrine_mode)WP14[P]
T072CLI-root LEGACY_CHARTER_STATE gateWP14
T073load_governance_config fails closed on legacy keysWP14
T074Delete shim tests; flip FR-011 xfailsWP14
T075Move shared handlers out of doctrine.py into charter/WP15
T076charter pack validate/assemble/regenerate-graph/asset homesWP15
T077charter consistency-check; doctor charter-packsWP15
T078In-repo callers: packs.yml, Makefile, generated_by, AGENTS.md, packs/internal, remediation stringsWP15
T079Tests; regenerate completion manifest and pack manifest; flip FR-006 xfailsWP15
T080Delete the doctrine group and its command modulesWP16
T081Rewrite the #4836 guidance gate as a removed-command gateWP16
T082Delete group tests; flip FR-007 xfailsWP16
T083ActiveCharterManager, ActiveCharterConfigErrorWP17
T084ACTIVE_CHARTER_CONFIG_INVALID; golden; ERROR_CODES.mdWP17
T085charter_pack_id in models, schemas, org-charter schema_version bump, validator messageWP17
T086ToolSurfaceKind.CHARTER_SKILLWP17[P]
T087Tests; flip FR-009 xfailsWP17
T088Skill renames and folds (seven spk-*, five folded)WP18
T089RETIRED_CANONICAL_SKILL_NAMES; skill manifests; references in prompts/skillsWP18
T090Regenerate derived files (docs/api/skills/*, regen fixtures, completion manifest)WP18
T091Tests; flip FR-008 xfailsWP18
T092R1 rename: offering, facades, kernel identifiersWP19
T093R1 tests followWP19
T094R1 docstrings/prose (tier sense only)WP19
T095R2 rename: activation identifiers (DoctrineService homonym resolved)WP20
T096R2 module renames (_doctrine_paths, doctrine_service_builder, action_doctrine_bundle)WP20
T097R2 tests and docstringsWP20
T098R3 rename: specify_cli command modules and neighboursWP21
T099R4 rename: migrations bodies (ids kept), synthesizer applier, doctrine_service_factory, gatesWP21
T100R3/R4 tests and pyproject entriesWP21
T101Built-in pack prose (tier sense; content sense kept)WP22
T102Living docs prose and charter-pack-usage-journeyWP22[P]
T103AGENTS.md / CLAUDE.md and packs/internal proseWP22[P]
T104Regenerate pack manifests and CLI referenceWP22
T105tests/doctrine/ → tests/charter_offering/; references in CLAUDE.md, pyproject, CIWP23
T106Residual test identifiersWP23
T107Glossary terms, retirements and "active" guard; ADR 2026-08-22-2 citationsWP24
T108Changelog Unreleased Before/AfterWP24
T109Runbook docs/migrations/charter-pack-cutover.md; historical bannersWP24
T110Flip FR-013/FR-017 xfailsWP24
T115Draft the public-packs sidecar PR (OD-2); the orchestrator opens it after mergeWP24[P]
T111FR-018 vocabulary gate (closed token and root lists, floor, planted tests)WP25
T112Reachability pins re-asserted or deleted with reasonsWP25
T113NFR-002 gate closeout (empty allowlists; shim tests deleted)WP25
T114Final traceability: zero pending_until markers remainWP25

Phase 0 — Acceptance first

Work Package WP01: Acceptance suite and golden "before" sets (Priority: P0)

Goal: every FR, measurable NFR and SC becomes a test before implementation (C-006); NFR-001's "before" sets are frozen while the pre-cutover code still reads legacy projects. Independent Test: the suite collects; every test that targets unbuilt behaviour is a strict xfail naming its WP; the traceability test passes. Prompt: tasks/WP01-acceptance-suite.md Requirement Refs: C-006, NFR-001, all FRs and SCs (as test owner) Estimated prompt size: ~650 lines

Included Subtasks

T001 Acceptance suite scaffold (WP01) T002 Legacy fixture-project builders (WP01) T003 Golden "before" generator and frozen sets (WP01) T004 Preset acceptance tests (WP01) T005 Upgrade acceptance tests (WP01) T006 CLI-surface acceptance tests (WP01) T007 Promotion acceptance tests (WP01) T008 Rename/skills/glossary acceptance tests (WP01) T009 Gate, latency and messaging acceptance tests (WP01) T010 Traceability test (WP01)

Dependencies

  • None (starting package).

Risks & Mitigations

  • A test that passes vacuously: every assertion has a positive control on the same fixture; strict xfail catches accidental passes.
  • Golden sets generated with post-cutover code: the generator records the base SHA and refuses to run once kernel/doctrine_root.py is gone.

Phase 1 — Foundations (paths, package split)

Work Package WP02: Kernel pack paths and read-side cutover (Priority: P1)

Goal: one kernel module names the project pack root and pack-relative paths; every reader resolves through it; layer-root resolution lives in charter. Independent Test: kernel/layer-root unit tests; touched readers' tests green; legacy read fallback still works (removed in WP14). Prompt: tasks/WP02-kernel-pack-paths-read-side.md Requirement Refs: FR-016, C-007 Estimated prompt size: ~400 lines

T011 kernel/charter_pack_paths.py (WP02) T012 charter.activation.layer_roots (WP02) T013 READ sites in kernel/charter/runtime (WP02) T014 READ sites in specify_cli (WP02) T015 Tests (WP02)

Dependencies: WP01.

Work Package WP03: Write-side cutover and path-authority gate (Priority: P1)

Goal: every writer targets .kittify/charter-packs/; the FR-016 gate forbids a "doctrine" segment joined to .kittify anywhere in src/. Independent Test: charter synthesize on a migrated fixture writes under .kittify/charter-packs/ and creates no .kittify/doctrine/; gate planted tests red. Prompt: tasks/WP03-write-side-cutover-and-path-gate.md Requirement Refs: FR-016 Estimated prompt size: ~400 lines

T016 Synthesizer writers (WP03) T017 Registration/seeding/scaffold/applier writers (WP03) T018 State contract, .gitignore, ci-router.yml (WP03) T019 FR-016 gate (WP03) T020 CLI synthesize test; flip xfails (WP03)

Dependencies: WP02.

Work Package WP04: Package split I — pack model and tooling to charter.offering.packs (Priority: P1)

Goal: prep moves that respect the offering→activation import ban, then the pack model/tooling move behind a new charter.packs facade. Independent Test: test_charter_offering_does_not_import_activation.py, boundary, census and layer-rule gates green; moved modules' tests green. Prompt: tasks/WP04-package-split-pack-tooling.md Requirement Refs: FR-010, C-007 Estimated prompt size: ~450 lines

T021–T025 (WP04)

Dependencies: WP02, WP03 (both edit synthesizer manifest, project registration and the doctrine command module).

Work Package WP05: Package split II — org charter, adapters, delete specify_cli.doctrine (Priority: P1)

Goal: finish OD-9; delete the old package and its boundary exemption (not moved). Independent Test: specify_cli.doctrine not importable; boundary/census/roster gates green with empty exemptions. Prompt: tasks/WP05-package-split-org-charter-adapters.md Requirement Refs: FR-010, C-007, NFR-002 Estimated prompt size: ~400 lines

T026–T029 (WP05)

Dependencies: WP04.


Phase 2 — Presets and promotion

Work Package WP06: Effective-set seam and fail-closed promotion (Priority: P1)

Goal: #4400 — promotion of an absent key seeds from the effective set and never narrows. Prompt: tasks/WP06-effective-set-seam.md Requirement Refs: FR-015, C-007 Estimated prompt size: ~400 lines

T030–T034 (WP06)

Dependencies: WP05, WP10, WP17 (WP10 neutralises the normalizer, whose [] writes would otherwise narrow the FR-015 upgrade row; WP17's ActiveCharterManager is used). WP06 deletes load_default_pack_activation_ids once its last caller is gone (test_no_dead_symbols); WP09 deletes the default_pack module.

Work Package WP07: Preset format, discovery and built-in presets (Priority: P1)

Goal: presets are pack data with a documented, validated schema, discovered from any pack. Prompt: tasks/WP07-preset-format-and-builtin-presets.md Requirement Refs: FR-002, FR-004, FR-019 Estimated prompt size: ~500 lines

T035–T040 (WP07)

Dependencies: WP05, WP06 (C-008: FR-015 before FR-002).

Work Package WP08: charter activate --preset and charter pack list/path (Priority: P1)

Goal: apply a preset with replace semantics; list packs and presets. Prompt: tasks/WP08-activate-preset-and-pack-list.md Requirement Refs: FR-001, FR-004, NFR-003, SC-001 Estimated prompt size: ~450 lines

T041–T045 (WP08)

Dependencies: WP06, WP07.

Work Package WP09: Provisioning reads the default preset (Priority: P1)

Goal: init, charter generate and upgrade provisioning read mission types from the built-in default preset; no other reader of default.yaml remains except the migration's frozen data. Prompt: tasks/WP09-provisioning-from-default-preset.md Requirement Refs: FR-003, FR-005 Estimated prompt size: ~300 lines

T046–T049 (WP09)

Dependencies: WP07, WP08 (the FR-003 init-vs-preset test drives charter activate --preset default), WP10 (WP10 edits WP09's test_init_provisioning.py).


Phase 3 — Upgrade migration

Work Package WP10: Migration framework — run-first ordering and neutralised migrations (Priority: P1)

Prompt: tasks/WP10-migration-framework.md Requirement Refs: FR-012, C-008 Estimated prompt size: ~350 lines

T050–T054 (WP10)

Dependencies: WP01.

Work Package WP11: Cutover migration I — keys, project root, path references (Priority: P1)

Prompt: tasks/WP11-cutover-migration-keys-and-paths.md Requirement Refs: FR-012, NFR-004 Estimated prompt size: ~550 lines

T055–T060 (WP11)

Dependencies: WP03, WP10, WP17 (the model reads charter_pack_id before the migration writes it). Removals and moves route through specify_cli.asset_preservation (destructive-op ownership gates).

Work Package WP12: Cutover migration II — stale lists, resets, skills, summary (Priority: P1)

Prompt: tasks/WP12-cutover-migration-resets-and-summary.md Requirement Refs: FR-012, NFR-001, NFR-004, SC-002 Estimated prompt size: ~500 lines

T061–T065 (WP12)

Dependencies: WP07, WP08 (its delete-capable activation writer), WP09 (WP09 edits WP12's upgrade.py), WP11.


Phase 4 — Removal (no aliases, no shims)

Work Package WP13: Retire the preset registry and the descriptor field (Priority: P1)

Prompt: tasks/WP13-retire-preset-registry.md Requirement Refs: FR-005, C-001 Estimated prompt size: ~300 lines

T066–T069 (WP13). T066 confirms default_pack is gone (deleted by WP06/WP09) and deletes the registry and src/charter/activation/packs/; T068 adds accompanies_doctrine_pack to WP17's retired_fields.py.

Dependencies: WP08, WP09, WP12.

Work Package WP14: Remove read-side shims; CLI-root legacy gate (Priority: P1)

Prompt: tasks/WP14-remove-shims-and-legacy-gate.md Requirement Refs: FR-011, C-001 Estimated prompt size: ~450 lines

T070–T074 (WP14)

Dependencies: WP12, WP13 (WP13 edits WP14's org_pack_config.py).

Work Package WP15: Charter homes for every doctrine command (Priority: P1)

Prompt: tasks/WP15-charter-command-homes.md Requirement Refs: FR-006, SC-004 Estimated prompt size: ~450 lines

T075–T079 (WP15)

Dependencies: WP05, WP08, WP13, WP14 (shared charter/pack.py and doctor tests).

Work Package WP16: Remove the spec-kitty doctrine group (Priority: P1)

Prompt: tasks/WP16-remove-doctrine-group.md Requirement Refs: FR-007, C-001 Estimated prompt size: ~250 lines

T080–T082 (WP16)

Dependencies: WP13, WP15.


Phase 5 — Names

Work Package WP17: Three meanings, three names; charter_pack_id (Priority: P2)

Prompt: tasks/WP17-three-names-and-charter-pack-id.md Requirement Refs: FR-009, FR-010 Estimated prompt size: ~400 lines

T083–T087 (WP17)

Dependencies: WP05. Runs after WP05 and before every WP that uses its names (WP06, WP11 and their descendants); it never waits for a later WP; creates src/charter/offering/packs/retired_fields.py (RETIRED_PACK_FIELD, doctrine_pack_id entry).

Work Package WP18: Skill families (Priority: P2)

Prompt: tasks/WP18-skill-families.md Requirement Refs: FR-008 Estimated prompt size: ~400 lines

T088–T091 (WP18)

Dependencies: WP12.

Work Package WP19: Identifier rename R1 — offering, facades, kernel (Priority: P2)

Prompt: tasks/WP19-rename-offering-facades-kernel.md Requirement Refs: FR-010 Estimated prompt size: ~300 lines

T092–T094 (WP19)

Dependencies: WP14, WP16, WP17, WP18 (WP19 edits skill prose WP18 owns).

Work Package WP20: Identifier rename R2 — activation (Priority: P2)

Prompt: tasks/WP20-rename-activation.md Requirement Refs: FR-010 Estimated prompt size: ~350 lines

T095–T097 (WP20)

Dependencies: WP19.

Work Package WP21: Identifier rename R3/R4 — specify_cli, migrations, gates (Priority: P2)

Prompt: tasks/WP21-rename-specify-cli-and-gates.md Requirement Refs: FR-010 Estimated prompt size: ~350 lines

T098–T100 (WP21)

Dependencies: WP16, WP20.

Work Package WP22: Prose in packs and living docs (Priority: P2)

Prompt: tasks/WP22-prose-packs-and-docs.md Requirement Refs: FR-010 Estimated prompt size: ~300 lines

T101–T104 (WP22)

Dependencies: WP18, WP21.

Work Package WP23: Rename tests/doctrine/ (Priority: P3)

Prompt: tasks/WP23-rename-tests-doctrine-directory.md Requirement Refs: FR-010 Estimated prompt size: ~200 lines

T105–T106 (WP23)

Dependencies: WP18, WP21, WP22 (AGENTS.md and tests WP18 edits).


Phase 6 — Messaging and closeout

Work Package WP24: Glossary, changelog and runbook (Priority: P2)

Prompt: tasks/WP24-glossary-changelog-runbook.md Requirement Refs: FR-013, FR-017, SC-005 Estimated prompt size: ~300 lines

T107–T110, T115 (WP24)

Dependencies: WP22.

Work Package WP25: Vocabulary gate, reachability pins, gate closeout (Priority: P1)

Prompt: tasks/WP25-vocabulary-gate-and-closeout.md Requirement Refs: FR-014, FR-018, NFR-002, SC-003 Estimated prompt size: ~350 lines

T111–T114 (WP25)

Dependencies: WP22, WP23, WP24.


Dependency graph

graph LR
  WP01 --> WP02 --> WP03 --> WP11
  WP02 --> WP04 --> WP05 --> WP17 --> WP06 --> WP07
  WP03 --> WP04
  WP05 --> WP15
  WP06 --> WP08
  WP07 --> WP08
  WP07 --> WP09
  WP01 --> WP10 --> WP11 --> WP12
  WP10 --> WP06
  WP10 --> WP09
  WP08 --> WP09
  WP07 --> WP12
  WP08 --> WP12
  WP09 --> WP12
  WP13 --> WP14
  WP18 --> WP19
  WP08 --> WP13
  WP09 --> WP13
  WP12 --> WP13
  WP12 --> WP14
  WP08 --> WP15
  WP13 --> WP16
  WP15 --> WP16
  WP17 --> WP11
  WP13 --> WP15
  WP14 --> WP15
  WP16 --> WP19
  WP18 --> WP23
  WP22 --> WP23
  WP12 --> WP18
  WP14 --> WP19
  WP17 --> WP19 --> WP20 --> WP21
  WP16 --> WP21
  WP18 --> WP22
  WP21 --> WP22 --> WP24 --> WP25
  WP21 --> WP23 --> WP25
  WP22 --> WP25

Parallel opportunities: WP10 runs beside WP02–WP05 and WP17; WP06/WP07/WP08/WP09 run beside WP11; WP18 runs beside WP13–WP16; WP23 runs beside WP24. MVP: WP01 (the suite is the contract every other WP is measured against).