报告创建请求、校正入口和同名类型改从 contracts 推导;同义的对象判断与 sha256 改走共享函数。调用处用 import 别名保留原名,使 diff 低于 1500 行。行为、哈希和状态字符串不变。 Co-Authored-By: Grok (agent loop)
51 lines
2.3 KiB
TypeScript
51 lines
2.3 KiB
TypeScript
import { resolveServerOwnedChartBirth } from "./chart-birth-truth.ts";
|
|
import { asRecord as record } from "@/lib/guards";
|
|
|
|
/**
|
|
* Report ↔ birth-data binding for the report cover (TASK-birth-sky-followup-20260928,
|
|
* product decision A).
|
|
*
|
|
* A report records the fingerprint of the birth data it was generated from, in
|
|
* `subject.birthFingerprint`. The fingerprint is the chart page's
|
|
* `profileFingerprint`: `resolveServerOwnedChartBirth` over the **stored** row,
|
|
* before any in-memory timezone fill. Reports generated before this field
|
|
* existed never get one. Nothing reads it back yet: the report sky cover that
|
|
* compared it was removed (TASK-mobile-chart-and-confirmed-edit-20260929 M5,
|
|
* product 2026-09-29); the field is kept so a later binding can use it. It is
|
|
* never sent to a client or to the model.
|
|
*/
|
|
|
|
/** Server-only key stamped on the loaded profile row; never persisted, never serialized to a client. */
|
|
export const REPORT_BIRTH_FINGERPRINT_KEY = "report_birth_fingerprint";
|
|
|
|
const FINGERPRINT_PATTERN = /^[0-9a-f]{32}$/;
|
|
|
|
/** Same algorithm and same input (the stored row) as the chart page's `profileFingerprint`. */
|
|
export function subjectBirthFingerprint(storedRow: unknown): string {
|
|
return resolveServerOwnedChartBirth(storedRow).fingerprint;
|
|
}
|
|
|
|
/**
|
|
* Carries the stored row's fingerprint on the timezone-filled row the
|
|
* generators read. Filling a missing offset changes the fingerprint, so it
|
|
* must be taken before the fill.
|
|
*/
|
|
export function stampReportBirthFingerprint(storedRow: unknown, filledRow: unknown): unknown {
|
|
const filled = record(filledRow);
|
|
if (!filled) return filledRow;
|
|
return { ...filled, [REPORT_BIRTH_FINGERPRINT_KEY]: subjectBirthFingerprint(storedRow) };
|
|
}
|
|
|
|
export function readReportBirthFingerprint(profile: unknown): string | undefined {
|
|
const value = record(profile)?.[REPORT_BIRTH_FINGERPRINT_KEY];
|
|
return typeof value === "string" && FINGERPRINT_PATTERN.test(value) ? value : undefined;
|
|
}
|
|
|
|
/** Writes `subject.birthFingerprint` on a report document; a missing fingerprint leaves it untouched. */
|
|
export function withReportBirthFingerprint<T>(document: T, fingerprint: string | undefined): T {
|
|
const source = record(document);
|
|
const subject = record(source?.subject);
|
|
if (!source || !subject || !fingerprint) return document;
|
|
return { ...source, subject: { ...subject, birthFingerprint: fingerprint } } as T;
|
|
}
|