import type { ClassroomGenerationJob } from '@/lib/server/classroom-job-store'; import { observeResourceAuthorization, type ResourceAuthorizationObservationDeps, } from '@/lib/server/authz/shadow-observer'; import type { ResourceAuthorizationAction, ResourceOwnership, } from '@/lib/server/authz/resource-ownership'; export function classroomJobOwnership(job: ClassroomGenerationJob): ResourceOwnership { const hasOwner = Object.prototype.hasOwnProperty.call(job, 'ownerPrincipalId'); const hasGuest = Object.prototype.hasOwnProperty.call(job, 'guestPrincipalId'); if (hasOwner && hasGuest) return { state: 'unknown' }; if (hasOwner) { if (typeof job.ownerPrincipalId === 'string' && job.ownerPrincipalId.trim().length > 0) { return { state: 'owned', ownerPrincipalId: job.ownerPrincipalId }; } return { state: 'unknown' }; } if (hasGuest) { if (typeof job.guestPrincipalId === 'string' && job.guestPrincipalId.trim().length > 0) { return { state: 'guest-owned', guestPrincipalId: job.guestPrincipalId }; } return { state: 'unknown' }; } return { state: 'legacy-unowned' }; } /** Observe-only classroom job policy seam; it does not authorize the route. */ export function observeClassroomJobAuthorization( request: Request, job: ClassroomGenerationJob, action: ResourceAuthorizationAction, deps?: ResourceAuthorizationObservationDeps, ): Promise { return observeResourceAuthorization( { request, resourceType: 'classroom-generation-job', resourceId: job.id, action, ownership: classroomJobOwnership(job), }, deps, ); }