@learncard/credential-library 2.0.4 → 2.0.5

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 (66) hide show
  1. package/dist/bundles/index.d.ts +5 -0
  2. package/dist/bundles/index.d.ts.map +1 -0
  3. package/dist/bundles/student.d.ts +3 -0
  4. package/dist/bundles/student.d.ts.map +1 -0
  5. package/dist/bundles/types.d.ts +24 -0
  6. package/dist/bundles/types.d.ts.map +1 -0
  7. package/dist/credential-library.cjs.development.js +10817 -682
  8. package/dist/credential-library.cjs.development.js.map +4 -4
  9. package/dist/credential-library.cjs.production.min.js +11 -1
  10. package/dist/credential-library.cjs.production.min.js.map +4 -4
  11. package/dist/credential-library.esm.js +10813 -676
  12. package/dist/credential-library.esm.js.map +4 -4
  13. package/dist/fixtures/clr/achievement-id-associations.d.ts +3 -0
  14. package/dist/fixtures/clr/achievement-id-associations.d.ts.map +1 -0
  15. package/dist/fixtures/clr/employment-record.d.ts +8 -0
  16. package/dist/fixtures/clr/employment-record.d.ts.map +1 -0
  17. package/dist/fixtures/clr/licensing-regulatory-record.d.ts +8 -0
  18. package/dist/fixtures/clr/licensing-regulatory-record.d.ts.map +1 -0
  19. package/dist/fixtures/clr/military-training-record.d.ts +8 -0
  20. package/dist/fixtures/clr/military-training-record.d.ts.map +1 -0
  21. package/dist/fixtures/clr/mixed-career-record.d.ts +8 -0
  22. package/dist/fixtures/clr/mixed-career-record.d.ts.map +1 -0
  23. package/dist/fixtures/clr/professional-organization-record.d.ts +8 -0
  24. package/dist/fixtures/clr/professional-organization-record.d.ts.map +1 -0
  25. package/dist/fixtures/clr/student-official-academic-transcript.d.ts +3 -0
  26. package/dist/fixtures/clr/student-official-academic-transcript.d.ts.map +1 -0
  27. package/dist/fixtures/clr/training-provider-record.d.ts +8 -0
  28. package/dist/fixtures/clr/training-provider-record.d.ts.map +1 -0
  29. package/dist/fixtures/index.d.ts +11 -1
  30. package/dist/fixtures/index.d.ts.map +1 -1
  31. package/dist/fixtures/obv3/student-additional-credentials.d.ts +3 -0
  32. package/dist/fixtures/obv3/student-additional-credentials.d.ts.map +1 -0
  33. package/dist/fixtures/obv3/student-sample-badges.d.ts +586 -0
  34. package/dist/fixtures/obv3/student-sample-badges.d.ts.map +1 -0
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/prepare.d.ts.map +1 -1
  38. package/package.json +6 -6
  39. package/src/__tests__/bundles.test.ts +234 -0
  40. package/src/__tests__/clr-non-academic.test.ts +220 -0
  41. package/src/__tests__/registry.test.ts +31 -0
  42. package/src/bundles/index.ts +19 -0
  43. package/src/bundles/student.ts +251 -0
  44. package/src/bundles/types.ts +25 -0
  45. package/src/fixtures/clr/README.md +142 -0
  46. package/src/fixtures/clr/achievement-id-associations.ts +342 -0
  47. package/src/fixtures/clr/employment-record.ts +487 -0
  48. package/src/fixtures/clr/licensing-regulatory-record.ts +388 -0
  49. package/src/fixtures/clr/military-training-record.ts +468 -0
  50. package/src/fixtures/clr/mixed-career-record.ts +814 -0
  51. package/src/fixtures/clr/professional-organization-record.ts +403 -0
  52. package/src/fixtures/clr/student-official-academic-transcript.ts +3202 -0
  53. package/src/fixtures/clr/training-provider-record.ts +510 -0
  54. package/src/fixtures/index.ts +41 -0
  55. package/src/fixtures/obv3/student-additional-credentials.ts +3912 -0
  56. package/src/fixtures/obv3/student-sample-badges.ts +424 -0
  57. package/src/index.ts +2 -0
  58. package/src/prepare.ts +55 -11
  59. package/dist/__tests__/docs-json.test.d.ts +0 -2
  60. package/dist/__tests__/docs-json.test.d.ts.map +0 -1
  61. package/dist/__tests__/issuance.test.d.ts +0 -2
  62. package/dist/__tests__/issuance.test.d.ts.map +0 -1
  63. package/dist/__tests__/registry.test.d.ts +0 -2
  64. package/dist/__tests__/registry.test.d.ts.map +0 -1
  65. package/dist/__tests__/sd-jwt-vc.test.d.ts +0 -2
  66. package/dist/__tests__/sd-jwt-vc.test.d.ts.map +0 -1
@@ -0,0 +1,251 @@
1
+ import type { CredentialBundle, CredentialBundleIssuer } from './types';
2
+
3
+ const ISSUERS = {
4
+ hillValleyHigh: {
5
+ profileId: 'sample-hill-valley-high',
6
+ displayName: 'Hill Valley High School',
7
+ image: 'https://cdn.filestackcontent.com/rko7HmtCQ5aI5gfS3r1o',
8
+ },
9
+ worldScouting: {
10
+ profileId: 'sample-world-scouting',
11
+ displayName: 'World Scouting',
12
+ image: 'https://cdn.filestackcontent.com/tY9KCX5T4mQK9GERTGhf',
13
+ },
14
+ royCharleston: {
15
+ profileId: 'sample-roy-charleston',
16
+ displayName: 'Roy Charleston',
17
+ },
18
+ toefl: {
19
+ profileId: 'sample-toefl',
20
+ displayName: 'TOEFL',
21
+ image: 'https://cdn.filestackcontent.com/s6P4u2TVSaeHDVS64UKw',
22
+ },
23
+ collegeBoard: {
24
+ profileId: 'sample-college-board',
25
+ displayName: 'College Board',
26
+ image: 'https://cdn.filestackcontent.com/TMTJ1xuKSKWuPOxMc2fQ',
27
+ },
28
+ arcadiaMediaLabs: {
29
+ profileId: 'sample-arcadia-media-labs',
30
+ displayName: 'Arcadia Media Labs',
31
+ image: 'https://cdn.filestackcontent.com/bfPLw9dQfWhpVYorZVfA',
32
+ },
33
+ codeRiseAcademy: {
34
+ profileId: 'sample-code-rise-academy',
35
+ displayName: 'CodeRise Academy',
36
+ image: 'https://cdn.filestackcontent.com/nHMhLsvFQmKU2TGKYzHK',
37
+ },
38
+ redwoodValleyUniversity: {
39
+ profileId: 'sample-redwood-valley-university',
40
+ displayName: 'Redwood Valley University',
41
+ image: 'https://cdn.filestackcontent.com/kok4oellRhKa2mWRllZS',
42
+ },
43
+ learningEconomy: {
44
+ profileId: 'sample-learning-economy',
45
+ displayName: 'Learning Economy',
46
+ image: 'https://cdn.filestackcontent.com/iLpqAJWYTDCxARqo6LN4',
47
+ },
48
+ oliviaTrujillo: {
49
+ profileId: 'sample-olivia-trujillo',
50
+ displayName: 'Olivia Trujillo',
51
+ image: 'https://cdn.filestackcontent.com/OKefWUSvTnuHELTSGH0z',
52
+ },
53
+ summitAccessibilityOffice: {
54
+ profileId: 'sample-summit-accessibility-office',
55
+ displayName: 'Summit Accessibility Office',
56
+ image: 'https://cdn.filestackcontent.com/JEAA9HfUSNa8SPp8nQiU',
57
+ },
58
+ kikuhanaInternationalUniversity: {
59
+ profileId: 'sample-kikuhana-international-university',
60
+ displayName: 'Kikuhana International University',
61
+ image: 'https://cdn.filestackcontent.com/HLQCIyRMQgSnxZtKmevv',
62
+ },
63
+ campTallPines: {
64
+ profileId: 'sample-camp-tall-pines',
65
+ displayName: 'Camp Tall Pines',
66
+ image: 'https://cdn.filestackcontent.com/frBHDn7SV2f8HKcxkGrj',
67
+ },
68
+ summitMarketing: {
69
+ profileId: 'sample-summit-marketing',
70
+ displayName: 'Summit Marketing',
71
+ image: 'https://cdn.filestackcontent.com/Q5BWlBiRJevkBlBlYaN2',
72
+ },
73
+ motlowStateCollege: {
74
+ profileId: 'sample-motlow-state-college',
75
+ displayName: 'Motlow State College',
76
+ image: 'https://cdn.filestackcontent.com/rjXzVVEjRVu0RSb8gYPZ',
77
+ },
78
+ } as const satisfies Record<string, CredentialBundleIssuer>;
79
+
80
+ export const studentBundle: CredentialBundle = {
81
+ id: 'student',
82
+ displayName: 'Student',
83
+ blurb: 'Explore academic, creative, leadership, service, and work credentials in a LearnCard.',
84
+ entries: [
85
+ {
86
+ fixtureId: 'obv3/student-afterschool-program-mentor',
87
+ validFromOffsetDays: -79,
88
+ issuer: ISSUERS.hillValleyHigh,
89
+ },
90
+ {
91
+ fixtureId: 'obv3/student-environment-badge',
92
+ validFromOffsetDays: -79,
93
+ issuer: ISSUERS.worldScouting,
94
+ },
95
+ {
96
+ fixtureId: 'obv3/student-rock-climbing-mentor',
97
+ validFromOffsetDays: -79,
98
+ issuer: ISSUERS.royCharleston,
99
+ },
100
+ {
101
+ fixtureId: 'obv3/student-park-cleanup-helper',
102
+ validFromOffsetDays: -79,
103
+ issuer: ISSUERS.royCharleston,
104
+ },
105
+ {
106
+ fixtureId: 'obv3/student-first-place-science-fair',
107
+ validFromOffsetDays: -80,
108
+ issuer: ISSUERS.hillValleyHigh,
109
+ },
110
+ {
111
+ fixtureId: 'obv3/student-toefl-certification',
112
+ validFromOffsetDays: -80,
113
+ issuer: ISSUERS.toefl,
114
+ },
115
+ {
116
+ fixtureId: 'obv3/student-senior-capstone-project',
117
+ validFromOffsetDays: -80,
118
+ issuer: ISSUERS.hillValleyHigh,
119
+ },
120
+ {
121
+ fixtureId: 'obv3/student-sat-score',
122
+ validFromOffsetDays: -80,
123
+ issuer: ISSUERS.collegeBoard,
124
+ },
125
+ {
126
+ fixtureId: 'obv3/student-hill-valley-high-school-diploma',
127
+ validFromOffsetDays: -80,
128
+ issuer: ISSUERS.hillValleyHigh,
129
+ },
130
+ {
131
+ fixtureId: 'obv3/student-biology-101',
132
+ validFromOffsetDays: -80,
133
+ issuer: ISSUERS.hillValleyHigh,
134
+ },
135
+ {
136
+ fixtureId: 'obv3/student-ai-fundamentals',
137
+ validFromOffsetDays: -80,
138
+ issuer: ISSUERS.arcadiaMediaLabs,
139
+ },
140
+ {
141
+ fixtureId: 'obv3/student-technical-bootcamp',
142
+ validFromOffsetDays: -80,
143
+ issuer: ISSUERS.codeRiseAcademy,
144
+ },
145
+ {
146
+ fixtureId: 'clr/student-official-academic-transcript',
147
+ validFromOffsetDays: -494,
148
+ issuer: ISSUERS.redwoodValleyUniversity,
149
+ },
150
+ {
151
+ fixtureId: 'obv3/student-ba-interactive-media-design',
152
+ validFromOffsetDays: -80,
153
+ issuer: ISSUERS.redwoodValleyUniversity,
154
+ },
155
+ {
156
+ fixtureId: 'obv3/student-ap-math-course',
157
+ validFromOffsetDays: -80,
158
+ issuer: ISSUERS.hillValleyHigh,
159
+ },
160
+ {
161
+ fixtureId: 'obv3/student-animated-short',
162
+ validFromOffsetDays: -80,
163
+ issuer: ISSUERS.learningEconomy,
164
+ },
165
+ {
166
+ fixtureId: 'obv3/student-capstone-project',
167
+ validFromOffsetDays: -80,
168
+ issuer: ISSUERS.hillValleyHigh,
169
+ },
170
+ {
171
+ fixtureId: 'obv3/student-skyway-magazine',
172
+ validFromOffsetDays: -80,
173
+ issuer: ISSUERS.learningEconomy,
174
+ },
175
+ {
176
+ fixtureId: 'obv3/student-photo-contest-award',
177
+ validFromOffsetDays: -80,
178
+ issuer: ISSUERS.oliviaTrujillo,
179
+ },
180
+ {
181
+ fixtureId: 'obv3/student-design-portfolio',
182
+ validFromOffsetDays: -80,
183
+ issuer: ISSUERS.oliviaTrujillo,
184
+ },
185
+ {
186
+ fixtureId: 'obv3/student-workplace-ergonomic-assessment',
187
+ validFromOffsetDays: -80,
188
+ issuer: ISSUERS.summitAccessibilityOffice,
189
+ },
190
+ {
191
+ fixtureId: 'obv3/student-iep-documentation',
192
+ validFromOffsetDays: -80,
193
+ issuer: ISSUERS.summitAccessibilityOffice,
194
+ },
195
+ {
196
+ fixtureId: 'obv3/student-accessibility-services-registration',
197
+ validFromOffsetDays: -80,
198
+ issuer: ISSUERS.summitAccessibilityOffice,
199
+ },
200
+ {
201
+ fixtureId: 'obv3/student-extended-time-on-exams-approval',
202
+ validFromOffsetDays: -80,
203
+ issuer: ISSUERS.summitAccessibilityOffice,
204
+ },
205
+ {
206
+ fixtureId: 'obv3/student-mental-health-accommodation-letter',
207
+ validFromOffsetDays: -80,
208
+ issuer: ISSUERS.summitAccessibilityOffice,
209
+ },
210
+ {
211
+ fixtureId: 'obv3/student-study-abroad-program',
212
+ validFromOffsetDays: -80,
213
+ issuer: ISSUERS.kikuhanaInternationalUniversity,
214
+ },
215
+ {
216
+ fixtureId: 'obv3/student-camp-counselor',
217
+ validFromOffsetDays: -80,
218
+ issuer: ISSUERS.campTallPines,
219
+ },
220
+ {
221
+ fixtureId: 'obv3/student-president-of-class',
222
+ validFromOffsetDays: -80,
223
+ issuer: ISSUERS.hillValleyHigh,
224
+ },
225
+ {
226
+ fixtureId: 'obv3/student-resume',
227
+ validFromOffsetDays: -80,
228
+ issuer: ISSUERS.oliviaTrujillo,
229
+ },
230
+ {
231
+ fixtureId: 'obv3/student-internship',
232
+ validFromOffsetDays: -80,
233
+ issuer: ISSUERS.summitMarketing,
234
+ },
235
+ {
236
+ fixtureId: 'obv3/student-world-scouting-troop-id',
237
+ validFromOffsetDays: -431,
238
+ issuer: ISSUERS.worldScouting,
239
+ },
240
+ {
241
+ fixtureId: 'obv3/student-hill-valley-high-school-student-id',
242
+ validFromOffsetDays: -431,
243
+ issuer: ISSUERS.hillValleyHigh,
244
+ },
245
+ {
246
+ fixtureId: 'obv3/student-motlow-college-id',
247
+ validFromOffsetDays: -431,
248
+ issuer: ISSUERS.motlowStateCollege,
249
+ },
250
+ ],
251
+ };
@@ -0,0 +1,25 @@
1
+ export interface CredentialBundleIssuer {
2
+ /** Namespaced profile ID created and owned by the sample seeder. */
3
+ profileId: `sample-${string}`;
4
+ /** Issuer name shown on the rendered credential. */
5
+ displayName: string;
6
+ /** Optional issuer avatar copied to the safe sample profile. */
7
+ image?: string;
8
+ }
9
+
10
+ export interface CredentialBundleEntry {
11
+ fixtureId: string;
12
+ /** Shift the fixture's issue date relative to the seed run. */
13
+ validFromOffsetDays: number;
14
+ /** Safe sample issuer used when publishing this credential. */
15
+ issuer: CredentialBundleIssuer;
16
+ /** Override the credential's display name after fixture preparation. */
17
+ name?: string;
18
+ }
19
+
20
+ export interface CredentialBundle {
21
+ id: string;
22
+ displayName: string;
23
+ blurb: string;
24
+ entries: readonly CredentialBundleEntry[];
25
+ }
@@ -0,0 +1,142 @@
1
+ # CLR fixture scenarios
2
+
3
+ ## LC-2184: beyond academic transcripts
4
+
5
+ These six **synthetic, unsigned display/issuance templates** extend the existing
6
+ academic CLR corpus. Both the enclosing CLR and the embedded achievement
7
+ credentials intentionally omit proofs. `validity: 'valid'` follows the library's
8
+ unsigned-template convention; it is not a claim of cryptographic verification or
9
+ 1EdTech certification.
10
+
11
+ The data uses the VC v2, OBv3 3.0.3, and cached CLR v2 contexts already used by
12
+ the library. The outer context adds explicit mappings for `partial` and the
13
+ learner `identifier`, which the cached CLR context does not retain during
14
+ JSON-LD signing. The [CLR 2.0 errata](https://www.imsglobal.org/spec/clr/v2p0/errata)
15
+ describes the `identifier` context gap. The versioned CLR 2.0.1 context is not
16
+ bundled in the current DIDKit runtime, so these samples use the cached URL plus
17
+ those mappings for local signing checks.
18
+ Category names here are scenario labels, not new CLR properties or enums.
19
+ There are no changes to the production renderer, schemas, wallet categorization,
20
+ server endpoints, or existing fixtures.
21
+
22
+ | Fixture ID | Children | What to inspect |
23
+ | -------------------------------------- | -------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | `clr/employment-record` | 3 | Workplace role, activity interval, distinct award/validity dates, assessor and creator, fieldwork hours, rubric-level-only competency result. |
25
+ | `clr/training-provider-record` | 4 | Non-credit course, score/required score, completion certificate, in-progress training, explicitly labeled hours, no GPA or academic term. |
26
+ | `clr/military-training-record` | 3 | Fictional non-combat logistics training, fieldwork role, assessment source, rubric level, and a training recognition award. |
27
+ | `clr/professional-organization-record` | 3 | Membership period and identifier, volunteer mentoring, and development evidence issued by a separate provider. |
28
+ | `clr/licensing-regulatory-record` | 3 | Synthetic license number, distinct validity windows, expired historical certification, renewal, and multiple issuer profiles. |
29
+ | `clr/mixed-career-record` | 6 | A course first, followed by employment activity, membership, apprenticeship, competency and license. Non-course records must not disappear when the transcript layout is selected. |
30
+
31
+ ### Discover and preview
32
+
33
+ ```ts
34
+ import { getFixtures, clrMixedCareerRecord } from '@learncard/credential-library';
35
+
36
+ const scenarios = getFixtures({ spec: 'clr-v2', tags: ['lc-2184'] });
37
+ const previewPayload = structuredClone(clrMixedCareerRecord.credential);
38
+ ```
39
+
40
+ All fixtures are registered in `ALL_FIXTURES` and named-exported, so the existing
41
+ credential viewer can discover them. The patch does not alter that viewer's UI.
42
+ For a raw JSON preview use the unsigned payload; a real issued/claimable record
43
+ requires the normal signing/delivery workflow.
44
+
45
+ ### Review checklist
46
+
47
+ Compare the source JSON with the current app, recording omissions rather than
48
+ changing source data to match a renderer limitation:
49
+
50
+ 1. Keep every child reachable when courses and other achievement types coexist.
51
+ 2. Preserve `Membership`, `Fieldwork`, `CommunityService`,
52
+ `CertificateOfCompletion`, and `ApprenticeshipCertificate` data even when there
53
+ is no specialized section.
54
+ 3. Display child issuers separately from the CLR publisher. `source` is assessor
55
+ attribution; `achievement.creator` describes the achievement author.
56
+ 4. Keep activity start/end, `awardedDate`, `validFrom`, and `validUntil` separate.
57
+ The employment fixture deliberately uses three different event dates.
58
+ 5. Preserve an achieved-level-only `Result`. Resolve `achievedLevel` and
59
+ `requiredLevel` within the associated achievement's `resultDescription`.
60
+ 6. Show stated score requirements without manufacturing pass/fail claims.
61
+ 7. Show membership identifiers and `licenseNumber` with appropriate labels.
62
+ The membership identity type is the extensible value `ext:membershipId`.
63
+ 8. Do not translate labeled participation hours into academic credits or CEUs.
64
+ 9. Keep narrative-only evidence visible even though it has no download URL.
65
+ 10. Render a partial record as partial, not necessarily as a partial transcript.
66
+ 11. Resolve `association.sourceId`/`targetId` to achievement IDs; those are not
67
+ interchangeable with the containing credential IDs.
68
+ 12. Do not label a whole collection expired just because one historical child is
69
+ expired. The licensing fixture's snapshot is **2026-09-01** and its outer
70
+ `validUntil` is **2030-08-31**; one child expired on **2025-01-31**.
71
+
72
+ The mixed fixture includes exact copies of selected source child credentials, with
73
+ their IDs retained deliberately. Their in-memory objects are independent. This
74
+ also supplies a realistic cross-collection deduplication scenario.
75
+
76
+ ### Signing and recipient binding
77
+
78
+ These are not pre-signed CLRs. `did:example` identifiers have no resolvable keys.
79
+ Do not add fabricated `proof` objects just to make verification UI look successful.
80
+
81
+ `prepareFixture()` changes the **outer** issuer, subject and timestamps and remaps
82
+ UUID references throughout the document. It does not recursively bind or sign
83
+ embedded credentials. Consequently, calling it once and signing only the outer
84
+ record does not establish independent child verification or same-learner binding
85
+ after a recipient change.
86
+
87
+ For an end-to-end multi-issuer test:
88
+
89
+ - Start from a cloned unsigned fixture and prepare/remap IDs before any signing.
90
+ - Bind the outer and all child subjects to the intended test learner. Replace or
91
+ remove the synthetic display-name/membership identifiers where appropriate.
92
+ - Map each fictional issuer to its own test signing wallet. Keep assessor/creator
93
+ provenance distinct instead of treating every profile as the signer.
94
+ - Sign each child with its mapped issuer, preserving achievement and result IDs.
95
+ - Embed the resulting children unchanged and sign the outer CLR with the publisher.
96
+ - Verify parent and children independently using the intended time and status policy.
97
+
98
+ Do not run UUID/identity rewriting over already-signed child credentials. Avoid
99
+ routing these rich payloads through a lossy form-template round trip during display
100
+ review. Direct JSON/template previews are not equivalent to verified credentials.
101
+
102
+ ### Deliberate boundaries
103
+
104
+ All people and organizations are fictional. `.example` framework/profile URLs
105
+ are identifiers for sample data, not live downloads or real qualification links.
106
+ Evidence is intentionally narrative-only to keep samples self-contained. No real
107
+ employment, licensing authorization, military rank, clearance or cross-domain
108
+ qualification equivalence is asserted.
109
+
110
+ There are no fake status-list services, JWTs, endorsements, remote images, or
111
+ invented sector-specific CLR properties. `Result.status: Completed` describes the
112
+ recorded outcome, not current license standing. `partial` is explicitly true
113
+ because these scenarios are selected record excerpts.
114
+
115
+ `Provisional` status and arbitrary external employment-VC schemas are not part of
116
+ these baseline fixtures: those need separate validator/adapter coverage rather
117
+ than registering known incompatible data as a supported baseline.
118
+
119
+ ### Tests
120
+
121
+ From `packages/credential-library` in an installed workspace:
122
+
123
+ ```sh
124
+ bun run test -- src/__tests__/clr-non-academic.test.ts
125
+ bun run test
126
+ bun run test:integration
127
+ ```
128
+
129
+ The new suite tests registration, local shared unsigned validators, consistent
130
+ learner identity, association/result/rubric references, UUID remapping, immutable
131
+ fixture inputs, scenario-specific fields and deliberate expired-child behavior.
132
+ The existing integration issuance suite discovers all six through the registry
133
+ and can sign each outer CLR using its bundled contexts.
134
+ That suite's outer-proof assertion alone is not recursive CLR conformance testing.
135
+
136
+ These fixture tests do not assert that missing UI support has already been fixed.
137
+ Use the scenarios for manual app review and add renderer tests with each follow-on
138
+ implementation ticket.
139
+
140
+ References: [CLR v2](https://www.imsglobal.org/spec/clr/v2p0),
141
+ [Open Badges v3](https://www.imsglobal.org/spec/ob/v3p0),
142
+ [credential library](../../../README.md).