mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 01:32:44 +08:00
419 lines
13 KiB
TypeScript
419 lines
13 KiB
TypeScript
export const LEGACY_SHADOW_PRIMARY_GATE_SCHEMA =
|
|
'qinglong/legacy-shadow-primary-gate@v1';
|
|
|
|
export type LegacyShadowPrimaryGateViolation =
|
|
| 'capture_schema_invalid'
|
|
| 'capture_profile_mismatch'
|
|
| 'capture_not_qualified'
|
|
| 'capture_origin_coverage_invalid'
|
|
| 'capture_window_invalid'
|
|
| 'capture_sample_budget_invalid'
|
|
| 'capture_conservation_invalid'
|
|
| 'startup_not_converged'
|
|
| 'terminal_schema_invalid'
|
|
| 'terminal_profile_mismatch'
|
|
| 'terminal_window_mismatch'
|
|
| 'terminal_coverage_invalid'
|
|
| 'terminal_not_matched'
|
|
| 'resource_schema_invalid'
|
|
| 'resource_profile_mismatch'
|
|
| 'resource_not_qualified'
|
|
| 'resource_not_compiled_full_rollback';
|
|
|
|
export interface LegacyShadowPrimaryGateReceipt {
|
|
schema: typeof LEGACY_SHADOW_PRIMARY_GATE_SCHEMA;
|
|
schemaVersion: 1;
|
|
profile: 'edge' | 'standalone';
|
|
origin: 'manual';
|
|
generatedAtMs: number;
|
|
assessment: 'eligible' | 'ineligible';
|
|
window: {
|
|
startInclusiveMs: number;
|
|
endExclusiveMs: number;
|
|
};
|
|
counts: {
|
|
admitted: number;
|
|
captured: number;
|
|
terminalScanned: number;
|
|
terminalMatched: number;
|
|
};
|
|
evidence: {
|
|
captureSha256: string;
|
|
terminalSha256: string;
|
|
resourceSha256: string;
|
|
};
|
|
sources: {
|
|
capture: unknown;
|
|
terminal: unknown;
|
|
resource: unknown;
|
|
};
|
|
violations: readonly LegacyShadowPrimaryGateViolation[];
|
|
}
|
|
|
|
export interface LegacyShadowPrimaryGateInput {
|
|
profile: 'edge' | 'standalone';
|
|
generatedAtMs: number;
|
|
capture: unknown;
|
|
terminal: unknown;
|
|
resource: unknown;
|
|
}
|
|
|
|
const SAMPLE_BUDGETS = Object.freeze({
|
|
edge: { minimum: 8, maximum: 8 },
|
|
standalone: { minimum: 32, maximum: 128 },
|
|
});
|
|
const SHA256_PATTERN = /^[a-f0-9]{64}$/u;
|
|
|
|
function object(value: unknown): Record<string, any> | undefined {
|
|
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
? (value as Record<string, any>)
|
|
: undefined;
|
|
}
|
|
|
|
function safeCount(value: unknown): value is number {
|
|
return Number.isSafeInteger(value) && Number(value) >= 0;
|
|
}
|
|
|
|
function add(
|
|
violations: LegacyShadowPrimaryGateViolation[],
|
|
violation: LegacyShadowPrimaryGateViolation,
|
|
): void {
|
|
if (!violations.includes(violation)) violations.push(violation);
|
|
}
|
|
|
|
function canonicalJson(value: unknown): string {
|
|
if (value === null) return 'null';
|
|
if (typeof value === 'string' || typeof value === 'boolean') {
|
|
return JSON.stringify(value);
|
|
}
|
|
if (typeof value === 'number') {
|
|
if (!Number.isFinite(value))
|
|
throw new TypeError('Evidence number is invalid');
|
|
return JSON.stringify(value);
|
|
}
|
|
if (Array.isArray(value)) {
|
|
return `[${value.map(canonicalJson).join(',')}]`;
|
|
}
|
|
const record = object(value);
|
|
if (!record) throw new TypeError('Evidence contains a non-JSON value');
|
|
return `{${Object.keys(record)
|
|
.sort()
|
|
.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`)
|
|
.join(',')}}`;
|
|
}
|
|
|
|
export function legacyShadowPrimaryEvidenceSha256(value: unknown): string {
|
|
return createHash('sha256').update(canonicalJson(value)).digest('hex');
|
|
}
|
|
|
|
export function createLegacyShadowPrimaryGateReceipt(
|
|
input: LegacyShadowPrimaryGateInput,
|
|
): LegacyShadowPrimaryGateReceipt {
|
|
if (input.profile !== 'edge' && input.profile !== 'standalone') {
|
|
throw new TypeError('Primary gate profile is invalid');
|
|
}
|
|
if (!safeCount(input.generatedAtMs)) {
|
|
throw new TypeError('Primary gate timestamp is invalid');
|
|
}
|
|
const sources = {
|
|
capture: JSON.parse(canonicalJson(input.capture)),
|
|
terminal: JSON.parse(canonicalJson(input.terminal)),
|
|
resource: JSON.parse(canonicalJson(input.resource)),
|
|
};
|
|
const evidence = {
|
|
captureSha256: legacyShadowPrimaryEvidenceSha256(sources.capture),
|
|
terminalSha256: legacyShadowPrimaryEvidenceSha256(sources.terminal),
|
|
resourceSha256: legacyShadowPrimaryEvidenceSha256(sources.resource),
|
|
};
|
|
const violations: LegacyShadowPrimaryGateViolation[] = [];
|
|
const captureEvidence = object(sources.capture);
|
|
const capture = object(captureEvidence?.capture);
|
|
const startup = object(captureEvidence?.startup);
|
|
const captureWindow = object(capture?.window);
|
|
const captureTotals = object(capture?.totals);
|
|
const captureByOriginValue = capture?.byOrigin;
|
|
const captureByOrigin = Array.isArray(captureByOriginValue)
|
|
? captureByOriginValue
|
|
: [];
|
|
const admittedValue = captureTotals?.admitted;
|
|
const capturedValue = captureTotals?.captured;
|
|
const admitted = safeCount(admittedValue) ? admittedValue : 0;
|
|
const captured = safeCount(capturedValue) ? capturedValue : 0;
|
|
|
|
if (
|
|
captureEvidence?.schema !== 'qinglong/legacy-shadow-capture-evidence@v1' ||
|
|
capture?.schema !== 'qinglong/legacy-shadow-capture-report@v1'
|
|
) {
|
|
add(violations, 'capture_schema_invalid');
|
|
}
|
|
if (
|
|
captureEvidence?.profile !== input.profile ||
|
|
capture?.profile !== input.profile
|
|
) {
|
|
add(violations, 'capture_profile_mismatch');
|
|
}
|
|
if (
|
|
object(captureEvidence?.qualification)?.passed !== true ||
|
|
capture?.assessment !== 'captured' ||
|
|
capture?.capturePermille !== 1_000
|
|
) {
|
|
add(violations, 'capture_not_qualified');
|
|
}
|
|
if (
|
|
capture?.configuredOriginCount !== 1 ||
|
|
captureByOrigin.length !== 1 ||
|
|
object(captureByOrigin[0])?.origin !== 'manual' ||
|
|
startup?.configuredOriginCount !== 1 ||
|
|
!Array.isArray(startup?.byOrigin) ||
|
|
startup.byOrigin.length !== 1 ||
|
|
object(startup.byOrigin[0])?.origin !== 'manual'
|
|
) {
|
|
add(violations, 'capture_origin_coverage_invalid');
|
|
}
|
|
const startInclusiveMs = captureWindow?.startInclusiveMs;
|
|
const endExclusiveMs = captureWindow?.endExclusiveMs;
|
|
if (
|
|
captureWindow?.basis !== 'process_local_legacy_admission' ||
|
|
!safeCount(startInclusiveMs) ||
|
|
!safeCount(endExclusiveMs) ||
|
|
startInclusiveMs >= endExclusiveMs ||
|
|
endExclusiveMs > input.generatedAtMs
|
|
) {
|
|
add(violations, 'capture_window_invalid');
|
|
}
|
|
const budget = SAMPLE_BUDGETS[input.profile];
|
|
if (admitted < budget.minimum || admitted > budget.maximum) {
|
|
add(violations, 'capture_sample_budget_invalid');
|
|
}
|
|
if (
|
|
!safeCount(captureTotals?.failed) ||
|
|
!safeCount(captureTotals?.pending) ||
|
|
captured !== admitted ||
|
|
captureTotals?.failed !== 0 ||
|
|
captureTotals?.pending !== 0
|
|
) {
|
|
add(violations, 'capture_conservation_invalid');
|
|
}
|
|
if (
|
|
startup?.schema !== 'qinglong/legacy-shadow-startup-difference-report@v1' ||
|
|
startup?.profile !== input.profile ||
|
|
startup?.assessment !== 'converged' ||
|
|
object(startup?.coverage)?.remaining !== false
|
|
) {
|
|
add(violations, 'startup_not_converged');
|
|
}
|
|
|
|
const terminal = object(sources.terminal);
|
|
const terminalWindow = object(terminal?.window);
|
|
const terminalCoverage = object(terminal?.coverage);
|
|
const terminalCounts = object(terminal?.counts);
|
|
const terminalByOriginValue = terminal?.byOrigin;
|
|
const terminalByOrigin = Array.isArray(terminalByOriginValue)
|
|
? terminalByOriginValue
|
|
: [];
|
|
const terminalScannedValue = terminal?.scanned;
|
|
const terminalMatchedValue = terminalCounts?.matched;
|
|
const terminalScanned = safeCount(terminalScannedValue)
|
|
? terminalScannedValue
|
|
: 0;
|
|
const terminalMatched = safeCount(terminalMatchedValue)
|
|
? terminalMatchedValue
|
|
: 0;
|
|
const terminalObservedAtMs = terminal?.observedAtMs;
|
|
if (
|
|
terminal?.schema !== 'qinglong/legacy-shadow-terminal-difference-report@v1'
|
|
) {
|
|
add(violations, 'terminal_schema_invalid');
|
|
}
|
|
if (terminal?.profile !== input.profile) {
|
|
add(violations, 'terminal_profile_mismatch');
|
|
}
|
|
if (
|
|
terminalWindow?.startInclusiveMs !== startInclusiveMs ||
|
|
terminalWindow?.endExclusiveMs !== endExclusiveMs ||
|
|
terminalWindow?.closed !== true ||
|
|
!safeCount(terminalObservedAtMs) ||
|
|
terminalObservedAtMs > input.generatedAtMs
|
|
) {
|
|
add(violations, 'terminal_window_mismatch');
|
|
}
|
|
if (
|
|
terminalCoverage?.direction !== 'shadow_to_legacy' ||
|
|
terminalCoverage?.cohort !== 'legacy_owned_shadow_runs' ||
|
|
terminalCoverage?.legacyWithoutShadow !== 'not_measured' ||
|
|
terminalByOrigin.length !== 1 ||
|
|
object(terminalByOrigin[0])?.origin !== 'manual' ||
|
|
object(terminalByOrigin[0])?.scanned !== terminalScanned
|
|
) {
|
|
add(violations, 'terminal_coverage_invalid');
|
|
}
|
|
if (
|
|
terminal?.assessment !== 'matched' ||
|
|
terminal?.remaining !== false ||
|
|
terminal?.evidenceComplete !== true ||
|
|
terminal?.terminalAgreementPermille !== 1_000 ||
|
|
terminal?.fullyComparablePermille !== 1_000 ||
|
|
terminalScanned !== captured ||
|
|
terminalMatched !== captured
|
|
) {
|
|
add(violations, 'terminal_not_matched');
|
|
}
|
|
|
|
const resource = object(sources.resource);
|
|
const workload = object(resource?.workload);
|
|
const rollback = object(resource?.rollback);
|
|
const qualification = object(resource?.qualification);
|
|
if (
|
|
resource?.schemaVersion !== 1 ||
|
|
resource?.fixture !== 'qinglong/legacy-shadow-resource-rollback-evidence@v1'
|
|
) {
|
|
add(violations, 'resource_schema_invalid');
|
|
}
|
|
if (resource?.profile !== input.profile) {
|
|
add(violations, 'resource_profile_mismatch');
|
|
}
|
|
if (
|
|
qualification?.passed !== true ||
|
|
qualification?.violations?.length !== 0
|
|
) {
|
|
add(violations, 'resource_not_qualified');
|
|
}
|
|
if (
|
|
workload?.mode !== 'full' ||
|
|
workload?.runtime !== 'compiled_backend' ||
|
|
rollback?.performed !== true ||
|
|
rollback?.legacyContinued !== true ||
|
|
rollback?.shadowWritesStopped !== true ||
|
|
rollback?.databaseIntegrity !== 'ok'
|
|
) {
|
|
add(violations, 'resource_not_compiled_full_rollback');
|
|
}
|
|
|
|
return Object.freeze({
|
|
schema: LEGACY_SHADOW_PRIMARY_GATE_SCHEMA,
|
|
schemaVersion: 1,
|
|
profile: input.profile,
|
|
origin: 'manual',
|
|
generatedAtMs: input.generatedAtMs,
|
|
assessment: violations.length === 0 ? 'eligible' : 'ineligible',
|
|
window: {
|
|
startInclusiveMs: safeCount(startInclusiveMs) ? startInclusiveMs : 0,
|
|
endExclusiveMs: safeCount(endExclusiveMs) ? endExclusiveMs : 0,
|
|
},
|
|
counts: { admitted, captured, terminalScanned, terminalMatched },
|
|
evidence,
|
|
sources,
|
|
violations,
|
|
});
|
|
}
|
|
|
|
function assertExactKeys(
|
|
value: Record<string, unknown>,
|
|
expected: readonly string[],
|
|
label: string,
|
|
): void {
|
|
const keys = Object.keys(value).sort();
|
|
const wanted = [...expected].sort();
|
|
if (
|
|
keys.length !== wanted.length ||
|
|
keys.some((key, index) => key !== wanted[index])
|
|
) {
|
|
throw new TypeError(`${label} shape is invalid`);
|
|
}
|
|
}
|
|
|
|
export function parseLegacyShadowPrimaryGateReceipt(
|
|
value: unknown,
|
|
): LegacyShadowPrimaryGateReceipt {
|
|
const receipt = object(value);
|
|
if (!receipt) throw new TypeError('Primary gate receipt must be an object');
|
|
assertExactKeys(
|
|
receipt,
|
|
[
|
|
'schema',
|
|
'schemaVersion',
|
|
'profile',
|
|
'origin',
|
|
'generatedAtMs',
|
|
'assessment',
|
|
'window',
|
|
'counts',
|
|
'evidence',
|
|
'sources',
|
|
'violations',
|
|
],
|
|
'receipt',
|
|
);
|
|
const window = object(receipt.window);
|
|
const counts = object(receipt.counts);
|
|
const evidence = object(receipt.evidence);
|
|
const sources = object(receipt.sources);
|
|
if (!window || !counts || !evidence || !sources) {
|
|
throw new TypeError('Primary gate receipt nested shape is invalid');
|
|
}
|
|
assertExactKeys(
|
|
window,
|
|
['startInclusiveMs', 'endExclusiveMs'],
|
|
'receipt.window',
|
|
);
|
|
assertExactKeys(
|
|
sources,
|
|
['capture', 'terminal', 'resource'],
|
|
'receipt.sources',
|
|
);
|
|
assertExactKeys(
|
|
counts,
|
|
['admitted', 'captured', 'terminalScanned', 'terminalMatched'],
|
|
'receipt.counts',
|
|
);
|
|
assertExactKeys(
|
|
evidence,
|
|
['captureSha256', 'terminalSha256', 'resourceSha256'],
|
|
'receipt.evidence',
|
|
);
|
|
if (
|
|
receipt.schema !== LEGACY_SHADOW_PRIMARY_GATE_SCHEMA ||
|
|
receipt.schemaVersion !== 1 ||
|
|
!['edge', 'standalone'].includes(receipt.profile) ||
|
|
receipt.origin !== 'manual' ||
|
|
!safeCount(receipt.generatedAtMs) ||
|
|
!['eligible', 'ineligible'].includes(receipt.assessment) ||
|
|
!safeCount(window.startInclusiveMs) ||
|
|
!safeCount(window.endExclusiveMs) ||
|
|
window.startInclusiveMs >= window.endExclusiveMs ||
|
|
!Object.values(counts).every(safeCount) ||
|
|
!Object.values(evidence).every(
|
|
(digest) => typeof digest === 'string' && SHA256_PATTERN.test(digest),
|
|
) ||
|
|
!Array.isArray(receipt.violations) ||
|
|
receipt.violations.some(
|
|
(violation: unknown) =>
|
|
typeof violation !== 'string' || violation.length > 64,
|
|
) ||
|
|
(receipt.assessment === 'eligible' && receipt.violations.length !== 0) ||
|
|
(receipt.assessment === 'ineligible' && receipt.violations.length === 0)
|
|
) {
|
|
throw new TypeError('Primary gate receipt is invalid');
|
|
}
|
|
const recomputed = createLegacyShadowPrimaryGateReceipt({
|
|
profile: receipt.profile as 'edge' | 'standalone',
|
|
generatedAtMs: receipt.generatedAtMs,
|
|
capture: sources.capture,
|
|
terminal: sources.terminal,
|
|
resource: sources.resource,
|
|
});
|
|
for (const field of [
|
|
'assessment',
|
|
'window',
|
|
'counts',
|
|
'evidence',
|
|
'violations',
|
|
] as const) {
|
|
if (canonicalJson(receipt[field]) !== canonicalJson(recomputed[field])) {
|
|
throw new TypeError(`Primary gate receipt ${field} was not reproduced`);
|
|
}
|
|
}
|
|
return receipt as unknown as LegacyShadowPrimaryGateReceipt;
|
|
}
|
|
import { createHash } from 'crypto';
|