@happyvertical/smrt-education 0.57.45 → 0.57.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +7 -1
  3. package/agents/learner-service.md +31 -2
  4. package/agents/question-extraction.md +108 -0
  5. package/agents/submission-service.md +15 -0
  6. package/dist/chunks/{workbook-photo-service-DKgoUHeb.js → workbook-photo-service-B7Tujv__.js} +6494 -1153
  7. package/dist/chunks/workbook-photo-service-B7Tujv__.js.map +1 -0
  8. package/dist/collections.d.ts +4 -1
  9. package/dist/collections.d.ts.map +1 -1
  10. package/dist/course-authoring-contracts.d.ts +1 -1
  11. package/dist/course-authoring-contracts.d.ts.map +1 -1
  12. package/dist/index.d.ts +11 -5
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1049 -4628
  15. package/dist/index.js.map +1 -1
  16. package/dist/ingestion.d.ts +2 -0
  17. package/dist/ingestion.d.ts.map +1 -1
  18. package/dist/ingestion.js +197 -2
  19. package/dist/ingestion.js.map +1 -1
  20. package/dist/learner-history.d.ts +50 -0
  21. package/dist/learner-history.d.ts.map +1 -0
  22. package/dist/learner-service.d.ts +78 -2
  23. package/dist/learner-service.d.ts.map +1 -1
  24. package/dist/manifest.json +4255 -1444
  25. package/dist/question-extraction-contracts.d.ts +231 -0
  26. package/dist/question-extraction-contracts.d.ts.map +1 -0
  27. package/dist/question-extraction-ingestion.d.ts +44 -0
  28. package/dist/question-extraction-ingestion.d.ts.map +1 -0
  29. package/dist/question-extraction-models.d.ts +56 -0
  30. package/dist/question-extraction-models.d.ts.map +1 -0
  31. package/dist/question-extraction-service.d.ts +71 -0
  32. package/dist/question-extraction-service.d.ts.map +1 -0
  33. package/dist/question-extraction.d.ts +317 -0
  34. package/dist/question-extraction.d.ts.map +1 -0
  35. package/dist/smrt-knowledge.json +961 -143
  36. package/dist/submission-service.d.ts +34 -1
  37. package/dist/submission-service.d.ts.map +1 -1
  38. package/dist/submissions.d.ts +25 -1
  39. package/dist/submissions.d.ts.map +1 -1
  40. package/package.json +10 -10
  41. package/dist/chunks/workbook-photo-service-DKgoUHeb.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ingestion.js","names":["book","current","value"],"sources":["../src/intake-original-evidence.ts","../src/ingestion-isolation.ts","../src/family-intake-ingestion.ts","../src/family-intake-service.ts","../src/workbook-photo-ingestion.ts","../src/ingestion.ts"],"sourcesContent":["/** Shared source convention: metadata parents contain independent originals;\n * descendants of a supported image/PDF original are its renditions. */\nexport const supportedIntakeOriginal = (type: string) =>\n ['image/png', 'image/jpeg', 'image/webp', 'application/pdf'].includes(type);\n\nexport function intakeOriginalEvidence<\n T extends {\n id: string;\n parentEvidenceId: string | null;\n mediaType: string;\n partId: string;\n },\n>(evidence: readonly T[]): T[] {\n const byId = new Map(evidence.map((entry) => [entry.id, entry]));\n return evidence\n .filter((entry) => {\n let parentId = entry.parentEvidenceId;\n const visited = new Set([entry.id]);\n while (parentId) {\n if (visited.has(parentId))\n throw new Error('Invalid family evidence lineage');\n visited.add(parentId);\n const parent = byId.get(parentId);\n if (!parent) throw new Error('Incomplete family evidence lineage');\n if (supportedIntakeOriginal(parent.mediaType)) return false;\n parentId = parent.parentEvidenceId;\n }\n return true;\n })\n .sort((a, b) => a.partId.localeCompare(b.partId));\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\n/** Verify a real Linux cgroup-v2 native-memory ceiling before enabling decoders.\n * The worker and its children must remain in this cgroup; deployments must deny\n * cgroup writes/escape and run without privileged container capabilities.\n */\nexport async function requireIngestionMemoryLimit(\n maximumBytes: number,\n): Promise<{ memoryLimitBytes: number }> {\n if (process.platform !== 'linux')\n throw new Error(\n 'Extraction requires a Linux cgroup-v2 memory-limited worker',\n );\n if (!Number.isSafeInteger(maximumBytes) || maximumBytes < 1)\n throw new Error('Invalid worker memory ceiling');\n const membership = await readFile('/proc/self/cgroup', 'utf8');\n const entry = membership.split('\\n').find((line) => line.startsWith('0::'));\n if (!entry) throw new Error('No cgroup-v2 membership');\n const relative = entry.slice(3);\n if (!relative.startsWith('/') || relative.split('/').includes('..'))\n throw new Error('Invalid cgroup membership');\n const root = '/sys/fs/cgroup';\n let directory = resolve(root, `.${relative}`);\n let limit = Number.POSITIVE_INFINITY;\n // An ancestor limit is authoritative too. Account for inherited limits while\n // never accepting a mere configuration promise or Node heap setting.\n while (directory === root || directory.startsWith(`${root}/`)) {\n const value = (await readFile(`${directory}/memory.max`, 'utf8')).trim();\n if (value !== 'max') {\n if (!/^\\d+$/.test(value)) throw new Error('Invalid cgroup memory limit');\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed) || parsed < 1)\n throw new Error('Invalid cgroup memory limit');\n limit = Math.min(limit, parsed);\n }\n if (directory === root) break;\n directory = resolve(directory, '..');\n }\n if (!Number.isFinite(limit) || limit > maximumBytes)\n throw new Error(\n 'Worker native-memory ceiling is missing or exceeds policy',\n );\n return { memoryLimitBytes: limit };\n}\n","/** Public family receipt bridge; transport source identity never supplies authority. */\nimport { createHash } from 'node:crypto';\nimport type {\n IngestionScope,\n IngestionService,\n ReceiveInput,\n} from '@happyvertical/smrt-ingestion/server';\nimport {\n type FamilyIntakeRequest,\n familyIntakeScopeId,\n} from './family-intake-contracts.js';\nimport type { FamilyIntakeService } from './family-intake-service.js';\nimport {\n intakeOriginalEvidence,\n supportedIntakeOriginal,\n} from './intake-original-evidence.js';\nimport type { SubmissionPage } from './submission-service.js';\n\ntype Input = {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n family: FamilyIntakeService;\n request: FamilyIntakeRequest;\n};\nfunction assertScope(input: Input) {\n if (\n input.scope.tenantId !== input.request.tenantId ||\n input.scope.actorId !== input.request.actorUserId ||\n input.scope.confidentialScopeId !==\n familyIntakeScopeId(input.request.tenantId)\n )\n throw new Error('Family intake scope mismatch');\n}\n/** Receive before learner attribution; duplicate deliveries repair interrupted retention. */\nexport async function receiveFamilyIntake(\n input: Input & { receive: ReceiveInput },\n) {\n assertScope(input);\n await input.family.authorizeFamilyIntake(\n input.request,\n 'education.family-intake.receive',\n );\n const receipt = await input.ingestion.receive(input.receive);\n if (!('itemId' in receipt) || !receipt.itemId)\n return { receipt, intake: null };\n return {\n receipt,\n intake: await retainFamilyIntakeReceipt({\n ...input,\n itemId: receipt.itemId,\n }),\n };\n}\n/** Copy authorized original evidence once into durable education ownership. */\nexport async function retainFamilyIntakeReceipt(\n input: Input & { itemId: string },\n) {\n assertScope(input);\n await input.family.authorizeFamilyIntake(\n input.request,\n 'education.family-intake.receive',\n );\n const identity = await input.ingestion.getReceiptSource(input.itemId);\n const evidence = await input.ingestion.getEvidence(input.itemId);\n if (evidence.length > 200)\n throw new Error('Family receipt evidence exceeds limit');\n const source = {\n ...identity,\n evidence: evidence.map((e) => ({\n evidenceId: e.id,\n partId: e.partId,\n parentEvidenceId: e.parentEvidenceId,\n mimeType: e.mediaType,\n sha256: e.contentHash,\n })),\n };\n const supported = supportedIntakeOriginal;\n const originalEvidence = intakeOriginalEvidence(evidence);\n if (\n originalEvidence.some(\n (e) => e.mediaType !== 'application/json' && !supported(e.mediaType),\n )\n )\n throw new Error(\n 'Unsupported family original: only JPEG, PNG, WebP and PDF are supported',\n );\n const originals = originalEvidence.filter((e) => supported(e.mediaType));\n if (\n !originals.length ||\n originals.length > 100 ||\n originals.some(\n (e) => e.byteLength < 1 || e.byteLength > 25 * 1024 * 1024,\n ) ||\n originals.reduce((n, e) => n + e.byteLength, 0) > 100 * 1024 * 1024\n )\n throw new Error('Unsupported or oversized family intake');\n const pages: SubmissionPage[] = [];\n const extensions = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/webp': 'webp',\n 'application/pdf': 'pdf',\n };\n for (const original of originals) {\n if (!Object.hasOwn(extensions, original.mediaType))\n throw new Error('Unsupported family original');\n const data = await input.ingestion.readEvidence(input.itemId, original.id);\n if (\n data.length !== original.byteLength ||\n createHash('sha256').update(data).digest('hex') !== original.contentHash\n )\n throw new Error('Family receipt integrity mismatch');\n pages.push({\n name:\n original.filename ||\n `${original.id}.${extensions[original.mediaType as keyof typeof extensions]}`,\n mimeType: original.mediaType as SubmissionPage['mimeType'],\n data: Buffer.from(data),\n });\n }\n return input.family.retainFamilyIntake({\n ...input.request,\n itemId: input.itemId,\n source,\n pages,\n });\n}\n","import { withPrivateAssetAccess } from '@happyvertical/smrt-assets';\nimport { getCurrentTenant } from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { CatalogAuthorizer } from './catalog-service.js';\nimport type {\n FamilyIntakeAuthorizer,\n FamilyIntakeRequest,\n FamilyIntakeSource,\n FamilyIntakeView,\n} from './family-intake-contracts.js';\nimport {\n FamilyIntakeAssetCollection,\n FamilyIntakeCollection,\n FamilyIntakeDecisionCollection,\n} from './family-intake-models.js';\nimport {\n LearnerAuthorizationError,\n type LearnerAuthorizer,\n} from './learner-service.js';\nimport type {\n SubmissionPage,\n SubmissionServiceOptions,\n} from './submission-service.js';\nimport {\n WorkbookPhotoAssetCollection,\n WorkbookPhotoIntakeCollection,\n} from './workbook-photo-models.js';\nimport { WorkbookPhotoService } from './workbook-photo-service.js';\n\nconst canonical = (value: unknown): string =>\n JSON.stringify(value, (_key, v) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => a.localeCompare(b)),\n )\n : v,\n );\nfunction digest(value: string | Uint8Array): string {\n const crypto =\n typeof process !== 'undefined' && process.getBuiltinModule?.('node:crypto');\n if (!crypto) throw new Error('Family intake requires a Node server');\n return crypto.createHash('sha256').update(value).digest('hex');\n}\nfunction key(value: string) {\n if (\n typeof value !== 'string' ||\n !value.trim() ||\n value.length > 200 ||\n Array.from(value).some(\n (c) => c.charCodeAt(0) < 32 || c.charCodeAt(0) === 127,\n )\n )\n throw new Error('Invalid family intake key');\n}\ntype Selection = FamilyIntakeRequest & { intakeId: string };\ntype Decision =\n | { kind: 'assign'; learnerId: string; reason: string }\n | { kind: 'adopt'; learnerId: string; photoIntakeId: string };\n/** Guardian-only original ownership before learner identity. Assignment never grades work. */\nexport class FamilyIntakeService extends WorkbookPhotoService {\n constructor(\n db: DatabaseInterface,\n authorize: LearnerAuthorizer,\n authorizeCatalog: CatalogAuthorizer,\n private readonly familyOptions: SubmissionServiceOptions,\n private readonly authorizeFamily: FamilyIntakeAuthorizer,\n ) {\n super(db, authorize, authorizeCatalog, familyOptions);\n }\n protected override createTransactionService(db: DatabaseInterface): this {\n return new FamilyIntakeService(\n db,\n this.authorize,\n this.authorizeCatalog,\n this.familyOptions,\n this.authorizeFamily,\n ) as this;\n }\n async authorizeFamilyIntake(\n request: FamilyIntakeRequest,\n action: Parameters<FamilyIntakeAuthorizer>[0]['action'] = 'education.family-intake.read',\n ) {\n this.assertServiceOpen();\n const context = getCurrentTenant();\n if (\n !context ||\n context.superAdminBypass ||\n context.tenantId !== request.tenantId ||\n context.userId !== request.actorUserId ||\n !request.tenantId ||\n !request.actorUserId ||\n !(await this.db.get('memberships', {\n tenant_id: request.tenantId,\n user_id: request.actorUserId,\n status: 'active',\n })) ||\n !(await this.db.get('users', {\n id: request.actorUserId,\n status: 'active',\n })) ||\n (await this.authorizeFamily({\n ...request,\n executor: this.db,\n action,\n })) !== true\n )\n throw new LearnerAuthorizationError();\n }\n private async familyRow(request: Selection) {\n await this.authorizeFamilyIntake(request);\n const row = await (\n await FamilyIntakeCollection.create({ db: this.db })\n ).get(\n { id: request.intakeId, tenantId: request.tenantId },\n { cache: false },\n );\n if (!row) throw new LearnerAuthorizationError();\n return row;\n }\n private async familyDecisions(request: Selection) {\n return (\n await (\n await FamilyIntakeDecisionCollection.create({ db: this.db })\n ).list({\n where: { tenantId: request.tenantId, intakeId: request.intakeId },\n limit: 10000,\n })\n ).sort((a, b) => a.sequence - b.sequence);\n }\n private async lockFamily(request: Selection) {\n await this.db.query(\n 'UPDATE family_intakes SET id=id WHERE id=? AND tenant_id=?',\n [request.intakeId, request.tenantId],\n );\n }\n private async appendFamily(\n request: Selection,\n requestKey: string,\n body: Decision,\n ) {\n return (\n await FamilyIntakeDecisionCollection.create({ db: this.db })\n ).create({\n _insertOnly: true,\n tenantId: request.tenantId,\n intakeId: request.intakeId,\n actorUserId: request.actorUserId,\n requestKey,\n sequence: (await this.familyDecisions(request)).length + 1,\n bodyJson: canonical(body),\n });\n }\n async retainFamilyIntake(\n request: FamilyIntakeRequest & {\n itemId: string;\n source: FamilyIntakeSource;\n pages: readonly SubmissionPage[];\n },\n ): Promise<FamilyIntakeView> {\n return this.composeMutation(async (service) => {\n if (service.executorBorrowed)\n throw new Error('Family storage requires an owned transaction');\n await service.authorizeFamilyIntake(\n request,\n 'education.family-intake.receive',\n );\n key(request.itemId);\n for (const value of [\n request.source?.sourceId,\n request.source?.sourceVersion,\n request.source?.deliveryKey,\n ])\n key(value);\n if (Buffer.byteLength(canonical(request.source)) > 128 * 1024)\n throw new Error('Family source provenance exceeds limit');\n if (request.source.evidence !== undefined) {\n if (\n !Array.isArray(request.source.evidence) ||\n request.source.evidence.length > 200\n )\n throw new Error('Invalid family source evidence');\n for (const evidence of request.source.evidence) {\n for (const value of [\n evidence.evidenceId,\n evidence.partId,\n evidence.mimeType,\n ])\n key(value);\n if (evidence.parentEvidenceId !== null)\n key(evidence.parentEvidenceId);\n if (\n typeof evidence.sha256 !== 'string' ||\n !/^[a-f0-9]{64}$/.test(evidence.sha256)\n )\n throw new Error('Invalid family source evidence hash');\n }\n }\n // Persist the public provenance contract, never arbitrary adapter options.\n const source: FamilyIntakeSource = {\n sourceId: request.source.sourceId,\n sourceVersion: request.source.sourceVersion,\n deliveryKey: request.source.deliveryKey,\n ...(request.source.evidence\n ? {\n evidence: request.source.evidence.map((e) => ({\n evidenceId: e.evidenceId,\n partId: e.partId,\n parentEvidenceId: e.parentEvidenceId,\n mimeType: e.mimeType,\n sha256: e.sha256,\n })),\n }\n : {}),\n };\n service.validatePages(request.pages);\n if (\n request.pages.reduce((n, p) => n + p.data.length, 0) >\n 100 * 1024 * 1024\n )\n throw new Error('Family intake exceeds total byte limit');\n // Serialize first-receipt races before consulting the unique receipt key.\n await service.db.query('UPDATE tenants SET id=id WHERE id=?', [\n request.tenantId,\n ]);\n const contentDigest = digest(\n canonical({\n source,\n pages: request.pages.map((p) => ({\n name: p.name,\n mimeType: p.mimeType,\n sha256: digest(p.data),\n })),\n }),\n );\n const collection = await FamilyIntakeCollection.create({\n db: service.db,\n });\n const prior = await collection.get(\n { tenantId: request.tenantId, itemId: request.itemId },\n { cache: false },\n );\n if (prior) {\n if (prior.contentDigest !== contentDigest)\n throw new Error('Family receipt retry content conflict');\n return service.getFamilyIntake({\n ...request,\n intakeId: String(prior.id),\n });\n }\n const actor = await service.db.get('users', { id: request.actorUserId });\n if (!actor?.profile_id) throw new LearnerAuthorizationError();\n const row = await collection.create({\n _insertOnly: true,\n tenantId: request.tenantId,\n itemId: request.itemId,\n actorUserId: request.actorUserId,\n ownerProfileId: actor.profile_id,\n contentDigest,\n sourceJson: canonical(source),\n });\n const links = await FamilyIntakeAssetCollection.create({\n db: service.db,\n });\n for (const [position, page] of request.pages.entries()) {\n const asset = await service.storePage(request, actor.profile_id, page);\n await links.create({\n _insertOnly: true,\n tenantId: request.tenantId,\n intakeId: String(row.id),\n assetId: String(asset.id),\n name: page.name,\n mimeType: page.mimeType,\n sha256: digest(page.data),\n position,\n });\n }\n return service.getFamilyIntake({ ...request, intakeId: String(row.id) });\n });\n }\n async getFamilyIntake(request: Selection): Promise<FamilyIntakeView> {\n const row = await this.familyRow(request);\n const decisions = await this.familyDecisions(request);\n const assignment = decisions\n .map((d) => JSON.parse(d.bodyJson) as Decision)\n .findLast((d) => d.kind === 'assign');\n const adoption = decisions\n .map((d) => JSON.parse(d.bodyJson) as Decision)\n .find((d) => d.kind === 'adopt');\n const originals = await (\n await FamilyIntakeAssetCollection.create({ db: this.db })\n ).list({\n where: { tenantId: request.tenantId, intakeId: request.intakeId },\n orderBy: 'position',\n limit: 100,\n });\n return {\n id: String(row.id),\n itemId: row.itemId,\n source: JSON.parse(row.sourceJson),\n revision: decisions.length,\n learnerId: assignment?.learnerId ?? null,\n photoIntakeId: adoption?.kind === 'adopt' ? adoption.photoIntakeId : null,\n originals: originals.map((o) => ({\n assetId: o.assetId,\n name: o.name,\n mimeType: o.mimeType,\n sha256: o.sha256,\n })),\n };\n }\n async listFamilyIntakes(\n request: FamilyIntakeRequest,\n options: { limit?: number; offset?: number } = {},\n ): Promise<FamilyIntakeView[]> {\n await this.authorizeFamilyIntake(request);\n const limit = options.limit ?? 20,\n offset = options.offset ?? 0;\n if (\n !Number.isSafeInteger(limit) ||\n limit < 1 ||\n limit > 100 ||\n !Number.isSafeInteger(offset) ||\n offset < 0\n )\n throw new Error('Invalid family inbox page');\n const rows = await (\n await FamilyIntakeCollection.create({ db: this.db })\n ).list({\n where: { tenantId: request.tenantId },\n orderBy: 'createdAt DESC',\n limit,\n offset,\n });\n return Promise.all(\n rows.map((row) =>\n this.getFamilyIntake({ ...request, intakeId: String(row.id) }),\n ),\n );\n }\n async countFamilyIntakes(request: FamilyIntakeRequest): Promise<number> {\n await this.authorizeFamilyIntake(request);\n const rows = await this.db.query(\n 'SELECT COUNT(*) AS total FROM family_intakes f WHERE f.tenant_id=? AND NOT EXISTS (SELECT 1 FROM workbook_photo_intakes p WHERE p.tenant_id=f.tenant_id AND p.family_intake_id=f.id)',\n [request.tenantId],\n );\n return Number(rows.rows[0]?.total ?? 0);\n }\n async getFamilyIntakeTimeline(request: Selection) {\n await this.familyRow(request);\n return (await this.familyDecisions(request)).map((d) => ({\n id: String(d.id),\n revision: d.sequence,\n actorUserId: d.actorUserId,\n requestKey: d.requestKey,\n decision: JSON.parse(d.bodyJson) as Decision,\n }));\n }\n async readFamilyIntakeOriginal(request: Selection & { assetId: string }) {\n const row = await this.familyRow(request);\n const view = await this.getFamilyIntake(request);\n const original = view.originals.find((o) => o.assetId === request.assetId);\n if (!original) throw new LearnerAuthorizationError();\n return withPrivateAssetAccess(\n {\n tenantId: request.tenantId,\n actorUserId: request.actorUserId,\n ownerProfileId: row.ownerProfileId,\n assetIds: [request.assetId],\n },\n async () => {\n const runtime = await this.assets();\n const asset = await runtime.collection.get(\n {\n id: request.assetId,\n tenantId: request.tenantId,\n ownerProfileId: row.ownerProfileId,\n },\n { cache: false },\n );\n if (asset?.accessMode !== 'private')\n throw new LearnerAuthorizationError();\n const data = await runtime.store.read(asset);\n if (digest(data) !== original.sha256)\n throw new Error('Retained family original integrity mismatch');\n return { data, mimeType: original.mimeType };\n },\n );\n }\n async assignFamilyIntake(\n request: Selection & {\n learnerId: string;\n guardianRelationshipId: string;\n requestKey: string;\n expectedRevision: number;\n reason: string;\n },\n ): Promise<FamilyIntakeView> {\n return this.composeMutation(async (service) => {\n await service.authorizeFamilyIntake(\n request,\n 'education.family-intake.assign',\n );\n await service.lockFamily(request);\n await service.requireActor(request, 'education.learner.plan');\n key(request.requestKey);\n key(request.reason);\n const view = await service.getFamilyIntake(request);\n const body: Decision = {\n kind: 'assign',\n learnerId: request.learnerId,\n reason: request.reason,\n };\n const prior = (await service.familyDecisions(request)).find(\n (d) => d.requestKey === request.requestKey,\n );\n if (prior) {\n if (prior.bodyJson !== canonical(body))\n throw new Error('Family decision retry content conflict');\n return view;\n }\n if (view.photoIntakeId)\n throw new Error('Adopted family intake cannot be retargeted');\n if (\n !Number.isSafeInteger(request.expectedRevision) ||\n request.expectedRevision !== view.revision\n )\n throw new Error('Family intake revision conflict');\n await service.appendFamily(request, request.requestKey, body);\n return service.getFamilyIntake(request);\n });\n }\n /** Freeze the explicit assignment and borrow exact originals; no capture or grading. */\n async adoptFamilyIntake(\n request: Selection & {\n learnerId: string;\n guardianRelationshipId: string;\n requestKey: string;\n expectedRevision: number;\n },\n ): Promise<FamilyIntakeView> {\n return this.composeMutation(async (service) => {\n await service.authorizeFamilyIntake(\n request,\n 'education.family-intake.assign',\n );\n await service.lockFamily(request);\n await service.requireActor(request, 'education.learner.plan');\n key(request.requestKey);\n const view = await service.getFamilyIntake(request);\n const prior = (await service.familyDecisions(request)).find(\n (d) => d.requestKey === request.requestKey,\n );\n if (prior) {\n const body = JSON.parse(prior.bodyJson) as Decision;\n if (body.kind !== 'adopt' || body.learnerId !== request.learnerId)\n throw new Error('Family decision retry content conflict');\n return view;\n }\n if (view.photoIntakeId || view.learnerId !== request.learnerId)\n throw new Error('Family intake assignment mismatch');\n if (\n !Number.isSafeInteger(request.expectedRevision) ||\n request.expectedRevision !== view.revision\n )\n throw new Error('Family intake revision conflict');\n const row = await service.familyRow(request);\n // Verify every retained hash before exposing it through a learner-bound join.\n for (const original of view.originals)\n await service.readFamilyIntakeOriginal({\n ...request,\n assetId: original.assetId,\n });\n const photoIntakeId = globalThis.crypto.randomUUID();\n await service.appendFamily(request, request.requestKey, {\n kind: 'adopt',\n learnerId: request.learnerId,\n photoIntakeId,\n });\n const photo = await (\n await WorkbookPhotoIntakeCollection.create({ db: service.db })\n ).create({\n id: photoIntakeId,\n _insertOnly: true,\n tenantId: request.tenantId,\n learnerId: request.learnerId,\n familyIntakeId: request.intakeId,\n itemId: row.itemId,\n actorUserId: row.actorUserId,\n contentDigest: row.contentDigest,\n });\n const links = await WorkbookPhotoAssetCollection.create({\n db: service.db,\n });\n for (const [position, original] of view.originals.entries())\n await links.create({\n _insertOnly: true,\n tenantId: request.tenantId,\n learnerId: request.learnerId,\n intakeId: String(photo.id),\n ...original,\n position,\n });\n\n return service.getFamilyIntake(request);\n });\n }\n}\n","/** Server-only pre-activity intake bridge. Uses public ingestion APIs exclusively. */\nimport { createHash } from 'node:crypto';\nimport type { OperationHandler } from '@happyvertical/smrt-ingestion/execution';\nimport {\n GenerationSnapshotStaleError,\n type IngestionScope,\n type IngestionService,\n ProposalsNotConfiguredError,\n type ReceiveInput,\n} from '@happyvertical/smrt-ingestion/server';\nimport { getCurrentTenant, withTenant } from '@happyvertical/smrt-tenancy';\nimport { registerPermissionDefinitions } from '@happyvertical/smrt-users';\nimport { processEducationAnalysis } from './ingestion.js';\nimport { intakeOriginalEvidence } from './intake-original-evidence.js';\nimport type { LearnerRequest } from './learner-service.js';\nimport type { SubmissionPage } from './submission-service.js';\nimport {\n validateWorkbookPhotoIdentification,\n type WorkbookPhotoProposal,\n} from './workbook-photo-contracts.js';\nimport {\n preservePhotoProposal,\n type WorkbookPhotoService,\n} from './workbook-photo-service.js';\n\nconst MODEL = '@happyvertical/smrt-education:WorkbookPhotoIntake';\nexport const WORKBOOK_PHOTO_HANDLER =\n '@happyvertical/smrt-education:identify-workbook-photo';\nregisterPermissionDefinitions([\n {\n slug: 'workbookphotointakes.read',\n collection: 'workbookphotointakes',\n qualifiedName: MODEL,\n name: 'Identify authorized workbook photos',\n },\n]);\nfunction assertScope(scope: Readonly<IngestionScope>, request: LearnerRequest) {\n if (\n scope.tenantId !== request.tenantId ||\n scope.actorId !== request.actorUserId ||\n scope.confidentialScopeId !== request.learnerId\n )\n throw new Error('Photo intake scope mismatch');\n}\nconst canonical = (value: unknown): string =>\n JSON.stringify(value, (_key, v) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => a.localeCompare(b)),\n )\n : v,\n );\nconst string = {\n type: 'string',\n maxLength: 2000,\n pattern: '^[^\\\\u0000-\\\\u001F\\\\u007F]*$',\n};\nconst schema = {\n type: 'object',\n additionalProperties: false,\n required: [\n 'identification',\n 'confidence',\n 'identityEvidence',\n 'lessonEvidence',\n ],\n properties: {\n workbookId: {\n type: 'string',\n maxLength: 64,\n description:\n 'Exact existing candidate id. Also copy its workbookKey, title and edition into the required identification.workbook object; this selects existing identity, not a new workbook.',\n },\n confidence: { type: 'string', enum: ['confident', 'uncertain'] },\n identityEvidence: {\n type: 'array',\n maxItems: 20,\n items: { ...string, minLength: 1 },\n },\n lessonEvidence: string,\n identification: {\n type: 'object',\n additionalProperties: false,\n required: ['kind', 'workState'],\n properties: {\n kind: {\n type: 'string',\n enum: ['lesson', 'work', 'cover', 'reference', 'uncertain'],\n },\n workState: { type: 'string', enum: ['blank', 'completed', 'unknown'] },\n notes: string,\n workbook: {\n type: 'object',\n additionalProperties: false,\n required: ['workbookKey', 'title'],\n properties: {\n workbookKey: string,\n title: string,\n edition: string,\n publisher: string,\n isbn: string,\n },\n },\n activity: {\n type: 'object',\n additionalProperties: false,\n required: ['pageKey', 'pageLabel'],\n properties: { pageKey: string, pageLabel: string },\n },\n },\n },\n },\n};\n/** Generation proposes material identity only; execution never writes educational outcomes. */\nexport function workbookPhotoIntakeHandlers(input: {\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n}): OperationHandler[] {\n const bound = async <T>(\n context: Parameters<OperationHandler['validate']>[1],\n work: (service: WorkbookPhotoService) => Promise<T>,\n ): Promise<T> => {\n const checked = async (service: WorkbookPhotoService) => {\n await service.assertWorkbookPhotoScope(\n input.request,\n context.scope,\n context.itemId,\n );\n return work(service);\n };\n if (!context.policy.requireReview)\n throw new Error('Photo intake requires review policy');\n if (!context.principal)\n return input.workbooks.withExecutor(context.db, checked);\n const tenant = getCurrentTenant();\n if (\n !tenant ||\n tenant.tenantId !== input.request.tenantId ||\n tenant.userId !== context.principal.context.userId ||\n context.principal.context.tenantId !== input.request.tenantId\n )\n throw new Error('Photo principal tenant mismatch');\n return withTenant(\n {\n ...tenant,\n tenantId: input.request.tenantId,\n userId: input.request.actorUserId,\n superAdminBypass: false,\n },\n () => input.workbooks.withExecutor(context.db, checked),\n );\n };\n const authorize = async (\n context: Parameters<OperationHandler['validate']>[1],\n ) =>\n bound(context, async (service) => {\n await service.authorizePhotoIntake(input.request);\n await service.getWorkbookPhotoIntakeByItem({\n ...input.request,\n itemId: context.itemId,\n });\n });\n return [\n {\n id: WORKBOOK_PHOTO_HANDLER,\n version: '1',\n description:\n 'Classify photos as work, lesson, cover, reference (contents/answer keys), or uncertain. Visible completed learner responses use work even without book/lesson identity: workState=completed; omit workbook/activity/workbookId; lessonEvidence=\"\". Confidence concerns visible material/completion, not missing identity. Printed examples/answer keys alone are not learner completion. Partial/unreadable answers can be unassessed later. Blank/unknown completion never auto-marks. For lesson/cover/reference identity: existing book selects exact workbookId AND copies candidate workbookKey/title/edition into identification.workbook. Unique current title+edition can match retained publisher context; publisher/ISBN need not reappear. identityEvidence quotes ONLY current photos, never candidate context. Conflicts, duplicate candidates or title/page-only matches cannot establish identity. New book needs visible ISBN or publisher/title/edition; workbookKey is a hint, never merge authority. Lesson activity requires printed lesson identifier: pageKey=lesson:<identifier>, pageLabel printed label, lessonEvidence quotes it; page number alone is insufficient. Multiple pages can share a lesson. Cover/reference omit activity. Missing book/lesson alone uses work, not uncertain. Ambiguous material/completion uses uncertain confidence. args: identification, confidence, identityEvidence, lessonEvidence, optional workbookId. identification: kind, workState, optional workbook, activity, notes. workbook: workbookKey,title, optional edition,publisher,isbn. activity: pageKey,pageLabel. Single-line visible quotes only; no controls/placeholders. Omit absent optional fields, never null or extra keys. Classify only; no marks or learning observations.',\n operation: { model: MODEL, action: 'get', version: '1' },\n capability: { effect: 'read', idempotent: true, openWorld: false },\n argsSchema: schema,\n resultSchema: schema,\n resultModels: {},\n discovery: {\n mediaTypes: [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'application/pdf',\n ],\n references: {\n workbookId: {\n kind: 'candidate',\n model: '@happyvertical/smrt-education:Workbook',\n },\n },\n candidates: async (query, context, page) => {\n await authorize(context);\n const books = await bound(context, (service) =>\n service.listWorkbookPhotoWorkbooks(input.request),\n );\n const needle = query.toLowerCase();\n const ordered = [...books].sort(\n (a, b) =>\n Number(b.title.toLowerCase().includes(needle)) -\n Number(a.title.toLowerCase().includes(needle)) ||\n a.id.localeCompare(b.id),\n );\n return {\n items: ordered.slice(0, page.limit).map((book) => ({\n model: '@happyvertical/smrt-education:Workbook',\n id: book.id,\n revision: workbookRevision(book),\n label: JSON.stringify(book),\n })),\n hasMore: ordered.length > page.limit,\n };\n },\n },\n validate: async (args, context) => {\n await authorize(context);\n validateWorkbookPhotoIdentification(\n (args as unknown as WorkbookPhotoProposal).identification,\n );\n return { ok: true };\n },\n preview: async (args, context) => {\n await authorize(context);\n return {\n display: { classification: args.identification, gradeApplied: false },\n normalizedArgs: args,\n targetPreconditions: [],\n };\n },\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n await authorize(context);\n return args;\n },\n },\n },\n ];\n}\nfunction workbookRevision(book: unknown) {\n return `workbook:${createHash('sha256').update(canonical(book)).digest('hex')}`;\n}\n/** Candidate freshness and authorization on ingestion's supplied executor. */\nexport function workbookPhotoIntakeTargetResolver(input: {\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n}): import('@happyvertical/smrt-ingestion/execution').IntakeExecutionOptions['assertTarget'] {\n return async ({ db, scope, itemId, model, id, revision }) => {\n if (model !== '@happyvertical/smrt-education:Workbook')\n throw new Error('Photo target unavailable');\n const books = await withTenant(\n {\n ...getCurrentTenant(),\n tenantId: input.request.tenantId,\n userId: input.request.actorUserId,\n superAdminBypass: false,\n },\n () =>\n input.workbooks.withExecutor(db, async (service) => {\n await service.assertWorkbookPhotoScope(input.request, scope, itemId);\n return service.listWorkbookPhotoWorkbooks(input.request);\n }),\n );\n const book = books.find((book) => book.id === id);\n if (!book) throw new Error('Photo target unavailable');\n const current = workbookRevision(book);\n if (revision !== undefined && revision !== current)\n throw new Error('Photo target changed');\n return { revision: current };\n };\n}\n/** Receive before asking for workbook selection; duplicate receipts repair interrupted copying. */\nexport async function receiveWorkbookPhotoIntake(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n receive: ReceiveInput;\n}) {\n assertScope(input.scope, input.request);\n await input.workbooks.authorizePhotoIntake(input.request);\n const receipt = await input.ingestion.receive(input.receive);\n if (!('itemId' in receipt) || !receipt.itemId)\n return { receipt, intake: null };\n const intake = await retainWorkbookPhotoReceipt({\n ...input,\n itemId: receipt.itemId,\n });\n return { receipt, intake };\n}\n/** Recovery after a receive succeeded but the private education copy was interrupted. */\nexport async function retainWorkbookPhotoReceipt(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n itemId: string;\n}) {\n assertScope(input.scope, input.request);\n await input.workbooks.authorizePhotoIntake(input.request);\n const extensions: Record<string, string> = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/webp': 'webp',\n 'application/pdf': 'pdf',\n };\n const originals = (await input.ingestion.getEvidence(input.itemId))\n .filter((e) => e.parentEvidenceId === null)\n .sort((a, b) => a.partId.localeCompare(b.partId));\n if (\n !originals.length ||\n originals.length > 100 ||\n originals.some(\n (e) =>\n !extensions[e.mediaType] ||\n e.byteLength < 1 ||\n e.byteLength > 25 * 1024 * 1024,\n ) ||\n originals.reduce((n, e) => n + e.byteLength, 0) > 100 * 1024 * 1024\n )\n throw new Error('Unsupported or oversized photo intake');\n const pages: SubmissionPage[] = [];\n for (const original of originals) {\n const data = await input.ingestion.readEvidence(input.itemId, original.id);\n if (\n data.length !== original.byteLength ||\n createHash('sha256').update(data).digest('hex') !== original.contentHash\n )\n throw new Error('Photo receipt integrity mismatch');\n pages.push({\n name: `${original.id}.${extensions[original.mediaType]}`,\n mimeType: original.mediaType as SubmissionPage['mimeType'],\n data: Buffer.from(data),\n });\n }\n return input.workbooks.retainWorkbookPhotoIntake({\n ...input.request,\n itemId: input.itemId,\n pages,\n });\n}\n/** Transfer immutable provider provenance; malformed/ambiguous/failed results stay pending. */\nexport async function preserveWorkbookPhotoIdentification(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest & { intakeId: string };\n}) {\n const view = await input.workbooks.getWorkbookPhotoIntake(input.request);\n await input.workbooks.assertWorkbookPhotoScope(\n input.request,\n input.scope,\n view.itemId,\n );\n let snapshot: Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>;\n try {\n snapshot = await input.ingestion.getCompletedAnalysis(view.itemId);\n } catch (error) {\n if (\n error instanceof ProposalsNotConfiguredError ||\n error instanceof GenerationSnapshotStaleError ||\n (error instanceof Error &&\n ['Analysis unavailable', 'Intake unavailable'].includes(error.message))\n )\n return view;\n throw error;\n }\n if (\n snapshot.itemId !== view.itemId ||\n snapshot.configuration.stage !== 'interpret' ||\n !['completed', 'partial'].includes(snapshot.result.status)\n )\n return view;\n const generation = (\n snapshot.result.output as unknown as {\n proposals?: import('@happyvertical/smrt-ingestion').GenerationOutput;\n }\n ).proposals;\n if (\n generation?.version !== 1 ||\n !['proposals', 'needs_review'].includes(generation.outcome)\n )\n return view;\n const suggestions = generation.suggestions.filter(\n (s) => s.handlerId === WORKBOOK_PHOTO_HANDLER,\n );\n const offered = generation.offered.find(\n (o) => o.handler.id === WORKBOOK_PHOTO_HANDLER,\n );\n if (\n suggestions.length !== 1 ||\n suggestions[0].missingFields.length ||\n !offered ||\n canonical(offered.handler.argsSchema) !== canonical(schema)\n )\n return view;\n const proposal = suggestions[0].args as unknown as WorkbookPhotoProposal;\n try {\n validateWorkbookPhotoIdentification(proposal.identification);\n if (\n !['confident', 'uncertain'].includes(proposal.confidence) ||\n !Array.isArray(proposal.identityEvidence) ||\n proposal.identityEvidence.length > 20 ||\n proposal.identityEvidence.some(\n (e) => typeof e !== 'string' || e.length > 2000,\n ) ||\n typeof proposal.lessonEvidence !== 'string' ||\n proposal.lessonEvidence.length > 200\n )\n return view;\n } catch {\n return view;\n }\n return input.workbooks[preservePhotoProposal]({\n ...input.request,\n requestKey: `analysis:${snapshot.attemptId}`,\n proposal,\n allowAutomaticResolution:\n generation.outcome === 'proposals' &&\n generation.suggestions.length === 1 &&\n suggestions[0].alternatives.length === 0 &&\n generation.splits.length === 0,\n sourceHashes: intakeOriginalEvidence(snapshot.evidence)\n .filter((e) => e.mediaType !== 'application/json')\n .map((e) => e.contentHash),\n provenance: {\n attemptId: snapshot.attemptId,\n revision: snapshot.revision,\n inputDigest: snapshot.inputDigest,\n outputDigest: snapshot.outputDigest,\n evidenceDigest: snapshot.evidenceDigest,\n configuration: snapshot.configuration,\n provider: snapshot.result.provider,\n model: snapshot.result.model,\n },\n });\n}\n/** Existing durable extraction/interpretation dispatcher, followed by preservation. */\nexport async function processWorkbookPhotoAnalysis(\n input: Parameters<typeof processEducationAnalysis>[0] & {\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest & { intakeId: string };\n },\n) {\n const view = await input.workbooks.getWorkbookPhotoIntake(input.request);\n await input.workbooks.assertWorkbookPhotoScope(\n input.request,\n input.scope,\n view.itemId,\n );\n if (view.itemId !== input.itemId)\n throw new Error('Photo worker receipt mismatch');\n const processing = await processEducationAnalysis(input);\n const intake = await preserveWorkbookPhotoIdentification(input);\n const capture =\n intake.status === 'resolved' &&\n ['lesson', 'work'].includes(intake.identification?.kind ?? '') &&\n intake.identification?.workState === 'completed'\n ? await input.workbooks.captureWorkbookPhotoIntake({\n ...input.request,\n requestKey: `photo:${intake.itemId}`,\n })\n : null;\n const current = capture\n ? await input.workbooks.getWorkbookPhotoIntake(input.request)\n : intake;\n return {\n processing,\n intake: current,\n capture,\n assessmentRequired: current.status === 'captured',\n };\n}\n","/** Server-only paper workflow integration. Never import from browser handlers. */\nimport {\n type ExtractionAdapter,\n type ExtractionLimits,\n extractAnalysis,\n GenerationSnapshotStaleError,\n type IngestionService,\n normalizeObservedImageRegions,\n ProposalsNotConfiguredError,\n} from '@happyvertical/smrt-ingestion/server';\nimport { intakeOriginalEvidence } from './intake-original-evidence.js';\nimport { normalizeWorkbookAnswerRegions } from './workbook-answer-regions.js';\n\nimport { normalizeWorkbookObservedLayout } from './workbook-layout.js';\n\nexport { requireIngestionMemoryLimit } from './ingestion-isolation.js';\n\n/** Immutable operator configuration; never populated from upload/model metadata. */\nexport interface EducationExtractionConfiguration {\n configurationRevision: string;\n limits: ExtractionLimits;\n}\n\n/** Allocate extraction after a durable receipt. The normal ingestion outbox\n * dispatches this revision to the application's registered job target.\n */\nexport async function queueEducationExtraction(\n ingestion: IngestionService,\n itemId: string,\n configuration: EducationExtractionConfiguration,\n submissionId?: string,\n) {\n return ingestion.analyze(\n itemId,\n { extraction: configuration },\n `education:extract:${configuration.configurationRevision}:${submissionId ?? 'identify'}`,\n );\n}\n\n/** A registered job invokes this with its persisted item/revision IDs and an\n * authenticated service scope. Providers execute outside database transactions.\n * Interpretation receives ingestion's immutable extraction pin. Neither stage\n * approves a suggestion, captures a submission, or applies a grade.\n */\nexport async function processEducationAnalysis(input: {\n ingestion: IngestionService;\n itemId: string;\n revision: number;\n workerId: string;\n adapter: ExtractionAdapter;\n extraction: EducationExtractionConfiguration;\n}): Promise<\n | { kind: 'unclaimed' | 'extraction_incomplete' | 'interpreted' }\n | { kind: 'generation_queued'; revision: number }\n> {\n const { ingestion, itemId } = input;\n const lease = await ingestion.claimAnalysis(\n itemId,\n input.revision,\n input.workerId,\n );\n if (!lease) return { kind: 'unclaimed' };\n const snapshot = await ingestion.getAnalysisInput(lease);\n if (snapshot.configuration.stage === 'interpret') {\n await ingestion.generateProposals(lease);\n return { kind: 'interpreted' };\n }\n if (!snapshot.configuration.extraction)\n throw new Error('Unsupported education analysis stage');\n const completed = await extractAnalysis(\n ingestion,\n lease,\n input.adapter,\n input.extraction,\n );\n if (!completed) return { kind: 'extraction_incomplete' };\n const result = await ingestion.getCompletedAnalysis(itemId, lease.attemptId);\n if (!['completed', 'partial'].includes(result.result.status))\n return { kind: 'extraction_incomplete' };\n const generation = await ingestion.prepareGeneration(\n itemId,\n result.attemptId,\n );\n const queued = await ingestion.analyze(\n itemId,\n {\n ...generation,\n educationEvidenceGrounding: educationEvidenceGrounding(result),\n },\n `education:interpret:${result.attemptId}`,\n );\n return { kind: 'generation_queued', revision: queued.revision };\n}\n\nimport { createHash } from 'node:crypto';\nimport type { IngestionScope } from '@happyvertical/smrt-ingestion/server';\nimport { getCurrentTenant, withTenant } from '@happyvertical/smrt-tenancy';\nimport { registerPermissionDefinitions } from '@happyvertical/smrt-users';\nimport type { LearnerRequest } from './learner-service.js';\nimport type {\n SubmissionPage,\n SubmissionService,\n} from './submission-service.js';\nimport {\n aggregateWorkbookQuestions,\n validateWorkbookAssessment,\n WORKBOOK_MATH_VOCABULARY,\n type WorkbookAssessment,\n WorkbookAssessmentValidationError,\n workbookAggregateFeedback,\n} from './workbook-contracts.js';\nimport { WorkbookService } from './workbook-service.js';\n\nexport type EducationIntakeCaptureRequest = LearnerRequest & {\n workbookActivityId?: string;\n assistance?: import('./workbook-contracts.js').WorkbookAssistance;\n enrollmentId: string;\n lessonId: string;\n itemId: string;\n kind: 'blank_reference' | 'completed_work';\n previousSubmissionId?: string;\n notes?: string;\n};\n\n/** Copy immutable retained originals into education's private ownership only\n * after the host has obtained explicit assignment confirmation. Supply service\n * and scope from the SAME authenticated server factory, never browser values.\n * The owning service persists unique tenant/item binding before allowing retries.\n */\nexport async function captureEducationIntake(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n submissions: SubmissionService;\n request: EducationIntakeCaptureRequest;\n}) {\n const { ingestion, submissions, scope, request } = input;\n if (\n request.tenantId !== scope.tenantId ||\n request.actorUserId !== scope.actorId ||\n request.enrollmentId !== scope.confidentialScopeId ||\n !['blank_reference', 'completed_work'].includes(request.kind) ||\n (request.kind === 'blank_reference' && request.previousSubmissionId)\n )\n throw new Error('Invalid education intake binding');\n // Prove the exact active learner/enrollment/lesson assignment before reading\n // any family-private retained evidence. Intake scopes are enrollment-bound.\n await submissions.assertLessonAssignment(request);\n const evidence = (await ingestion.getEvidence(request.itemId)).filter(\n (entry) => entry.parentEvidenceId === null,\n );\n const extensions: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n 'application/pdf': 'pdf',\n };\n if (\n !evidence.length ||\n evidence.length > 100 ||\n evidence.some(\n (entry) =>\n !extensions[entry.mediaType] ||\n !Number.isSafeInteger(entry.byteLength) ||\n entry.byteLength < 1 ||\n entry.byteLength > 25 * 1024 * 1024,\n ) ||\n evidence.reduce((sum, entry) => sum + entry.byteLength, 0) >\n 100 * 1024 * 1024\n )\n throw new Error('Unsupported or oversized education intake');\n evidence.sort((a, b) => a.partId.localeCompare(b.partId));\n const pages: SubmissionPage[] = [];\n for (const entry of evidence) {\n const bytes = await ingestion.readEvidence(request.itemId, entry.id);\n if (\n bytes.byteLength !== entry.byteLength ||\n createHash('sha256').update(bytes).digest('hex') !== entry.contentHash\n )\n throw new Error('Education intake integrity mismatch');\n pages.push({\n name: `${entry.id}.${extensions[entry.mediaType]}`,\n mimeType: entry.mediaType as SubmissionPage['mimeType'],\n data: Buffer.from(bytes),\n });\n }\n const capture = {\n ...request,\n requestKey: `education:intake:${request.itemId}`,\n pages,\n intake: {\n intakeItemId: request.itemId,\n kind: request.kind,\n previousSubmissionId: request.previousSubmissionId,\n },\n };\n if (request.workbookActivityId) {\n if (\n !(submissions instanceof WorkbookService) ||\n request.kind !== 'completed_work'\n )\n throw new Error(\n 'Workbook intake requires WorkbookService completed work',\n );\n const attempt = await submissions.captureWorkbookWork({\n ...request,\n activityId: request.workbookActivityId,\n intakeItemId: request.itemId,\n requestKey: capture.requestKey,\n pages,\n });\n return attempt.submission;\n }\n if (request.kind === 'blank_reference')\n return submissions.captureBlankReference({\n ...capture,\n intakeItemId: request.itemId,\n });\n return request.previousSubmissionId\n ? submissions.resubmitSubmission({\n intakeItemId: request.itemId,\n ...capture,\n previousSubmissionId: request.previousSubmissionId,\n })\n : submissions.captureSubmission(capture);\n}\n\nimport type {\n HandlerContext,\n IntakeValues,\n OperationHandler,\n} from '@happyvertical/smrt-ingestion/execution';\n\nconst LESSON = '@happyvertical/smrt-education:Lesson';\nconst SUBMISSION = '@happyvertical/smrt-education:Submission';\nconst GRADE = '@happyvertical/smrt-education:Grade';\nconst idSchema = { type: 'string', minLength: 1, maxLength: 64 };\n// Closed model transports intentionally generate no operation permissions.\n// Declaring this server catalog does not grant it to any principal or actor.\nregisterPermissionDefinitions([\n {\n slug: 'lessons.read',\n collection: 'lessons',\n qualifiedName: LESSON,\n name: 'Identify authorized education assignments',\n },\n {\n slug: 'grades.create',\n collection: 'grades',\n qualifiedName: GRADE,\n name: 'Apply guardian-reviewed education grades',\n },\n]);\n\n/** Build the authoritative discovery/review catalog for ONE authenticated\n * learner/enrollment. The application resolves request from its session and\n * assignment; model/browser output can select a lesson but cannot select a user.\n * Keep all ingestion policy layers requireReview=true; no automation opt-in.\n */\nexport function educationIntakeHandlers(input: {\n submissions: SubmissionService;\n request: LearnerRequest & { enrollmentId: string };\n /** After capture, bind a new grading stage to this exact immutable attempt. */\n submissionId?: string;\n workbookActivityId?: string;\n workbookVocabulary?: WorkbookAssessment['vocabulary'];\n}): OperationHandler[] {\n const { submissions, request } = input;\n const bound = async <T>(\n context: HandlerContext,\n work: (service: SubmissionService) => Promise<T>,\n ): Promise<T> => {\n if (\n context.scope.tenantId !== request.tenantId ||\n context.scope.actorId !== request.actorUserId ||\n !context.policy.requireReview\n )\n throw new Error('Education intake scope mismatch');\n // Ingestion's stable execution principal is not the human requester.\n // Preserve tenant permissions and the separate PrincipalRun runtime; only\n // the domain actor changes to the already-authenticated scope actor.\n if (!context.principal) return submissions.withExecutor(context.db, work);\n const tenant = getCurrentTenant();\n if (\n !tenant ||\n tenant.tenantId !== request.tenantId ||\n tenant.userId !== context.principal.context.userId ||\n context.principal.context.tenantId !== request.tenantId\n )\n throw new Error('Education principal tenant mismatch');\n return withTenant(\n {\n ...tenant,\n tenantId: request.tenantId,\n userId: request.actorUserId,\n superAdminBypass: false,\n },\n () => submissions.withExecutor(context.db, work),\n );\n };\n const lessons = (context: HandlerContext) =>\n bound(context, (service) => service.assignmentLessons(request));\n const requireLesson = async (args: IntakeValues, context: HandlerContext) => {\n const found = (await lessons(context)).find(\n (entry) => entry.lesson.id === args.lessonId,\n );\n if (!found) throw new Error('Education assignment unavailable');\n await context.assertTarget(LESSON, found.lesson.id);\n return found;\n };\n const handlers: OperationHandler[] = [\n {\n id: '@happyvertical/smrt-education:identify-assignment',\n version: '1',\n description:\n 'Identify an assigned lesson from a blank or completed scan. Ambiguity requires guardian correction; this action does not grade or capture.',\n operation: { model: LESSON, action: 'get', version: '1' },\n capability: { effect: 'read', idempotent: true, openWorld: false },\n argsSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['lessonId'],\n properties: { lessonId: idSchema },\n },\n resultSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['lessonId'],\n properties: { lessonId: idSchema },\n },\n resultModels: { lessonId: LESSON },\n discovery: {\n mediaTypes: [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'application/pdf',\n ],\n references: { lessonId: { kind: 'candidate', model: LESSON } },\n candidates: async (query, context, page) => {\n // Authorize/filter exact enrollment FIRST; text only ranks that set.\n const visible = await lessons(context);\n const needle = query.toLocaleLowerCase();\n const ordered = [...visible].sort(\n (a, b) =>\n Number(b.lesson.title.toLocaleLowerCase().includes(needle)) -\n Number(a.lesson.title.toLocaleLowerCase().includes(needle)) ||\n a.lesson.id.localeCompare(b.lesson.id),\n );\n return {\n items: ordered.slice(0, page.limit).map((entry) => ({\n model: LESSON,\n id: entry.lesson.id,\n // Version binds immutable assignment identity; the host target\n // resolver must use this same format and reauthorize the plan.\n revision: `assignment:${request.enrollmentId}:${entry.lesson.id}`,\n label: entry.lesson.title,\n })),\n hasMore: ordered.length > page.limit,\n };\n },\n },\n validate: async (args, context) => {\n await requireLesson(args, context);\n return { ok: true };\n },\n preview: async (args, context) => {\n const found = await requireLesson(args, context);\n return {\n display: { lesson: found.lesson.title, gradeApplied: false },\n normalizedArgs: args,\n targetPreconditions: [\n {\n model: LESSON,\n id: found.lesson.id,\n revision: `assignment:${request.enrollmentId}:${found.lesson.id}`,\n },\n ],\n };\n },\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n const found = await requireLesson(args, context);\n return { lessonId: found.lesson.id };\n },\n },\n },\n ];\n if (!input.submissionId) return handlers;\n const submissionId = input.submissionId;\n const current = (context: HandlerContext) =>\n bound(context, (service) =>\n service.getSubmission({ ...request, submissionId }),\n );\n const requireSubmission = async (\n args: IntakeValues,\n context: HandlerContext,\n ) => {\n if (args.submissionId !== submissionId)\n throw new Error('Education attempt binding mismatch');\n const submission = await current(context);\n if (\n submission.intakeItemId !== context.itemId ||\n submission.kind !== 'completed_work'\n )\n throw new Error('Education intake/attempt binding mismatch');\n await context.assertTarget(SUBMISSION, submissionId);\n return submission;\n };\n const workbook = input.workbookActivityId;\n if (workbook && !(submissions instanceof WorkbookService))\n throw new Error('Workbook handler requires WorkbookService');\n const vocabulary = input.workbookVocabulary ?? WORKBOOK_MATH_VOCABULARY;\n handlers.push({\n id: '@happyvertical/smrt-education:review-submission',\n version: '1',\n description: workbook\n ? 'Assess visible questions from current captured evidence only. Historical IDs indicate correspondence, never current answers. Prompt is printed task text excluding response; answer is observed learner response only. Printed solved examples/answer keys are not learner answers or learning evidence. Never solve a task and call it the observed response. Matching answers require explicitly observed line endpoints; unreadable connections are unassessed/illegible or missing_context. Missing book/lesson identity never blocks visible work. Use printed number+occurrence/subpart IDs when present. Unnumbered tasks use u:<short printed-task slug>:<occurrence/subpart>, excluding learner answers and solved results. Occurrence identifies visible tasks, never output-array position. Retain exact known IDs on correction; absent/ambiguous correspondence is unassessed/not_present, never guessed or renumbered. Cite original evidence IDs only; no page/rect/coordinate fields, as service retains whole-source grounding. Correct/incorrect/partially_correct use reason none. Unsupported, unanswered, illegible, missing_context and not_present are unassessed, never incorrect, with null points. Judge objectively solvable arithmetic without a printed rubric. Correctness is independent of points: absent evidenced allocation, BOTH points and possiblePoints are null, including incorrect. Never invent weights/rubric or mix null/numeric fields. Only use incorrect points=0 when possiblePoints is known; correct earns that known total. No aggregate score/summary: service computes totals. Concepts are supplied-vocabulary suggestions; no match uses conceptIds [] and still assesses normally. markingCertainty=uncertain requires result=unassessed, reason illegible/missing_context/unsupported/unanswered/not_present, points=null and possiblePoints=null. Never assert correctness with uncertain marking. Mapping certainty is separate. Guardian review is required for authority.'\n : 'Suggest marks and feedback for this captured attempt. Only a current authorized guardian decision may apply a grade.',\n operation: { model: GRADE, action: 'create', version: '1' },\n capability: { effect: 'write', idempotent: false, openWorld: false },\n argsSchema: {\n type: 'object',\n additionalProperties: false,\n required: workbook\n ? ['submissionId', 'questions']\n : ['submissionId', 'score', 'feedback'],\n properties: {\n submissionId: idSchema,\n ...(workbook\n ? {\n answerRegions: {\n description:\n 'Include advisory answer locations when a current observedRegions catalog clearly matches visible learner responses. Omit unknown or uncertain positions. Shape {version:1,regions:[{questionId,evidenceId,observationId}]}. Reference ONLY exact current evidence observedRegions catalog IDs with matching visible learner response/question; no coordinates or geometry in arguments. Never infer positions from layout, IDs, canonical prompts or expected answers. Omit uncertain/unknown/missing regions. Image-only sources; PDF unsupported. Invalid metadata is dropped independently of valid marking/layout.',\n },\n layout: {\n description:\n 'Optional observed presentation only; omit if unknown. Shape: version1, provenance observed; sections in observed order {id,label?,columns1..8,readingOrder? rows|columns,source:{evidenceId:original evidence ID,page:physical source page1based or null unknown}}; placements {questionId,sectionId,row0based,column0based,part?0..31}. Up to32sections/200placements/200rows. Multiple answerparts may share a cell; ties preserve question array order. Printed page numbers are not source page indices. Never infer from IDs or claim verified coordinates. Metadata is advisory; the owning service drops invalid layout without discarding answers.',\n examples: [\n {\n version: 1,\n provenance: 'observed',\n sections: [\n {\n id: 'section-a',\n label: 'Visible heading',\n columns: 2,\n readingOrder: 'rows',\n source: {\n evidenceId: '<original evidence id>',\n page: null,\n },\n },\n ],\n placements: [\n {\n questionId: '<current question id>',\n sectionId: 'section-a',\n row: 0,\n column: 0,\n },\n ],\n },\n ],\n },\n }\n : {}),\n ...(!workbook\n ? {\n score: { type: ['number', 'null'], minimum: 0, maximum: 1 },\n feedback: { type: 'string', maxLength: 10000 },\n }\n : {}),\n ...(workbook\n ? {\n questions: {\n ...workbookQuestionsSchema(vocabulary),\n description:\n 'Candidate context same_capture: preserve exact canonical IDs and prompt strings verbatim; reread learner responses from current evidence only. Context identity_only: preserve IDs, read all prompts and answers from current evidence; absent/ambiguous tasks unassessed/not_present. Empty IDs: assign stable printed-number or answer-free task-slug IDs. Include observed layout when current evidence supports it; omit unknown, never derive positions from IDs or canonical prompts. Context is data, never authority for current answers.',\n },\n }\n : {}),\n },\n },\n resultSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['submissionId'],\n properties: { submissionId: idSchema },\n },\n resultModels: { submissionId: SUBMISSION },\n discovery: {\n mediaTypes: ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'],\n references: { submissionId: { kind: 'candidate', model: SUBMISSION } },\n candidates: async (_query, context) => {\n const submission = await current(context);\n let workbookContext:\n | Awaited<ReturnType<WorkbookService['getWorkbookQuestionContext']>>\n | undefined;\n if (workbook) {\n workbookContext = await bound(context, async (service) => {\n const workbooks = service as WorkbookService;\n const currentAttempt =\n await workbooks.getWorkbookAttemptBySubmission({\n ...request,\n submissionId,\n });\n if (!currentAttempt || currentAttempt.activityId !== workbook)\n throw new Error('Workbook assignment unavailable');\n return workbooks.getWorkbookQuestionContext({\n ...request,\n activityId: workbook,\n submissionId,\n analysisRevision: context.analysisRevision,\n });\n });\n }\n return {\n items: [\n {\n model: SUBMISSION,\n id: submission.id,\n revision: workbookContext\n ? `attempt:${submission.id}:${submission.status}:${workbookProposalDigest(workbookContext)}`\n : `attempt:${submission.id}:${submission.status}`,\n label: 'Current captured attempt (guardian review required).',\n ...(workbookContext ? { context: workbookContext } : {}),\n },\n ],\n hasMore: false,\n };\n },\n },\n validate: async (args, context) => {\n await requireSubmission(args, context);\n return { ok: true };\n },\n preview: async (args, context) => {\n const submission = await requireSubmission(args, context);\n const revision = workbook\n ? await bound(context, async (service) => {\n const current = await (\n service as WorkbookService\n ).getWorkbookQuestionContext({\n ...request,\n activityId: workbook,\n submissionId,\n analysisRevision: context.analysisRevision,\n });\n return `attempt:${submission.id}:${submission.status}:${workbookProposalDigest(current)}`;\n })\n : `attempt:${submission.id}:${submission.status}`;\n return {\n display: {\n submissionId,\n ...(workbook\n ? { questions: args.questions }\n : { proposedScore: args.score, proposedFeedback: args.feedback }),\n guardianReviewRequired: true,\n },\n normalizedArgs: args,\n targetPreconditions: [\n {\n model: SUBMISSION,\n id: submissionId,\n revision,\n },\n ],\n };\n },\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n await requireSubmission(args, context);\n if (workbook) {\n await bound(context, async (service) => {\n const workbooks = service as WorkbookService;\n let cursor: string | undefined;\n let attempt:\n | Awaited<\n ReturnType<WorkbookService['getWorkbookTimeline']>\n >['attempts'][number]\n | undefined;\n do {\n const timeline = await workbooks.getWorkbookTimeline({\n ...request,\n activityId: workbook,\n ...(cursor ? { cursor } : {}),\n });\n attempt = timeline.attempts.find(\n (entry) => entry.submissionId === submissionId,\n );\n cursor = timeline.nextCursor ?? undefined;\n } while (!attempt && cursor);\n const proposal = attempt?.revisions.find(\n (revision) =>\n revision.kind === 'ai' &&\n revision.assessment.provenance.proposalDigest ===\n workbookProposalDigest(args),\n );\n if (!proposal)\n throw new Error(\n 'Workbook analysis must be preserved before guardian apply',\n );\n await workbooks.reviewWorkbookAssessment({\n ...request,\n activityId: workbook,\n submissionId,\n revisionId: proposal.id,\n expectedHeadId: null,\n requestKey: `ingestion-review:${proposal.id}`,\n });\n });\n return { submissionId };\n }\n await bound(context, (service) =>\n service.applyReviewedSubmission({\n ...request,\n submissionId,\n score: args.score as number | null,\n feedback: String(args.feedback),\n }),\n );\n return { submissionId };\n },\n },\n });\n return handlers;\n}\n\n/** Owning education target resolver for ingestion's transactional host hook.\n * Serializes with education enrollment mutations, then performs public service\n * authorization on the supplied executor. The host still owns live principal\n * grant/revocation serialization in its execution authorize callback.\n */\nexport function educationIntakeTargetResolver(input: {\n submissions: SubmissionService;\n request: LearnerRequest & { enrollmentId: string };\n submissionId?: string;\n}): import('@happyvertical/smrt-ingestion/execution').IntakeExecutionOptions['assertTarget'] {\n return async ({\n db,\n scope,\n itemId,\n analysisRevision,\n model,\n id,\n revision,\n }) => {\n const { request, submissions } = input;\n if (\n scope.tenantId !== request.tenantId ||\n scope.actorId !== request.actorUserId\n )\n throw new Error('Education intake scope mismatch');\n // Match workbook capture/review ordering: learner first, then enrollment.\n await db.query(\n 'UPDATE learners SET id=id WHERE id=? AND tenant_id=?',\n request.learnerId,\n request.tenantId,\n );\n await db.query(\n 'UPDATE enrollments SET id=id WHERE id=? AND tenant_id=?',\n request.enrollmentId,\n request.tenantId,\n );\n const current = await withTenant(\n {\n ...getCurrentTenant(),\n tenantId: request.tenantId,\n userId: request.actorUserId,\n superAdminBypass: false,\n },\n () =>\n submissions.withExecutor(db, async (service) => {\n if (model === LESSON) {\n const available = await service.assignmentLessons(request);\n if (!available.some((entry) => entry.lesson.id === id))\n throw new Error('Education assignment unavailable');\n return `assignment:${request.enrollmentId}:${id}`;\n }\n if (model !== SUBMISSION || id !== input.submissionId)\n throw new Error('Education target unavailable');\n const submission = await service.getSubmission({\n ...request,\n submissionId: id,\n });\n if (\n submission.intakeItemId !== itemId ||\n submission.kind !== 'completed_work'\n )\n throw new Error('Education intake/attempt binding mismatch');\n if (service instanceof WorkbookService) {\n const attempt = await service.getWorkbookAttemptBySubmission({\n ...request,\n submissionId: id,\n });\n if (attempt) {\n const context = await service.getWorkbookQuestionContext({\n ...request,\n activityId: attempt.activityId,\n submissionId: id,\n analysisRevision,\n });\n return `attempt:${submission.id}:${submission.status}:${workbookProposalDigest(context)}`;\n }\n }\n return `attempt:${submission.id}:${submission.status}`;\n }),\n );\n if (revision !== undefined && revision !== current)\n throw new Error('Education target changed');\n return { revision: current };\n };\n}\n\nfunction workbookProposalDigest(value: unknown): string {\n // Canonical object keys permit DTO/JSON roundtrips without changing identity.\n const canonical = (v: unknown): unknown =>\n Array.isArray(v)\n ? v.map(canonical)\n : v && typeof v === 'object'\n ? Object.fromEntries(\n Object.entries(v)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, x]) => [k, canonical(x)]),\n )\n : v;\n return createHash('sha256')\n .update(JSON.stringify(canonical(value)))\n .digest('hex');\n}\n\nfunction workbookQuestionsSchema(vocabulary: WorkbookAssessment['vocabulary']) {\n return {\n type: 'array',\n minItems: 1,\n maxItems: 200,\n items: {\n type: 'object',\n additionalProperties: false,\n required: [\n 'id',\n 'prompt',\n 'answer',\n 'result',\n 'reason',\n 'feedback',\n 'points',\n 'possiblePoints',\n 'anchors',\n 'conceptIds',\n 'markingCertainty',\n 'mappingCertainty',\n 'evidenceLimitations',\n ],\n oneOf: [\n {\n properties: {\n result: { enum: ['correct', 'incorrect', 'partially_correct'] },\n markingCertainty: { enum: ['clear', 'unknown'] },\n reason: { const: 'none' },\n },\n },\n {\n properties: {\n result: { const: 'unassessed' },\n reason: {\n enum: [\n 'unanswered',\n 'illegible',\n 'missing_context',\n 'unsupported',\n 'not_present',\n ],\n },\n points: { type: 'null' },\n possiblePoints: { type: 'null' },\n },\n },\n ],\n properties: {\n id: { type: 'string', minLength: 1, maxLength: 200 },\n prompt: { type: 'string', maxLength: 10000 },\n answer: { type: 'string', maxLength: 10000 },\n result: {\n type: 'string',\n enum: ['correct', 'incorrect', 'partially_correct', 'unassessed'],\n },\n reason: {\n type: 'string',\n enum: [\n 'none',\n 'unanswered',\n 'illegible',\n 'missing_context',\n 'unsupported',\n 'not_present',\n ],\n },\n feedback: { type: 'string', maxLength: 10000 },\n points: { type: ['number', 'null'], minimum: 0 },\n possiblePoints: { type: ['number', 'null'], minimum: 0 },\n markingCertainty: {\n type: 'string',\n enum: ['clear', 'uncertain', 'unknown'],\n },\n mappingCertainty: {\n type: 'string',\n enum: ['clear', 'uncertain', 'unknown'],\n },\n evidenceLimitations: {\n type: 'array',\n maxItems: 20,\n items: { type: 'string', maxLength: 500 },\n },\n conceptIds: {\n type: 'array',\n maxItems: 10,\n items: { type: 'string', enum: vocabulary.concepts.map((c) => c.id) },\n },\n anchors: {\n type: 'array',\n minItems: 1,\n maxItems: 20,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['evidenceId'],\n properties: {\n evidenceId: idSchema,\n },\n },\n },\n },\n },\n };\n}\n\n/** Bounded geometry capability transfer, pinned in the generation configuration. */\nfunction educationEvidenceGrounding(\n snapshot: Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>,\n) {\n const results = Array.isArray(snapshot.result.output?.results)\n ? snapshot.result.output.results\n : [];\n const sources = results.slice(0, 100).flatMap((value) => {\n if (!value || typeof value !== 'object') return [];\n const result = value as {\n evidence?: { id?: string; contentHash?: string; mediaType?: string };\n capabilities?: { location?: string }[];\n segments?: {\n location?: { kind?: string; page?: number };\n observedRegions?: unknown;\n }[];\n };\n const evidence = (snapshot.evidence ?? []).find(\n (e) =>\n e.id === result.evidence?.id &&\n e.contentHash === result.evidence?.contentHash,\n );\n if (!evidence) return [];\n const pageCapable =\n Array.isArray(result.capabilities) &&\n result.capabilities.some((c) => c.location === 'page');\n const pages =\n pageCapable && Array.isArray(result.segments)\n ? [\n ...new Set(\n result.segments.flatMap((segment) =>\n segment.location?.kind === 'page' &&\n Number.isSafeInteger(segment.location.page) &&\n (segment.location.page ?? 0) > 0\n ? [segment.location.page as number]\n : [],\n ),\n ),\n ].slice(0, 1000)\n : [];\n const catalogs =\n typeof evidence.mediaType === 'string' &&\n evidence.mediaType.startsWith('image/') &&\n Array.isArray(result.segments)\n ? result.segments\n .filter((s) => s.location?.kind === 'source')\n .map((s) => normalizeObservedImageRegions(s.observedRegions))\n .filter((s) => s !== undefined)\n : [];\n return [\n {\n evidenceId: evidence.id,\n sha256: evidence.contentHash,\n pages,\n ...(catalogs.length === 1 ? { observedRegions: catalogs[0] } : {}),\n },\n ];\n });\n return { version: 1, extractionAttemptId: snapshot.attemptId, sources };\n}\n\nexport type WorkbookPreservationResult =\n | { kind: 'pending' }\n | { kind: 'unavailable' }\n | { kind: 'retained'; revisionId: string }\n | { kind: 'preserved'; revisionId: string }\n | {\n kind: 'needs_review';\n reason:\n | 'invalid_assessment'\n | 'ungrounded_source'\n | 'ambiguous_proposal'\n | 'stale_analysis';\n };\n\n/** Preserve validated question evidence; invalid model output is reviewable status,\n * never an educational mark or a generic server error. Education authorization,\n * integrity and DB errors throw; unavailable scratch never grants raw access.\n */\nexport async function preserveWorkbookIntakeAnalysis(input: {\n ingestion: IngestionService;\n workbooks: WorkbookService;\n request: LearnerRequest & { enrollmentId: string };\n activityId: string;\n submissionId: string;\n workbookVocabulary?: WorkbookAssessment['vocabulary'];\n}): Promise<WorkbookPreservationResult> {\n const { ingestion, workbooks, request, activityId, submissionId } = input;\n const attempt = await workbooks.getWorkbookAttemptBySubmission({\n ...request,\n submissionId,\n });\n if (\n !attempt ||\n attempt.activityId !== activityId ||\n !attempt.submission.intakeItemId\n )\n throw new Error('Workbook intake binding unavailable');\n const itemId = attempt.submission.intakeItemId;\n const state = await workbooks.getWorkbookPreservationState({\n ...request,\n activityId,\n submissionId,\n });\n const latestRetained = state.retainedAnalyses.at(-1);\n const legacyRetained = state.retainedAnalyses.every(\n (entry) => entry.analysisRevision === null,\n )\n ? latestRetained\n : undefined;\n let currentRevision: number;\n try {\n currentRevision = (await ingestion.getItem(itemId)).analysisRevision;\n } catch (error) {\n if (error instanceof Error && error.message === 'Intake unavailable')\n return latestRetained\n ? { kind: 'retained', revisionId: latestRetained.assessmentRevisionId }\n : { kind: 'unavailable' };\n throw error;\n }\n const exact = state.retainedAnalyses.find(\n (entry) => entry.analysisRevision === currentRevision,\n );\n if (exact)\n return { kind: 'retained', revisionId: exact.assessmentRevisionId };\n let snapshot: Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>;\n try {\n snapshot = await ingestion.getCompletedAnalysis(itemId);\n } catch (error) {\n if (error instanceof ProposalsNotConfiguredError)\n return legacyRetained\n ? { kind: 'retained', revisionId: legacyRetained.assessmentRevisionId }\n : { kind: 'unavailable' };\n if (error instanceof GenerationSnapshotStaleError)\n return legacyRetained\n ? { kind: 'retained', revisionId: legacyRetained.assessmentRevisionId }\n : { kind: 'needs_review', reason: 'stale_analysis' };\n if (error instanceof Error && error.message === 'Intake unavailable')\n return latestRetained\n ? { kind: 'retained', revisionId: latestRetained.assessmentRevisionId }\n : { kind: 'unavailable' };\n if (error instanceof Error && error.message === 'Analysis unavailable')\n return latestRetained\n ? { kind: 'retained', revisionId: latestRetained.assessmentRevisionId }\n : { kind: 'pending' };\n throw error;\n }\n if (\n snapshot.configuration.stage !== 'interpret' ||\n !['completed', 'partial'].includes(snapshot.result.status)\n )\n return { kind: 'pending' };\n const importedAttempt = state.retainedAnalyses.find(\n (entry) => entry.analysisAttemptId === snapshot.attemptId,\n );\n if (importedAttempt)\n return {\n kind: 'retained',\n revisionId: importedAttempt.assessmentRevisionId,\n };\n const sources = await workbooks.getWorkbookSourceAnchors({\n ...request,\n activityId,\n submissionId,\n });\n const originals = intakeOriginalEvidence(snapshot.evidence).filter(\n (e) => e.mediaType !== 'application/json',\n );\n if (\n originals.length !== sources.length ||\n originals.some((e, i) => e.contentHash !== sources[i].sha256)\n )\n throw new Error('Workbook retained source mismatch');\n let assessment: WorkbookAssessment;\n try {\n const generation = (\n snapshot.result.output as unknown as {\n proposals?: import('@happyvertical/smrt-ingestion').GenerationOutput;\n }\n ).proposals;\n if (\n !generation ||\n generation.version !== 1 ||\n !Array.isArray(generation.suggestions)\n )\n throw new WorkbookAssessmentValidationError(\n 'Malformed workbook generation',\n );\n if (!['proposals', 'needs_review'].includes(generation.outcome))\n return {\n kind: 'needs_review',\n reason:\n generation.outcome === 'ambiguous'\n ? 'ambiguous_proposal'\n : 'invalid_assessment',\n };\n const suggestions = generation.suggestions.filter(\n (s) => s.handlerId === '@happyvertical/smrt-education:review-submission',\n );\n if (suggestions.length !== 1)\n throw new WorkbookAssessmentValidationError(\n 'Expected one workbook proposal',\n 'ambiguous_proposal',\n );\n const suggestion = suggestions[0];\n if (\n suggestion.args.submissionId !== submissionId ||\n !Array.isArray(suggestion.args.questions) ||\n suggestion.missingFields.length\n )\n throw new WorkbookAssessmentValidationError(\n 'Incomplete workbook question proposal',\n );\n const offered = generation.offered.find(\n (entry) => entry.handler.id === suggestion.handlerId,\n );\n const questionSchema = (\n offered?.handler.argsSchema.properties as\n | Record<string, unknown>\n | undefined\n )?.questions as\n | { items: { properties: { conceptIds: { items: { enum: string[] } } } } }\n | undefined;\n if (!questionSchema)\n throw new WorkbookAssessmentValidationError(\n 'Generation did not use workbook question contract',\n );\n const curated = input.workbookVocabulary ?? WORKBOOK_MATH_VOCABULARY;\n if (\n JSON.stringify(questionSchema.items.properties.conceptIds.items.enum) !==\n JSON.stringify(curated.concepts.map((c) => c.id))\n )\n throw new WorkbookAssessmentValidationError(\n 'Unsupported workbook vocabulary',\n );\n const grounding = snapshot.configuration.educationEvidenceGrounding as\n | {\n version?: number;\n extractionAttemptId?: string;\n sources?: {\n evidenceId: string;\n sha256: string;\n pages: number[];\n observedRegions?: unknown;\n }[];\n }\n | undefined;\n const trustedGrounding =\n grounding?.version === 1 &&\n grounding.extractionAttemptId === generation.source?.attemptId\n ? grounding\n : undefined;\n const questions = suggestion.args.questions.map((value) => {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new WorkbookAssessmentValidationError(\n 'Invalid workbook question',\n );\n const q = value as Record<string, unknown>;\n if (!Array.isArray(q.anchors))\n throw new WorkbookAssessmentValidationError(\n 'Missing workbook source anchors',\n 'ungrounded_source',\n );\n const limitations = new Set(\n Array.isArray(q.evidenceLimitations)\n ? (q.evidenceLimitations as string[])\n : [],\n );\n const anchors = q.anchors.map((value) => {\n const anchor = value as { evidenceId?: string };\n const index = originals.findIndex((e) => e.id === anchor?.evidenceId);\n if (index < 0)\n throw new WorkbookAssessmentValidationError(\n 'Question must cite a captured original',\n 'ungrounded_source',\n );\n const original = originals[index];\n const page = original.mediaType?.startsWith('image/') ? 1 : null;\n const level = 'source' as const;\n limitations.add(\n 'Source-level evidence only; no verified question page or region was supplied by extraction.',\n );\n return {\n assetId: sources[index].assetId,\n sha256: sources[index].sha256,\n page,\n rect: [0, 0, 1, 1] as [number, number, number, number],\n grounding: level,\n ...(trustedGrounding?.extractionAttemptId\n ? { extractionAttemptId: trustedGrounding.extractionAttemptId }\n : {}),\n };\n });\n return {\n ...q,\n anchors,\n evidenceLimitations: [...limitations],\n } as unknown as WorkbookAssessment['questions'][number];\n });\n let observedLayout: unknown = suggestion.args.layout;\n if (\n observedLayout &&\n typeof observedLayout === 'object' &&\n !Array.isArray(observedLayout)\n ) {\n const candidate = observedLayout as Record<string, unknown>;\n if (\n Array.isArray(candidate.sections) &&\n candidate.sections.length <= 32\n ) {\n observedLayout = {\n ...candidate,\n sections: candidate.sections.map((section: unknown) => {\n if (\n !section ||\n typeof section !== 'object' ||\n Array.isArray(section)\n )\n return section;\n const row = section as Record<string, unknown>;\n const source = row.source as\n | { evidenceId?: unknown; page?: unknown }\n | undefined;\n const index = originals.findIndex(\n (e) => e.id === source?.evidenceId,\n );\n return {\n ...row,\n source: {\n assetId: index >= 0 ? sources[index].assetId : '',\n page: source?.page,\n },\n };\n }),\n };\n }\n }\n let mappedRegions: unknown = suggestion.args.answerRegions;\n if (\n mappedRegions &&\n typeof mappedRegions === 'object' &&\n !Array.isArray(mappedRegions)\n ) {\n const proposed = mappedRegions as Record<string, unknown>;\n if (proposed.version === 1 && Array.isArray(proposed.regions)) {\n mappedRegions = {\n version: 1,\n provenance: 'observed',\n coordinateSpace: 'display-oriented',\n regions: proposed.regions.map((entry: unknown) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry))\n return {};\n const r = entry as Record<string, unknown>;\n if (\n Object.keys(r).some(\n (key) =>\n !['questionId', 'evidenceId', 'observationId'].includes(key),\n )\n )\n return {};\n const index = originals.findIndex(\n (e) =>\n e.id === r.evidenceId &&\n typeof e.mediaType === 'string' &&\n e.mediaType.startsWith('image/'),\n );\n const catalogSource = trustedGrounding?.sources?.find(\n (source) =>\n source.evidenceId === r.evidenceId &&\n source.sha256 === originals[index]?.contentHash,\n );\n const catalog = normalizeObservedImageRegions(\n catalogSource?.observedRegions,\n );\n const observed = catalog?.regions.find(\n (region) => region.id === r.observationId,\n );\n return {\n questionId: r.questionId,\n source: {\n assetId: index >= 0 ? sources[index].assetId : '',\n page: 1,\n },\n observationId: r.observationId,\n rect: observed?.rect,\n };\n }),\n };\n }\n }\n assessment = {\n version: 1,\n feedback: '',\n questions,\n ...normalizeWorkbookObservedLayout(observedLayout, questions, sources),\n ...normalizeWorkbookAnswerRegions(mappedRegions, questions, sources),\n vocabulary: structuredClone(curated),\n provenance: {\n provider: generation.provenance.generative.provider,\n model:\n generation.provenance.generativeResponseModel ??\n generation.provenance.generative.model,\n configurationVersion: generation.provenance.configurationVersion,\n rubricVersion: generation.provenance.promptVersion,\n inputHash: snapshot.inputDigest,\n analysisId: snapshot.attemptId,\n analysisRevision: snapshot.revision,\n proposalDigest: workbookProposalDigest(suggestion.args),\n providerVersion: generation.provenance.generative.version,\n sourceAnalysis: generation.source,\n catalogDigest: generation.provenance.catalogDigest,\n policyVersions: generation.provenance.policyVersions,\n },\n };\n validateWorkbookAssessment(assessment);\n assessment.aggregate = aggregateWorkbookQuestions(assessment.questions);\n assessment.feedback = workbookAggregateFeedback(assessment.aggregate);\n } catch (error) {\n if (error instanceof WorkbookAssessmentValidationError)\n return { kind: 'needs_review', reason: error.reason };\n if (error instanceof TypeError)\n return { kind: 'needs_review', reason: 'invalid_assessment' };\n throw error;\n }\n try {\n const revision = await workbooks.recordWorkbookAnalysis({\n ...request,\n activityId,\n submissionId,\n requestKey: `ingestion:${snapshot.attemptId}`,\n assessment,\n });\n return { kind: 'preserved', revisionId: revision.id };\n } catch (error) {\n if (error instanceof WorkbookAssessmentValidationError)\n return { kind: 'needs_review', reason: error.reason };\n throw error;\n }\n}\n\nexport {\n receiveFamilyIntake,\n retainFamilyIntakeReceipt,\n} from './family-intake-ingestion.js';\n\nexport { FamilyIntakeService } from './family-intake-service.js';\nexport {\n preserveWorkbookPhotoIdentification,\n processWorkbookPhotoAnalysis,\n receiveWorkbookPhotoIntake,\n retainWorkbookPhotoReceipt,\n WORKBOOK_PHOTO_HANDLER,\n workbookPhotoIntakeHandlers,\n workbookPhotoIntakeTargetResolver,\n} from './workbook-photo-ingestion.js';\n"],"mappings":"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"}
1
+ {"version":3,"file":"ingestion.js","names":["book","current","value"],"sources":["../src/intake-original-evidence.ts","../src/ingestion-isolation.ts","../src/family-intake-ingestion.ts","../src/family-intake-service.ts","../src/question-extraction-ingestion.ts","../src/workbook-photo-ingestion.ts","../src/ingestion.ts"],"sourcesContent":["/** Shared source convention: metadata parents contain independent originals;\n * descendants of a supported image/PDF original are its renditions. */\nexport const supportedIntakeOriginal = (type: string) =>\n ['image/png', 'image/jpeg', 'image/webp', 'application/pdf'].includes(type);\n\nexport function intakeOriginalEvidence<\n T extends {\n id: string;\n parentEvidenceId: string | null;\n mediaType: string;\n partId: string;\n },\n>(evidence: readonly T[]): T[] {\n const byId = new Map(evidence.map((entry) => [entry.id, entry]));\n return evidence\n .filter((entry) => {\n let parentId = entry.parentEvidenceId;\n const visited = new Set([entry.id]);\n while (parentId) {\n if (visited.has(parentId))\n throw new Error('Invalid family evidence lineage');\n visited.add(parentId);\n const parent = byId.get(parentId);\n if (!parent) throw new Error('Incomplete family evidence lineage');\n if (supportedIntakeOriginal(parent.mediaType)) return false;\n parentId = parent.parentEvidenceId;\n }\n return true;\n })\n .sort((a, b) => a.partId.localeCompare(b.partId));\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\n/** Verify a real Linux cgroup-v2 native-memory ceiling before enabling decoders.\n * The worker and its children must remain in this cgroup; deployments must deny\n * cgroup writes/escape and run without privileged container capabilities.\n */\nexport async function requireIngestionMemoryLimit(\n maximumBytes: number,\n): Promise<{ memoryLimitBytes: number }> {\n if (process.platform !== 'linux')\n throw new Error(\n 'Extraction requires a Linux cgroup-v2 memory-limited worker',\n );\n if (!Number.isSafeInteger(maximumBytes) || maximumBytes < 1)\n throw new Error('Invalid worker memory ceiling');\n const membership = await readFile('/proc/self/cgroup', 'utf8');\n const entry = membership.split('\\n').find((line) => line.startsWith('0::'));\n if (!entry) throw new Error('No cgroup-v2 membership');\n const relative = entry.slice(3);\n if (!relative.startsWith('/') || relative.split('/').includes('..'))\n throw new Error('Invalid cgroup membership');\n const root = '/sys/fs/cgroup';\n let directory = resolve(root, `.${relative}`);\n let limit = Number.POSITIVE_INFINITY;\n // An ancestor limit is authoritative too. Account for inherited limits while\n // never accepting a mere configuration promise or Node heap setting.\n while (directory === root || directory.startsWith(`${root}/`)) {\n const value = (await readFile(`${directory}/memory.max`, 'utf8')).trim();\n if (value !== 'max') {\n if (!/^\\d+$/.test(value)) throw new Error('Invalid cgroup memory limit');\n const parsed = Number(value);\n if (!Number.isSafeInteger(parsed) || parsed < 1)\n throw new Error('Invalid cgroup memory limit');\n limit = Math.min(limit, parsed);\n }\n if (directory === root) break;\n directory = resolve(directory, '..');\n }\n if (!Number.isFinite(limit) || limit > maximumBytes)\n throw new Error(\n 'Worker native-memory ceiling is missing or exceeds policy',\n );\n return { memoryLimitBytes: limit };\n}\n","/** Public family receipt bridge; transport source identity never supplies authority. */\nimport { createHash } from 'node:crypto';\nimport type {\n IngestionScope,\n IngestionService,\n ReceiveInput,\n} from '@happyvertical/smrt-ingestion/server';\nimport {\n type FamilyIntakeRequest,\n familyIntakeScopeId,\n} from './family-intake-contracts.js';\nimport type { FamilyIntakeService } from './family-intake-service.js';\nimport {\n intakeOriginalEvidence,\n supportedIntakeOriginal,\n} from './intake-original-evidence.js';\nimport type { SubmissionPage } from './submission-service.js';\n\ntype Input = {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n family: FamilyIntakeService;\n request: FamilyIntakeRequest;\n};\nfunction assertScope(input: Input) {\n if (\n input.scope.tenantId !== input.request.tenantId ||\n input.scope.actorId !== input.request.actorUserId ||\n input.scope.confidentialScopeId !==\n familyIntakeScopeId(input.request.tenantId)\n )\n throw new Error('Family intake scope mismatch');\n}\n/** Receive before learner attribution; duplicate deliveries repair interrupted retention. */\nexport async function receiveFamilyIntake(\n input: Input & { receive: ReceiveInput },\n) {\n assertScope(input);\n await input.family.authorizeFamilyIntake(\n input.request,\n 'education.family-intake.receive',\n );\n const receipt = await input.ingestion.receive(input.receive);\n if (!('itemId' in receipt) || !receipt.itemId)\n return { receipt, intake: null };\n return {\n receipt,\n intake: await retainFamilyIntakeReceipt({\n ...input,\n itemId: receipt.itemId,\n }),\n };\n}\n/** Copy authorized original evidence once into durable education ownership. */\nexport async function retainFamilyIntakeReceipt(\n input: Input & { itemId: string },\n) {\n assertScope(input);\n await input.family.authorizeFamilyIntake(\n input.request,\n 'education.family-intake.receive',\n );\n const identity = await input.ingestion.getReceiptSource(input.itemId);\n const evidence = await input.ingestion.getEvidence(input.itemId);\n if (evidence.length > 200)\n throw new Error('Family receipt evidence exceeds limit');\n const source = {\n ...identity,\n evidence: evidence.map((e) => ({\n evidenceId: e.id,\n partId: e.partId,\n parentEvidenceId: e.parentEvidenceId,\n mimeType: e.mediaType,\n sha256: e.contentHash,\n })),\n };\n const supported = supportedIntakeOriginal;\n const originalEvidence = intakeOriginalEvidence(evidence);\n if (\n originalEvidence.some(\n (e) => e.mediaType !== 'application/json' && !supported(e.mediaType),\n )\n )\n throw new Error(\n 'Unsupported family original: only JPEG, PNG, WebP and PDF are supported',\n );\n const originals = originalEvidence.filter((e) => supported(e.mediaType));\n if (\n !originals.length ||\n originals.length > 100 ||\n originals.some(\n (e) => e.byteLength < 1 || e.byteLength > 25 * 1024 * 1024,\n ) ||\n originals.reduce((n, e) => n + e.byteLength, 0) > 100 * 1024 * 1024\n )\n throw new Error('Unsupported or oversized family intake');\n const pages: SubmissionPage[] = [];\n const extensions = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/webp': 'webp',\n 'application/pdf': 'pdf',\n };\n for (const original of originals) {\n if (!Object.hasOwn(extensions, original.mediaType))\n throw new Error('Unsupported family original');\n const data = await input.ingestion.readEvidence(input.itemId, original.id);\n if (\n data.length !== original.byteLength ||\n createHash('sha256').update(data).digest('hex') !== original.contentHash\n )\n throw new Error('Family receipt integrity mismatch');\n pages.push({\n name:\n original.filename ||\n `${original.id}.${extensions[original.mediaType as keyof typeof extensions]}`,\n mimeType: original.mediaType as SubmissionPage['mimeType'],\n data: Buffer.from(data),\n });\n }\n return input.family.retainFamilyIntake({\n ...input.request,\n itemId: input.itemId,\n source,\n pages,\n });\n}\n","import { withPrivateAssetAccess } from '@happyvertical/smrt-assets';\nimport { getCurrentTenant } from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { CatalogAuthorizer } from './catalog-service.js';\nimport type {\n FamilyIntakeAuthorizer,\n FamilyIntakeRequest,\n FamilyIntakeSource,\n FamilyIntakeView,\n} from './family-intake-contracts.js';\nimport {\n FamilyIntakeAssetCollection,\n FamilyIntakeCollection,\n FamilyIntakeDecisionCollection,\n} from './family-intake-models.js';\nimport {\n LearnerAuthorizationError,\n type LearnerAuthorizer,\n} from './learner-service.js';\nimport type {\n SubmissionPage,\n SubmissionServiceOptions,\n} from './submission-service.js';\nimport {\n WorkbookPhotoAssetCollection,\n WorkbookPhotoIntakeCollection,\n} from './workbook-photo-models.js';\nimport { WorkbookPhotoService } from './workbook-photo-service.js';\n\nconst canonical = (value: unknown): string =>\n JSON.stringify(value, (_key, v) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => a.localeCompare(b)),\n )\n : v,\n );\nfunction digest(value: string | Uint8Array): string {\n const crypto =\n typeof process !== 'undefined' && process.getBuiltinModule?.('node:crypto');\n if (!crypto) throw new Error('Family intake requires a Node server');\n return crypto.createHash('sha256').update(value).digest('hex');\n}\nfunction key(value: string) {\n if (\n typeof value !== 'string' ||\n !value.trim() ||\n value.length > 200 ||\n Array.from(value).some(\n (c) => c.charCodeAt(0) < 32 || c.charCodeAt(0) === 127,\n )\n )\n throw new Error('Invalid family intake key');\n}\ntype Selection = FamilyIntakeRequest & { intakeId: string };\ntype Decision =\n | { kind: 'assign'; learnerId: string; reason: string }\n | { kind: 'adopt'; learnerId: string; photoIntakeId: string };\n/** Guardian-only original ownership before learner identity. Assignment never grades work. */\nexport class FamilyIntakeService extends WorkbookPhotoService {\n constructor(\n db: DatabaseInterface,\n authorize: LearnerAuthorizer,\n authorizeCatalog: CatalogAuthorizer,\n private readonly familyOptions: SubmissionServiceOptions,\n private readonly authorizeFamily: FamilyIntakeAuthorizer,\n ) {\n super(db, authorize, authorizeCatalog, familyOptions);\n }\n protected override createTransactionService(db: DatabaseInterface): this {\n return new FamilyIntakeService(\n db,\n this.authorize,\n this.authorizeCatalog,\n this.familyOptions,\n this.authorizeFamily,\n ) as this;\n }\n async authorizeFamilyIntake(\n request: FamilyIntakeRequest,\n action: Parameters<FamilyIntakeAuthorizer>[0]['action'] = 'education.family-intake.read',\n ) {\n this.assertServiceOpen();\n const context = getCurrentTenant();\n if (\n !context ||\n context.superAdminBypass ||\n context.tenantId !== request.tenantId ||\n context.userId !== request.actorUserId ||\n !request.tenantId ||\n !request.actorUserId ||\n !(await this.db.get('memberships', {\n tenant_id: request.tenantId,\n user_id: request.actorUserId,\n status: 'active',\n })) ||\n !(await this.db.get('users', {\n id: request.actorUserId,\n status: 'active',\n })) ||\n (await this.authorizeFamily({\n ...request,\n executor: this.db,\n action,\n })) !== true\n )\n throw new LearnerAuthorizationError();\n }\n private async familyRow(request: Selection) {\n await this.authorizeFamilyIntake(request);\n const row = await (\n await FamilyIntakeCollection.create({ db: this.db })\n ).get(\n { id: request.intakeId, tenantId: request.tenantId },\n { cache: false },\n );\n if (!row) throw new LearnerAuthorizationError();\n return row;\n }\n private async familyDecisions(request: Selection) {\n return (\n await (\n await FamilyIntakeDecisionCollection.create({ db: this.db })\n ).list({\n where: { tenantId: request.tenantId, intakeId: request.intakeId },\n limit: 10000,\n })\n ).sort((a, b) => a.sequence - b.sequence);\n }\n private async lockFamily(request: Selection) {\n await this.db.query(\n 'UPDATE family_intakes SET id=id WHERE id=? AND tenant_id=?',\n [request.intakeId, request.tenantId],\n );\n }\n private async appendFamily(\n request: Selection,\n requestKey: string,\n body: Decision,\n ) {\n return (\n await FamilyIntakeDecisionCollection.create({ db: this.db })\n ).create({\n _insertOnly: true,\n tenantId: request.tenantId,\n intakeId: request.intakeId,\n actorUserId: request.actorUserId,\n requestKey,\n sequence: (await this.familyDecisions(request)).length + 1,\n bodyJson: canonical(body),\n });\n }\n async retainFamilyIntake(\n request: FamilyIntakeRequest & {\n itemId: string;\n source: FamilyIntakeSource;\n pages: readonly SubmissionPage[];\n },\n ): Promise<FamilyIntakeView> {\n return this.composeMutation(async (service) => {\n if (service.executorBorrowed)\n throw new Error('Family storage requires an owned transaction');\n await service.authorizeFamilyIntake(\n request,\n 'education.family-intake.receive',\n );\n key(request.itemId);\n for (const value of [\n request.source?.sourceId,\n request.source?.sourceVersion,\n request.source?.deliveryKey,\n ])\n key(value);\n if (Buffer.byteLength(canonical(request.source)) > 128 * 1024)\n throw new Error('Family source provenance exceeds limit');\n if (request.source.evidence !== undefined) {\n if (\n !Array.isArray(request.source.evidence) ||\n request.source.evidence.length > 200\n )\n throw new Error('Invalid family source evidence');\n for (const evidence of request.source.evidence) {\n for (const value of [\n evidence.evidenceId,\n evidence.partId,\n evidence.mimeType,\n ])\n key(value);\n if (evidence.parentEvidenceId !== null)\n key(evidence.parentEvidenceId);\n if (\n typeof evidence.sha256 !== 'string' ||\n !/^[a-f0-9]{64}$/.test(evidence.sha256)\n )\n throw new Error('Invalid family source evidence hash');\n }\n }\n // Persist the public provenance contract, never arbitrary adapter options.\n const source: FamilyIntakeSource = {\n sourceId: request.source.sourceId,\n sourceVersion: request.source.sourceVersion,\n deliveryKey: request.source.deliveryKey,\n ...(request.source.evidence\n ? {\n evidence: request.source.evidence.map((e) => ({\n evidenceId: e.evidenceId,\n partId: e.partId,\n parentEvidenceId: e.parentEvidenceId,\n mimeType: e.mimeType,\n sha256: e.sha256,\n })),\n }\n : {}),\n };\n service.validatePages(request.pages);\n if (\n request.pages.reduce((n, p) => n + p.data.length, 0) >\n 100 * 1024 * 1024\n )\n throw new Error('Family intake exceeds total byte limit');\n // Serialize first-receipt races before consulting the unique receipt key.\n await service.db.query('UPDATE tenants SET id=id WHERE id=?', [\n request.tenantId,\n ]);\n const contentDigest = digest(\n canonical({\n source,\n pages: request.pages.map((p) => ({\n name: p.name,\n mimeType: p.mimeType,\n sha256: digest(p.data),\n })),\n }),\n );\n const collection = await FamilyIntakeCollection.create({\n db: service.db,\n });\n const prior = await collection.get(\n { tenantId: request.tenantId, itemId: request.itemId },\n { cache: false },\n );\n if (prior) {\n if (prior.contentDigest !== contentDigest)\n throw new Error('Family receipt retry content conflict');\n return service.getFamilyIntake({\n ...request,\n intakeId: String(prior.id),\n });\n }\n const actor = await service.db.get('users', { id: request.actorUserId });\n if (!actor?.profile_id) throw new LearnerAuthorizationError();\n const row = await collection.create({\n _insertOnly: true,\n tenantId: request.tenantId,\n itemId: request.itemId,\n actorUserId: request.actorUserId,\n ownerProfileId: actor.profile_id,\n contentDigest,\n sourceJson: canonical(source),\n });\n const links = await FamilyIntakeAssetCollection.create({\n db: service.db,\n });\n for (const [position, page] of request.pages.entries()) {\n const asset = await service.storePage(request, actor.profile_id, page);\n await links.create({\n _insertOnly: true,\n tenantId: request.tenantId,\n intakeId: String(row.id),\n assetId: String(asset.id),\n name: page.name,\n mimeType: page.mimeType,\n sha256: digest(page.data),\n position,\n });\n }\n return service.getFamilyIntake({ ...request, intakeId: String(row.id) });\n });\n }\n async getFamilyIntake(request: Selection): Promise<FamilyIntakeView> {\n const row = await this.familyRow(request);\n const decisions = await this.familyDecisions(request);\n const assignment = decisions\n .map((d) => JSON.parse(d.bodyJson) as Decision)\n .findLast((d) => d.kind === 'assign');\n const adoption = decisions\n .map((d) => JSON.parse(d.bodyJson) as Decision)\n .find((d) => d.kind === 'adopt');\n const originals = await (\n await FamilyIntakeAssetCollection.create({ db: this.db })\n ).list({\n where: { tenantId: request.tenantId, intakeId: request.intakeId },\n orderBy: 'position',\n limit: 100,\n });\n return {\n id: String(row.id),\n itemId: row.itemId,\n source: JSON.parse(row.sourceJson),\n revision: decisions.length,\n learnerId: assignment?.learnerId ?? null,\n photoIntakeId: adoption?.kind === 'adopt' ? adoption.photoIntakeId : null,\n originals: originals.map((o) => ({\n assetId: o.assetId,\n name: o.name,\n mimeType: o.mimeType,\n sha256: o.sha256,\n })),\n };\n }\n async listFamilyIntakes(\n request: FamilyIntakeRequest,\n options: { limit?: number; offset?: number } = {},\n ): Promise<FamilyIntakeView[]> {\n await this.authorizeFamilyIntake(request);\n const limit = options.limit ?? 20,\n offset = options.offset ?? 0;\n if (\n !Number.isSafeInteger(limit) ||\n limit < 1 ||\n limit > 100 ||\n !Number.isSafeInteger(offset) ||\n offset < 0\n )\n throw new Error('Invalid family inbox page');\n const rows = await (\n await FamilyIntakeCollection.create({ db: this.db })\n ).list({\n where: { tenantId: request.tenantId },\n orderBy: 'createdAt DESC',\n limit,\n offset,\n });\n return Promise.all(\n rows.map((row) =>\n this.getFamilyIntake({ ...request, intakeId: String(row.id) }),\n ),\n );\n }\n async countFamilyIntakes(request: FamilyIntakeRequest): Promise<number> {\n await this.authorizeFamilyIntake(request);\n const rows = await this.db.query(\n 'SELECT COUNT(*) AS total FROM family_intakes f WHERE f.tenant_id=? AND NOT EXISTS (SELECT 1 FROM workbook_photo_intakes p WHERE p.tenant_id=f.tenant_id AND p.family_intake_id=f.id)',\n [request.tenantId],\n );\n return Number(rows.rows[0]?.total ?? 0);\n }\n async getFamilyIntakeTimeline(request: Selection) {\n await this.familyRow(request);\n return (await this.familyDecisions(request)).map((d) => ({\n id: String(d.id),\n revision: d.sequence,\n actorUserId: d.actorUserId,\n requestKey: d.requestKey,\n decision: JSON.parse(d.bodyJson) as Decision,\n }));\n }\n async readFamilyIntakeOriginal(request: Selection & { assetId: string }) {\n const row = await this.familyRow(request);\n const view = await this.getFamilyIntake(request);\n const original = view.originals.find((o) => o.assetId === request.assetId);\n if (!original) throw new LearnerAuthorizationError();\n return withPrivateAssetAccess(\n {\n tenantId: request.tenantId,\n actorUserId: request.actorUserId,\n ownerProfileId: row.ownerProfileId,\n assetIds: [request.assetId],\n },\n async () => {\n const runtime = await this.assets();\n const asset = await runtime.collection.get(\n {\n id: request.assetId,\n tenantId: request.tenantId,\n ownerProfileId: row.ownerProfileId,\n },\n { cache: false },\n );\n if (asset?.accessMode !== 'private')\n throw new LearnerAuthorizationError();\n const data = await runtime.store.read(asset);\n if (digest(data) !== original.sha256)\n throw new Error('Retained family original integrity mismatch');\n return { data, mimeType: original.mimeType };\n },\n );\n }\n async assignFamilyIntake(\n request: Selection & {\n learnerId: string;\n guardianRelationshipId: string;\n requestKey: string;\n expectedRevision: number;\n reason: string;\n },\n ): Promise<FamilyIntakeView> {\n return this.composeMutation(async (service) => {\n await service.authorizeFamilyIntake(\n request,\n 'education.family-intake.assign',\n );\n await service.lockFamily(request);\n await service.requireActor(request, 'education.learner.plan');\n key(request.requestKey);\n key(request.reason);\n const view = await service.getFamilyIntake(request);\n const body: Decision = {\n kind: 'assign',\n learnerId: request.learnerId,\n reason: request.reason,\n };\n const prior = (await service.familyDecisions(request)).find(\n (d) => d.requestKey === request.requestKey,\n );\n if (prior) {\n if (prior.bodyJson !== canonical(body))\n throw new Error('Family decision retry content conflict');\n return view;\n }\n if (view.photoIntakeId)\n throw new Error('Adopted family intake cannot be retargeted');\n if (\n !Number.isSafeInteger(request.expectedRevision) ||\n request.expectedRevision !== view.revision\n )\n throw new Error('Family intake revision conflict');\n await service.appendFamily(request, request.requestKey, body);\n return service.getFamilyIntake(request);\n });\n }\n /** Freeze the explicit assignment and borrow exact originals; no capture or grading. */\n async adoptFamilyIntake(\n request: Selection & {\n learnerId: string;\n guardianRelationshipId: string;\n requestKey: string;\n expectedRevision: number;\n },\n ): Promise<FamilyIntakeView> {\n return this.composeMutation(async (service) => {\n await service.authorizeFamilyIntake(\n request,\n 'education.family-intake.assign',\n );\n await service.lockFamily(request);\n await service.requireActor(request, 'education.learner.plan');\n key(request.requestKey);\n const view = await service.getFamilyIntake(request);\n const prior = (await service.familyDecisions(request)).find(\n (d) => d.requestKey === request.requestKey,\n );\n if (prior) {\n const body = JSON.parse(prior.bodyJson) as Decision;\n if (body.kind !== 'adopt' || body.learnerId !== request.learnerId)\n throw new Error('Family decision retry content conflict');\n return view;\n }\n if (view.photoIntakeId || view.learnerId !== request.learnerId)\n throw new Error('Family intake assignment mismatch');\n if (\n !Number.isSafeInteger(request.expectedRevision) ||\n request.expectedRevision !== view.revision\n )\n throw new Error('Family intake revision conflict');\n const row = await service.familyRow(request);\n // Verify every retained hash before exposing it through a learner-bound join.\n for (const original of view.originals)\n await service.readFamilyIntakeOriginal({\n ...request,\n assetId: original.assetId,\n });\n const photoIntakeId = globalThis.crypto.randomUUID();\n await service.appendFamily(request, request.requestKey, {\n kind: 'adopt',\n learnerId: request.learnerId,\n photoIntakeId,\n });\n const photo = await (\n await WorkbookPhotoIntakeCollection.create({ db: service.db })\n ).create({\n id: photoIntakeId,\n _insertOnly: true,\n tenantId: request.tenantId,\n learnerId: request.learnerId,\n familyIntakeId: request.intakeId,\n itemId: row.itemId,\n actorUserId: row.actorUserId,\n contentDigest: row.contentDigest,\n });\n const links = await WorkbookPhotoAssetCollection.create({\n db: service.db,\n });\n for (const [position, original] of view.originals.entries())\n await links.create({\n _insertOnly: true,\n tenantId: request.tenantId,\n learnerId: request.learnerId,\n intakeId: String(photo.id),\n ...original,\n position,\n });\n\n return service.getFamilyIntake(request);\n });\n }\n}\n","/**\n * Server-only ingestion bridge for question extraction (SMRT #4517): the\n * `extract-questions` catalog handler and the preserve step that validates a\n * completed proposal against retained evidence. Never import from browser code.\n */\nimport type {\n HandlerContext,\n OperationHandler,\n} from '@happyvertical/smrt-ingestion/execution';\nimport {\n type IngestionService,\n normalizeObservedImageRegions,\n} from '@happyvertical/smrt-ingestion/server';\nimport { getCurrentTenant, withTenant } from '@happyvertical/smrt-tenancy';\nimport { registerPermissionDefinitions } from '@happyvertical/smrt-users';\nimport type { CourseAuthoringActor } from './course-authoring-contracts.js';\nimport { intakeOriginalEvidence } from './intake-original-evidence.js';\nimport type { WorksheetBundle } from './question-contracts.js';\nimport { QUESTION_EXTRACTION_ARGS_SCHEMA } from './question-extraction.js';\nimport {\n MAX_EXTRACTED_PAGES,\n type QuestionExtractionGrounding,\n QuestionExtractionPendingError,\n QuestionExtractionValidationError,\n type QuestionExtractionView,\n} from './question-extraction-contracts.js';\nimport {\n type QuestionExtractionService,\n questionExtractionProposalDigest,\n} from './question-extraction-service.js';\n\nexport const QUESTION_EXTRACTION_HANDLER_ID =\n '@happyvertical/smrt-education:extract-questions';\nconst QUESTION = '@happyvertical/smrt-education:Question';\nconst MEDIA_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'application/pdf',\n];\n\n// Closed model transports generate no operation permissions; declaring this\n// server catalog entry grants nothing to any principal or actor.\nregisterPermissionDefinitions([\n {\n slug: 'questions.create',\n collection: 'questions',\n qualifiedName: QUESTION,\n name: 'Apply reviewed question extractions',\n },\n]);\n\nconst DESCRIPTION =\n 'Extract the printed questions of a scanned worksheet or imported course file as structured data for extraction review. ' +\n 'Report every source page in pages with its role (exercise, example, instructions, cover, answer_key, mixed, unknown) and readability; never drop a page. ' +\n 'questions holds printed task text only: prompt, numbering exactly as printed, subparts, choices, section, diagram/table/image references and any answer key or rubric printed in the source (origin source). ' +\n 'Mark anything you supply yourself origin inferred; never present an inferred key, type or points as printed. ' +\n 'Unreadable or unsupported tasks keep their key and numbering with status unreadable/unsupported and prompt null; content you cannot extract goes in omissions. ' +\n 'Worked examples use role example. Learner handwriting goes only in studentWork (observed text, or null when illegible), never in prompts or keys; never solve a task and report it as observed work. ' +\n 'Keys: printed numbering path (for example 3, 3b), else u:<short printed-task slug>:<occurrence>. ' +\n 'worksheetVersionId only when a wsv1- id is printed on the page. Anchors cite original evidenceId, the physical source page (1-based, or null when unknown; printed page numbers are not pages) and regionId only from that evidence observedRegions catalog, else null; never coordinates. ' +\n 'Applying needs a human extraction decision; it creates or links question records and never grades or attaches learner work.';\n\n/** Bind a handler call to the authenticated host actor; same rules as education intake. */\nfunction bound<T>(\n request: CourseAuthoringActor,\n context: HandlerContext,\n work: () => Promise<T>,\n): Promise<T> {\n if (\n context.scope.tenantId !== request.tenantId ||\n context.scope.actorId !== request.actorUserId ||\n !context.policy.requireReview\n )\n throw new Error('Question extraction scope mismatch');\n if (!context.principal) return work();\n // Ingestion's stable execution principal is not the human requester: keep\n // its tenant permissions, change only the domain actor to the scope actor.\n const tenant = getCurrentTenant();\n if (\n !tenant ||\n tenant.tenantId !== request.tenantId ||\n tenant.userId !== context.principal.context.userId ||\n context.principal.context.tenantId !== request.tenantId\n )\n throw new Error('Question extraction principal tenant mismatch');\n return withTenant(\n {\n ...tenant,\n tenantId: request.tenantId,\n userId: request.actorUserId,\n superAdminBypass: false,\n },\n work,\n );\n}\n\nfunction summary(view: QuestionExtractionView) {\n const count = (outcome: string) =>\n view.match.questions.filter((m) => m.outcome === outcome).length;\n return {\n extractionId: view.extractionId,\n sourceKind: view.extraction.sourceKind,\n worksheetVersionId: view.match.worksheetVersionId,\n worksheetKnown: view.match.worksheetKnown,\n questions: view.extraction.questions.length,\n matched: count('matched'),\n ambiguous: count('ambiguous'),\n unmatched: count('unmatched'),\n unreadable: view.extraction.questions.filter(\n (q) => q.status === 'unreadable' || q.status === 'unsupported',\n ).length,\n studentWork: view.studentWork.length,\n omissions: view.extraction.omissions.length,\n sourceWarnings: view.extraction.sourceWarnings,\n extractionReviewRequired: true,\n };\n}\n\n/**\n * The `extract-questions` handler for ONE authenticated actor (guardian or a\n * delegated agent). The application resolves `request` from its session. Keep\n * every ingestion policy layer `requireReview: true`; there is no automation.\n * Apply requires `preserveQuestionExtractionAnalysis` to have kept the exact\n * proposal first.\n */\nexport function educationQuestionExtractionHandler(input: {\n extractions: QuestionExtractionService;\n request: CourseAuthoringActor;\n}): OperationHandler {\n const { extractions, request } = input;\n const preserved = async (\n args: Record<string, unknown>,\n context: HandlerContext,\n ) => {\n const view = await bound(request, context, () =>\n extractions.withExecutor(context.db).findExtraction({\n ...request,\n intakeItemId: context.itemId,\n proposalDigest: questionExtractionProposalDigest(args),\n }),\n );\n if (!view)\n throw new Error('Question extraction must be preserved before review');\n return view;\n };\n return {\n id: QUESTION_EXTRACTION_HANDLER_ID,\n version: '1',\n label: 'Extract questions',\n description: DESCRIPTION,\n operation: { model: QUESTION, action: 'create', version: '1' },\n capability: { effect: 'write', idempotent: true, openWorld: false },\n argsSchema: QUESTION_EXTRACTION_ARGS_SCHEMA as unknown as Record<\n string,\n unknown\n >,\n resultSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['extractionId'],\n properties: {\n extractionId: { type: 'string', minLength: 1, maxLength: 64 },\n },\n },\n resultModels: {},\n discovery: { mediaTypes: MEDIA_TYPES, references: {} },\n validate: async (args, context) => {\n await preserved(args, context);\n return { ok: true };\n },\n preview: async (args, context) => ({\n display: summary(await preserved(args, context)),\n normalizedArgs: args,\n targetPreconditions: [],\n }),\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n const view = await preserved(args, context);\n await bound(request, context, () =>\n extractions\n .withExecutor(context.db)\n .applyExtraction({ ...request, extractionId: view.extractionId }),\n );\n return { extractionId: view.extractionId };\n },\n },\n };\n}\n\ntype Snapshot = Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>;\n\n/** Retained original evidence of one completed analysis, as extraction grounding. */\nexport function questionExtractionGrounding(\n snapshot: Snapshot,\n warnings: readonly string[] = [],\n): QuestionExtractionGrounding {\n const results = Array.isArray(snapshot.result.output?.results)\n ? (snapshot.result.output.results as unknown[])\n : [];\n const originals = intakeOriginalEvidence(snapshot.evidence ?? []).filter(\n (e) => e.mediaType !== 'application/json',\n );\n type Location = {\n kind?: string;\n page?: number;\n startPage?: number;\n endPage?: number;\n };\n /** Physical pages named by one location; ranges are expanded, never trimmed. */\n const pagesOf = (location: Location | undefined): number[] => {\n const valid = (n: unknown): n is number =>\n Number.isSafeInteger(n) && (n as number) > 0;\n if (location?.kind === 'page' && valid(location.page))\n return [location.page];\n if (\n location?.kind === 'pages' &&\n valid(location.startPage) &&\n valid(location.endPage) &&\n location.endPage >= location.startPage\n ) {\n if (location.endPage - location.startPage >= MAX_EXTRACTED_PAGES)\n throw new QuestionExtractionValidationError('Too many source pages');\n return Array.from(\n { length: location.endPage - location.startPage + 1 },\n (_, i) => (location.startPage as number) + i,\n );\n }\n return [];\n };\n const sources = originals.map((evidence) => {\n const base = {\n evidenceId: evidence.id,\n sha256: evidence.contentHash,\n mediaType: evidence.mediaType,\n };\n const result = results.find(\n (value) =>\n !!value &&\n typeof value === 'object' &&\n (value as { evidence?: { id?: string; contentHash?: string } }).evidence\n ?.id === evidence.id &&\n (value as { evidence?: { contentHash?: string } }).evidence\n ?.contentHash === evidence.contentHash,\n ) as\n | {\n segments?: { location?: Location; observedRegions?: unknown }[];\n errors?: { location?: Location }[];\n omitted?: Location[];\n truncated?: boolean;\n }\n | undefined;\n // A retained original with no result is still a source: it must stay visible.\n if (!result) return { ...base, pages: [], extracted: false };\n const segments = Array.isArray(result.segments) ? result.segments : [];\n const failed = [\n ...(Array.isArray(result.omitted) ? result.omitted : []),\n ...(Array.isArray(result.errors)\n ? result.errors.map((e) => e?.location)\n : []),\n ];\n const extractedPages = segments.flatMap((s) => pagesOf(s.location));\n const omittedPages = [...new Set(failed.flatMap((l) => pagesOf(l)))]\n .filter((p) => !extractedPages.includes(p))\n .sort((a, b) => a - b);\n const pages = [...new Set([...extractedPages, ...omittedPages])].sort(\n (a, b) => a - b,\n );\n if (pages.length > MAX_EXTRACTED_PAGES)\n throw new QuestionExtractionValidationError('Too many source pages');\n const catalogs = evidence.mediaType.startsWith('image/')\n ? segments\n .filter((s) => s.location?.kind === 'source')\n .map((s) => normalizeObservedImageRegions(s.observedRegions))\n .filter((c) => c !== undefined)\n : [];\n const incomplete = result.truncated === true || failed.length > 0;\n return {\n ...base,\n pages,\n ...(omittedPages.length ? { omittedPages } : {}),\n ...(incomplete ? { incomplete: true } : {}),\n ...(catalogs.length === 1 ? { observedRegions: catalogs[0] } : {}),\n };\n });\n const codes = [\n ...new Set([\n ...warnings.filter((w) => /^[a-z][a-z0-9_.-]{0,47}$/.test(w)),\n ...(snapshot.result.output?.truncated === true\n ? ['source_incomplete']\n : []),\n ]),\n ]\n .sort()\n .slice(0, 16);\n return {\n version: 1,\n extractionAttemptId: snapshot.attemptId,\n ...(codes.length ? { warnings: codes } : {}),\n sources,\n };\n}\n\n/**\n * Preserve the current completed `extract-questions` proposal of one intake\n * item for extraction review: validates it against retained evidence, matches\n * it to known worksheets and records it (idempotent per analysis attempt).\n * Not ready, no proposal or competing proposals throw\n * `QuestionExtractionPendingError`; invalid output throws\n * `QuestionExtractionValidationError`. Writes no question records.\n */\nexport async function preserveQuestionExtractionAnalysis(input: {\n ingestion: IngestionService;\n extractions: QuestionExtractionService;\n request: CourseAuthoringActor;\n itemId: string;\n expectedWorksheetVersionId?: string;\n worksheets?: readonly WorksheetBundle[];\n}): Promise<QuestionExtractionView> {\n let snapshot: Snapshot;\n try {\n snapshot = await input.ingestion.getCompletedAnalysis(input.itemId);\n } catch (error) {\n if (error instanceof Error && error.message === 'Analysis unavailable')\n throw new QuestionExtractionPendingError('pending');\n throw error;\n }\n if (\n snapshot.configuration.stage !== 'interpret' ||\n !['completed', 'partial'].includes(snapshot.result.status)\n )\n throw new QuestionExtractionPendingError('pending');\n const generation = (\n snapshot.result.output as unknown as {\n proposals?: import('@happyvertical/smrt-ingestion').GenerationOutput;\n }\n ).proposals;\n if (generation?.version !== 1 || !Array.isArray(generation.suggestions))\n throw new QuestionExtractionValidationError('Malformed generation output');\n if (generation.outcome === 'ambiguous')\n throw new QuestionExtractionPendingError('ambiguous');\n if (!['proposals', 'needs_review'].includes(generation.outcome))\n throw new QuestionExtractionPendingError('no_proposal');\n const suggestions = generation.suggestions.filter(\n (s) => s.handlerId === QUESTION_EXTRACTION_HANDLER_ID,\n );\n if (!suggestions.length)\n throw new QuestionExtractionPendingError('no_proposal');\n if (suggestions.length > 1)\n throw new QuestionExtractionPendingError('ambiguous');\n const suggestion = suggestions[0];\n if (suggestion.missingFields.length)\n throw new QuestionExtractionValidationError(\n 'Incomplete question extraction',\n );\n const generative = generation.provenance.generative;\n return input.extractions.preserveExtraction({\n ...input.request,\n intakeItemId: input.itemId,\n analysisAttemptId: snapshot.attemptId,\n grounding: questionExtractionGrounding(snapshot, generation.warnings ?? []),\n extractor: {\n provider: generative.provider,\n model: generative.model,\n version: generative.version,\n configurationVersion: generation.provenance.configurationVersion,\n promptVersion: generation.provenance.promptVersion,\n },\n extraction: suggestion.args,\n ...(input.expectedWorksheetVersionId\n ? { expectedWorksheetVersionId: input.expectedWorksheetVersionId }\n : {}),\n ...(input.worksheets ? { worksheets: input.worksheets } : {}),\n });\n}\n","/** Server-only pre-activity intake bridge. Uses public ingestion APIs exclusively. */\nimport { createHash } from 'node:crypto';\nimport type { OperationHandler } from '@happyvertical/smrt-ingestion/execution';\nimport {\n GenerationSnapshotStaleError,\n type IngestionScope,\n type IngestionService,\n ProposalsNotConfiguredError,\n type ReceiveInput,\n} from '@happyvertical/smrt-ingestion/server';\nimport { getCurrentTenant, withTenant } from '@happyvertical/smrt-tenancy';\nimport { registerPermissionDefinitions } from '@happyvertical/smrt-users';\nimport { processEducationAnalysis } from './ingestion.js';\nimport { intakeOriginalEvidence } from './intake-original-evidence.js';\nimport type { LearnerRequest } from './learner-service.js';\nimport type { SubmissionPage } from './submission-service.js';\nimport {\n validateWorkbookPhotoIdentification,\n type WorkbookPhotoProposal,\n} from './workbook-photo-contracts.js';\nimport {\n preservePhotoProposal,\n type WorkbookPhotoService,\n} from './workbook-photo-service.js';\n\nconst MODEL = '@happyvertical/smrt-education:WorkbookPhotoIntake';\nexport const WORKBOOK_PHOTO_HANDLER =\n '@happyvertical/smrt-education:identify-workbook-photo';\nregisterPermissionDefinitions([\n {\n slug: 'workbookphotointakes.read',\n collection: 'workbookphotointakes',\n qualifiedName: MODEL,\n name: 'Identify authorized workbook photos',\n },\n]);\nfunction assertScope(scope: Readonly<IngestionScope>, request: LearnerRequest) {\n if (\n scope.tenantId !== request.tenantId ||\n scope.actorId !== request.actorUserId ||\n scope.confidentialScopeId !== request.learnerId\n )\n throw new Error('Photo intake scope mismatch');\n}\nconst canonical = (value: unknown): string =>\n JSON.stringify(value, (_key, v) =>\n v && typeof v === 'object' && !Array.isArray(v)\n ? Object.fromEntries(\n Object.entries(v).sort(([a], [b]) => a.localeCompare(b)),\n )\n : v,\n );\nconst string = {\n type: 'string',\n maxLength: 2000,\n pattern: '^[^\\\\u0000-\\\\u001F\\\\u007F]*$',\n};\nconst schema = {\n type: 'object',\n additionalProperties: false,\n required: [\n 'identification',\n 'confidence',\n 'identityEvidence',\n 'lessonEvidence',\n ],\n properties: {\n workbookId: {\n type: 'string',\n maxLength: 64,\n description:\n 'Exact existing candidate id. Also copy its workbookKey, title and edition into the required identification.workbook object; this selects existing identity, not a new workbook.',\n },\n confidence: { type: 'string', enum: ['confident', 'uncertain'] },\n identityEvidence: {\n type: 'array',\n maxItems: 20,\n items: { ...string, minLength: 1 },\n },\n lessonEvidence: string,\n identification: {\n type: 'object',\n additionalProperties: false,\n required: ['kind', 'workState'],\n properties: {\n kind: {\n type: 'string',\n enum: ['lesson', 'work', 'cover', 'reference', 'uncertain'],\n },\n workState: { type: 'string', enum: ['blank', 'completed', 'unknown'] },\n notes: string,\n workbook: {\n type: 'object',\n additionalProperties: false,\n required: ['workbookKey', 'title'],\n properties: {\n workbookKey: string,\n title: string,\n edition: string,\n publisher: string,\n isbn: string,\n },\n },\n activity: {\n type: 'object',\n additionalProperties: false,\n required: ['pageKey', 'pageLabel'],\n properties: { pageKey: string, pageLabel: string },\n },\n },\n },\n },\n};\n/** Generation proposes material identity only; execution never writes educational outcomes. */\nexport function workbookPhotoIntakeHandlers(input: {\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n}): OperationHandler[] {\n const bound = async <T>(\n context: Parameters<OperationHandler['validate']>[1],\n work: (service: WorkbookPhotoService) => Promise<T>,\n ): Promise<T> => {\n const checked = async (service: WorkbookPhotoService) => {\n await service.assertWorkbookPhotoScope(\n input.request,\n context.scope,\n context.itemId,\n );\n return work(service);\n };\n if (!context.policy.requireReview)\n throw new Error('Photo intake requires review policy');\n if (!context.principal)\n return input.workbooks.withExecutor(context.db, checked);\n const tenant = getCurrentTenant();\n if (\n !tenant ||\n tenant.tenantId !== input.request.tenantId ||\n tenant.userId !== context.principal.context.userId ||\n context.principal.context.tenantId !== input.request.tenantId\n )\n throw new Error('Photo principal tenant mismatch');\n return withTenant(\n {\n ...tenant,\n tenantId: input.request.tenantId,\n userId: input.request.actorUserId,\n superAdminBypass: false,\n },\n () => input.workbooks.withExecutor(context.db, checked),\n );\n };\n const authorize = async (\n context: Parameters<OperationHandler['validate']>[1],\n ) =>\n bound(context, async (service) => {\n await service.authorizePhotoIntake(input.request);\n await service.getWorkbookPhotoIntakeByItem({\n ...input.request,\n itemId: context.itemId,\n });\n });\n return [\n {\n id: WORKBOOK_PHOTO_HANDLER,\n version: '1',\n description:\n 'Classify photos as work, lesson, cover, reference (contents/answer keys), or uncertain. Visible completed learner responses use work even without book/lesson identity: workState=completed; omit workbook/activity/workbookId; lessonEvidence=\"\". Confidence concerns visible material/completion, not missing identity. Printed examples/answer keys alone are not learner completion. Partial/unreadable answers can be unassessed later. Blank/unknown completion never auto-marks. For lesson/cover/reference identity: existing book selects exact workbookId AND copies candidate workbookKey/title/edition into identification.workbook. Unique current title+edition can match retained publisher context; publisher/ISBN need not reappear. identityEvidence quotes ONLY current photos, never candidate context. Conflicts, duplicate candidates or title/page-only matches cannot establish identity. New book needs visible ISBN or publisher/title/edition; workbookKey is a hint, never merge authority. Lesson activity requires printed lesson identifier: pageKey=lesson:<identifier>, pageLabel printed label, lessonEvidence quotes it; page number alone is insufficient. Multiple pages can share a lesson. Cover/reference omit activity. Missing book/lesson alone uses work, not uncertain. Ambiguous material/completion uses uncertain confidence. args: identification, confidence, identityEvidence, lessonEvidence, optional workbookId. identification: kind, workState, optional workbook, activity, notes. workbook: workbookKey,title, optional edition,publisher,isbn. activity: pageKey,pageLabel. Single-line visible quotes only; no controls/placeholders. Omit absent optional fields, never null or extra keys. Classify only; no marks or learning observations.',\n operation: { model: MODEL, action: 'get', version: '1' },\n capability: { effect: 'read', idempotent: true, openWorld: false },\n argsSchema: schema,\n resultSchema: schema,\n resultModels: {},\n discovery: {\n mediaTypes: [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'application/pdf',\n ],\n references: {\n workbookId: {\n kind: 'candidate',\n model: '@happyvertical/smrt-education:Workbook',\n },\n },\n candidates: async (query, context, page) => {\n await authorize(context);\n const books = await bound(context, (service) =>\n service.listWorkbookPhotoWorkbooks(input.request),\n );\n const needle = query.toLowerCase();\n const ordered = [...books].sort(\n (a, b) =>\n Number(b.title.toLowerCase().includes(needle)) -\n Number(a.title.toLowerCase().includes(needle)) ||\n a.id.localeCompare(b.id),\n );\n return {\n items: ordered.slice(0, page.limit).map((book) => ({\n model: '@happyvertical/smrt-education:Workbook',\n id: book.id,\n revision: workbookRevision(book),\n label: JSON.stringify(book),\n })),\n hasMore: ordered.length > page.limit,\n };\n },\n },\n validate: async (args, context) => {\n await authorize(context);\n validateWorkbookPhotoIdentification(\n (args as unknown as WorkbookPhotoProposal).identification,\n );\n return { ok: true };\n },\n preview: async (args, context) => {\n await authorize(context);\n return {\n display: { classification: args.identification, gradeApplied: false },\n normalizedArgs: args,\n targetPreconditions: [],\n };\n },\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n await authorize(context);\n return args;\n },\n },\n },\n ];\n}\nfunction workbookRevision(book: unknown) {\n return `workbook:${createHash('sha256').update(canonical(book)).digest('hex')}`;\n}\n/** Candidate freshness and authorization on ingestion's supplied executor. */\nexport function workbookPhotoIntakeTargetResolver(input: {\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n}): import('@happyvertical/smrt-ingestion/execution').IntakeExecutionOptions['assertTarget'] {\n return async ({ db, scope, itemId, model, id, revision }) => {\n if (model !== '@happyvertical/smrt-education:Workbook')\n throw new Error('Photo target unavailable');\n const books = await withTenant(\n {\n ...getCurrentTenant(),\n tenantId: input.request.tenantId,\n userId: input.request.actorUserId,\n superAdminBypass: false,\n },\n () =>\n input.workbooks.withExecutor(db, async (service) => {\n await service.assertWorkbookPhotoScope(input.request, scope, itemId);\n return service.listWorkbookPhotoWorkbooks(input.request);\n }),\n );\n const book = books.find((book) => book.id === id);\n if (!book) throw new Error('Photo target unavailable');\n const current = workbookRevision(book);\n if (revision !== undefined && revision !== current)\n throw new Error('Photo target changed');\n return { revision: current };\n };\n}\n/** Receive before asking for workbook selection; duplicate receipts repair interrupted copying. */\nexport async function receiveWorkbookPhotoIntake(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n receive: ReceiveInput;\n}) {\n assertScope(input.scope, input.request);\n await input.workbooks.authorizePhotoIntake(input.request);\n const receipt = await input.ingestion.receive(input.receive);\n if (!('itemId' in receipt) || !receipt.itemId)\n return { receipt, intake: null };\n const intake = await retainWorkbookPhotoReceipt({\n ...input,\n itemId: receipt.itemId,\n });\n return { receipt, intake };\n}\n/** Recovery after a receive succeeded but the private education copy was interrupted. */\nexport async function retainWorkbookPhotoReceipt(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest;\n itemId: string;\n}) {\n assertScope(input.scope, input.request);\n await input.workbooks.authorizePhotoIntake(input.request);\n const extensions: Record<string, string> = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/webp': 'webp',\n 'application/pdf': 'pdf',\n };\n const originals = (await input.ingestion.getEvidence(input.itemId))\n .filter((e) => e.parentEvidenceId === null)\n .sort((a, b) => a.partId.localeCompare(b.partId));\n if (\n !originals.length ||\n originals.length > 100 ||\n originals.some(\n (e) =>\n !extensions[e.mediaType] ||\n e.byteLength < 1 ||\n e.byteLength > 25 * 1024 * 1024,\n ) ||\n originals.reduce((n, e) => n + e.byteLength, 0) > 100 * 1024 * 1024\n )\n throw new Error('Unsupported or oversized photo intake');\n const pages: SubmissionPage[] = [];\n for (const original of originals) {\n const data = await input.ingestion.readEvidence(input.itemId, original.id);\n if (\n data.length !== original.byteLength ||\n createHash('sha256').update(data).digest('hex') !== original.contentHash\n )\n throw new Error('Photo receipt integrity mismatch');\n pages.push({\n name: `${original.id}.${extensions[original.mediaType]}`,\n mimeType: original.mediaType as SubmissionPage['mimeType'],\n data: Buffer.from(data),\n });\n }\n return input.workbooks.retainWorkbookPhotoIntake({\n ...input.request,\n itemId: input.itemId,\n pages,\n });\n}\n/** Transfer immutable provider provenance; malformed/ambiguous/failed results stay pending. */\nexport async function preserveWorkbookPhotoIdentification(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest & { intakeId: string };\n}) {\n const view = await input.workbooks.getWorkbookPhotoIntake(input.request);\n await input.workbooks.assertWorkbookPhotoScope(\n input.request,\n input.scope,\n view.itemId,\n );\n let snapshot: Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>;\n try {\n snapshot = await input.ingestion.getCompletedAnalysis(view.itemId);\n } catch (error) {\n if (\n error instanceof ProposalsNotConfiguredError ||\n error instanceof GenerationSnapshotStaleError ||\n (error instanceof Error &&\n ['Analysis unavailable', 'Intake unavailable'].includes(error.message))\n )\n return view;\n throw error;\n }\n if (\n snapshot.itemId !== view.itemId ||\n snapshot.configuration.stage !== 'interpret' ||\n !['completed', 'partial'].includes(snapshot.result.status)\n )\n return view;\n const generation = (\n snapshot.result.output as unknown as {\n proposals?: import('@happyvertical/smrt-ingestion').GenerationOutput;\n }\n ).proposals;\n if (\n generation?.version !== 1 ||\n !['proposals', 'needs_review'].includes(generation.outcome)\n )\n return view;\n const suggestions = generation.suggestions.filter(\n (s) => s.handlerId === WORKBOOK_PHOTO_HANDLER,\n );\n const offered = generation.offered.find(\n (o) => o.handler.id === WORKBOOK_PHOTO_HANDLER,\n );\n if (\n suggestions.length !== 1 ||\n suggestions[0].missingFields.length ||\n !offered ||\n canonical(offered.handler.argsSchema) !== canonical(schema)\n )\n return view;\n const proposal = suggestions[0].args as unknown as WorkbookPhotoProposal;\n try {\n validateWorkbookPhotoIdentification(proposal.identification);\n if (\n !['confident', 'uncertain'].includes(proposal.confidence) ||\n !Array.isArray(proposal.identityEvidence) ||\n proposal.identityEvidence.length > 20 ||\n proposal.identityEvidence.some(\n (e) => typeof e !== 'string' || e.length > 2000,\n ) ||\n typeof proposal.lessonEvidence !== 'string' ||\n proposal.lessonEvidence.length > 200\n )\n return view;\n } catch {\n return view;\n }\n return input.workbooks[preservePhotoProposal]({\n ...input.request,\n requestKey: `analysis:${snapshot.attemptId}`,\n proposal,\n allowAutomaticResolution:\n generation.outcome === 'proposals' &&\n generation.suggestions.length === 1 &&\n suggestions[0].alternatives.length === 0 &&\n generation.splits.length === 0,\n sourceHashes: intakeOriginalEvidence(snapshot.evidence)\n .filter((e) => e.mediaType !== 'application/json')\n .map((e) => e.contentHash),\n provenance: {\n attemptId: snapshot.attemptId,\n revision: snapshot.revision,\n inputDigest: snapshot.inputDigest,\n outputDigest: snapshot.outputDigest,\n evidenceDigest: snapshot.evidenceDigest,\n configuration: snapshot.configuration,\n provider: snapshot.result.provider,\n model: snapshot.result.model,\n },\n });\n}\n/** Existing durable extraction/interpretation dispatcher, followed by preservation. */\nexport async function processWorkbookPhotoAnalysis(\n input: Parameters<typeof processEducationAnalysis>[0] & {\n scope: Readonly<IngestionScope>;\n workbooks: WorkbookPhotoService;\n request: LearnerRequest & { intakeId: string };\n },\n) {\n const view = await input.workbooks.getWorkbookPhotoIntake(input.request);\n await input.workbooks.assertWorkbookPhotoScope(\n input.request,\n input.scope,\n view.itemId,\n );\n if (view.itemId !== input.itemId)\n throw new Error('Photo worker receipt mismatch');\n const processing = await processEducationAnalysis(input);\n const intake = await preserveWorkbookPhotoIdentification(input);\n const capture =\n intake.status === 'resolved' &&\n ['lesson', 'work'].includes(intake.identification?.kind ?? '') &&\n intake.identification?.workState === 'completed'\n ? await input.workbooks.captureWorkbookPhotoIntake({\n ...input.request,\n requestKey: `photo:${intake.itemId}`,\n })\n : null;\n const current = capture\n ? await input.workbooks.getWorkbookPhotoIntake(input.request)\n : intake;\n return {\n processing,\n intake: current,\n capture,\n assessmentRequired: current.status === 'captured',\n };\n}\n","/** Server-only paper workflow integration. Never import from browser handlers. */\nimport {\n type ExtractionAdapter,\n type ExtractionLimits,\n extractAnalysis,\n GenerationSnapshotStaleError,\n type IngestionService,\n normalizeObservedImageRegions,\n ProposalsNotConfiguredError,\n} from '@happyvertical/smrt-ingestion/server';\nimport { intakeOriginalEvidence } from './intake-original-evidence.js';\nimport { normalizeWorkbookAnswerRegions } from './workbook-answer-regions.js';\n\nimport { normalizeWorkbookObservedLayout } from './workbook-layout.js';\n\nexport { requireIngestionMemoryLimit } from './ingestion-isolation.js';\n\n/** Immutable operator configuration; never populated from upload/model metadata. */\nexport interface EducationExtractionConfiguration {\n configurationRevision: string;\n limits: ExtractionLimits;\n}\n\n/** Allocate extraction after a durable receipt. The normal ingestion outbox\n * dispatches this revision to the application's registered job target.\n */\nexport async function queueEducationExtraction(\n ingestion: IngestionService,\n itemId: string,\n configuration: EducationExtractionConfiguration,\n submissionId?: string,\n) {\n return ingestion.analyze(\n itemId,\n { extraction: configuration },\n `education:extract:${configuration.configurationRevision}:${submissionId ?? 'identify'}`,\n );\n}\n\n/** A registered job invokes this with its persisted item/revision IDs and an\n * authenticated service scope. Providers execute outside database transactions.\n * Interpretation receives ingestion's immutable extraction pin. Neither stage\n * approves a suggestion, captures a submission, or applies a grade.\n */\nexport async function processEducationAnalysis(input: {\n ingestion: IngestionService;\n itemId: string;\n revision: number;\n workerId: string;\n adapter: ExtractionAdapter;\n extraction: EducationExtractionConfiguration;\n}): Promise<\n | { kind: 'unclaimed' | 'extraction_incomplete' | 'interpreted' }\n | { kind: 'generation_queued'; revision: number }\n> {\n const { ingestion, itemId } = input;\n const lease = await ingestion.claimAnalysis(\n itemId,\n input.revision,\n input.workerId,\n );\n if (!lease) return { kind: 'unclaimed' };\n const snapshot = await ingestion.getAnalysisInput(lease);\n if (snapshot.configuration.stage === 'interpret') {\n await ingestion.generateProposals(lease);\n return { kind: 'interpreted' };\n }\n if (!snapshot.configuration.extraction)\n throw new Error('Unsupported education analysis stage');\n const completed = await extractAnalysis(\n ingestion,\n lease,\n input.adapter,\n input.extraction,\n );\n if (!completed) return { kind: 'extraction_incomplete' };\n const result = await ingestion.getCompletedAnalysis(itemId, lease.attemptId);\n if (!['completed', 'partial'].includes(result.result.status))\n return { kind: 'extraction_incomplete' };\n const generation = await ingestion.prepareGeneration(\n itemId,\n result.attemptId,\n );\n const queued = await ingestion.analyze(\n itemId,\n {\n ...generation,\n educationEvidenceGrounding: educationEvidenceGrounding(result),\n },\n `education:interpret:${result.attemptId}`,\n );\n return { kind: 'generation_queued', revision: queued.revision };\n}\n\nimport { createHash } from 'node:crypto';\nimport type { IngestionScope } from '@happyvertical/smrt-ingestion/server';\nimport { getCurrentTenant, withTenant } from '@happyvertical/smrt-tenancy';\nimport { registerPermissionDefinitions } from '@happyvertical/smrt-users';\nimport type { LearnerRequest } from './learner-service.js';\nimport type {\n SubmissionPage,\n SubmissionService,\n} from './submission-service.js';\nimport {\n aggregateWorkbookQuestions,\n validateWorkbookAssessment,\n WORKBOOK_MATH_VOCABULARY,\n type WorkbookAssessment,\n WorkbookAssessmentValidationError,\n workbookAggregateFeedback,\n} from './workbook-contracts.js';\nimport { WorkbookService } from './workbook-service.js';\n\nexport type EducationIntakeCaptureRequest = LearnerRequest & {\n workbookActivityId?: string;\n assistance?: import('./workbook-contracts.js').WorkbookAssistance;\n enrollmentId: string;\n lessonId: string;\n itemId: string;\n kind: 'blank_reference' | 'completed_work';\n previousSubmissionId?: string;\n notes?: string;\n};\n\n/** Copy immutable retained originals into education's private ownership only\n * after the host has obtained explicit assignment confirmation. Supply service\n * and scope from the SAME authenticated server factory, never browser values.\n * The owning service persists unique tenant/item binding before allowing retries.\n */\nexport async function captureEducationIntake(input: {\n ingestion: IngestionService;\n scope: Readonly<IngestionScope>;\n submissions: SubmissionService;\n request: EducationIntakeCaptureRequest;\n}) {\n const { ingestion, submissions, scope, request } = input;\n if (\n request.tenantId !== scope.tenantId ||\n request.actorUserId !== scope.actorId ||\n request.enrollmentId !== scope.confidentialScopeId ||\n !['blank_reference', 'completed_work'].includes(request.kind) ||\n (request.kind === 'blank_reference' && request.previousSubmissionId)\n )\n throw new Error('Invalid education intake binding');\n // Prove the exact active learner/enrollment/lesson assignment before reading\n // any family-private retained evidence. Intake scopes are enrollment-bound.\n await submissions.assertLessonAssignment(request);\n const evidence = (await ingestion.getEvidence(request.itemId)).filter(\n (entry) => entry.parentEvidenceId === null,\n );\n const extensions: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n 'application/pdf': 'pdf',\n };\n if (\n !evidence.length ||\n evidence.length > 100 ||\n evidence.some(\n (entry) =>\n !extensions[entry.mediaType] ||\n !Number.isSafeInteger(entry.byteLength) ||\n entry.byteLength < 1 ||\n entry.byteLength > 25 * 1024 * 1024,\n ) ||\n evidence.reduce((sum, entry) => sum + entry.byteLength, 0) >\n 100 * 1024 * 1024\n )\n throw new Error('Unsupported or oversized education intake');\n evidence.sort((a, b) => a.partId.localeCompare(b.partId));\n const pages: SubmissionPage[] = [];\n for (const entry of evidence) {\n const bytes = await ingestion.readEvidence(request.itemId, entry.id);\n if (\n bytes.byteLength !== entry.byteLength ||\n createHash('sha256').update(bytes).digest('hex') !== entry.contentHash\n )\n throw new Error('Education intake integrity mismatch');\n pages.push({\n name: `${entry.id}.${extensions[entry.mediaType]}`,\n mimeType: entry.mediaType as SubmissionPage['mimeType'],\n data: Buffer.from(bytes),\n });\n }\n const capture = {\n ...request,\n requestKey: `education:intake:${request.itemId}`,\n pages,\n intake: {\n intakeItemId: request.itemId,\n kind: request.kind,\n previousSubmissionId: request.previousSubmissionId,\n },\n };\n if (request.workbookActivityId) {\n if (\n !(submissions instanceof WorkbookService) ||\n request.kind !== 'completed_work'\n )\n throw new Error(\n 'Workbook intake requires WorkbookService completed work',\n );\n const attempt = await submissions.captureWorkbookWork({\n ...request,\n activityId: request.workbookActivityId,\n intakeItemId: request.itemId,\n requestKey: capture.requestKey,\n pages,\n });\n return attempt.submission;\n }\n if (request.kind === 'blank_reference')\n return submissions.captureBlankReference({\n ...capture,\n intakeItemId: request.itemId,\n });\n return request.previousSubmissionId\n ? submissions.resubmitSubmission({\n intakeItemId: request.itemId,\n ...capture,\n previousSubmissionId: request.previousSubmissionId,\n })\n : submissions.captureSubmission(capture);\n}\n\nimport type {\n HandlerContext,\n IntakeValues,\n OperationHandler,\n} from '@happyvertical/smrt-ingestion/execution';\n\nconst LESSON = '@happyvertical/smrt-education:Lesson';\nconst SUBMISSION = '@happyvertical/smrt-education:Submission';\nconst GRADE = '@happyvertical/smrt-education:Grade';\nconst idSchema = { type: 'string', minLength: 1, maxLength: 64 };\n// Closed model transports intentionally generate no operation permissions.\n// Declaring this server catalog does not grant it to any principal or actor.\nregisterPermissionDefinitions([\n {\n slug: 'lessons.read',\n collection: 'lessons',\n qualifiedName: LESSON,\n name: 'Identify authorized education assignments',\n },\n {\n slug: 'grades.create',\n collection: 'grades',\n qualifiedName: GRADE,\n name: 'Apply guardian-reviewed education grades',\n },\n]);\n\n/** Build the authoritative discovery/review catalog for ONE authenticated\n * learner/enrollment. The application resolves request from its session and\n * assignment; model/browser output can select a lesson but cannot select a user.\n * Keep all ingestion policy layers requireReview=true; no automation opt-in.\n */\nexport function educationIntakeHandlers(input: {\n submissions: SubmissionService;\n request: LearnerRequest & { enrollmentId: string };\n /** After capture, bind a new grading stage to this exact immutable attempt. */\n submissionId?: string;\n workbookActivityId?: string;\n workbookVocabulary?: WorkbookAssessment['vocabulary'];\n}): OperationHandler[] {\n const { submissions, request } = input;\n const bound = async <T>(\n context: HandlerContext,\n work: (service: SubmissionService) => Promise<T>,\n ): Promise<T> => {\n if (\n context.scope.tenantId !== request.tenantId ||\n context.scope.actorId !== request.actorUserId ||\n !context.policy.requireReview\n )\n throw new Error('Education intake scope mismatch');\n // Ingestion's stable execution principal is not the human requester.\n // Preserve tenant permissions and the separate PrincipalRun runtime; only\n // the domain actor changes to the already-authenticated scope actor.\n if (!context.principal) return submissions.withExecutor(context.db, work);\n const tenant = getCurrentTenant();\n if (\n !tenant ||\n tenant.tenantId !== request.tenantId ||\n tenant.userId !== context.principal.context.userId ||\n context.principal.context.tenantId !== request.tenantId\n )\n throw new Error('Education principal tenant mismatch');\n return withTenant(\n {\n ...tenant,\n tenantId: request.tenantId,\n userId: request.actorUserId,\n superAdminBypass: false,\n },\n () => submissions.withExecutor(context.db, work),\n );\n };\n const lessons = (context: HandlerContext) =>\n bound(context, (service) => service.assignmentLessons(request));\n const requireLesson = async (args: IntakeValues, context: HandlerContext) => {\n const found = (await lessons(context)).find(\n (entry) => entry.lesson.id === args.lessonId,\n );\n if (!found) throw new Error('Education assignment unavailable');\n await context.assertTarget(LESSON, found.lesson.id);\n return found;\n };\n const handlers: OperationHandler[] = [\n {\n id: '@happyvertical/smrt-education:identify-assignment',\n version: '1',\n description:\n 'Identify an assigned lesson from a blank or completed scan. Ambiguity requires guardian correction; this action does not grade or capture.',\n operation: { model: LESSON, action: 'get', version: '1' },\n capability: { effect: 'read', idempotent: true, openWorld: false },\n argsSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['lessonId'],\n properties: { lessonId: idSchema },\n },\n resultSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['lessonId'],\n properties: { lessonId: idSchema },\n },\n resultModels: { lessonId: LESSON },\n discovery: {\n mediaTypes: [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'application/pdf',\n ],\n references: { lessonId: { kind: 'candidate', model: LESSON } },\n candidates: async (query, context, page) => {\n // Authorize/filter exact enrollment FIRST; text only ranks that set.\n const visible = await lessons(context);\n const needle = query.toLocaleLowerCase();\n const ordered = [...visible].sort(\n (a, b) =>\n Number(b.lesson.title.toLocaleLowerCase().includes(needle)) -\n Number(a.lesson.title.toLocaleLowerCase().includes(needle)) ||\n a.lesson.id.localeCompare(b.lesson.id),\n );\n return {\n items: ordered.slice(0, page.limit).map((entry) => ({\n model: LESSON,\n id: entry.lesson.id,\n // Version binds immutable assignment identity; the host target\n // resolver must use this same format and reauthorize the plan.\n revision: `assignment:${request.enrollmentId}:${entry.lesson.id}`,\n label: entry.lesson.title,\n })),\n hasMore: ordered.length > page.limit,\n };\n },\n },\n validate: async (args, context) => {\n await requireLesson(args, context);\n return { ok: true };\n },\n preview: async (args, context) => {\n const found = await requireLesson(args, context);\n return {\n display: { lesson: found.lesson.title, gradeApplied: false },\n normalizedArgs: args,\n targetPreconditions: [\n {\n model: LESSON,\n id: found.lesson.id,\n revision: `assignment:${request.enrollmentId}:${found.lesson.id}`,\n },\n ],\n };\n },\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n const found = await requireLesson(args, context);\n return { lessonId: found.lesson.id };\n },\n },\n },\n ];\n if (!input.submissionId) return handlers;\n const submissionId = input.submissionId;\n const current = (context: HandlerContext) =>\n bound(context, (service) =>\n service.getSubmission({ ...request, submissionId }),\n );\n const requireSubmission = async (\n args: IntakeValues,\n context: HandlerContext,\n ) => {\n if (args.submissionId !== submissionId)\n throw new Error('Education attempt binding mismatch');\n const submission = await current(context);\n if (\n submission.intakeItemId !== context.itemId ||\n submission.kind !== 'completed_work'\n )\n throw new Error('Education intake/attempt binding mismatch');\n await context.assertTarget(SUBMISSION, submissionId);\n return submission;\n };\n const workbook = input.workbookActivityId;\n if (workbook && !(submissions instanceof WorkbookService))\n throw new Error('Workbook handler requires WorkbookService');\n const vocabulary = input.workbookVocabulary ?? WORKBOOK_MATH_VOCABULARY;\n handlers.push({\n id: '@happyvertical/smrt-education:review-submission',\n version: '1',\n description: workbook\n ? 'Assess visible questions from current captured evidence only. Historical IDs indicate correspondence, never current answers. Prompt is printed task text excluding response; answer is observed learner response only. Printed solved examples/answer keys are not learner answers or learning evidence. Never solve a task and call it the observed response. Matching answers require explicitly observed line endpoints; unreadable connections are unassessed/illegible or missing_context. Missing book/lesson identity never blocks visible work. Use printed number+occurrence/subpart IDs when present. Unnumbered tasks use u:<short printed-task slug>:<occurrence/subpart>, excluding learner answers and solved results. Occurrence identifies visible tasks, never output-array position. Retain exact known IDs on correction; absent/ambiguous correspondence is unassessed/not_present, never guessed or renumbered. Cite original evidence IDs only; no page/rect/coordinate fields, as service retains whole-source grounding. Correct/incorrect/partially_correct use reason none. Unsupported, unanswered, illegible, missing_context and not_present are unassessed, never incorrect, with null points. Judge objectively solvable arithmetic without a printed rubric. Correctness is independent of points: absent evidenced allocation, BOTH points and possiblePoints are null, including incorrect. Never invent weights/rubric or mix null/numeric fields. Only use incorrect points=0 when possiblePoints is known; correct earns that known total. No aggregate score/summary: service computes totals. Concepts are supplied-vocabulary suggestions; no match uses conceptIds [] and still assesses normally. markingCertainty=uncertain requires result=unassessed, reason illegible/missing_context/unsupported/unanswered/not_present, points=null and possiblePoints=null. Never assert correctness with uncertain marking. Mapping certainty is separate. Guardian review is required for authority.'\n : 'Suggest marks and feedback for this captured attempt. Only a current authorized guardian decision may apply a grade.',\n operation: { model: GRADE, action: 'create', version: '1' },\n capability: { effect: 'write', idempotent: false, openWorld: false },\n argsSchema: {\n type: 'object',\n additionalProperties: false,\n required: workbook\n ? ['submissionId', 'questions']\n : ['submissionId', 'score', 'feedback'],\n properties: {\n submissionId: idSchema,\n ...(workbook\n ? {\n answerRegions: {\n description:\n 'Include advisory answer locations when a current observedRegions catalog clearly matches visible learner responses. Omit unknown or uncertain positions. Shape {version:1,regions:[{questionId,evidenceId,observationId}]}. Reference ONLY exact current evidence observedRegions catalog IDs with matching visible learner response/question; no coordinates or geometry in arguments. Never infer positions from layout, IDs, canonical prompts or expected answers. Omit uncertain/unknown/missing regions. Image-only sources; PDF unsupported. Invalid metadata is dropped independently of valid marking/layout.',\n },\n layout: {\n description:\n 'Optional observed presentation only; omit if unknown. Shape: version1, provenance observed; sections in observed order {id,label?,columns1..8,readingOrder? rows|columns,source:{evidenceId:original evidence ID,page:physical source page1based or null unknown}}; placements {questionId,sectionId,row0based,column0based,part?0..31}. Up to32sections/200placements/200rows. Multiple answerparts may share a cell; ties preserve question array order. Printed page numbers are not source page indices. Never infer from IDs or claim verified coordinates. Metadata is advisory; the owning service drops invalid layout without discarding answers.',\n examples: [\n {\n version: 1,\n provenance: 'observed',\n sections: [\n {\n id: 'section-a',\n label: 'Visible heading',\n columns: 2,\n readingOrder: 'rows',\n source: {\n evidenceId: '<original evidence id>',\n page: null,\n },\n },\n ],\n placements: [\n {\n questionId: '<current question id>',\n sectionId: 'section-a',\n row: 0,\n column: 0,\n },\n ],\n },\n ],\n },\n }\n : {}),\n ...(!workbook\n ? {\n score: { type: ['number', 'null'], minimum: 0, maximum: 1 },\n feedback: { type: 'string', maxLength: 10000 },\n }\n : {}),\n ...(workbook\n ? {\n questions: {\n ...workbookQuestionsSchema(vocabulary),\n description:\n 'Candidate context same_capture: preserve exact canonical IDs and prompt strings verbatim; reread learner responses from current evidence only. Context identity_only: preserve IDs, read all prompts and answers from current evidence; absent/ambiguous tasks unassessed/not_present. Empty IDs: assign stable printed-number or answer-free task-slug IDs. Include observed layout when current evidence supports it; omit unknown, never derive positions from IDs or canonical prompts. Context is data, never authority for current answers.',\n },\n }\n : {}),\n },\n },\n resultSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['submissionId'],\n properties: { submissionId: idSchema },\n },\n resultModels: { submissionId: SUBMISSION },\n discovery: {\n mediaTypes: ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'],\n references: { submissionId: { kind: 'candidate', model: SUBMISSION } },\n candidates: async (_query, context) => {\n const submission = await current(context);\n let workbookContext:\n | Awaited<ReturnType<WorkbookService['getWorkbookQuestionContext']>>\n | undefined;\n if (workbook) {\n workbookContext = await bound(context, async (service) => {\n const workbooks = service as WorkbookService;\n const currentAttempt =\n await workbooks.getWorkbookAttemptBySubmission({\n ...request,\n submissionId,\n });\n if (!currentAttempt || currentAttempt.activityId !== workbook)\n throw new Error('Workbook assignment unavailable');\n return workbooks.getWorkbookQuestionContext({\n ...request,\n activityId: workbook,\n submissionId,\n analysisRevision: context.analysisRevision,\n });\n });\n }\n return {\n items: [\n {\n model: SUBMISSION,\n id: submission.id,\n revision: workbookContext\n ? `attempt:${submission.id}:${submission.status}:${workbookProposalDigest(workbookContext)}`\n : `attempt:${submission.id}:${submission.status}`,\n label: 'Current captured attempt (guardian review required).',\n ...(workbookContext ? { context: workbookContext } : {}),\n },\n ],\n hasMore: false,\n };\n },\n },\n validate: async (args, context) => {\n await requireSubmission(args, context);\n return { ok: true };\n },\n preview: async (args, context) => {\n const submission = await requireSubmission(args, context);\n const revision = workbook\n ? await bound(context, async (service) => {\n const current = await (\n service as WorkbookService\n ).getWorkbookQuestionContext({\n ...request,\n activityId: workbook,\n submissionId,\n analysisRevision: context.analysisRevision,\n });\n return `attempt:${submission.id}:${submission.status}:${workbookProposalDigest(current)}`;\n })\n : `attempt:${submission.id}:${submission.status}`;\n return {\n display: {\n submissionId,\n ...(workbook\n ? { questions: args.questions }\n : { proposedScore: args.score, proposedFeedback: args.feedback }),\n guardianReviewRequired: true,\n },\n normalizedArgs: args,\n targetPreconditions: [\n {\n model: SUBMISSION,\n id: submissionId,\n revision,\n },\n ],\n };\n },\n execution: {\n kind: 'database',\n apply: async (args, context) => {\n await requireSubmission(args, context);\n if (workbook) {\n await bound(context, async (service) => {\n const workbooks = service as WorkbookService;\n let cursor: string | undefined;\n let attempt:\n | Awaited<\n ReturnType<WorkbookService['getWorkbookTimeline']>\n >['attempts'][number]\n | undefined;\n do {\n const timeline = await workbooks.getWorkbookTimeline({\n ...request,\n activityId: workbook,\n ...(cursor ? { cursor } : {}),\n });\n attempt = timeline.attempts.find(\n (entry) => entry.submissionId === submissionId,\n );\n cursor = timeline.nextCursor ?? undefined;\n } while (!attempt && cursor);\n const proposal = attempt?.revisions.find(\n (revision) =>\n revision.kind === 'ai' &&\n revision.assessment.provenance.proposalDigest ===\n workbookProposalDigest(args),\n );\n if (!proposal)\n throw new Error(\n 'Workbook analysis must be preserved before guardian apply',\n );\n await workbooks.reviewWorkbookAssessment({\n ...request,\n activityId: workbook,\n submissionId,\n revisionId: proposal.id,\n expectedHeadId: null,\n requestKey: `ingestion-review:${proposal.id}`,\n });\n });\n return { submissionId };\n }\n await bound(context, (service) =>\n service.applyReviewedSubmission({\n ...request,\n submissionId,\n score: args.score as number | null,\n feedback: String(args.feedback),\n }),\n );\n return { submissionId };\n },\n },\n });\n return handlers;\n}\n\n/** Owning education target resolver for ingestion's transactional host hook.\n * Serializes with education enrollment mutations, then performs public service\n * authorization on the supplied executor. The host still owns live principal\n * grant/revocation serialization in its execution authorize callback.\n */\nexport function educationIntakeTargetResolver(input: {\n submissions: SubmissionService;\n request: LearnerRequest & { enrollmentId: string };\n submissionId?: string;\n}): import('@happyvertical/smrt-ingestion/execution').IntakeExecutionOptions['assertTarget'] {\n return async ({\n db,\n scope,\n itemId,\n analysisRevision,\n model,\n id,\n revision,\n }) => {\n const { request, submissions } = input;\n if (\n scope.tenantId !== request.tenantId ||\n scope.actorId !== request.actorUserId\n )\n throw new Error('Education intake scope mismatch');\n // Match workbook capture/review ordering: learner first, then enrollment.\n await db.query(\n 'UPDATE learners SET id=id WHERE id=? AND tenant_id=?',\n request.learnerId,\n request.tenantId,\n );\n await db.query(\n 'UPDATE enrollments SET id=id WHERE id=? AND tenant_id=?',\n request.enrollmentId,\n request.tenantId,\n );\n const current = await withTenant(\n {\n ...getCurrentTenant(),\n tenantId: request.tenantId,\n userId: request.actorUserId,\n superAdminBypass: false,\n },\n () =>\n submissions.withExecutor(db, async (service) => {\n if (model === LESSON) {\n const available = await service.assignmentLessons(request);\n if (!available.some((entry) => entry.lesson.id === id))\n throw new Error('Education assignment unavailable');\n return `assignment:${request.enrollmentId}:${id}`;\n }\n if (model !== SUBMISSION || id !== input.submissionId)\n throw new Error('Education target unavailable');\n const submission = await service.getSubmission({\n ...request,\n submissionId: id,\n });\n if (\n submission.intakeItemId !== itemId ||\n submission.kind !== 'completed_work'\n )\n throw new Error('Education intake/attempt binding mismatch');\n if (service instanceof WorkbookService) {\n const attempt = await service.getWorkbookAttemptBySubmission({\n ...request,\n submissionId: id,\n });\n if (attempt) {\n const context = await service.getWorkbookQuestionContext({\n ...request,\n activityId: attempt.activityId,\n submissionId: id,\n analysisRevision,\n });\n return `attempt:${submission.id}:${submission.status}:${workbookProposalDigest(context)}`;\n }\n }\n return `attempt:${submission.id}:${submission.status}`;\n }),\n );\n if (revision !== undefined && revision !== current)\n throw new Error('Education target changed');\n return { revision: current };\n };\n}\n\nfunction workbookProposalDigest(value: unknown): string {\n // Canonical object keys permit DTO/JSON roundtrips without changing identity.\n const canonical = (v: unknown): unknown =>\n Array.isArray(v)\n ? v.map(canonical)\n : v && typeof v === 'object'\n ? Object.fromEntries(\n Object.entries(v)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, x]) => [k, canonical(x)]),\n )\n : v;\n return createHash('sha256')\n .update(JSON.stringify(canonical(value)))\n .digest('hex');\n}\n\nfunction workbookQuestionsSchema(vocabulary: WorkbookAssessment['vocabulary']) {\n return {\n type: 'array',\n minItems: 1,\n maxItems: 200,\n items: {\n type: 'object',\n additionalProperties: false,\n required: [\n 'id',\n 'prompt',\n 'answer',\n 'result',\n 'reason',\n 'feedback',\n 'points',\n 'possiblePoints',\n 'anchors',\n 'conceptIds',\n 'markingCertainty',\n 'mappingCertainty',\n 'evidenceLimitations',\n ],\n oneOf: [\n {\n properties: {\n result: { enum: ['correct', 'incorrect', 'partially_correct'] },\n markingCertainty: { enum: ['clear', 'unknown'] },\n reason: { const: 'none' },\n },\n },\n {\n properties: {\n result: { const: 'unassessed' },\n reason: {\n enum: [\n 'unanswered',\n 'illegible',\n 'missing_context',\n 'unsupported',\n 'not_present',\n ],\n },\n points: { type: 'null' },\n possiblePoints: { type: 'null' },\n },\n },\n ],\n properties: {\n id: { type: 'string', minLength: 1, maxLength: 200 },\n prompt: { type: 'string', maxLength: 10000 },\n answer: { type: 'string', maxLength: 10000 },\n result: {\n type: 'string',\n enum: ['correct', 'incorrect', 'partially_correct', 'unassessed'],\n },\n reason: {\n type: 'string',\n enum: [\n 'none',\n 'unanswered',\n 'illegible',\n 'missing_context',\n 'unsupported',\n 'not_present',\n ],\n },\n feedback: { type: 'string', maxLength: 10000 },\n points: { type: ['number', 'null'], minimum: 0 },\n possiblePoints: { type: ['number', 'null'], minimum: 0 },\n markingCertainty: {\n type: 'string',\n enum: ['clear', 'uncertain', 'unknown'],\n },\n mappingCertainty: {\n type: 'string',\n enum: ['clear', 'uncertain', 'unknown'],\n },\n evidenceLimitations: {\n type: 'array',\n maxItems: 20,\n items: { type: 'string', maxLength: 500 },\n },\n conceptIds: {\n type: 'array',\n maxItems: 10,\n items: { type: 'string', enum: vocabulary.concepts.map((c) => c.id) },\n },\n anchors: {\n type: 'array',\n minItems: 1,\n maxItems: 20,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['evidenceId'],\n properties: {\n evidenceId: idSchema,\n },\n },\n },\n },\n },\n };\n}\n\n/** Bounded geometry capability transfer, pinned in the generation configuration. */\nfunction educationEvidenceGrounding(\n snapshot: Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>,\n) {\n const results = Array.isArray(snapshot.result.output?.results)\n ? snapshot.result.output.results\n : [];\n const sources = results.slice(0, 100).flatMap((value) => {\n if (!value || typeof value !== 'object') return [];\n const result = value as {\n evidence?: { id?: string; contentHash?: string; mediaType?: string };\n capabilities?: { location?: string }[];\n segments?: {\n location?: { kind?: string; page?: number };\n observedRegions?: unknown;\n }[];\n };\n const evidence = (snapshot.evidence ?? []).find(\n (e) =>\n e.id === result.evidence?.id &&\n e.contentHash === result.evidence?.contentHash,\n );\n if (!evidence) return [];\n const pageCapable =\n Array.isArray(result.capabilities) &&\n result.capabilities.some((c) => c.location === 'page');\n const pages =\n pageCapable && Array.isArray(result.segments)\n ? [\n ...new Set(\n result.segments.flatMap((segment) =>\n segment.location?.kind === 'page' &&\n Number.isSafeInteger(segment.location.page) &&\n (segment.location.page ?? 0) > 0\n ? [segment.location.page as number]\n : [],\n ),\n ),\n ].slice(0, 1000)\n : [];\n const catalogs =\n typeof evidence.mediaType === 'string' &&\n evidence.mediaType.startsWith('image/') &&\n Array.isArray(result.segments)\n ? result.segments\n .filter((s) => s.location?.kind === 'source')\n .map((s) => normalizeObservedImageRegions(s.observedRegions))\n .filter((s) => s !== undefined)\n : [];\n return [\n {\n evidenceId: evidence.id,\n sha256: evidence.contentHash,\n pages,\n ...(catalogs.length === 1 ? { observedRegions: catalogs[0] } : {}),\n },\n ];\n });\n return { version: 1, extractionAttemptId: snapshot.attemptId, sources };\n}\n\nexport type WorkbookPreservationResult =\n | { kind: 'pending' }\n | { kind: 'unavailable' }\n | { kind: 'retained'; revisionId: string }\n | { kind: 'preserved'; revisionId: string }\n | {\n kind: 'needs_review';\n reason:\n | 'invalid_assessment'\n | 'ungrounded_source'\n | 'ambiguous_proposal'\n | 'stale_analysis';\n };\n\n/** Preserve validated question evidence; invalid model output is reviewable status,\n * never an educational mark or a generic server error. Education authorization,\n * integrity and DB errors throw; unavailable scratch never grants raw access.\n */\nexport async function preserveWorkbookIntakeAnalysis(input: {\n ingestion: IngestionService;\n workbooks: WorkbookService;\n request: LearnerRequest & { enrollmentId: string };\n activityId: string;\n submissionId: string;\n workbookVocabulary?: WorkbookAssessment['vocabulary'];\n}): Promise<WorkbookPreservationResult> {\n const { ingestion, workbooks, request, activityId, submissionId } = input;\n const attempt = await workbooks.getWorkbookAttemptBySubmission({\n ...request,\n submissionId,\n });\n if (\n !attempt ||\n attempt.activityId !== activityId ||\n !attempt.submission.intakeItemId\n )\n throw new Error('Workbook intake binding unavailable');\n const itemId = attempt.submission.intakeItemId;\n const state = await workbooks.getWorkbookPreservationState({\n ...request,\n activityId,\n submissionId,\n });\n const latestRetained = state.retainedAnalyses.at(-1);\n const legacyRetained = state.retainedAnalyses.every(\n (entry) => entry.analysisRevision === null,\n )\n ? latestRetained\n : undefined;\n let currentRevision: number;\n try {\n currentRevision = (await ingestion.getItem(itemId)).analysisRevision;\n } catch (error) {\n if (error instanceof Error && error.message === 'Intake unavailable')\n return latestRetained\n ? { kind: 'retained', revisionId: latestRetained.assessmentRevisionId }\n : { kind: 'unavailable' };\n throw error;\n }\n const exact = state.retainedAnalyses.find(\n (entry) => entry.analysisRevision === currentRevision,\n );\n if (exact)\n return { kind: 'retained', revisionId: exact.assessmentRevisionId };\n let snapshot: Awaited<ReturnType<IngestionService['getCompletedAnalysis']>>;\n try {\n snapshot = await ingestion.getCompletedAnalysis(itemId);\n } catch (error) {\n if (error instanceof ProposalsNotConfiguredError)\n return legacyRetained\n ? { kind: 'retained', revisionId: legacyRetained.assessmentRevisionId }\n : { kind: 'unavailable' };\n if (error instanceof GenerationSnapshotStaleError)\n return legacyRetained\n ? { kind: 'retained', revisionId: legacyRetained.assessmentRevisionId }\n : { kind: 'needs_review', reason: 'stale_analysis' };\n if (error instanceof Error && error.message === 'Intake unavailable')\n return latestRetained\n ? { kind: 'retained', revisionId: latestRetained.assessmentRevisionId }\n : { kind: 'unavailable' };\n if (error instanceof Error && error.message === 'Analysis unavailable')\n return latestRetained\n ? { kind: 'retained', revisionId: latestRetained.assessmentRevisionId }\n : { kind: 'pending' };\n throw error;\n }\n if (\n snapshot.configuration.stage !== 'interpret' ||\n !['completed', 'partial'].includes(snapshot.result.status)\n )\n return { kind: 'pending' };\n const importedAttempt = state.retainedAnalyses.find(\n (entry) => entry.analysisAttemptId === snapshot.attemptId,\n );\n if (importedAttempt)\n return {\n kind: 'retained',\n revisionId: importedAttempt.assessmentRevisionId,\n };\n const sources = await workbooks.getWorkbookSourceAnchors({\n ...request,\n activityId,\n submissionId,\n });\n const originals = intakeOriginalEvidence(snapshot.evidence).filter(\n (e) => e.mediaType !== 'application/json',\n );\n if (\n originals.length !== sources.length ||\n originals.some((e, i) => e.contentHash !== sources[i].sha256)\n )\n throw new Error('Workbook retained source mismatch');\n let assessment: WorkbookAssessment;\n try {\n const generation = (\n snapshot.result.output as unknown as {\n proposals?: import('@happyvertical/smrt-ingestion').GenerationOutput;\n }\n ).proposals;\n if (\n !generation ||\n generation.version !== 1 ||\n !Array.isArray(generation.suggestions)\n )\n throw new WorkbookAssessmentValidationError(\n 'Malformed workbook generation',\n );\n if (!['proposals', 'needs_review'].includes(generation.outcome))\n return {\n kind: 'needs_review',\n reason:\n generation.outcome === 'ambiguous'\n ? 'ambiguous_proposal'\n : 'invalid_assessment',\n };\n const suggestions = generation.suggestions.filter(\n (s) => s.handlerId === '@happyvertical/smrt-education:review-submission',\n );\n if (suggestions.length !== 1)\n throw new WorkbookAssessmentValidationError(\n 'Expected one workbook proposal',\n 'ambiguous_proposal',\n );\n const suggestion = suggestions[0];\n if (\n suggestion.args.submissionId !== submissionId ||\n !Array.isArray(suggestion.args.questions) ||\n suggestion.missingFields.length\n )\n throw new WorkbookAssessmentValidationError(\n 'Incomplete workbook question proposal',\n );\n const offered = generation.offered.find(\n (entry) => entry.handler.id === suggestion.handlerId,\n );\n const questionSchema = (\n offered?.handler.argsSchema.properties as\n | Record<string, unknown>\n | undefined\n )?.questions as\n | { items: { properties: { conceptIds: { items: { enum: string[] } } } } }\n | undefined;\n if (!questionSchema)\n throw new WorkbookAssessmentValidationError(\n 'Generation did not use workbook question contract',\n );\n const curated = input.workbookVocabulary ?? WORKBOOK_MATH_VOCABULARY;\n if (\n JSON.stringify(questionSchema.items.properties.conceptIds.items.enum) !==\n JSON.stringify(curated.concepts.map((c) => c.id))\n )\n throw new WorkbookAssessmentValidationError(\n 'Unsupported workbook vocabulary',\n );\n const grounding = snapshot.configuration.educationEvidenceGrounding as\n | {\n version?: number;\n extractionAttemptId?: string;\n sources?: {\n evidenceId: string;\n sha256: string;\n pages: number[];\n observedRegions?: unknown;\n }[];\n }\n | undefined;\n const trustedGrounding =\n grounding?.version === 1 &&\n grounding.extractionAttemptId === generation.source?.attemptId\n ? grounding\n : undefined;\n const questions = suggestion.args.questions.map((value) => {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new WorkbookAssessmentValidationError(\n 'Invalid workbook question',\n );\n const q = value as Record<string, unknown>;\n if (!Array.isArray(q.anchors))\n throw new WorkbookAssessmentValidationError(\n 'Missing workbook source anchors',\n 'ungrounded_source',\n );\n const limitations = new Set(\n Array.isArray(q.evidenceLimitations)\n ? (q.evidenceLimitations as string[])\n : [],\n );\n const anchors = q.anchors.map((value) => {\n const anchor = value as { evidenceId?: string };\n const index = originals.findIndex((e) => e.id === anchor?.evidenceId);\n if (index < 0)\n throw new WorkbookAssessmentValidationError(\n 'Question must cite a captured original',\n 'ungrounded_source',\n );\n const original = originals[index];\n const page = original.mediaType?.startsWith('image/') ? 1 : null;\n const level = 'source' as const;\n limitations.add(\n 'Source-level evidence only; no verified question page or region was supplied by extraction.',\n );\n return {\n assetId: sources[index].assetId,\n sha256: sources[index].sha256,\n page,\n rect: [0, 0, 1, 1] as [number, number, number, number],\n grounding: level,\n ...(trustedGrounding?.extractionAttemptId\n ? { extractionAttemptId: trustedGrounding.extractionAttemptId }\n : {}),\n };\n });\n return {\n ...q,\n anchors,\n evidenceLimitations: [...limitations],\n } as unknown as WorkbookAssessment['questions'][number];\n });\n let observedLayout: unknown = suggestion.args.layout;\n if (\n observedLayout &&\n typeof observedLayout === 'object' &&\n !Array.isArray(observedLayout)\n ) {\n const candidate = observedLayout as Record<string, unknown>;\n if (\n Array.isArray(candidate.sections) &&\n candidate.sections.length <= 32\n ) {\n observedLayout = {\n ...candidate,\n sections: candidate.sections.map((section: unknown) => {\n if (\n !section ||\n typeof section !== 'object' ||\n Array.isArray(section)\n )\n return section;\n const row = section as Record<string, unknown>;\n const source = row.source as\n | { evidenceId?: unknown; page?: unknown }\n | undefined;\n const index = originals.findIndex(\n (e) => e.id === source?.evidenceId,\n );\n return {\n ...row,\n source: {\n assetId: index >= 0 ? sources[index].assetId : '',\n page: source?.page,\n },\n };\n }),\n };\n }\n }\n let mappedRegions: unknown = suggestion.args.answerRegions;\n if (\n mappedRegions &&\n typeof mappedRegions === 'object' &&\n !Array.isArray(mappedRegions)\n ) {\n const proposed = mappedRegions as Record<string, unknown>;\n if (proposed.version === 1 && Array.isArray(proposed.regions)) {\n mappedRegions = {\n version: 1,\n provenance: 'observed',\n coordinateSpace: 'display-oriented',\n regions: proposed.regions.map((entry: unknown) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry))\n return {};\n const r = entry as Record<string, unknown>;\n if (\n Object.keys(r).some(\n (key) =>\n !['questionId', 'evidenceId', 'observationId'].includes(key),\n )\n )\n return {};\n const index = originals.findIndex(\n (e) =>\n e.id === r.evidenceId &&\n typeof e.mediaType === 'string' &&\n e.mediaType.startsWith('image/'),\n );\n const catalogSource = trustedGrounding?.sources?.find(\n (source) =>\n source.evidenceId === r.evidenceId &&\n source.sha256 === originals[index]?.contentHash,\n );\n const catalog = normalizeObservedImageRegions(\n catalogSource?.observedRegions,\n );\n const observed = catalog?.regions.find(\n (region) => region.id === r.observationId,\n );\n return {\n questionId: r.questionId,\n source: {\n assetId: index >= 0 ? sources[index].assetId : '',\n page: 1,\n },\n observationId: r.observationId,\n rect: observed?.rect,\n };\n }),\n };\n }\n }\n assessment = {\n version: 1,\n feedback: '',\n questions,\n ...normalizeWorkbookObservedLayout(observedLayout, questions, sources),\n ...normalizeWorkbookAnswerRegions(mappedRegions, questions, sources),\n vocabulary: structuredClone(curated),\n provenance: {\n provider: generation.provenance.generative.provider,\n model:\n generation.provenance.generativeResponseModel ??\n generation.provenance.generative.model,\n configurationVersion: generation.provenance.configurationVersion,\n rubricVersion: generation.provenance.promptVersion,\n inputHash: snapshot.inputDigest,\n analysisId: snapshot.attemptId,\n analysisRevision: snapshot.revision,\n proposalDigest: workbookProposalDigest(suggestion.args),\n providerVersion: generation.provenance.generative.version,\n sourceAnalysis: generation.source,\n catalogDigest: generation.provenance.catalogDigest,\n policyVersions: generation.provenance.policyVersions,\n },\n };\n validateWorkbookAssessment(assessment);\n assessment.aggregate = aggregateWorkbookQuestions(assessment.questions);\n assessment.feedback = workbookAggregateFeedback(assessment.aggregate);\n } catch (error) {\n if (error instanceof WorkbookAssessmentValidationError)\n return { kind: 'needs_review', reason: error.reason };\n if (error instanceof TypeError)\n return { kind: 'needs_review', reason: 'invalid_assessment' };\n throw error;\n }\n try {\n const revision = await workbooks.recordWorkbookAnalysis({\n ...request,\n activityId,\n submissionId,\n requestKey: `ingestion:${snapshot.attemptId}`,\n assessment,\n });\n return { kind: 'preserved', revisionId: revision.id };\n } catch (error) {\n if (error instanceof WorkbookAssessmentValidationError)\n return { kind: 'needs_review', reason: error.reason };\n throw error;\n }\n}\n\nexport {\n receiveFamilyIntake,\n retainFamilyIntakeReceipt,\n} from './family-intake-ingestion.js';\n\nexport { FamilyIntakeService } from './family-intake-service.js';\nexport {\n educationQuestionExtractionHandler,\n preserveQuestionExtractionAnalysis,\n QUESTION_EXTRACTION_HANDLER_ID,\n questionExtractionGrounding,\n} from './question-extraction-ingestion.js';\nexport {\n preserveWorkbookPhotoIdentification,\n processWorkbookPhotoAnalysis,\n receiveWorkbookPhotoIntake,\n retainWorkbookPhotoReceipt,\n WORKBOOK_PHOTO_HANDLER,\n workbookPhotoIntakeHandlers,\n workbookPhotoIntakeTargetResolver,\n} from './workbook-photo-ingestion.js';\n"],"mappings":"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"}