@happyvertical/smrt-education 0.57.43 → 0.57.44

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 (82) hide show
  1. package/AGENTS.md +12 -0
  2. package/README.md +5 -0
  3. package/agents/course-authoring-service.md +179 -0
  4. package/agents/course-generation-review.md +79 -0
  5. package/agents/learner-service.md +33 -0
  6. package/agents/question-records.md +100 -0
  7. package/dist/chunks/{workbook-photo-service-C6mbUUp6.js → workbook-photo-service-BxvZDqjM.js} +1440 -309
  8. package/dist/chunks/workbook-photo-service-BxvZDqjM.js.map +1 -0
  9. package/dist/course-append-only.d.ts +15 -0
  10. package/dist/course-append-only.d.ts.map +1 -0
  11. package/dist/course-authoring-contracts.d.ts +464 -0
  12. package/dist/course-authoring-contracts.d.ts.map +1 -0
  13. package/dist/course-authoring-licence.d.ts +15 -0
  14. package/dist/course-authoring-licence.d.ts.map +1 -0
  15. package/dist/course-authoring-models.d.ts +291 -0
  16. package/dist/course-authoring-models.d.ts.map +1 -0
  17. package/dist/course-authoring-service.d.ts +244 -0
  18. package/dist/course-authoring-service.d.ts.map +1 -0
  19. package/dist/course-delegation.d.ts +26 -0
  20. package/dist/course-delegation.d.ts.map +1 -0
  21. package/dist/course-generation-contracts.d.ts +150 -0
  22. package/dist/course-generation-contracts.d.ts.map +1 -0
  23. package/dist/course-generation-models.d.ts +94 -0
  24. package/dist/course-generation-models.d.ts.map +1 -0
  25. package/dist/course-generation-output.d.ts +31 -0
  26. package/dist/course-generation-output.d.ts.map +1 -0
  27. package/dist/course-generation-proposal-generator.d.ts +94 -0
  28. package/dist/course-generation-proposal-generator.d.ts.map +1 -0
  29. package/dist/course-generation-review-service.d.ts +149 -0
  30. package/dist/course-generation-review-service.d.ts.map +1 -0
  31. package/dist/course-release-scope.d.ts +37 -0
  32. package/dist/course-release-scope.d.ts.map +1 -0
  33. package/dist/course-review-contracts.d.ts +127 -0
  34. package/dist/course-review-contracts.d.ts.map +1 -0
  35. package/dist/course-review-digest.d.ts +4 -0
  36. package/dist/course-review-digest.d.ts.map +1 -0
  37. package/dist/course-review-evaluation.d.ts +63 -0
  38. package/dist/course-review-evaluation.d.ts.map +1 -0
  39. package/dist/course-review-gate.d.ts +15 -0
  40. package/dist/course-review-gate.d.ts.map +1 -0
  41. package/dist/course-review-models.d.ts +96 -0
  42. package/dist/course-review-models.d.ts.map +1 -0
  43. package/dist/group-sharing-contracts.d.ts +5 -0
  44. package/dist/group-sharing-contracts.d.ts.map +1 -1
  45. package/dist/group-sharing-policy.d.ts.map +1 -1
  46. package/dist/group-sharing-reader.d.ts.map +1 -1
  47. package/dist/index.d.ts +27 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +5658 -116
  50. package/dist/index.js.map +1 -1
  51. package/dist/ingestion.js +1 -1
  52. package/dist/learner-plan-service.d.ts.map +1 -1
  53. package/dist/learner-service.d.ts +81 -7
  54. package/dist/learner-service.d.ts.map +1 -1
  55. package/dist/learners.d.ts +6 -0
  56. package/dist/learners.d.ts.map +1 -1
  57. package/dist/manifest.json +14304 -2177
  58. package/dist/question-authoring-service.d.ts +125 -0
  59. package/dist/question-authoring-service.d.ts.map +1 -0
  60. package/dist/question-content.d.ts +25 -0
  61. package/dist/question-content.d.ts.map +1 -0
  62. package/dist/question-contracts.d.ts +240 -0
  63. package/dist/question-contracts.d.ts.map +1 -0
  64. package/dist/question-models.d.ts +124 -0
  65. package/dist/question-models.d.ts.map +1 -0
  66. package/dist/question-render.d.ts +20 -0
  67. package/dist/question-render.d.ts.map +1 -0
  68. package/dist/question-response-contracts.d.ts +54 -0
  69. package/dist/question-response-contracts.d.ts.map +1 -0
  70. package/dist/question-response-service.d.ts +63 -0
  71. package/dist/question-response-service.d.ts.map +1 -0
  72. package/dist/question-rubric.d.ts +23 -0
  73. package/dist/question-rubric.d.ts.map +1 -0
  74. package/dist/smrt-knowledge.json +5410 -910
  75. package/dist/submission-service.d.ts.map +1 -1
  76. package/dist/submissions.d.ts +5 -0
  77. package/dist/submissions.d.ts.map +1 -1
  78. package/dist/workbook-contracts.d.ts +6 -0
  79. package/dist/workbook-contracts.d.ts.map +1 -1
  80. package/dist/workbook-models.d.ts.map +1 -1
  81. package/package.json +8 -8
  82. package/dist/chunks/workbook-photo-service-C6mbUUp6.js.map +0 -1
@@ -0,0 +1,150 @@
1
+ import { CourseAuthoringError } from './course-authoring-contracts.js';
2
+ export type CourseGenerationStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled';
3
+ export declare const COURSE_GENERATION_STATUSES: readonly CourseGenerationStatus[];
4
+ export declare const COURSE_GENERATION_TERMINAL: readonly CourseGenerationStatus[];
5
+ /** Provider identity, shaped like the ingestion `ProviderIdentity`. */
6
+ export interface CourseGeneratorIdentity {
7
+ provider: string;
8
+ model: string;
9
+ version: string;
10
+ }
11
+ /** What a generator is given: the exact snapshot retained on the job. */
12
+ export interface CourseGeneratorRequest {
13
+ tenantId: string;
14
+ courseId: string;
15
+ jobId: string;
16
+ instruction: string;
17
+ /** Immutable snapshot of the base revision; never contains answer keys. */
18
+ material: unknown;
19
+ }
20
+ /**
21
+ * Host-injected generation port. It matches the ingestion `ProposalGenerator`
22
+ * result contract (untrusted `output`, optional `usage` and `responseModel`).
23
+ * The service never selects a provider; the output is validated against the
24
+ * closed proposal schema before anything is written.
25
+ */
26
+ export interface CourseMaterialGenerator {
27
+ identity: CourseGeneratorIdentity;
28
+ generate(request: CourseGeneratorRequest, options: {
29
+ signal: AbortSignal;
30
+ maxOutputBytes: number;
31
+ }): Promise<{
32
+ output: unknown;
33
+ completion: 'complete' | 'unknown';
34
+ usage?: Record<string, number>;
35
+ responseModel?: string;
36
+ }>;
37
+ }
38
+ export interface CourseGenerationLimits {
39
+ timeoutMs: number;
40
+ maxOutputBytes: number;
41
+ }
42
+ /** Closed, validated generation output. Absent members are not proposed. */
43
+ export interface CourseGenerationProposalLesson {
44
+ /** Existing lesson to propose changes to; omitted for a new lesson. */
45
+ lessonKey?: string;
46
+ /** New lessons only. */
47
+ sectionKey?: string;
48
+ sectionTitle?: string;
49
+ title?: string;
50
+ body?: string;
51
+ estimatedMinutes?: number;
52
+ difficulty?: number;
53
+ }
54
+ export interface CourseGenerationProposal {
55
+ course: {
56
+ summary?: string;
57
+ subject?: string;
58
+ objectives?: string[];
59
+ };
60
+ lessons: CourseGenerationProposalLesson[];
61
+ rationale: string;
62
+ }
63
+ export type CourseProposalFieldStatus = 'added' | 'filled' | 'conflict' | 'unchanged';
64
+ export type CourseProposalDecisionKind = 'accepted' | 'rejected';
65
+ /** One field of the supplied-versus-proposed comparison. */
66
+ export interface CourseProposalFieldView {
67
+ /** `course.summary`, `lesson:<key>.body` or `new-lesson:<n>`. */
68
+ field: string;
69
+ status: CourseProposalFieldStatus;
70
+ /** Supplied value when the proposal was made; null when there was none. */
71
+ supplied: unknown;
72
+ proposed: unknown;
73
+ /** Value in the current draft head; differs from `supplied` once edited. */
74
+ current: unknown;
75
+ /** A conflict stays undecided until a guardian or delegate decides it. */
76
+ decision: CourseProposalDecisionKind | null;
77
+ }
78
+ export interface CourseProposalView {
79
+ proposalId: string;
80
+ jobId: string;
81
+ courseId: string;
82
+ baseRevisionId: string;
83
+ /** The new draft revision holding only additions and fills. */
84
+ resultRevisionId: string;
85
+ rationale: string;
86
+ fields: CourseProposalFieldView[];
87
+ }
88
+ export interface CourseGenerationUsageView {
89
+ inputTokens: number | null;
90
+ outputTokens: number | null;
91
+ cost: number | null;
92
+ costCurrency: string | null;
93
+ raw: Record<string, number>;
94
+ }
95
+ export interface CourseGenerationEventView {
96
+ sequence: number;
97
+ status: CourseGenerationStatus;
98
+ provider: string;
99
+ model: string;
100
+ version: string;
101
+ responseModel: string;
102
+ usage: CourseGenerationUsageView;
103
+ errorCode: string | null;
104
+ detail: string;
105
+ proposalId: string | null;
106
+ resultRevisionId: string | null;
107
+ actorUserId: string;
108
+ delegatingGuardianUserId: string | null;
109
+ delegationId: string | null;
110
+ recordedAt: string;
111
+ }
112
+ export interface CourseGenerationView {
113
+ jobId: string;
114
+ courseId: string;
115
+ baseRevisionId: string;
116
+ requestKey: string;
117
+ instruction: string;
118
+ status: CourseGenerationStatus;
119
+ provider: string;
120
+ model: string;
121
+ usage: CourseGenerationUsageView;
122
+ errorCode: string | null;
123
+ proposalId: string | null;
124
+ resultRevisionId: string | null;
125
+ requestedByUserId: string;
126
+ delegatingGuardianUserId: string | null;
127
+ delegationId: string | null;
128
+ events: CourseGenerationEventView[];
129
+ }
130
+ export declare class CourseGeneratorNotConfiguredError extends CourseAuthoringError {
131
+ constructor();
132
+ }
133
+ export declare class CourseGenerationNotFoundError extends CourseAuthoringError {
134
+ constructor();
135
+ }
136
+ export declare class CourseGenerationInProgressError extends CourseAuthoringError {
137
+ constructor();
138
+ }
139
+ export declare class CourseGenerationOutputError extends CourseAuthoringError {
140
+ readonly path: string;
141
+ constructor(path: string);
142
+ }
143
+ export declare class CourseProposalNotFoundError extends CourseAuthoringError {
144
+ constructor();
145
+ }
146
+ export declare class CourseProposalFieldError extends CourseAuthoringError {
147
+ readonly fields: readonly string[];
148
+ constructor(fields: readonly string[]);
149
+ }
150
+ //# sourceMappingURL=course-generation-contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-generation-contracts.d.ts","sourceRoot":"","sources":["../src/course-generation-contracts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { SmrtCollection, SmrtObject, type SmrtSaveOptions } from '@happyvertical/smrt-core';
2
+ /** Immutable generation request with its retained input snapshot. */
3
+ export declare class CourseGenerationJob extends SmrtObject {
4
+ tenantId: string;
5
+ courseId: string;
6
+ baseRevisionId: string;
7
+ requestKey: string;
8
+ payloadDigest: string;
9
+ instruction: string;
10
+ /** The exact material snapshot offered to the provider. */
11
+ inputJson: string;
12
+ requestedByUserId: string;
13
+ delegatingGuardianUserId: string;
14
+ delegationId: string;
15
+ recordedAt: Date;
16
+ constructor(options?: Record<string, unknown>);
17
+ delete(): Promise<void>;
18
+ save(options?: SmrtSaveOptions): Promise<this>;
19
+ }
20
+ export declare class CourseGenerationJobCollection extends SmrtCollection<CourseGenerationJob> {
21
+ static readonly _itemClass: typeof CourseGenerationJob;
22
+ }
23
+ /** Append-only status log; the highest sequence is the job's status and outcome. */
24
+ export declare class CourseGenerationEvent extends SmrtObject {
25
+ tenantId: string;
26
+ jobId: string;
27
+ courseId: string;
28
+ sequence: number;
29
+ status: string;
30
+ provider: string;
31
+ model: string;
32
+ version: string;
33
+ responseModel: string;
34
+ inputTokens: number | null;
35
+ outputTokens: number | null;
36
+ cost: number | null;
37
+ costCurrency: string | null;
38
+ usageJson: string;
39
+ errorCode: string | null;
40
+ detail: string;
41
+ proposalId: string | null;
42
+ resultRevisionId: string | null;
43
+ actorUserId: string;
44
+ delegatingGuardianUserId: string;
45
+ delegationId: string;
46
+ requestKey: string;
47
+ recordedAt: Date;
48
+ constructor(options?: Record<string, unknown>);
49
+ delete(): Promise<void>;
50
+ save(options?: SmrtSaveOptions): Promise<this>;
51
+ }
52
+ export declare class CourseGenerationEventCollection extends SmrtCollection<CourseGenerationEvent> {
53
+ static readonly _itemClass: typeof CourseGenerationEvent;
54
+ }
55
+ /** The validated proposal for one job and its supplied-versus-proposed plan. */
56
+ export declare class CourseProposal extends SmrtObject {
57
+ tenantId: string;
58
+ jobId: string;
59
+ courseId: string;
60
+ baseRevisionId: string;
61
+ resultRevisionId: string;
62
+ rationale: string;
63
+ proposalJson: string;
64
+ planJson: string;
65
+ recordedAt: Date;
66
+ constructor(options?: Record<string, unknown>);
67
+ delete(): Promise<void>;
68
+ save(options?: SmrtSaveOptions): Promise<this>;
69
+ }
70
+ export declare class CourseProposalCollection extends SmrtCollection<CourseProposal> {
71
+ static readonly _itemClass: typeof CourseProposal;
72
+ }
73
+ /** Explicit, recorded accept or reject of conflicting proposal fields. */
74
+ export declare class CourseProposalDecision extends SmrtObject {
75
+ tenantId: string;
76
+ proposalId: string;
77
+ courseId: string;
78
+ decision: string;
79
+ fieldsJson: string;
80
+ resultRevisionId: string | null;
81
+ actorUserId: string;
82
+ delegatingGuardianUserId: string;
83
+ delegationId: string;
84
+ requestKey: string;
85
+ payloadDigest: string;
86
+ recordedAt: Date;
87
+ constructor(options?: Record<string, unknown>);
88
+ delete(): Promise<void>;
89
+ save(options?: SmrtSaveOptions): Promise<this>;
90
+ }
91
+ export declare class CourseProposalDecisionCollection extends SmrtCollection<CourseProposalDecision> {
92
+ static readonly _itemClass: typeof CourseProposalDecision;
93
+ }
94
+ //# sourceMappingURL=course-generation-models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-generation-models.d.ts","sourceRoot":"","sources":["../src/course-generation-models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { CourseDraftInput, CourseRevisionView } from './course-authoring-contracts.js';
2
+ import { type CourseGenerationProposal, type CourseProposalFieldStatus } from './course-generation-contracts.js';
3
+ /**
4
+ * Validates untrusted provider output against the closed proposal schema.
5
+ * `existingLessonKeys` are the lessons of the snapshot the job ran against: a
6
+ * proposal may only address a lesson that exists there.
7
+ */
8
+ export declare function validateCourseGenerationOutput(output: unknown, existingLessonKeys: ReadonlySet<string>): CourseGenerationProposal;
9
+ /** Field paths a proposal can decide, and how to read the current value. */
10
+ export interface ProposalFieldPlan {
11
+ field: string;
12
+ status: CourseProposalFieldStatus;
13
+ supplied: unknown;
14
+ proposed: unknown;
15
+ }
16
+ /** Per-field comparison of a proposal against the supplied base revision. */
17
+ export declare function planProposal(base: CourseRevisionView, proposal: CourseGenerationProposal): ProposalFieldPlan[];
18
+ /** Stable key for a generated lesson, so a replayed job reproduces the same row. */
19
+ export declare const generatedLessonKey: (jobId: string, index: number) => string;
20
+ /** Rebuilds a draft input from a stored revision, preserving materials and questions. */
21
+ export declare function draftFromRevision(view: CourseRevisionView): CourseDraftInput;
22
+ /**
23
+ * Applies the selected plan entries to a draft built from `view`. Returns
24
+ * the fields that no longer apply (for example a deleted lesson).
25
+ */
26
+ export declare function applyProposalFields(draft: CourseDraftInput, entries: ReadonlyArray<ProposalFieldPlan>, options: {
27
+ jobId: string;
28
+ }): {
29
+ missing: string[];
30
+ };
31
+ //# sourceMappingURL=course-generation-output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-generation-output.d.ts","sourceRoot":"","sources":["../src/course-generation-output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAEhB,kBAAkB,EACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,wBAAwB,EAE7B,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAyC1C;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,OAAO,EACf,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,GACtC,wBAAwB,CAkF1B;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,yBAAyB,CAAC;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAmBD,6EAA6E;AAC7E,wBAAgB,YAAY,CAC1B,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,wBAAwB,GACjC,iBAAiB,EAAE,CA+CrB;AAED,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,EAAE,OAAO,MAAM,WACS,CAAC;AAIzE,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,gBAAgB,CAuC5E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACzC,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAuEvB"}
@@ -0,0 +1,94 @@
1
+ import type { ProposalGenerator } from '@happyvertical/smrt-ingestion/proposals';
2
+ import type { CourseMaterialGenerator } from './course-generation-contracts.js';
3
+ export declare const COURSE_PROPOSAL_HANDLER = "@happyvertical/smrt-education:propose-course-material";
4
+ /** The closed JSON shape a model is asked to produce; validated again on receipt. */
5
+ export declare const COURSE_PROPOSAL_ARGS_SCHEMA: {
6
+ readonly type: "object";
7
+ readonly additionalProperties: false;
8
+ readonly properties: {
9
+ readonly course: {
10
+ readonly type: "object";
11
+ readonly additionalProperties: false;
12
+ readonly properties: {
13
+ readonly summary: {
14
+ type: string;
15
+ minLength: number;
16
+ maxLength: number;
17
+ };
18
+ readonly subject: {
19
+ type: string;
20
+ minLength: number;
21
+ maxLength: number;
22
+ };
23
+ readonly objectives: {
24
+ readonly type: "array";
25
+ readonly minItems: 1;
26
+ readonly maxItems: 50;
27
+ readonly items: {
28
+ type: string;
29
+ minLength: number;
30
+ maxLength: number;
31
+ };
32
+ };
33
+ };
34
+ };
35
+ readonly lessons: {
36
+ readonly type: "array";
37
+ readonly maxItems: 50;
38
+ readonly items: {
39
+ readonly type: "object";
40
+ readonly additionalProperties: false;
41
+ readonly properties: {
42
+ readonly lessonKey: {
43
+ type: string;
44
+ minLength: number;
45
+ maxLength: number;
46
+ };
47
+ readonly sectionKey: {
48
+ type: string;
49
+ minLength: number;
50
+ maxLength: number;
51
+ };
52
+ readonly sectionTitle: {
53
+ type: string;
54
+ minLength: number;
55
+ maxLength: number;
56
+ };
57
+ readonly title: {
58
+ type: string;
59
+ minLength: number;
60
+ maxLength: number;
61
+ };
62
+ readonly body: {
63
+ type: string;
64
+ minLength: number;
65
+ maxLength: number;
66
+ };
67
+ readonly estimatedMinutes: {
68
+ readonly type: "integer";
69
+ readonly minimum: 1;
70
+ readonly maximum: 1440;
71
+ };
72
+ readonly difficulty: {
73
+ readonly type: "integer";
74
+ readonly minimum: 1;
75
+ readonly maximum: 10;
76
+ };
77
+ };
78
+ };
79
+ };
80
+ readonly rationale: {
81
+ type: string;
82
+ minLength: number;
83
+ maxLength: number;
84
+ };
85
+ };
86
+ };
87
+ /**
88
+ * Adapts an ingestion `ProposalGenerator` (the host's trusted SDK-bound
89
+ * adapter) to the course generation port. The material is offered as one
90
+ * evidence segment; the model's output stays untrusted and is validated by the
91
+ * service against the closed proposal schema. No provider is chosen here.
92
+ */
93
+ export declare function createProposalCourseGenerator(generator: ProposalGenerator): CourseMaterialGenerator;
94
+ //# sourceMappingURL=course-generation-proposal-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-generation-proposal-generator.d.ts","sourceRoot":"","sources":["../src/course-generation-proposal-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,KAAK,EAEV,uBAAuB,EACxB,MAAM,kCAAkC,CAAC;AAG1C,eAAO,MAAM,uBAAuB,0DACqB,CAAC;AAO1D,qFAAqF;AACrF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqC9B,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,iBAAiB,GAC3B,uBAAuB,CAoDzB"}
@@ -0,0 +1,149 @@
1
+ import type { DatabaseInterface } from '@happyvertical/sql';
2
+ import { type CourseAuthoringActor, type CourseAuthoringAuthorizer } from './course-authoring-contracts.js';
3
+ import { type CourseGenerationLimits, type CourseGenerationView, type CourseMaterialGenerator, type CourseProposalView } from './course-generation-contracts.js';
4
+ import { type CourseFindingResolutionKind, type CourseReviewContextInput, type CourseReviewFindingInput, type CourseReviewView } from './course-review-contracts.js';
5
+ import { QuestionAuthoringService, type QuestionAuthoringServiceOptions } from './question-authoring-service.js';
6
+ type Tx = DatabaseInterface;
7
+ export interface CourseGenerationReviewServiceOptions extends QuestionAuthoringServiceOptions {
8
+ /** Host-supplied generation port; without it `runGeneration` fails closed. */
9
+ generator?: CourseMaterialGenerator;
10
+ generationLimits?: Partial<CourseGenerationLimits>;
11
+ }
12
+ /**
13
+ * Generation proposals and revision-bound educational review (SMRT #4516).
14
+ * It extends `QuestionAuthoringService`, so it adds only the generation and
15
+ * review operations and uses the same authorizer, tenancy checks and CAS save
16
+ * path. Its release gate and discard guard default to the review-backed ones.
17
+ */
18
+ export declare class CourseGenerationReviewService extends QuestionAuthoringService {
19
+ private readonly generator;
20
+ private readonly limits;
21
+ constructor(db: DatabaseInterface, authorizer: CourseAuthoringAuthorizer, options?: CourseGenerationReviewServiceOptions);
22
+ private baseView;
23
+ /** Provider-facing snapshot: no keys, assets or personal-use lesson bodies. */
24
+ private material;
25
+ private jobRow;
26
+ private jobEvents;
27
+ private usageView;
28
+ private eventView;
29
+ private generationView;
30
+ private appendEvent;
31
+ /**
32
+ * Records a generation request against the draft head the caller saw. A
33
+ * retried key returns the existing job and its proposal; the same key with
34
+ * different input is a typed conflict. Nothing is generated or written to the
35
+ * draft here.
36
+ */
37
+ requestGeneration(request: CourseAuthoringActor & {
38
+ courseId: string;
39
+ expectedHeadRevisionId: string;
40
+ requestKey: string;
41
+ instruction?: string;
42
+ }): Promise<CourseGenerationView>;
43
+ /**
44
+ * Runs a queued job through the injected generator outside any transaction,
45
+ * then records the outcome. Success writes a new draft revision holding only
46
+ * additions and fills; conflicting proposals wait for an explicit decision.
47
+ * Failure, timeout, cancellation, a stale head or invalid output leave the
48
+ * head unchanged and keep the input.
49
+ */
50
+ runGeneration(request: CourseAuthoringActor & {
51
+ jobId: string;
52
+ }): Promise<CourseGenerationView>;
53
+ /** Cancels a queued or running job; a finished job is returned unchanged. */
54
+ cancelGeneration(request: CourseAuthoringActor & {
55
+ jobId: string;
56
+ requestKey: string;
57
+ }): Promise<CourseGenerationView>;
58
+ getGeneration(request: CourseAuthoringActor & {
59
+ jobId: string;
60
+ }): Promise<CourseGenerationView>;
61
+ private currentValue;
62
+ private proposalView;
63
+ private proposalRow;
64
+ /** Supplied-versus-proposed comparison, per field, against the current head. */
65
+ getProposal(request: CourseAuthoringActor & {
66
+ courseId: string;
67
+ proposalId: string;
68
+ }): Promise<CourseProposalView>;
69
+ /**
70
+ * Explicitly accepts or rejects conflicting proposal fields. Accepting appends
71
+ * a new draft revision on the expected head (compare and swap); supplied
72
+ * content is replaced only by this recorded decision.
73
+ */
74
+ decideProposal(request: CourseAuthoringActor & {
75
+ courseId: string;
76
+ proposalId: string;
77
+ expectedHeadRevisionId: string;
78
+ decision: 'accept' | 'reject';
79
+ fields: string[];
80
+ requestKey: string;
81
+ }): Promise<CourseProposalView & {
82
+ headRevisionId: string;
83
+ }>;
84
+ private normalizeFindings;
85
+ private reviewContext;
86
+ private reviewView;
87
+ /** Revision ids a finding may point at: the course revision, its lessons and questions. */
88
+ private targetIds;
89
+ /**
90
+ * Records an educational review of one exact revision, authored by the
91
+ * caller (a guardian, or an agent for its delegating guardian). The review
92
+ * has no score; level target and theme come from the revision, and a learner
93
+ * review must name the evidence snapshot it used.
94
+ */
95
+ recordReview(request: CourseAuthoringActor & {
96
+ courseId: string;
97
+ revisionId: string;
98
+ requestKey: string;
99
+ context?: CourseReviewContextInput;
100
+ generalSummary?: string;
101
+ learnerSummary?: string;
102
+ findings: CourseReviewFindingInput[];
103
+ reviewer?: {
104
+ provider?: string;
105
+ model?: string;
106
+ };
107
+ }): Promise<CourseReviewView>;
108
+ /** Reviews of a course, newest first, with findings, resolutions and outdated state. */
109
+ listReviews(request: CourseAuthoringActor & {
110
+ courseId: string;
111
+ revisionId?: string;
112
+ }): Promise<CourseReviewView[]>;
113
+ getReview(request: CourseAuthoringActor & {
114
+ courseId: string;
115
+ reviewId: string;
116
+ }): Promise<CourseReviewView>;
117
+ private markOutdated;
118
+ /** A new draft revision makes every review of an earlier revision outdated. */
119
+ protected onDraftRevisionAppended(tx: Tx, actor: CourseAuthoringActor, revision: {
120
+ courseId: string;
121
+ revisionId: string;
122
+ }): Promise<void>;
123
+ /**
124
+ * Records that a learner's evidence snapshot changed: learner reviews of this
125
+ * course that used a different snapshot become outdated.
126
+ */
127
+ noteContextChange(request: CourseAuthoringActor & {
128
+ courseId: string;
129
+ learnerId: string;
130
+ evidenceSnapshotRef: string;
131
+ requestKey: string;
132
+ }): Promise<{
133
+ outdatedReviewIds: string[];
134
+ }>;
135
+ /**
136
+ * Resolves one finding. Only a person may resolve a finding flagged for human
137
+ * verification; a delegated agent is refused. Release stays blocked while any
138
+ * blocking or human-verification finding is unresolved.
139
+ */
140
+ resolveFinding(request: CourseAuthoringActor & {
141
+ courseId: string;
142
+ findingId: string;
143
+ resolution: CourseFindingResolutionKind;
144
+ note?: string;
145
+ requestKey: string;
146
+ }): Promise<CourseReviewView>;
147
+ }
148
+ export {};
149
+ //# sourceMappingURL=course-generation-review-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-generation-review-service.d.ts","sourceRoot":"","sources":["../src/course-generation-review-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { DatabaseInterface } from '@happyvertical/sql';
2
+ import type { EffectiveLessonView } from './course-authoring-contracts.js';
3
+ /**
4
+ * The single rule for which immutable lesson rows apply to a pinned enrollment.
5
+ * Callers authorize the actor and enrollment first; every read here is bound to
6
+ * the supplied executor (so it joins the caller's transaction) and the exact
7
+ * tenant and enrollment. `getEnrollmentRelease` and the learner projections both
8
+ * call this, so the two can never disagree.
9
+ */
10
+ export type EnrollmentLessonSelection = Readonly<{
11
+ /** The release the enrollment currently follows. */
12
+ currentReleaseId: string;
13
+ /** Every release the enrollment has been pinned to, oldest first. */
14
+ lineage: ReadonlyArray<string>;
15
+ /** Effective lessons, sorted by stable lessonKey. */
16
+ lessons: EffectiveLessonView[];
17
+ /** The materialized Course row of each release that contributes a lesson. */
18
+ releaseCourseIds: ReadonlyMap<string, string>;
19
+ /** Stable lessonKey to lesson row id, per release in the lineage. */
20
+ keysByRelease: ReadonlyMap<string, ReadonlyMap<string, string>>;
21
+ /** Learner ids recorded on the pins (a mismatch with the enrollment fails closed). */
22
+ pinLearnerIds: ReadonlySet<string>;
23
+ }>;
24
+ /**
25
+ * Started lessons stay on the immutable row they were started on, in every
26
+ * release the enrollment has followed; unstarted lessons follow the current
27
+ * release. Returns null for an enrollment that has never been pinned.
28
+ */
29
+ export declare function resolveEnrollmentLessons(db: DatabaseInterface, tenantId: string, enrollmentId: string): Promise<EnrollmentLessonSelection | null>;
30
+ /**
31
+ * Orders effective lessons for learners: the current release's own order first,
32
+ * then lessons kept only because they were started (removed from the current
33
+ * release) by release age and their original order. `orderOf` lists a release's
34
+ * lesson row ids in course order.
35
+ */
36
+ export declare function orderEffectiveLessons(selection: EnrollmentLessonSelection, orderOf: (releaseId: string) => ReadonlyArray<string>): EffectiveLessonView[];
37
+ //# sourceMappingURL=course-release-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"course-release-scope.d.ts","sourceRoot":"","sources":["../src/course-release-scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAM3E;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,oDAAoD;IACpD,gBAAgB,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B,qDAAqD;IACrD,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,6EAA6E;IAC7E,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,qEAAqE;IACrE,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,sFAAsF;IACtF,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACpC,CAAC,CAAC;AAEH;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,iBAAiB,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAwE3C;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,yBAAyB,EACpC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa,CAAC,MAAM,CAAC,GACpD,mBAAmB,EAAE,CAuBvB"}