65 lines
3.4 KiB
JavaScript
65 lines
3.4 KiB
JavaScript
import { existsSync, readFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
|
|
const root = process.cwd();
|
|
const manifestPath = resolve(root, 'docs/contracts/refactoring-r0-manifest.json');
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) {
|
|
throw new Error(message);
|
|
}
|
|
}
|
|
|
|
function read(relativePath) {
|
|
const absolutePath = resolve(root, relativePath);
|
|
assert(existsSync(absolutePath), `R0 baseline file is missing: ${relativePath}`);
|
|
return readFileSync(absolutePath, 'utf8');
|
|
}
|
|
|
|
const manifest = JSON.parse(read('docs/contracts/refactoring-r0-manifest.json'));
|
|
assert(manifest.version === 'r0', 'R0 manifest version must be r0');
|
|
assert(/^[0-9a-f]{40}$/.test(manifest.baselineCommit), 'R0 baselineCommit must be a full Git commit');
|
|
|
|
for (const contract of manifest.contracts) {
|
|
for (const path of [contract.schema, contract.validator, ...(contract.examples ?? []), ...(contract.tests ?? [])].filter(Boolean)) {
|
|
read(path);
|
|
}
|
|
assert((contract.invariants?.length ?? contract.examples?.length ?? 0) > 0, `${contract.kind}: no frozen examples or invariants`);
|
|
}
|
|
|
|
const facadeChecks = [
|
|
['api/src/send-chain/send-chain.service.ts', 'export class SendChainService'],
|
|
['api/src/channels/channels.service.ts', 'export class ChannelsService'],
|
|
['api/src/operations/operations.service.ts', 'export class OperationsService'],
|
|
['api/src/sms-config/sms-config.service.ts', 'export class SmsConfigService'],
|
|
['api/src/report-materials/report-materials.service.ts', 'export class ReportMaterialsService'],
|
|
['src/api/adminApi.ts', 'export const adminApi'],
|
|
['gateway/internal/inbound/server.go', 'type Server struct'],
|
|
['gateway/internal/upstream/manager.go', 'type Manager struct'],
|
|
];
|
|
|
|
for (const [path, stableExport] of facadeChecks) {
|
|
assert(read(path).includes(stableExport), `${path}: stable facade not found: ${stableExport}`);
|
|
}
|
|
|
|
const characterizationChecks = [
|
|
['api/src/send-chain/send-chain.service.spec.ts', 'allows only one retry submit when three long-message failure receipts race'],
|
|
['api/src/send-chain/send-chain.service.spec.ts', 'creates and sends only one downstream receipt for the same fragment dedupe key'],
|
|
['api/src/send-chain/downstream-receipt-targets.spec.ts', 'queues one HTTP event and one CMPP receipt for each registered client fragment'],
|
|
['api/src/send-chain/send-chain.service.spec.ts', 'atomically claims a downstream manual requeue so concurrent requests only call Gateway once'],
|
|
['api/src/billing/billing.service.spec.ts', 'serializes and replays concurrent refunds with one balance mutation'],
|
|
['gateway/internal/inbound/server_test.go', 'TestDownstreamDeliveryRequiresAcknowledgement'],
|
|
['gateway/internal/upstream/connection_loss_test.go', 'TestReconnectDelayUsesCappedBackoffAndSlowAuthenticationRetry'],
|
|
['gateway/internal/upstream/reconnect_integration_test.go', 'TestFailedSupplierConnectionReconnectsWhenEndpointRecovers'],
|
|
['gateway/internal/cmpp/gocmpp_integration_test.go', 'TestGocmppDeliverReceiptPackAndUnpack'],
|
|
];
|
|
|
|
for (const [path, behavior] of characterizationChecks) {
|
|
assert(read(path).includes(behavior), `${path}: required characterization test is missing: ${behavior}`);
|
|
}
|
|
|
|
read('docs/refactoring/r0-responsibility-index.md');
|
|
read('docs/refactoring/r0-release-gate.md');
|
|
|
|
console.log(`R0 refactoring baseline verified: ${manifest.contracts.length} contract groups, ${facadeChecks.length} stable facades, ${characterizationChecks.length} critical behaviors.`);
|