fix: expose dynamic scoring persistence
This commit is contained in:
@@ -5,6 +5,8 @@ import {
|
||||
} from "./birth-time-journey-turn-protocol.ts";
|
||||
import type { DynamicJourneyTurnState } from "./birth-time-journey-turn-protocol.ts";
|
||||
import type {
|
||||
DynamicScoringJobCommand,
|
||||
DynamicScoringJobFailureCommand,
|
||||
DynamicStoredRectificationCase,
|
||||
LegacyStoredRectificationCase,
|
||||
StoredRectificationCase,
|
||||
@@ -68,6 +70,7 @@ function privateState(value: DynamicStoredRectificationCase): DynamicPrivateJour
|
||||
|
||||
function isStaleRpc(error: RpcError): boolean {
|
||||
return error.message.includes("stale_birth_time_dynamic_turn")
|
||||
|| error.message.includes("stale_birth_time_dynamic_scoring_job")
|
||||
|| error.message.includes("stale_birth_time_legacy_upgrade");
|
||||
}
|
||||
|
||||
@@ -84,6 +87,43 @@ export function createDynamicTurnPersistence(
|
||||
return loaded;
|
||||
}
|
||||
|
||||
async function savedDynamicScoring(
|
||||
value: DynamicStoredRectificationCase,
|
||||
expectedVersion: number,
|
||||
result: RpcResult,
|
||||
): Promise<DynamicStoredRectificationCase> {
|
||||
if (result.error) {
|
||||
if (isStaleRpc(result.error)) {
|
||||
const current = await loadCase(value.userId, value.id);
|
||||
throw new StaleJourneyTurnError(
|
||||
value.id,
|
||||
expectedVersion,
|
||||
current?.turnVersion ?? 0,
|
||||
);
|
||||
}
|
||||
throw new BirthTimeJourneyStoreError("update_case");
|
||||
}
|
||||
const version = rpcVersionSchema.safeParse(result.data);
|
||||
if (!version.success || version.data !== expectedVersion + 1) {
|
||||
throw new BirthTimeJourneyStoreError("update_case");
|
||||
}
|
||||
const loaded = await loadedDynamic(value.userId, value.id);
|
||||
if (
|
||||
loaded.turnVersion !== version.data
|
||||
|| loaded.dynamicTurnState.turnVersion !== version.data
|
||||
) throw new BirthTimeJourneyStoreError("load_case");
|
||||
return loaded;
|
||||
}
|
||||
|
||||
function scoringIdentity(command: DynamicScoringJobCommand) {
|
||||
return {
|
||||
p_job_id: command.jobId,
|
||||
p_expected_version: command.expectedVersion,
|
||||
p_evidence_fingerprint: command.evidenceFingerprint,
|
||||
p_algorithm_version: command.algorithmVersion,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
async saveDynamicTurn(
|
||||
value: DynamicStoredRectificationCase,
|
||||
@@ -119,6 +159,38 @@ export function createDynamicTurnPersistence(
|
||||
return loadedDynamic(value.userId, value.id);
|
||||
},
|
||||
|
||||
async completeDynamicScoringJob(
|
||||
value: DynamicStoredRectificationCase,
|
||||
command: DynamicScoringJobCommand,
|
||||
): Promise<DynamicStoredRectificationCase> {
|
||||
if (!value.candidateResult) throw new BirthTimeJourneyStoreError("update_case");
|
||||
const result = await client.rpc("complete_birth_time_dynamic_scoring_job", {
|
||||
p_user_id: value.userId,
|
||||
p_case_id: value.id,
|
||||
...scoringIdentity(command),
|
||||
p_public_turn_state: publicTurn(value, command.expectedVersion + 1),
|
||||
p_snapshot: value.snapshot,
|
||||
p_candidate_result: value.candidateResult,
|
||||
p_private_state: privateState(value),
|
||||
});
|
||||
return savedDynamicScoring(value, command.expectedVersion, result);
|
||||
},
|
||||
|
||||
async failDynamicScoringJob(
|
||||
value: DynamicStoredRectificationCase,
|
||||
command: DynamicScoringJobFailureCommand,
|
||||
): Promise<DynamicStoredRectificationCase> {
|
||||
const result = await client.rpc("fail_birth_time_dynamic_scoring_job", {
|
||||
p_user_id: value.userId,
|
||||
p_case_id: value.id,
|
||||
...scoringIdentity(command),
|
||||
p_failure_code: command.failureCode,
|
||||
p_public_turn_state: publicTurn(value, command.expectedVersion + 1),
|
||||
p_private_state: privateState(value),
|
||||
});
|
||||
return savedDynamicScoring(value, command.expectedVersion, result);
|
||||
},
|
||||
|
||||
async upgradeLegacyActiveCase(
|
||||
value: LegacyStoredRectificationCase,
|
||||
): Promise<StoredRectificationCase> {
|
||||
|
||||
@@ -133,16 +133,27 @@ export type LegacyStoredRectificationCase = StoredRectificationCaseBase
|
||||
export type DynamicStoredRectificationCase = StoredRectificationCaseBase
|
||||
& DynamicStoredFields;
|
||||
|
||||
export type StoredRectificationCase =
|
||||
| LegacyStoredRectificationCase
|
||||
export type StoredRectificationCase = LegacyStoredRectificationCase
|
||||
| DynamicStoredRectificationCase;
|
||||
|
||||
export type DynamicScoringJobCommand = {
|
||||
readonly expectedVersion: number;
|
||||
readonly jobId: string;
|
||||
readonly evidenceFingerprint: string;
|
||||
readonly algorithmVersion: string;
|
||||
};
|
||||
|
||||
export type DynamicScoringJobFailureCommand = DynamicScoringJobCommand
|
||||
& { readonly failureCode: string };
|
||||
|
||||
export interface BirthTimeJourneyStore {
|
||||
saveAssessment(value: PersistedJourneyAssessment): Promise<string>;
|
||||
loadCase(userId: string, caseId: string): Promise<StoredRectificationCase | null>;
|
||||
saveScoring(value: LegacyStoredRectificationCase): Promise<void>;
|
||||
saveTurn(value: LegacyStoredRectificationCase, expectedVersion: number, actionId: string): Promise<StoredRectificationCase>;
|
||||
saveDynamicTurn(value: DynamicStoredRectificationCase, expectedVersion: number, actionId: string): Promise<DynamicStoredRectificationCase>;
|
||||
completeDynamicScoringJob(value: DynamicStoredRectificationCase, command: DynamicScoringJobCommand): Promise<DynamicStoredRectificationCase>;
|
||||
failDynamicScoringJob(value: DynamicStoredRectificationCase, command: DynamicScoringJobFailureCommand): Promise<DynamicStoredRectificationCase>;
|
||||
upgradeLegacyActiveCase(value: LegacyStoredRectificationCase): Promise<StoredRectificationCase>;
|
||||
createScoringJob(value: LegacyStoredRectificationCase, expectedVersion: number, actionId: string, job: ScoringJobSpec): Promise<StoredRectificationCase>;
|
||||
claimScoringJob(identity: ScoringJobIdentity): Promise<ScoringJobClaim>;
|
||||
|
||||
Reference in New Issue
Block a user