Implementation Plan: CI router selects charter + dossier for mission-manifest edits
Branch: issue-6125-ci-router-charter-dossier-routing | Date: 2026-10-13 | Spec: spec.md Input: Mission specification from kitty-specs/ci-router-charter-dossier-routing-01M4SW1A/spec.md
Summary
Close the #6125 per-PR → red-main routing gap: an edit to a mission's packs/built-in/missions//expected-artifacts.yaml must select the charter and dossier test modules. Technical approach (grounded in research/code-grounding.md): add the file-specific glob packs/built-in/missions/*/expected-artifacts.yaml to the charter group and a newly-minted dossier module group, in all three verbatim-coupled authorities (scrub roots, registry roots, router filter) in lockstep; mint dossier as a real module with test_dirs [tests/dossier, tests/specify_cli/dossier], released from out_of_matrix_test_dirs; capture real measured shard timings. Pinned by an ATDD router-parity test proven RED on origin/main.
Technical Context
Language/Version: Python 3.11+ (test + CI-config change; no product code) Primary Dependencies: scripts/ci/gate_selection.py (routing authority), pyyaml, pytest Storage: N/A — the authorities are on-disk YAML/JSON (ci-router.yml, ci-module-registry.yml, ci_retirement_scrub.json, ci-shard-timings.json) Testing: pytest; the new gate lives beside the existing router/registry gates in tests/architectural/; make test-fast + the specific named CI gate files (never a tests/architectural/ sweep, per NO_FULL_HEAVY_SUITES_IN_MISSION) Target Platform: GitHub Actions CI (Linux runners) Project Type: single (CLI repo) Performance Goals: N/A (routing config); dossier shard_count chosen so no shard exceeds the per-shard timeout Constraints: router verbatim guard (C-001), file-specific glob only (C-002), no product code (C-003) Scale/Scope: ~5 files edited; one new registry row + one new scrub group + one new router filter group + one measured timings entry + one new test file
Charter Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
routing change; reviewer verifies RED on base, GREEN on final.
non-vacuous call-site gate (a self-break, e.g. dropping the glob, flips it red); it adds no allowlist, so no baseline entry is needed (ADR 2026-09-30-1).
in lockstep; no second path→group map.
- ATDD-first (C-011): PASS — FR-001 is a red-first parity test committed before the
- Architectural gate discipline (Standing Order #5): PASS — the parity test is a
- Single canonical authority (NFR-001): PASS — registry/scrub/router stay verbatim
- No new size/length ratchet (NFR-002): PASS — routing gate only (operator ruling).
- No product code (C-003): PASS — CI wiring + tests only.
- Terminology canon: PASS — no new user-facing surface; "Mission" vocabulary preserved.
No violations → Complexity Tracking left empty.
Project Structure
Documentation (this mission)
kitty-specs/ci-router-charter-dossier-routing-01M4SW1A/
├── spec.md
├── plan.md # this file
├── research/code-grounding.md # empirical grounding + guard map
├── tasks.md # Phase 2 (/spec-kitty.tasks)
├── tasks/ # WP files
├── tooling-friction.md # tracer
├── approach.md # tracer
└── design-decisions.md # tracer
Source Code (repository root)
.github/
├── ci-module-registry.yml # add `dossier` row; append manifest glob to `charter` roots; drop dossier dirs from out_of_matrix
├── workflows/ci-router.yml # add `dossier` filter group + output + unmatched-loop + heavy-battery gate; append manifest glob to `charter` filter
└── ci-shard-timings.json # measured `dossier` capture (via capture_shard_timings.py)
tests/
├── release/ci_retirement_scrub.json # add `dossier` group; append manifest glob to `charter` roots
└── architectural/test_manifest_edit_routes_charter_and_dossier.py # NEW red-first parity gate
Structure Decision: Single-project CLI repo. The change is confined to the CI routing authorities under .github/ + tests/release/ci_retirement_scrub.json, plus a new gate test under tests/architectural/ (co-located with the sibling router/registry gates test_gate_selection_authority.py, test_module_shard_registry.py, test_ci_router_transcription_guards.py). No src/** changes.
Complexity Tracking
No Charter Check violations — not applicable.
Implementation Concern Map
> Concerns are not work packages. /spec-kitty.tasks translates these into executable WPs.
IC-01 — Red-first router-parity gate
charter+dossier) with a non-vacuous ATDD gate, proven RED on base.
prove RED on origin/main to avoid a vacuous gate.
- Purpose: Pin the user-observable contract (a mission-manifest diff selects
- Relevant requirements: FR-001; SC-001.
- Affected surfaces:
tests/architectural/test_manifest_edit_routes_charter_and_dossier.py(new). - Sequencing/depends-on: none (lands first, RED).
- Risks: Must assert through the real authority
select_modules(not a hand map), and
IC-02 — Charter leg (route the manifest glob to the charter module)
file-specific glob to the charter group in all three verbatim authorities.
.github/ci-module-registry.yml (charter roots), .github/workflows/ci-router.yml (charter filter).
file-specific so the corpus golden (foo.md) stays green.
- Purpose: Make a manifest edit select the
chartermodule by adding the - Relevant requirements: FR-002; NFR-001, C-001, C-002.
- Affected surfaces:
tests/release/ci_retirement_scrub.json(charterroots), - Sequencing/depends-on: IC-01 (turns the gate's charter half green).
- Risks: Ordered-append in all three (verbatim guard is list-equality); keep the glob
IC-03 — Dossier module leg (mint the module + route it)
route both dossier-source and manifest edits to it, and capture measured timings.
.github/ci-module-registry.yml (new row + out_of_matrix_test_dirs removal), .github/workflows/ci-router.yml (new filter group + changes.outputs + unmatched loop + heavy-battery if:), .github/ci-shard-timings.json (measured capture).
must exist before capture_shard_timings.py --module dossier can measure it.
unmatched union + heavy-battery gate; shard-timings must be measured (committed == collected), never guessed.
- Purpose: Give
tests/dossier+tests/specify_cli/dossiera real per-PR module, - Relevant requirements: FR-003, FR-004, FR-005; NFR-001, NFR-003.
- Affected surfaces:
tests/release/ci_retirement_scrub.json(newdossiergroup), - Sequencing/depends-on: IC-01 (turns the gate's dossier half green); the registry row
- Risks: bijection + verbatim + claim-once guards; src-backed group must join the