/* Resolve a dotted field path through a data object, reporting the first missing segment — the shared primitive behind content-reference substitution (RFC-0045 / RFC-0138). Do not perform substitution or formatting — only path resolution. Do not throw on a missing field; report it in the result. RFC-0155: add Compass scaffolding markers for compass.validate compliance. */ export interface FieldResolution { value: unknown; missingField: string | null; } /** * Walks a field path through a data object. Returns the value and the first * missing field name, or null if the entire path resolves. */ export function resolveFieldPath(data: unknown, fieldPath: string[]): FieldResolution { let value: unknown = data; for (let i = 0; i < fieldPath.length; i++) { const field = fieldPath[i]; if (value === null || value === undefined) { return { value: undefined, missingField: field }; } if (typeof value !== "object") { return { value: undefined, missingField: field }; } if (!(field in value)) { const nextField = i + 1 < fieldPath.length ? fieldPath[i + 1] : null; return { value: undefined, missingField: nextField }; } value = (value as Record)[field]; } return { value, missingField: null }; }