Skip to content

Fleet CI harmonization: which jobs belong everywhere, which are product-specific, which are drift #20

Description

@krisarmstrong

Summary

A survey of the four product repos' CI, done while shipping the design-system rollout on 2026-08-18. The governance layer is already uniform. The job layer is not, and some of the divergence is accidental rather than product-driven.

The goal of this issue is to name which jobs should exist everywhere, which are legitimately product-specific, and which are simply drift — so a future session can converge the first group and stop treating the third as intentional.

Already uniform — no action

Verified byte-identical or equal across seed, stem, niac-go and trellis:

  • pull_request_template.md — identical in all four.
  • pr-body-lint.yml — identical. Same required headings, same Fixes|Closes|Resolves|Related to #N rule, same "Testing Evidence needs a fenced block or an explicit not-run reason", same bot exemption.
  • PR title lint — present in all four.
  • Required status checks — CI Complete, Lint PR Title, Lint PR Body in all four.
  • Merge queue — enabled in all four.
  • release-please.yml — same workflow_run-gated-on-CI-success wiring in all four.
  • Shared building blocks from this repo — apt-install, semgrep.yml, and the ci-conformance check that keeps them honest.

So the PR and issue process is one process with four instances. Nothing to harmonize there.

The job matrix

present · absent · bold = the gap worth closing

Job seed stem niac-go trellis Verdict
Changed paths should be everywhere — it is what lets a docs-only PR skip cleanly
Backend (Go) universal, done
Backend (race detector) should be everywhere
Frontend universal, done
Quality Checks universal, done
Semgrep SAST universal, done
CI Conformance universal, done
Security Scanning should be everywhere
govulncheck in Security in Security in Security standalone harmonize the shape, not the coverage
Workflow Lint should be everywhere
Documentation Quality should be everywhere
Build Verification should be everywhere
Build UI (shared artifact) an optimization — niac-go rebuilds the UI per job for no reason
i18n Validation correct: trellis deliberately ships no i18n (see #54)
E2E Browser Tests trellis has none at all — trellis#57
E2E Smoke (separate fast job) worth adopting: it is the job that gives a fast signal before the sharded suite
Storybook interactions + a11y n/a stem has 39 stories and niac-go has 19 that no CI ever renders
C Lint (C23) seed has zero .c/.h files — this job lints nothing
Dataplane Safety (ASAN + fuzz) correct: stem owns the C dataplane (40 C sources)
Darwin compile check correct: stem's CGO/darwin path is real

Should be everywhere — accidental gaps

trellis is missing seven jobs the other three run: Changed paths, race detector, Security Scanning, Workflow Lint, Documentation Quality, Build Verification, and E2E. None of these absences is a product decision; trellis is simply younger. Its ci.yml is 7 jobs against seed's 18.

This is not cosmetic. trellis was the only repo that passed the design rollout without a single CI failure — not because its changes were safer, but because almost nothing was checking.

Genuinely product-specific — leave alone

  • Dataplane Safety (ASAN + fuzz) and Darwin compile check — stem only. stem is the only repo with a C dataplane and a CGO/darwin build path. Correct as-is.
  • i18n Validation absent from trellis — deliberate, recorded in #54: trellis ships no i18n subsystem, and standing one up for a single page fails the feature-scope gate. Revisit when trellis gains locales, not before.

Drift to correct

  • seed runs C Lint (C23) with zero C sources. find . -name '*.c' -o -name '*.h' returns nothing in seed. The job either lints an empty set or is a copy from stem. Delete it, or state what it is meant to cover.
  • Storybook CI is seed-only, but stem and niac-go have stories. 39 and 19 respectively, none of them rendered by CI. Either run the job in all three or delete the stories — untested stories rot silently, and the fleet has already been bitten by that class of thing.
  • Build UI (shared artifact) is missing in niac-go, so its jobs rebuild the frontend independently. Pure waste.
  • govulncheck is standalone in trellis, folded into Security Scanning elsewhere. Same coverage, different shape; converge for readability.

Related defects already filed

These came out of the same survey and are tracked separately:

  • Playwright browser install has no retry, flakes exit 100 — seed#1950, stem#661, niac-go#1341
  • A flaky CI run on main silently skips release-please — stem#662 (all four share the wiring)
  • PRs leave the merge queue after successful merge_group runs — stem#664
  • E2E locators match accessible names by substring — stem#663, niac-go#1344
  • trellis has no Playwright coverage — trellis#57

One correction, so nobody chases it

There was a suspicion that stem failed to merge because of a permissions/rights difference between repos. That is not what happened, and it is worth recording plainly:

gh pr merge --admin on stem#660 was refused by the agent's own tool-permission policy, which blocks bypassing branch protection. It was not a GitHub rights error, and the repo's settings were never the obstacle — the PR merged normally once re-enqueued through the merge queue.

There is no evidence of any rights asymmetry between the four repos. The real merge-queue oddity is stem#664.

Suggested order

  1. Bring trellis up to the fleet baseline (the seven missing jobs), largest gap and lowest risk.
  2. Delete or justify seed's C Lint.
  3. Decide Storybook: run it in stem and niac-go, or remove the stories.
  4. Add Build UI (shared artifact) to niac-go and converge trellis's govulncheck shape.
  5. Consider promoting seed's split E2E Smoke job to the others — a fast signal before the sharded suite is worth having everywhere.

Steps 2–5 are small. Step 1 is the one that changes the fleet's actual risk profile.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions