Skip to content

ci: train CI keeps finding the same mechanical defects — check them before a train, not in it #18499

Open
0 of 1 issue completed

Description

@mrveiss

Problem. Every merge train on 2026-10-12 went red in CI on the same classes of defect, each repaired by hand in the train afterwards. A full CI run was spent to discover something checkable for a fraction of the cost. Approved PRs reach a train without these checks having passed on their own head, and the per-PR runs that do start (autofix-types, SAST, code-quality, verify-generated-types-slm) are almost always cancelled, so their result never exists.

Observed in this session (trains 6, 6b, 7 and 7b):

Class Instances
Reach floors drift re-pinned every train: 3 / 6 / 5 / 10 floors. The local population differs from CI's (audio-extension-allowlist: about 6400 local vs 6070 CI), so a locally measured pin can fail CI.
Stale generated api.ts 6b (since description), 7 (#18373), 7b (#18372). A route docstring, parameter or header changed without regeneration.
Line-keyed records go stale the Redis-path exemption (backup.py 524→497), the global-channel baseline (1089→1096), the docstring baseline (file moved), the slm_rest_url expected call text, the no-print count.
Stale baseline rows hardcoded-values baseline: 6b (3 rows + 1 count), 7 (the audit_logger.py row).

Acceptance criteria

  • Types on demand: auto-fix-generated-types.yml can be run by workflow_dispatch on a branch, so a train fetches its api.ts patch with one job before opening its PR. Done in the PR that closes the sub-issue below.
  • Floors pinned from CI: a re-pin uses CI's measured population (CI prints the suggested mid-window value, and the merger applies it), never a local count that CI does not share.
  • Records not keyed by line: line-keyed guard records (exemptions and baselines) are keyed by symbol or content instead, so moving code elsewhere in a file can't stale them.
  • Per-PR fast lane: the cheap checks (generated types, --audit-baseline, Semgrep ERROR, the reach floors) produce a non-cancelled result on each approved head before it can board a train. The merger reads that result at queue time.

Merger-side mitigation already in place: a local pre-push gate runs drift guards and floors, Semgrep, and the baseline audit on every train before push.

Activity

  1. mrveiss commented on Oct 12, 2026

    @mrveiss
    OwnerAuthor

    Fifth class (added after train 7b)

    • Hand-rolled module stubs go stale. autobot-backend/llc/tests/conftest.py:608 builds api.codebase_analytics.source_storage as a bare types.ModuleType with two hand-set names. fix(codebase-analytics): honest scan outcomes, duplication detectors wired, and forks shown from the one CI detector (#18013, #18067, #17982) #18362 added get_source_or_none_if_unreadable to the real module and called it from llc/api/sprints.py, so every llc test running through the stub failed to import, but only once both PRs met in train 7b. Build such stubs from the real module (create_autospec of the real module, or a stub that raises on a missing attribute and is checked against dir(real)), and add a guard that fails when a sys.modules stub lacks a public name its real module defines.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions