Implementation Plan: Modular per-package CI + automated asset/prompt regeneration

Branch: mission/modular-per-package-ci | Date: 2026-08-15 | Spec: spec.md Input: Feature specification from kitty-specs/modular-per-package-ci-01M025GV/spec.md Research: research.md (Phase 0 — both load-bearing decisions settled)

Summary

Extract kernel, doctrine, and packs into self-contained reusable workflows (on: workflow_call) invoked as ordered uses: jobs inside ci-quality.yml (decision D1(a)), so each module has its own build boundary while coverage still aggregates in one run and Sonar stays a single scan. In parallel, add a standalone spec-kitty regen [--check] that regenerates the 168 committed generated fixtures (144 command baselines + 24 skill snapshots) from source templates, wire it into trust-tiered CI (same-repo auto-commit / fork check-only / regen-label PAT-push), narrow the byte-grid gates to structural invariants + one canonical snapshot, and re-home the completeness baselines to the module partition. Approach and evidence are settled in research.md.

Technical Context

Language/Version: Python 3.11+ (CLI); GitHub Actions YAML (CI). Primary Dependencies: typer, existing render surfaces (render_command_template, command_renderer); GitHub Actions workflow_call / pull_request_target. Storage: Filesystem fixtures under tests/specify_cli/; committed workflow YAML under .github/workflows/. Testing: pytest (targeted module packages per WP); GitHub Actions dry-runs via PRs; ruff + mypy --strict. Target Platform: GitHub-hosted CI runners (Linux). Project Type: single (CLI + CI infra). Performance Goals: ci-quality wall-clock within ~5% of baseline (NFR-002); reusable workflows run same-run. Constraints*: preserve coverage-.xml / <slug>-reports names (C-004); quality-gate stays the pinned required check (C-005); no wheel-publish gate (C-002); Sonar scope unchanged (C-007); no red merge-blocking gate (C-001). Scale/Scope: 3 module workflows + 1 new CLI command + 1 CI automation workflow + gate narrowing + baseline re-homing. ~5–6 work packages.

Charter Check

GATE: passed at plan time; re-check after design.

on spec-kitty doctrine regenerate-graph --check; lift existing CI job bodies verbatim. ✅ no improvisation.

aggregation assertion, check-only exit-code test) RED on base, GREEN on final commit. ✅ captured per-WP.

ships disabled until NFR-003 sign-off. ✅

gate. ✅

uses: jobs; coverage-name preservation asserted by construction. ✅

before pushing prose/doctrine. ✅

  • Canonical sources (DIRECTIVE_044): reuse render_command_template / command_renderer; model regen
  • ATDD-first (C-011): every implementation WP lands a failing-first test (regen fidelity test, coverage
  • Red-main / no red gate (ADR 2026-07-17-1): new gates land green or non-blocking; the PAT-push workflow
  • Shared Package Boundary (ADR 2026-04-25-1): per-package pyproject.tomls stay dormant; no wheel-publish
  • Architectural gate discipline (DIRECTIVE_043): CI-model guards updated non-vacuously to understand
  • Terminology canon: Mission (not Feature); guard with tests/architectural/test_no_legacy_terminology.py

Project Structure

Documentation (this mission)

kitty-specs/modular-per-package-ci-01M025GV/
├── plan.md              # This file
├── research.md          # Phase 0 (decisions settled)
├── data-model.md        # Entity sketch
├── research/            # evidence-log.csv, source-register.csv
├── spec.md              # Mission spec
└── tasks/               # Phase 2 (WP files) — created by /spec-kitty.tasks

Source Code (repository root)

.github/workflows/
├── ci-quality.yml           # MODIFY: replace kernel/doctrine/packs job bodies with `uses:` callers
├── module-kernel.yml        # NEW: on: workflow_call — lifted kernel-tests steps
├── module-doctrine.yml      # NEW: on: workflow_call — doctrine fast + integration legs
├── module-packs.yml         # NEW: on: workflow_call — lifted fast-tests-corpus
└── regen-assets.yml         # NEW: trust-tiered regen automation

src/specify_cli/
├── cli/commands/regen.py    # NEW: `spec-kitty regen [--check] [--json]`
├── cli/commands/__init__.py # MODIFY: register regen alongside materialize
├── template/asset_generator.py     # REUSE: render_command_template()
└── skills/command_renderer.py      # REUSE: render().to_skill_md()
                                    # + NEW shared version-pin constants module

tests/
├── specify_cli/regression/         # twelve-agent gate + baselines (narrow + re-home)
├── specify_cli/skills/             # command_renderer gate + snapshots (narrow + re-home)
├── architectural/                  # CI-model guards (update for uses: jobs) + marker/collection oracles
└── specify_cli/cli/commands/       # NEW: test_regen.py

Structure Decision: single-project layout; CI infra under .github/workflows/, CLI under src/specify_cli/, tests mirror source. No new top-level packages (per-package pyprojects stay dormant).

Complexity Tracking

ViolationWhy NeededSimpler Alternative Rejected Because
New privileged PAT secret (NFR-003)Operator chose label→PAT-push fork UX for best contributor DevExCheck-only-only rejected by operator; PAT is the only way to write to a fork branch from CI
First workflow_call files in repoD1(a) requires reusable workflows; none exist yetworkflow_run (b) fragments Sonar single-run context — rejected in research

Implementation Concern Map

> Concerns are architectural areas, not WPs. /spec-kitty.tasks translates these into executable WPs.

IC-01 — Kernel reusable-workflow POC + coverage-aggregation proof

coverage still aggregates in one run and reaches diff-coverage + the nightly Sonar scan.

uses: caller), the coverage-name preservation assertion.

may assume inline steps: — may need a small guard update even for the POC.

  • Purpose: Prove D1(a) end-to-end on the smallest package: kernel steps run inside a workflow_call file,
  • Relevant requirements: FR-001, FR-002; NFR-001, NFR-002; C-004, C-005.
  • Affected surfaces: .github/workflows/module-kernel.yml (new), ci-quality.yml (kernel-tests job →
  • Sequencing/depends-on: none (first slice).
  • Risks: required-check pinning (verify quality-gate is the pinned check); architectural CI-model guards

IC-02 — Standalone regen tool + shared version pins

to a PYTEST_UPDATE_SNAPSHOTS=1 run, with a followable check-mode failure.

version-pin constants module, reuses asset_generator.render_command_template + command_renderer.render.

proven by a fidelity test comparing regen output to a pytest-update run.

  • Purpose: A single spec-kitty regen [--check] that regenerates the 168 fixtures from source, byte-identical
  • Relevant requirements: FR-003, FR-004, FR-005; NFR-004, NFR-005; C-006.
  • Affected surfaces: src/specify_cli/cli/commands/regen.py (new), __init__.py (register), new shared
  • Sequencing/depends-on: none (independent of the workflow split — can proceed in parallel with IC-01).
  • Risks: version-pin asymmetry (3.1.2a3 vs 3.0.0) — must be reproduced exactly via the shared constants,

IC-03 — Doctrine + packs reusable workflows + CI-model guard updates

update the architectural guards that parse the job graph so they tolerate uses: caller jobs.

guards (test_ci_collection_completeness, test_ci_quality_path_filters, _gate_coverage, test_coverage_root_collisions, test_release_ci_ownership).

non-vacuous.

  • Purpose: Generalize the proven POC to doctrine (fast + integration legs) and packs (corpus group), and
  • Relevant requirements: FR-006, FR-007, FR-008; NFR-001; C-004.
  • Affected surfaces: module-doctrine.yml, module-packs.yml (new); ci-quality.yml; the five CI-model
  • Sequencing/depends-on: IC-01 (mechanism validated).
  • Risks: doctrine's two legs + any future sharding must keep coverage names unique; guard updates must stay

IC-04 — Trust-tiered regen CI automation

regen-label PAT-push into the fork branch.

PAT-push path disabled until the NFR-003 sign-off is recorded.

  • Purpose: Keep fixtures fresh automatically per trust tier: same-repo/dispatch auto-commit, fork check-only,
  • Relevant requirements: FR-009, FR-010, FR-011; NFR-003; C-003.
  • Affected surfaces: .github/workflows/regen-assets.yml (new), modeled on all-contributors-normalize.yml.
  • Sequencing/depends-on: IC-02 (the tool must exist).
  • Risks: security — pull_request_target trusted-tooling pattern mandatory; PAT least-privilege; ship the

IC-05 — Narrow the drift gates

one-line source edit stops fanning out to ~14 fixture failures.

strong enough that a genuinely wrong render still fails.

  • Purpose: Replace the 144+24 byte grid with structural invariants + one canonical snapshot per suite, so a
  • Relevant requirements: FR-012; SC-005.
  • Affected surfaces: test_twelve_agent_parity.py, test_command_renderer.py (+ their fixtures).
  • Sequencing/depends-on: IC-02 (regen proven equivalent first, so narrowing can't hide a real regression).
  • Risks: narrowing must not lose real drift-detection coverage — keep the canonical snapshot + invariants

IC-06 — Re-home completeness baselines to the module partition

split; ensure every relocated test resolves to exactly one CI home.

_arch_shard_map.py / _next_shard_map.py, marker/collection completeness oracles.

or two homes reds; verify each relocation resolves to exactly one gate.

  • Purpose: Relocate golden-count ceilings, CI path filters, and marker/shard maps to match the module-owned
  • Relevant requirements: FR-013.
  • Affected surfaces: golden-count assertions, ci-quality.yml path filters, tests/_shard_registry.py /
  • Sequencing/depends-on: IC-03 + IC-05 (partition + gate shape final).
  • Risks: the double-marker CI-home trap (test_marker_job_completeness.py) — a relocated test with no home