Core Concepts
Frontend Contract Guard records real API traffic, compares a known-good baseline with a candidate build, and traces each changed field to the TypeScript, Angular or Vue code that reads it. Detection is deterministic: the same inputs always produce the same findings.
Stages 01–05The pipeline, baseline to report
- 01Redacted snapshotCapture & sanitize
capture/build.tsDrop non-JSON noise and known analytics hosts, normalize endpoint paths (
/hotels/htl_01 → /hotels/:id), and redact headers, query params and configured JSON paths — before anything is written to disk. - 02Shape per endpointInfer shape
schema-diff/infer.tsPer endpoint: types, occurrence counts and a sample, for the baseline and for the candidate separately.
- 03Structural changesCompare structurally
compare.tsDeterministic diff of the two shapes: removed, added, type-changed, nullability, optionality and status changes. Value differences are ignored unless you turn them on.
- 04File and line referencesMap to source
source-mapperOne TypeScript Program over your project finds call sites, type-linked response access, and Angular/Vue template bindings that read the changed field.
- 05JSON · Markdown · HTMLScore & report
analyzer + report-generatorSeverity, confidence and an evidence tier are attached to each finding; the report ships as JSON, Markdown and HTML, with a draft Playwright test per finding.
StateBaselines vs. candidates
A baseline is a known-good capture for one environment, created by a person from a capture — not auto-generated from a git merge. Candidates are compared against it, and baselines are never overwritten: replacing one archives the old version.
There’s no CI step that mints a new baseline on merge. You choose the capture that becomes the baseline, and you choose when to replace it.
| Property | Baseline | Candidate |
|---|---|---|
| Created by | A person, from a capture | Any capture you compare |
| Scope | One environment of one project | The same environment; another environment must be confirmed |
| When it changes | Only when you replace it; the old one is archived | With every new capture |
| Role | The reference the build is checked against | The build being checked |
ClassificationBreaking vs. informational changes
Severity and confidence are two separate axes. Severity (critical / high / medium / low / info) is how much a change could break things; confidence (high / medium / low / unresolved) is how strong the evidence is that the frontend actually reads the field.
- Field removed from the response
- A value’s type changed (e.g. a number became a string)
- A non-nullable field started returning null
- A new property added with no mapped consumer yet
- A timestamp or other value difference (off unless you turn value-diffing on)
- Array order, when only value differences changed
TriageEvidence tiers
Each finding is labelled with how strong the evidence is — never auto-confirmed by a missing field alone.
- 01Structural
The response shape changed; no evidence yet that the frontend depends on it.
- 02Potentially breaking
A removal, type or nullability change the frontend calls, without a matched usage.
- 03Affected usage
Source code that reads the field was found — type-linked or a name match.
- 04Confirmed by test
A person recorded a failing test for this finding. This is the only way a finding becomes confirmed.
SourceHow source mapping works
One TypeScript Program is built over your .ts files (tests and node_modules excluded). It records HTTP call sites (fetch, axios, Angular HttpClient), the response type at each site, every property access the type checker resolves, and Angular/Vue template bindings — then walks from a changed response field to the exact file and line that reads it.
data.hotels[].price.amountGET /api/hotels/search · removed in the candidatecore/api/hotel-api.service.ts:13HttpClient.get<HotelSearchResponse>hotel-price.component.ts:14 · hotel-card.component.html:6Component code and its templateConfidence levels
highThe access resolves via the TypeScript checker to the declared response type, and the endpoint was observed on a browser route.
mediumType-linked without a route, or a name/template match on at least two trailing path segments.
lowThe endpoint is called from source, but no usage of the field was found — not proof the field is unused.
unresolvedNo source analyzed, or no call site matched the endpoint.
Noise controlHandling volatile fields
High-traffic APIs return non-deterministic values — transaction IDs, timestamps, counters. Configure ignore rules and redaction paths in fcg.config.json (the desktop app can export a project’s config under CI & Integrations) so those fields don’t generate noise.
{
"rules": {
"ignore": [
{
"id": "trace-ids",
"path": "**.traceId",
"reason": "A new id on every request; the UI never reads it"
},
{
"id": "search-request-id",
"endpoint": "GET /api/hotels/search",
"path": "meta.requestId",
"kinds": [
"type-changed",
"nullability-changed"
],
"reason": "Generated per request by the gateway"
}
],
"reportValueChanges": false
}
}Each rule needs a reason and at least an endpoint, a path or change kinds. Paths use ** for any depth and * within one segment.
A wildcard ignore rule on a whole object can hide a real backend change along with the noise. Scope ignore rules to the specific volatile field.