Skip to content

Commit 2572a29

Browse files
committed
fix: remove HS grade support — use grades 9-12 directly
API confirmed HS standards have gradeLevel=['9','10','11','12']; the KG API does not accept gradeLevel=HS as a query parameter. - Remove 'HS' from SUPPORTED_GRADES, VALID_GRADES, input_schema.json - Remove HS prefix parsing from parseGradeFromStandard (HSA-APR.A.1 now throws ValidationError — callers should pass grade='9') - Remove dead client-side MP normalizedStatementType filter (API never returns Mathematical Practice for Mathematics subject queries) - Simplify README to bare minimum
1 parent 5702318 commit 2572a29

6 files changed

Lines changed: 34 additions & 68 deletions

File tree

evals/prompts/math/standards-alignment/input_schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
"grade": {
1515
"type": "string",
1616
"description": "Grade level the question targets.",
17-
"enum": ["K", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "HS"]
17+
"enum": ["K", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
1818
},
1919
"statementCode": {
2020
"type": "string",
21-
"description": "CCSS math standard code (e.g. '3.MD.C.7.d', 'HSA-APR.A.1').",
21+
"description": "CCSS math standard code (e.g. '3.MD.C.7.d', 'K.CC.A.1').",
2222
"minLength": 1,
2323
"maxLength": 50
2424
}
Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
# Knowledge Graph client
22

3-
HTTP client for the [Learning Commons Knowledge Graph API](https://api.learningcommons.org/knowledge-graph/v0), used by `MathStandardsAlignmentEvaluator` to fetch academic standards and learning components.
3+
HTTP client for the [Learning Commons Knowledge Graph API](https://api.learningcommons.org/knowledge-graph/v0).
44

5-
## Files
6-
7-
| File | Purpose |
8-
|---|---|
9-
| `kg-api.d.ts` | **Generated.** TypeScript types from the KG OpenAPI spec — do not edit by hand |
10-
| `types.ts` | Internal types: `AcademicStandard`, `LearningComponent`, `StandardInfo`, `parseGradeFromStandard` |
11-
| `client.ts` | `KnowledgeGraphClient` — HTTP calls, concurrency limiting, promise caching |
12-
| `index.ts` | Barrel |
13-
14-
## Regenerating `kg-api.d.ts`
5+
## Regenerate types
156

167
```bash
178
npm run generate:kg-types
189
```
1910

20-
Pulls the spec from `https://docs.learningcommons.org/api-reference/knowledge-graph-api/openapi.yaml`.
21-
22-
> **Note on spec enums:** `normalizedStatementType` and `gradeLevel` use `string` in our interfaces rather than the spec's enum types — the spec enums are incomplete (omit `"Mathematical Practice"` and `"HS"`).
11+
Pulls from `https://docs.learningcommons.org/api-reference/knowledge-graph-api/openapi.yaml`.
12+
`kg-api.d.ts` is generated — do not edit by hand.

sdks/typescript/src/knowledge-graph/client.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,19 @@ export class KnowledgeGraphClient {
9999
`&gradeLevel=${encodeURIComponent(grade)}` +
100100
`&normalizedStatementType=Standard`;
101101

102-
const data = (await kgFetch(url, this.apiKey)) as { data: Array<AcademicStandard> };
102+
const data = (await kgFetch(url, this.apiKey)) as {
103+
data: Array<AcademicStandard>;
104+
pagination?: { hasMore: boolean; nextCursor: string | null };
105+
};
103106

104-
return (data.data ?? [])
105-
.filter((item) => item.normalizedStatementType !== 'Mathematical Practice')
106-
.map((item) => ({
107+
if (data.pagination?.hasMore) {
108+
throw new KnowledgeGraphError(
109+
`getStandardsByGrade returned a paginated result for grade "${grade}" — ` +
110+
`increase limit or implement cursor pagination to retrieve all standards.`,
111+
);
112+
}
113+
114+
return (data.data ?? []).map((item) => ({
107115
caseIdentifierUUID: item.caseIdentifierUUID,
108116
statementCode: item.statementCode,
109117
description: item.description,

sdks/typescript/src/knowledge-graph/types.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { ValidationError } from '../errors.js';
22

3-
// The generated spec types are in kg-api.d.ts — see npm run generate:kg-types.
4-
// We use string for normalizedStatementType and gradeLevel because the spec's
5-
// enum types are incomplete (omit "Mathematical Practice" and "HS").
3+
// Generated spec types are in kg-api.d.ts — see npm run generate:kg-types.
4+
// We use string for normalizedStatementType and gradeLevel rather than the
5+
// spec's strict enum types so the interfaces remain compatible if the API
6+
// returns values outside the current spec.
67

78
/**
89
* An academic standard from the LC Knowledge Graph (spec: StandardsFrameworkItem).
@@ -33,12 +34,9 @@ export interface StandardInfo {
3334

3435
// ---------------------------------------------------------------------------
3536

36-
const VALID_GRADES = new Set(['K', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'HS']);
37+
const VALID_GRADES = new Set(['K', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']);
3738

3839
export function parseGradeFromStandard(code: string): string {
39-
// High school standards use a domain letter + hyphen: HSA-APR.A.1, HSF-BF.A.1, etc.
40-
if (/^HS[A-Z]-/.test(code)) return 'HS';
41-
4240
const match = code.match(/^(K|\d+)\./);
4341
if (!match || !VALID_GRADES.has(match[1])) {
4442
throw new ValidationError(`Cannot parse grade from standard code: "${code}"`);

sdks/typescript/tests/unit/evaluators/math/standards-alignment.test.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,6 @@ describe('MathStandardsAlignmentEvaluator - evaluate', () => {
170170
await expect(evaluator.evaluate(QUESTION, GRADE, '')).rejects.toThrow(ValidationError);
171171
});
172172

173-
it('accepts grade HS with a high school standard code', async () => {
174-
const hsRepo = makeMockKgClient({
175-
getLearningComponentsByCode: vi.fn().mockResolvedValue({ uuid: 'uuid-abc', components: [{ description: 'Factor polynomials' }] }),
176-
});
177-
vi.mocked(mockProvider.generateStructured).mockResolvedValue({
178-
...MOCK_BATCH_RESPONSE,
179-
data: { evaluations: [{ reasoning: 'ok', aligned: true, feedback: '' }] },
180-
});
181-
const evaluator = new MathStandardsAlignmentEvaluator(makeConfig({ _kgClient: hsRepo }));
182-
const result = await evaluator.evaluate('Factor x² + 5x + 6.', 'HS', 'HSA-APR.A.1');
183-
expect(result.grade).toBe('HS');
184-
expect(result.statementCode).toBe('HSA-APR.A.1');
185-
});
186-
187173
it('correctly handles grade K standard', async () => {
188174
const kRepo = makeMockKgClient({
189175
getLearningComponentsByCode: vi.fn().mockResolvedValue({ uuid: 'uuid-abc', components: [{ description: 'Count objects' }] }),
@@ -516,12 +502,6 @@ describe('parseGradeFromStandard', () => {
516502
['3.MD.C.7.d', '3'],
517503
['10.NBT.A.1', '10'],
518504
['12.F.BF.1', '12'],
519-
// High school standards use domain letter + hyphen, not a numeric grade prefix
520-
['HSA-APR.A.1', 'HS'],
521-
['HSF-BF.A.1', 'HS'],
522-
['HSG-CO.A.1', 'HS'],
523-
['HSN-CN.A.1', 'HS'],
524-
['HSS-ID.A.1', 'HS'],
525505
])('%s → %s', (code, expected) => {
526506
expect(parseGradeFromStandard(code)).toBe(expected);
527507
});
@@ -531,7 +511,7 @@ describe('parseGradeFromStandard', () => {
531511
['ZZ.OA.A.1'],
532512
['no-dots'],
533513
['13.MD.C.7'],
534-
['HSA.APR.A.1'], // missing hyphen — not a valid HS code
514+
['HSA-APR.A.1'], // HS codes not supported — use grade 9/10/11/12 directly
535515
])('throws ValidationError for "%s"', (code) => {
536516
expect(() => parseGradeFromStandard(code)).toThrow(ValidationError);
537517
});

sdks/typescript/tests/unit/knowledge-graph/client.test.ts

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -134,31 +134,21 @@ describe('KnowledgeGraphClient - getLearningComponents', () => {
134134
});
135135

136136
describe('KnowledgeGraphClient - getStandardsByGrade', () => {
137-
it('excludes Mathematical Practice standards', async () => {
138-
mockFetch(200, { data: [
137+
it('returns standards filtered to normalizedStatementType=Standard via URL', async () => {
138+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200, json: () => Promise.resolve({ data: [
139139
{ caseIdentifierUUID: 'u1', statementCode: '3.MD.C.7.d', normalizedStatementType: 'Standard', gradeLevel: ['3'] },
140-
{ caseIdentifierUUID: 'u2', statementCode: '3.MP.1', normalizedStatementType: 'Mathematical Practice', gradeLevel: ['3'] },
141-
]});
142-
const results = await new KnowledgeGraphClient(API_KEY).getStandardsByGrade('3');
143-
expect(results.map((s) => s.statementCode)).toContain('3.MD.C.7.d');
144-
expect(results.map((s) => s.statementCode)).not.toContain('3.MP.1');
145-
});
146-
147-
it('always includes normalizedStatementType=Standard in URL', async () => {
148-
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200, json: () => Promise.resolve({ data: [] }), text: () => Promise.resolve('') });
140+
] }), text: () => Promise.resolve('') });
149141
vi.stubGlobal('fetch', fetchMock);
150-
await new KnowledgeGraphClient(API_KEY).getStandardsByGrade('3');
142+
const results = await new KnowledgeGraphClient(API_KEY).getStandardsByGrade('3');
151143
expect(fetchMock.mock.calls[0][0]).toContain('normalizedStatementType=Standard');
144+
expect(results).toHaveLength(1);
145+
expect(results[0].statementCode).toBe('3.MD.C.7.d');
152146
});
153147

154-
it('uses normalizedStatementType not statementCode string to exclude MP', async () => {
155-
mockFetch(200, { data: [
156-
{ caseIdentifierUUID: 'u1', statementCode: 'HSS-IC.MP.2', normalizedStatementType: 'Standard', gradeLevel: ['HS'] },
157-
{ caseIdentifierUUID: 'u2', statementCode: '3.MP.1', normalizedStatementType: 'Mathematical Practice', gradeLevel: ['3'] },
158-
]});
159-
const results = await new KnowledgeGraphClient(API_KEY).getStandardsByGrade('HS');
160-
expect(results.map((s) => s.statementCode)).toContain('HSS-IC.MP.2');
161-
expect(results.map((s) => s.statementCode)).not.toContain('3.MP.1');
148+
it('throws KnowledgeGraphError if hasMore=true (pagination not implemented for standards)', async () => {
149+
mockFetch(200, { data: [], pagination: { hasMore: true, nextCursor: 'page-2' } });
150+
await expect(new KnowledgeGraphClient(API_KEY).getStandardsByGrade('3'))
151+
.rejects.toThrow(KnowledgeGraphError);
162152
});
163153
});
164154

0 commit comments

Comments
 (0)