refactor: remove read-time repair from canonical hydrate paths
This commit is contained in:
@@ -22,7 +22,9 @@ interface RequiredRoleMetadataInput {
|
||||
|
||||
interface OptionalRoleMetadataInput extends RequiredRoleMetadataInput {}
|
||||
|
||||
function resolveRequiredAgentType(input: RequiredRoleMetadataInput): AgentType {
|
||||
function resolveFilledRequiredAgentType(
|
||||
input: RequiredRoleMetadataInput,
|
||||
): AgentType {
|
||||
const persistedAgentType = normalizeStoredAgentType(input.storedAgentType);
|
||||
const inferredAgentType = inferAgentTypeFromServiceShadow(
|
||||
input.storedServiceId,
|
||||
@@ -48,7 +50,33 @@ function resolveRequiredAgentType(input: RequiredRoleMetadataInput): AgentType {
|
||||
);
|
||||
}
|
||||
|
||||
function resolveRequiredServiceId(
|
||||
function readStoredRequiredAgentType(
|
||||
input: RequiredRoleMetadataInput,
|
||||
): AgentType {
|
||||
const persistedAgentType = normalizeStoredAgentType(input.storedAgentType);
|
||||
const inferredAgentType = inferAgentTypeFromServiceShadow(
|
||||
input.storedServiceId,
|
||||
);
|
||||
if (
|
||||
persistedAgentType &&
|
||||
inferredAgentType &&
|
||||
persistedAgentType !== inferredAgentType
|
||||
) {
|
||||
throw new Error(
|
||||
`${input.context}: ${input.role}_agent_type conflicts with ${input.role}_service_id`,
|
||||
);
|
||||
}
|
||||
|
||||
if (persistedAgentType) {
|
||||
return persistedAgentType;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`${input.context}: cannot read ${input.role}_agent_type from stored row metadata`,
|
||||
);
|
||||
}
|
||||
|
||||
function resolveFilledRequiredServiceId(
|
||||
context: string,
|
||||
role: PairedRoomRole,
|
||||
agentType: AgentType,
|
||||
@@ -65,7 +93,21 @@ function resolveRequiredServiceId(
|
||||
);
|
||||
}
|
||||
|
||||
function resolveOptionalRoleMetadata(input: OptionalRoleMetadataInput): {
|
||||
function readStoredRequiredServiceId(
|
||||
context: string,
|
||||
role: PairedRoomRole,
|
||||
storedServiceId?: string | null,
|
||||
): string {
|
||||
if (storedServiceId) {
|
||||
return storedServiceId;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`${context}: cannot read ${role}_service_id from stored row metadata`,
|
||||
);
|
||||
}
|
||||
|
||||
function resolveFilledOptionalRoleMetadata(input: OptionalRoleMetadataInput): {
|
||||
agentType: AgentType | null;
|
||||
serviceId: string | null;
|
||||
} {
|
||||
@@ -73,10 +115,10 @@ function resolveOptionalRoleMetadata(input: OptionalRoleMetadataInput): {
|
||||
return { agentType: null, serviceId: null };
|
||||
}
|
||||
|
||||
const agentType = resolveRequiredAgentType(input);
|
||||
const agentType = resolveFilledRequiredAgentType(input);
|
||||
return {
|
||||
agentType,
|
||||
serviceId: resolveRequiredServiceId(
|
||||
serviceId: resolveFilledRequiredServiceId(
|
||||
input.context,
|
||||
input.role,
|
||||
agentType,
|
||||
@@ -85,6 +127,25 @@ function resolveOptionalRoleMetadata(input: OptionalRoleMetadataInput): {
|
||||
};
|
||||
}
|
||||
|
||||
function readStoredOptionalRoleMetadata(input: OptionalRoleMetadataInput): {
|
||||
agentType: AgentType | null;
|
||||
serviceId: string | null;
|
||||
} {
|
||||
if (!input.storedAgentType && !input.storedServiceId) {
|
||||
return { agentType: null, serviceId: null };
|
||||
}
|
||||
|
||||
const agentType = readStoredRequiredAgentType(input);
|
||||
return {
|
||||
agentType,
|
||||
serviceId: readStoredRequiredServiceId(
|
||||
input.context,
|
||||
input.role,
|
||||
input.storedServiceId,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export interface CanonicalPairedTaskMetadata {
|
||||
ownerAgentType: AgentType;
|
||||
reviewerAgentType: AgentType;
|
||||
@@ -93,7 +154,7 @@ export interface CanonicalPairedTaskMetadata {
|
||||
reviewerServiceId: string;
|
||||
}
|
||||
|
||||
export function canonicalizePairedTaskMetadata(input: {
|
||||
export function fillCanonicalPairedTaskMetadata(input: {
|
||||
id: string;
|
||||
owner_service_id?: string | null;
|
||||
reviewer_service_id?: string | null;
|
||||
@@ -102,14 +163,14 @@ export function canonicalizePairedTaskMetadata(input: {
|
||||
arbiter_agent_type?: string | null;
|
||||
}): CanonicalPairedTaskMetadata {
|
||||
const context = `paired_tasks(${input.id})`;
|
||||
const ownerAgentType = resolveRequiredAgentType({
|
||||
const ownerAgentType = resolveFilledRequiredAgentType({
|
||||
context,
|
||||
role: 'owner',
|
||||
storedAgentType: input.owner_agent_type,
|
||||
storedServiceId: input.owner_service_id,
|
||||
fallbackAgentType: OWNER_AGENT_TYPE,
|
||||
});
|
||||
const reviewerAgentType = resolveRequiredAgentType({
|
||||
const reviewerAgentType = resolveFilledRequiredAgentType({
|
||||
context,
|
||||
role: 'reviewer',
|
||||
storedAgentType: input.reviewer_agent_type,
|
||||
@@ -124,13 +185,13 @@ export function canonicalizePairedTaskMetadata(input: {
|
||||
normalizeStoredAgentType(input.arbiter_agent_type) ??
|
||||
ARBITER_AGENT_TYPE ??
|
||||
null,
|
||||
ownerServiceId: resolveRequiredServiceId(
|
||||
ownerServiceId: resolveFilledRequiredServiceId(
|
||||
context,
|
||||
'owner',
|
||||
ownerAgentType,
|
||||
input.owner_service_id,
|
||||
),
|
||||
reviewerServiceId: resolveRequiredServiceId(
|
||||
reviewerServiceId: resolveFilledRequiredServiceId(
|
||||
context,
|
||||
'reviewer',
|
||||
reviewerAgentType,
|
||||
@@ -139,6 +200,46 @@ export function canonicalizePairedTaskMetadata(input: {
|
||||
};
|
||||
}
|
||||
|
||||
export function readCanonicalPairedTaskMetadata(input: {
|
||||
id: string;
|
||||
owner_service_id?: string | null;
|
||||
reviewer_service_id?: string | null;
|
||||
owner_agent_type?: string | null;
|
||||
reviewer_agent_type?: string | null;
|
||||
arbiter_agent_type?: string | null;
|
||||
}): CanonicalPairedTaskMetadata {
|
||||
const context = `paired_tasks(${input.id})`;
|
||||
const ownerAgentType = readStoredRequiredAgentType({
|
||||
context,
|
||||
role: 'owner',
|
||||
storedAgentType: input.owner_agent_type,
|
||||
storedServiceId: input.owner_service_id,
|
||||
});
|
||||
const reviewerAgentType = readStoredRequiredAgentType({
|
||||
context,
|
||||
role: 'reviewer',
|
||||
storedAgentType: input.reviewer_agent_type,
|
||||
storedServiceId: input.reviewer_service_id,
|
||||
});
|
||||
|
||||
return {
|
||||
ownerAgentType,
|
||||
reviewerAgentType,
|
||||
arbiterAgentType:
|
||||
normalizeStoredAgentType(input.arbiter_agent_type) ?? null,
|
||||
ownerServiceId: readStoredRequiredServiceId(
|
||||
context,
|
||||
'owner',
|
||||
input.owner_service_id,
|
||||
),
|
||||
reviewerServiceId: readStoredRequiredServiceId(
|
||||
context,
|
||||
'reviewer',
|
||||
input.reviewer_service_id,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export interface CanonicalChannelOwnerLeaseMetadata {
|
||||
ownerAgentType: AgentType;
|
||||
reviewerAgentType: AgentType | null;
|
||||
@@ -148,7 +249,7 @@ export interface CanonicalChannelOwnerLeaseMetadata {
|
||||
arbiterServiceId: string | null;
|
||||
}
|
||||
|
||||
export function canonicalizeChannelOwnerLeaseMetadata(input: {
|
||||
export function fillCanonicalChannelOwnerLeaseMetadata(input: {
|
||||
chat_jid: string;
|
||||
owner_service_id?: string | null;
|
||||
reviewer_service_id?: string | null;
|
||||
@@ -158,19 +259,19 @@ export function canonicalizeChannelOwnerLeaseMetadata(input: {
|
||||
arbiter_agent_type?: string | null;
|
||||
}): CanonicalChannelOwnerLeaseMetadata {
|
||||
const context = `channel_owner(${input.chat_jid})`;
|
||||
const ownerAgentType = resolveRequiredAgentType({
|
||||
const ownerAgentType = resolveFilledRequiredAgentType({
|
||||
context,
|
||||
role: 'owner',
|
||||
storedAgentType: input.owner_agent_type,
|
||||
storedServiceId: input.owner_service_id,
|
||||
});
|
||||
const reviewer = resolveOptionalRoleMetadata({
|
||||
const reviewer = resolveFilledOptionalRoleMetadata({
|
||||
context,
|
||||
role: 'reviewer',
|
||||
storedAgentType: input.reviewer_agent_type,
|
||||
storedServiceId: input.reviewer_service_id,
|
||||
});
|
||||
const arbiter = resolveOptionalRoleMetadata({
|
||||
const arbiter = resolveFilledOptionalRoleMetadata({
|
||||
context,
|
||||
role: 'arbiter',
|
||||
storedAgentType: input.arbiter_agent_type,
|
||||
@@ -181,7 +282,7 @@ export function canonicalizeChannelOwnerLeaseMetadata(input: {
|
||||
ownerAgentType,
|
||||
reviewerAgentType: reviewer.agentType,
|
||||
arbiterAgentType: arbiter.agentType,
|
||||
ownerServiceId: resolveRequiredServiceId(
|
||||
ownerServiceId: resolveFilledRequiredServiceId(
|
||||
context,
|
||||
'owner',
|
||||
ownerAgentType,
|
||||
@@ -192,6 +293,49 @@ export function canonicalizeChannelOwnerLeaseMetadata(input: {
|
||||
};
|
||||
}
|
||||
|
||||
export function readCanonicalChannelOwnerLeaseMetadata(input: {
|
||||
chat_jid: string;
|
||||
owner_service_id?: string | null;
|
||||
reviewer_service_id?: string | null;
|
||||
arbiter_service_id?: string | null;
|
||||
owner_agent_type?: string | null;
|
||||
reviewer_agent_type?: string | null;
|
||||
arbiter_agent_type?: string | null;
|
||||
}): CanonicalChannelOwnerLeaseMetadata {
|
||||
const context = `channel_owner(${input.chat_jid})`;
|
||||
const ownerAgentType = readStoredRequiredAgentType({
|
||||
context,
|
||||
role: 'owner',
|
||||
storedAgentType: input.owner_agent_type,
|
||||
storedServiceId: input.owner_service_id,
|
||||
});
|
||||
const reviewer = readStoredOptionalRoleMetadata({
|
||||
context,
|
||||
role: 'reviewer',
|
||||
storedAgentType: input.reviewer_agent_type,
|
||||
storedServiceId: input.reviewer_service_id,
|
||||
});
|
||||
const arbiter = readStoredOptionalRoleMetadata({
|
||||
context,
|
||||
role: 'arbiter',
|
||||
storedAgentType: input.arbiter_agent_type,
|
||||
storedServiceId: input.arbiter_service_id,
|
||||
});
|
||||
|
||||
return {
|
||||
ownerAgentType,
|
||||
reviewerAgentType: reviewer.agentType,
|
||||
arbiterAgentType: arbiter.agentType,
|
||||
ownerServiceId: readStoredRequiredServiceId(
|
||||
context,
|
||||
'owner',
|
||||
input.owner_service_id,
|
||||
),
|
||||
reviewerServiceId: reviewer.serviceId,
|
||||
arbiterServiceId: arbiter.serviceId,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeHandoffRole(
|
||||
role: string | null | undefined,
|
||||
): PairedRoomRole | null {
|
||||
@@ -232,7 +376,7 @@ export interface CanonicalServiceHandoffMetadata {
|
||||
targetServiceId: string;
|
||||
}
|
||||
|
||||
export function canonicalizeServiceHandoffMetadata(input: {
|
||||
export function fillCanonicalServiceHandoffMetadata(input: {
|
||||
id: number | string;
|
||||
chat_jid: string;
|
||||
source_service_id?: string | null;
|
||||
@@ -265,8 +409,6 @@ export function canonicalizeServiceHandoffMetadata(input: {
|
||||
`${context}: source_agent_type conflicts with source_service_id`,
|
||||
);
|
||||
}
|
||||
const sourceAgentType =
|
||||
storedSourceAgentType ?? inferredSourceAgentType ?? null;
|
||||
const storedTargetAgentType = normalizeStoredAgentType(
|
||||
input.target_agent_type,
|
||||
);
|
||||
@@ -301,12 +443,133 @@ export function canonicalizeServiceHandoffMetadata(input: {
|
||||
);
|
||||
}
|
||||
|
||||
const sourceAgentTypeForShadow =
|
||||
storedSourceAgentType ?? inferredSourceAgentType ?? null;
|
||||
const sourceServiceId =
|
||||
input.source_service_id ??
|
||||
(sourceRole != null && sourceAgentType != null
|
||||
? resolveRoleServiceShadow(sourceRole, sourceAgentType)
|
||||
(sourceRole != null && sourceAgentTypeForShadow != null
|
||||
? resolveRoleServiceShadow(sourceRole, sourceAgentTypeForShadow)
|
||||
: null) ??
|
||||
SERVICE_SESSION_SCOPE;
|
||||
const sourceAgentType =
|
||||
storedSourceAgentType ??
|
||||
inferredSourceAgentType ??
|
||||
inferAgentTypeFromServiceShadow(sourceServiceId) ??
|
||||
null;
|
||||
|
||||
assertStoredRoleMatchesServiceShadow({
|
||||
context,
|
||||
storedRole: sourceRole,
|
||||
agentType: sourceAgentType,
|
||||
serviceId: sourceServiceId,
|
||||
roleField: 'source_role',
|
||||
serviceField: 'source_service_id',
|
||||
});
|
||||
assertStoredRoleMatchesServiceShadow({
|
||||
context,
|
||||
storedRole: targetRole,
|
||||
agentType: targetAgentType,
|
||||
serviceId: targetServiceId,
|
||||
roleField: 'target_role',
|
||||
serviceField: 'target_service_id',
|
||||
});
|
||||
|
||||
return {
|
||||
sourceRole,
|
||||
targetRole,
|
||||
sourceAgentType,
|
||||
targetAgentType,
|
||||
sourceServiceId,
|
||||
targetServiceId,
|
||||
};
|
||||
}
|
||||
|
||||
function readStoredHandoffAgentType(args: {
|
||||
context: string;
|
||||
field: 'source_agent_type' | 'target_agent_type';
|
||||
serviceField: 'source_service_id' | 'target_service_id';
|
||||
storedAgentType?: string | null;
|
||||
storedServiceId?: string | null;
|
||||
}): AgentType {
|
||||
const persistedAgentType = normalizeStoredAgentType(args.storedAgentType);
|
||||
const inferredAgentType = inferAgentTypeFromServiceShadow(
|
||||
args.storedServiceId,
|
||||
);
|
||||
if (
|
||||
persistedAgentType &&
|
||||
inferredAgentType &&
|
||||
persistedAgentType !== inferredAgentType
|
||||
) {
|
||||
throw new Error(
|
||||
`${args.context}: ${args.field} conflicts with ${args.serviceField}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (persistedAgentType) {
|
||||
return persistedAgentType;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`${args.context}: cannot read ${args.field} from stored row metadata`,
|
||||
);
|
||||
}
|
||||
|
||||
function readStoredHandoffServiceId(args: {
|
||||
context: string;
|
||||
field: 'source_service_id' | 'target_service_id';
|
||||
storedServiceId?: string | null;
|
||||
}): string {
|
||||
if (args.storedServiceId) {
|
||||
return args.storedServiceId;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`${args.context}: cannot read ${args.field} from stored row metadata`,
|
||||
);
|
||||
}
|
||||
|
||||
export function readCanonicalServiceHandoffMetadata(input: {
|
||||
id: number | string;
|
||||
chat_jid: string;
|
||||
source_service_id?: string | null;
|
||||
target_service_id?: string | null;
|
||||
source_role?: string | null;
|
||||
target_role?: string | null;
|
||||
intended_role?: string | null;
|
||||
source_agent_type?: string | null;
|
||||
target_agent_type?: string | null;
|
||||
}): CanonicalServiceHandoffMetadata {
|
||||
const context = `service_handoffs(${input.id})`;
|
||||
const sourceRole =
|
||||
normalizeHandoffRole(input.source_role) ??
|
||||
normalizeHandoffRole(input.intended_role);
|
||||
const targetRole =
|
||||
normalizeHandoffRole(input.target_role) ??
|
||||
normalizeHandoffRole(input.intended_role);
|
||||
const sourceServiceId = readStoredHandoffServiceId({
|
||||
context,
|
||||
field: 'source_service_id',
|
||||
storedServiceId: input.source_service_id,
|
||||
});
|
||||
const targetServiceId = readStoredHandoffServiceId({
|
||||
context,
|
||||
field: 'target_service_id',
|
||||
storedServiceId: input.target_service_id,
|
||||
});
|
||||
const sourceAgentType = readStoredHandoffAgentType({
|
||||
context,
|
||||
field: 'source_agent_type',
|
||||
serviceField: 'source_service_id',
|
||||
storedAgentType: input.source_agent_type,
|
||||
storedServiceId: sourceServiceId,
|
||||
});
|
||||
const targetAgentType = readStoredHandoffAgentType({
|
||||
context,
|
||||
field: 'target_agent_type',
|
||||
serviceField: 'target_service_id',
|
||||
storedAgentType: input.target_agent_type,
|
||||
storedServiceId: targetServiceId,
|
||||
});
|
||||
|
||||
assertStoredRoleMatchesServiceShadow({
|
||||
context,
|
||||
@@ -351,7 +614,7 @@ export function inferExecutionLeaseServiceIdFromCanonicalMetadata(
|
||||
): string | null {
|
||||
switch (row.role) {
|
||||
case 'owner': {
|
||||
const owner = resolveOptionalRoleMetadata({
|
||||
const owner = resolveFilledOptionalRoleMetadata({
|
||||
context: `paired_task_execution_leases(${row.rowid})`,
|
||||
role: 'owner',
|
||||
storedAgentType: row.owner_agent_type,
|
||||
@@ -360,7 +623,7 @@ export function inferExecutionLeaseServiceIdFromCanonicalMetadata(
|
||||
return owner.serviceId;
|
||||
}
|
||||
case 'reviewer': {
|
||||
const reviewer = resolveOptionalRoleMetadata({
|
||||
const reviewer = resolveFilledOptionalRoleMetadata({
|
||||
context: `paired_task_execution_leases(${row.rowid})`,
|
||||
role: 'reviewer',
|
||||
storedAgentType: row.reviewer_agent_type,
|
||||
@@ -369,7 +632,7 @@ export function inferExecutionLeaseServiceIdFromCanonicalMetadata(
|
||||
return reviewer.serviceId;
|
||||
}
|
||||
case 'arbiter': {
|
||||
const arbiter = resolveOptionalRoleMetadata({
|
||||
const arbiter = resolveFilledOptionalRoleMetadata({
|
||||
context: `paired_task_execution_leases(${row.rowid})`,
|
||||
role: 'arbiter',
|
||||
storedAgentType: row.arbiter_agent_type,
|
||||
|
||||
Reference in New Issue
Block a user