← Blog

Local-first validation: dropping a hosted check your deploy platform already runs

A hosted CI check that repeats your deploy platform's build adds cost and a second place to fail, not new information. What we validate locally, and what stays hosted.

Nissan Dookeran7 min readCIValidationAgent WorkflowsField Notes

Field note. Evidence last verified 2026-10-14 (UTC). The cost argument here is qualitative: we publish no run counts, minutes or spend for any private repository.

What changed

We moved "validated" away from "a hosted CI run went green" and made hosted CI the last and narrowest layer. A change is validated first on the machine that made it. Then the deploy platform builds that exact commit and gives us a preview to open. Hosted CI is kept for what only a hosted runner can answer, and where the check allows it we scope the workflow by path so that an unrelated edit cannot start it.

The concrete case was a private site repository. It had a hosted check that ran the production build on every push to the main branch and on every pull request into it. The deploy platform we use runs the build command for each of those changes anyway and reports a status on the commit.

We removed the hosted check.

Why it mattered

Two checks that run the same build do not give two signals. When both pass they say the same thing twice. When the build breaks, the platform's own status already says so, with the log. What the duplicate adds is a second status that has to go green, a second place where a failure can come from the runner instead of the change, and metered hosted time on every push.

The honest counter-argument is that the two environments were not identical. Our hosted job pinned its own Node and package-manager versions and installed from a frozen lockfile; the platform uses its own settings. That difference is the only extra thing the duplicate could tell us. We judged it cheaper to catch locally than to keep a permanent second check: run the frozen-lockfile install and the build before the change leaves the machine.

There was a second weakness. The site's build configuration at the time ignored TypeScript and ESLint errors, so a green build check said less than it sounds. It said the app compiled, not that types or lint were clean. Removing the duplicate did not itself fix that; the same site refresh also turned on the TypeScript and ESLint build gates.

What failed

The strongest public evidence that "green hosted CI" is not the same as "validated" is not ours. It is a failure record from the Reddi Agent Protocol (RAP) repository.

On 2026-10-02 RAP published a post-incident audit of a hosted run on pilot pull request number 668. The word "audit" here means RAP's own post-incident review of one hosted run; it is not a security audit of RAP. The first hosted run was green, and the audit's first paragraph says it is "not accepted as safe pilot validation". The pilot had added a script to the repository's root package.json, and an existing workflow listed package.json in its pull-request path filter. That started a job the pilot's own boundary prohibited: the audit records a local test-validator lane (Surfpool) that built programs, generated three throwaway keypairs, funded them with synthetic local balances and ran local transactions.

The audit is careful about what did not happen. It found loopback-only endpoints and no live-value movement in the log, and it found no evidence of persisted private keys while saying plainly that it deliberately did not download the uploaded artifact. The audit records a broken boundary and synthetic local funding and transactions; it reports no live-value movement in the inspected log, not proof of universal absence of loss.

The audit records a corrective boundary: removal of the unnecessary root script entry, retention of heavy evidence generation as an explicit local command, addition of a dedicated hosted workflow limited to syntax, formatting, lint (clippy) and host-native client compatibility, and preservation of the existing workflow's safeguards. GitHub shows that pilot pull request as closed, not merged; the audit does not say why, and we do not claim a connection.

The lesson is about path filters. They are code. A broad filter plus a root file that most changes touch turns an unrelated edit into an unwanted job.

Evidence

  • The audit. RAP's hosted-CI safety audit, dated 2026-10-02: green status did not waive the pilot's no-key-generation, no-validator, no-signing, no-transaction and no-deployment boundary.
  • Local first, hosted for the one thing only it can answer. RAP pull request 654 (merged 2026-09-30) records its validation in a Testing section. It reports a static gate over 40 surfaces, a must-fail control that exited 1, 18 adversarial mutations of a scratch copy, and 13 of 14 scenarios against a locally running app. The 14th scenario was whether the new workflow's paths filter would trigger on a documentation-only change. It was recorded as untested, because "GitHub Actions is the only consumer that evaluates on.paths". A hosted pull_request run of that workflow on the pull request's head commit exists and succeeded, so the workflow did trigger. That run does not by itself prove the documentation-only case the scenario asked about.
  • What a path-scoped hosted workflow looks like. RAP's public-claim-boundary workflow lists the paths that start it, installs no dependencies and has a 10-minute timeout.
  • Not everything is path-scoped. RAP's browser funnel workflow runs on every push and pull request to the main branch. Its own comment says no lane runs the full 39-spec suite and that several kinds of spec run locally with npm run test:e2e. We cite it as an example of a deliberate local/hosted split, not as evidence that RAP's hosted CI is minimal.

Claim boundary

  • What we claim. A duplicate of the platform's build adds no new information, apart from environment differences we name above. Hosted CI should be reserved for what a hosted runner uniquely provides. Green hosted status is not proof that a change is safe.
  • What we do not claim. We do not claim a measured saving, and we publish no cost, run-count or minutes figure for any private repository. We do not claim local validation is sufficient on its own; a hosted check that enforces a gate a contributor could skip, or that depends on provider behaviour, stays.
  • Visibility. The RAP artifacts are public. The site-side facts (the duplicated build check, the platform status, the build setting) are internal and cannot be inspected by readers.
  • RAP. Reddi Agent Protocol is an open, integration-first receipt and conformance layer for paid MCP/API and agent work. Its current public evidence is local/offline and devnet-bounded, and it makes no production, mainnet or live-settlement claim. We cite its repository for two artifacts only.

How to inspect or reproduce

  1. Read the audit. Check the "Trigger and run" and "Corrective boundary" sections.
  2. Open pull request 654 and find "Workflow path-filter semantics (parsed, not a live GitHub run)" in the Testing section.
  3. Open the hosted run for that pull request's head commit.
  4. For your own repository, list every workflow with its triggers and path filters. For each one, ask what it tells you that your local run and your platform's preview do not. If the answer is nothing, remove it. As a quick test, change only a root manifest file on a scratch branch and see which workflows start. That is a suggested method; we have not measured it.

What we learned

  • A second hosted check is worth keeping when it observes something the other layers cannot: how the provider evaluates a filter, a required status, or a gate a contributor might skip. It is not worth keeping when it repeats the platform's build.
  • Review path filters as code. Root manifests and lockfiles match more than you expect.
  • Say what a green check does not cover. A build that ignores type and lint errors, or a hosted run that quietly started the wrong lane, can both be green.