From a22578ebfc32f75574d58569ab1b16ac7b239fd6 Mon Sep 17 00:00:00 2001 From: solaawojobi00-bit Date: Tue, 29 Sep 2026 10:10:19 +0100 Subject: [PATCH] fix(backend): repair schema snapshot tooling and regenerate health/ready snapshots (#1378) --- backend/schema-snapshots/get-_health.json | 2 +- backend/schema-snapshots/get-_ready.json | 2 +- backend/src/__tests__/issues711.test.ts | 37 +++++++++++++++++------ backend/src/apiContractSnapshots.ts | 5 +-- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/backend/schema-snapshots/get-_health.json b/backend/schema-snapshots/get-_health.json index c62ee2340..05101c579 100644 --- a/backend/schema-snapshots/get-_health.json +++ b/backend/schema-snapshots/get-_health.json @@ -135,4 +135,4 @@ "sorobanCircuitBreaker" ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/backend/schema-snapshots/get-_ready.json b/backend/schema-snapshots/get-_ready.json index ce8460efd..cca011448 100644 --- a/backend/schema-snapshots/get-_ready.json +++ b/backend/schema-snapshots/get-_ready.json @@ -42,4 +42,4 @@ "dependencies" ], "additionalProperties": false -} \ No newline at end of file +} diff --git a/backend/src/__tests__/issues711.test.ts b/backend/src/__tests__/issues711.test.ts index 7feef6c6b..94b3d1195 100644 --- a/backend/src/__tests__/issues711.test.ts +++ b/backend/src/__tests__/issues711.test.ts @@ -8,10 +8,11 @@ import { diffSchemaShapes, generateSnapshotFor, loadSnapshot, + snapshotPathFor, validateResponseAgainstSchema, - writeAllSnapshots, zodToJsonShape, HealthResponseSchema, + JsonSchemaShape, } from '../apiContractSnapshots'; import * as fs from 'fs'; import * as path from 'path'; @@ -19,10 +20,6 @@ import * as path from 'path'; const SNAPSHOT_DIR = path.join(__dirname, '..', '..', 'schema-snapshots'); describe('#711 API contract schema snapshots', () => { - beforeAll(() => { - writeAllSnapshots(); - }); - it('defines snapshots for all critical public endpoints', () => { expect(CRITICAL_ENDPOINTS.length).toBeGreaterThanOrEqual(4); for (const endpoint of CRITICAL_ENDPOINTS) { @@ -47,11 +44,11 @@ describe('#711 API contract schema snapshots', () => { }); it('detects newly added required fields as breaking changes', () => { - const baseline = zodToJsonShape(HealthResponseSchema); - const current = JSON.parse(JSON.stringify(baseline)) as typeof baseline; + const current = zodToJsonShape(HealthResponseSchema); + const baseline = JSON.parse(JSON.stringify(current)) as typeof current; // Simulate an older snapshot that is missing the 'indexer' field - delete current.properties?.checks?.properties?.indexer; - current.properties!.checks!.required = (current.properties!.checks!.required ?? []).filter( + delete baseline.properties?.checks?.properties?.indexer; + baseline.properties!.checks!.required = (baseline.properties!.checks!.required ?? []).filter( (k: string) => k !== 'indexer', ); @@ -172,4 +169,26 @@ describe('#711 API contract schema snapshots', () => { const issues = diffSchemaShapes(baseline, current, 'GET /health'); expect(issues.some((issue) => issue.message === 'new field added to live schema (snapshot drift)' && issue.path === 'GET /health.newField')).toBe(true); }); + + // #1378: committed snapshots must be generator output, not hand-edited, and + // must carry the indexer check that /health and /ready emit. + it('committed snapshots match generator output byte-for-byte', () => { + for (const endpoint of CRITICAL_ENDPOINTS) { + const committed = fs.readFileSync(snapshotPathFor(endpoint), 'utf8'); + expect(committed).toBe(JSON.stringify(generateSnapshotFor(endpoint), null, 2) + '\n'); + } + }); + + it('health and ready snapshots include the indexer check', () => { + const health = loadSnapshot('GET /health'); + expect(health?.properties?.checks?.properties?.indexer).toEqual({ + type: 'string', + enum: ['up', 'down', 'degraded', 'unknown'], + }); + expect(health?.properties?.checks?.required).toContain('indexer'); + + const ready = loadSnapshot('GET /ready'); + expect(ready?.properties?.dependencies?.properties?.indexer).toEqual({ type: 'boolean' }); + expect(ready?.properties?.dependencies?.required).toContain('indexer'); + }); }); diff --git a/backend/src/apiContractSnapshots.ts b/backend/src/apiContractSnapshots.ts index acaa02eb4..a9c56d597 100644 --- a/backend/src/apiContractSnapshots.ts +++ b/backend/src/apiContractSnapshots.ts @@ -249,7 +249,7 @@ export function diffSchemaShapes( } for (const key of baselineRequired) { - if (!(key in baseline.properties ?? {})) { + if (!(key in baselineProps)) { issues.push({ path: at(key), message: 'required field missing from snapshot properties (orphaned reference)' }); } if (!(key in currentProps)) { @@ -260,8 +260,9 @@ export function diffSchemaShapes( } for (const key of currentRequired) { - if (!(key in current.properties ?? {})) { + if (!(key in currentProps)) { issues.push({ path: at(key), message: 'required field missing from live schema properties (invalid schema)' }); + } if (!baselineRequired.has(key)) { issues.push({ path: at(key), message: 'field is now required — regenerate snapshots with npm run snapshots:write' }); }