Data Model — CI Pipeline Reinstatement (Phase 1)
The "entities" of a CI mission are its config contracts, not runtime records. Each below has a schema, invariants, and (where relevant) a lifecycle.
E1 — Workflow disposition (governance verdict map)
docs/convergence/interim-ci-producer.md row + test_release_ci_ownership.py set.
- Fields:
path(workflow file),disposition∈ {restore,defer,never-restore,introduced},rationale. - Invariant: the enforcer asserts an exact set per disposition; every
.github/workflows/*file maps to exactly one; net-new files useintroduced; retired files staynever-restore/absent. - Lifecycle:
defer → restore(de-defer) or∅ → introduced(net-new), always in the same change as the workflow edit (C-001 lockstep).
E2 — Coverage/xunit artefact (naming contract)
- Fields: coverage file
coverage-<tier>-<module>.xml(dotted--cov=<module>,relative_files=true); artifactname: <job>-reports,path: out/reports/; xunitxunit-result-<shard>-<run_id>.xml. - Invariant: basename unique per shard (dedup is by basename); artifact name ends
-reports(glob*-reports). Producer→consumer: shards →diff-cover(PR gate) +sonar.yml(nightly).
E3 — Dead-code census (P1 machine oracle)
- Fields:
surface(path/symbol),status∈ {dead,live},evidence(importer count / ADR / retirement gate ref),authorizes(drop | denominator-exclude). - Invariants: (a) a base-red may be dropped ONLY if the census marks its subject
dead; (b) a census-deadsurface is excluded from the coverage denominator; (c) the census itself is non-vacuous — a planted dead-code-shard / retired-import is flagged, proven by a self-mutation negative test; (d) census-dead≠ enforcement-allowlist target (those stay always-on).
E4 — Allowlist-vs-shape-guard membership (P2)
- Fields:
test_id,class∈ {enforcement-allowlist,shape-guard,behavioral}. - Invariant: committed, machine-checkable; a test's class cannot be silently relabeled to move it on/off the blocking gate.
enforcement-allowlist→ always-on blocking;shape-guard→ off the blocking gate (advisory/derived-from-source).
E5 — Filter-group → job routing model (two-authority)
- Fields:
group(name),globs[],jobs[]gated byneeds.changes.outputs.<group>. - Invariants: two hand-authorities only (dorny block, job
if:); every derived surface asserted against them;src/**unmatched →run-all;docs/corpusare non-src (excluded from unmatched loop); a collection-completeness oracle (non-vacuous, reads real YAML) fails if any test is zero-gated.
E6 — Run mode
- Values:
pr(fail-fast, short-circuit, no perf/e2e) |full(nightly + manual "run full": run-all,if: always(), incl. perf/e2e/interpreter). - Invariant: in
pr, a successor skipped by short-circuit is NOT merge-eligible-green; infull, job count is 100% regardless of failures.
E7 — Shard boundary registry
- Fields:
group → {roots, shard_count, marker_prefix, units}; boundaries derived from a recorded--durationsrun (run-id captured) on the post-scrub live basis. - Invariant: skew ≤20%; balanced on measured duration, not file count; re-derived against live
src/**after the retirement scrub (never before).
E8 — Warmup env artefact
- Fields: cache key = hash(
uv.lock+ resolvedspec_kitty_eventsrev); PR→pinned rev, nightly→latest mainline. - Invariant: deterministic per (lockfile, rev); one build reused by all downstream shards.