Research index: charter-pack-cutover-01M491G6

Phase 0 output. Each decision links to the research file that holds its evidence (file:line) and rejected alternatives. No [NEEDS CLARIFICATION] remains; owner rulings are recorded in spec.md (OD-1..OD-10) and decisions/.

#TopicDecisionEvidence
R1Stale default.yaml listsFrozen per-key snapshots of every released default.yaml (174 releases scanned; 30 ship the file, 5 distinct contents) in original, post-rtk, post-rc5 and post-rtk+rc5 forms; per-key, order-insensitive, id-normalised equality (DIRECTIVE_NNN ↔ numbered stem, static map).research/default-yaml-snapshots.md, .yaml
R2Released minimal kind gateEvery released minimal.yaml sets activated_kinds: [directives, tactics]; removed by the migration and reported (DM-01M497F0NAQARAK3JZFVWF1SD0). No minimal list equals a default list for the same key, so reset and report classes never collide.same
R3Normalizer [] listsm_3_2_x_normalize_activation_absence wrote [] (nothing active) for absent keys from 3.2.6rc1, contradicting the live absent-means-all contract (pack_context.py:738, ArtifactKind.effective_when_absent). The migration is neutralised and the cutover resets [] per-artifact keys to absent with a report (DM-01M497EW60HNWWJQCXDFA99R0H).research/runtime-seams.md §1.5
R4Run-first orderingruns_first flag on BaseMigration, applied in MigrationRegistry.get_applicable; get_all() keeps version order (chain-integrity test). detect() is content-based. Rejected: sentinel low target version (never selected on newer projects), runner pre-phase (preview ≠ run).runtime-seams §1.3
R5Older migrationsrc35 → stub (detect() false, recorded skipped; precedent m_2_1_2_fix_charter_doctrine_skill); normalizer → stub; m_2_1_2_fix_glossary_context_skill → stub; module-level imports of deleted modules removed (rc35, m_unify_charter_activation); m_3_1_1_charter_rename stops recreating spec-kitty-charter-doctrine; finalize drops the compat-helper call.runtime-seams §1.4–1.5
R6WorktreesUpgrade skips lane/coord/mission worktrees (#5457, runner.py:81-112); .kittify/-only lane commits are exempt from approved_bound (reconciliation.py:1277), .gitignore/agent-dir changes are not. Runbook: merge the upgraded target into a lane, never rebase (APPROVAL_STAMP_NOT_ON_LANE).runtime-seams §2
R7Detection seamOne predicate next to check_schema_version in _run_startup_project_gates (specify_cli/__init__.py:165), shared with the migration's detect(); two stats plus a prefiltered config.yaml read (never charter.yaml, 155 KB here); exempt upgrade, init, --version, --help; checks the current checkout too (stale lane). load_governance_config fails closed on a legacy key (unknown keys are otherwise ignored → silent loss).runtime-seams §3
R8Doctrine group11 leaves; fetch/new/validate/org already share handlers; callers in packs.yml:225,229, builtin_manifest.py:48 (generated_by, regenerate), AGENTS.md (CLAUDE.md symlink), 9 files in packs/internal, completion manifest, ci-router.yml:233. doctor doctrine → doctor charter-packs, JSON keys kept.runtime-seams §4
R9Skill retirementRETIRED_CANONICAL_SKILL_NAMES retires user-global copies on every run (agent_skills.py:196-206); project roots via the upgrade finalizer's manifest; unmanifested copies removed by a hash-matched step in the cutover migration, edited copies kept and reported. Agent copies are git-ignored here; regenerate completion manifest, docs/api/skills/*, regen fixtures, pack manifest.runtime-seams §5
R10Error codesCHARTER_PACK_CONFIG_INVALID hard-coded once (charter/mission_type.py:143), golden mission_create_refusals.json:601; not in ERROR_CODES.md (FR-009 adds it under the new name).runtime-seams §6
R11Package splitRuled destinations work after prep moves: hash helpers and org_extends to offering, absorb_synthesis_manifest to activation, OrgCharterPolicy steps behind hooks, pure manifest writer out of snapshot; new charter.packs facade; charter.drg exports CORE_KIND_PLURALS, resolve_relative_path_within_root; _layer_roots → charter.activation.layer_roots (no blocker); config.py folded into org_charter. 7-step order, leaves first, atomic delete last.research/package-split-and-paths.md §A
R12Project pack pathskernel/charter_pack_paths.py replaces kernel/doctrine_root.py; layer_roots["project"] returns the pack root. 56 path sites in 50 files (12 write); state contract project_doctrine_graph; .gitignore:97-114. Gate modelled on test_charter_path_literal_authority.py plus f-string and alias-constant detection, per-shape planted tests. Staging subtree and org nested layout follow the flat project root; frozen migrations exempt by file.package-split-and-paths §B
R13Rename sizingsrc: 1,087 "doctrine" identifier tokens in 139 files (DoctrineService 181 lines in 42 files); tests: 2,618 tokens in 471 files; tests/doctrine/ 193 files. Split R1 offering/facades/kernel (~21), R2 activation (~42), R3 specify_cli surface (~45), R4 migrations/synthesizer/gates (~15); tests/doctrine/ directory last.package-split-and-paths §C
R14Post-spec squadArchitecture, testability and consumer findings folded into spec.md revision 1d82b937.research/postspec-squad-*.md

No dependency is added, upgraded or removed, so the supply-chain controls (DIRECTIVE_051) do not apply.