Remote CI gates for an Angular monorepo: four minutes to release, fifteen to verify
The useful part
Separate fast feedback, browser verification and deployment checks. Decide explicitly which evidence is required before production promotion.
A useful test suite needs both meaningful assertions and feedback people can act on. When the full suite of an Angular monorepo needs an hour, developers stop running it, reviewers stop waiting for it and the suite becomes a nightly curiosity. This article describes the gates behind my own product: what runs where, how the full gate went from 31 to 15 minutes, and the rules that keep a shared CI agent honest. The product is GeoAtlas, a map portal with over 5,000 unit tests and 1,337 end-to-end tests in two Playwright suites; the design choices can be adapted to other Angular workspaces. These are historical observations recorded on 1 October 2026, not delivery targets for a client project. The case study distinguishes source test counts from executed suite totals.
Nothing heavy on the workstation
In this workspace, cheap unit checks may run locally; browser suites and visual acceptance run on a dedicated CI runner with a fixed toolchain. That is an operating choice, not a requirement of Playwright or Angular. Local browser tests can be useful for diagnosis. The shared runner gives this project a consistent environment and centrally stored reports.
The agent is a container with a fixed toolchain. Reports and traces for every run are published to an internal reports service, so a failure is a link, not a description.
Three gates with three purposes
The fast gate runs on every push to the main branch: lint, unit tests in jsdom and in a browser, coverage, build, and the release of the main branch to the server. About four minutes. It provides early feedback and, in this own-product setup, deploys main before the full browser suite finishes.
The full gate runs after a green fast gate: both Playwright suites, the catalog's 819 scenarios and the application's 518, with axe accessibility checks over recorded catalog states. About fifteen minutes. Its job is to catch what unit tests cannot: a demo added to a shared page that broke a neighbour's locator, a keyboard path that stopped working, a phone layout that lost a button.
The nightly run executes both suites against the deployment itself, not against a build, and first checks that the deployment serves the revision it expects. Under an hour. Its job is to notice that the server, the proxy, the data services or a certificate changed under the application.
This ordering is a deliberate risk trade-off: a later browser failure can occur after a release. For a client product that requires full verification before production, deploy to staging after the fast gate and promote the same artifact only after the full gate succeeds. Keep a rollback path in either design.
A release decision a product owner can inspect
| Evidence | Next action |
|---|---|
| Unit checks and build pass for a named SHA | Deploy that artifact to staging |
| Critical browser journeys pass on the same artifact | Approve promotion to production |
| Deployment serves a different SHA or a smoke check fails | Stop promotion or use the recorded rollback |
From 31 to 15 minutes
The full gate originally took 31 minutes because its stages ran one after another and the catalog suite ran on four workers. Two changes brought it to 15.
Stages that do not depend on each other run in parallel: lint and unit tests next to the production builds, then both Playwright suites side by side.
The catalog suite on six workers instead of four went from 1,055 to 760 seconds. The interesting part is not the number but what the extra workers exposed: tests that passed on four workers and failed on six were load-sensitive. The extra load exposed a wall-clock assertion and an interaction that read the map position before its animation finished. Each was fixed at the cause, a fake clock, animations disabled in the library under test, and re-measured twice. Raising timeouts or adding retries would have hidden the problem and kept the suite slow.
The second large saving was coverage. Collecting coverage for the application took 1,113 seconds; using coverage maps without embedded source content brought it to 187 in the recorded comparison. When two runs are merged (jsdom and browser mode), validate the branch denominator and clear stale output first. A faster run with incorrectly merged coverage is not a valid improvement.
Measure before restructuring
Separate page startup, test execution, accessibility scans and coverage processing before changing the architecture. Scanning a relevant demo region can reduce duplicate work on a long catalog page, but it also narrows coverage. Keep page-level checks for landmarks, shared navigation and overlays, and use manual keyboard and assistive-technology checks alongside automation.
One lock on the agent
Heavy CI stages and ad hoc tests can compete for CPU and memory. Use an explicit admission rule: a shared lock, a queue or isolated capacity. Every entry point must participate, including targeted test scripts. The mechanism is an operational detail; a stable, identified execution environment is the requirement.
Small targeted runs answer whether the changed behaviour works; the full gate checks the wider integration. Record when a run waited or collided with another job so its duration and failures can be interpreted correctly.
Evidence, not green ticks
A gate result is evidence only with its context: the build number, the revision it tested, the result per stage. Record the build ID, commit SHA, environment, per-stage result and report location together. An illustrative report should say explicitly that it is an example; it should not invent a successful build. The same standard applies to people and to AI coding agents working on the product: a report counts only with a test seen failing and then passing, and a check that was not run is never reported as passed.
Two more rules protect the evidence. A concurrent nightly run can kill the full gate's servers; when that happens the gate is rerun and the report says so. And the nightly suite verifies the deployed revision before testing it, so a green nightly cannot be a test of yesterday's build.
Keeping it honest over time
Gates decay. A test gets a retry, a timeout grows, a flaky spec is skipped "for now". Three habits keep the suites trustworthy:
- Keep failures visible and investigate them. Retries can collect diagnostic evidence, but a retry pass should not silently erase an unstable result. Any temporary quarantine needs an owner and a restoration condition.
- Keep a per-run report with traces, so a failure can be read instead of reproduced.
- Record the gate's numbers in the hand-off document that is updated with every unit of work. When the fast gate drifts from four minutes to eight, somebody notices in the same week.
The How I work page lists the full sequence from a user's task to a verified release; this article is the part of it that runs on machines. If your Angular workspace has tests that nobody waits for, that sequence is where I would start.
Sources and scope
Timings are historical observations from the project’s 1 October 2026 engineering record. The release-policy table is illustrative, and the figures do not predict another product’s runtime.