standardgraph 1.1.2__tar.gz → 1.2.2__tar.gz

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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: standardgraph
3
- Version: 1.1.2
4
- Summary: 156,000+ education standards (math, science, ELA, social studies, CS, arts) across 298 curriculum systems, cross-referenced via NLP — accessible as a Claude MCP server
3
+ Version: 1.2.2
4
+ Summary: 158,000+ education standards (math, science, ELA, social studies, CS, arts) across 300 curriculum systems, cross-referenced via NLP — accessible as a Claude MCP server
5
5
  Author: StandardGraph
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/swoopeagle/standardgraph
@@ -22,9 +22,9 @@ Requires-Dist: numpy>=1.26.0
22
22
 
23
23
  # standardgraph
24
24
 
25
- **20,000+ math standards across 75+ curriculum systems, accessible as a Claude MCP server.**
25
+ **157,000+ education standards across 298 curriculum systems, accessible as a Claude MCP server.**
26
26
 
27
- Covers the US (CCSS + all 50 states), Canada, Australia, UK, Singapore, Japan, New Zealand, Ireland, Hong Kong, India, Ghana, South Africa, Rwanda, Cambridge International, IB MYP/DP, and more all cross-referenced to CCSS via NLP semantic similarity.
27
+ Covers seven subjects — Mathematics, Science, ELA, Social Studies, Computer Science, Arts, and World Languages — across the US (CCSS + all 50 states), Canada, Australia, UK, Singapore, Japan, New Zealand, Ireland, Hong Kong, India, Ghana, South Africa, Rwanda, Cambridge International, IB MYP/DP, AP, and more. Standards are cross-referenced to subject hubs (CCSS for math, NGSS for science, etc.) via semantic similarity, with LLM quality scores on the strongest mappings.
28
28
 
29
29
  ## Install (macOS)
30
30
 
@@ -1,8 +1,8 @@
1
1
  # standardgraph
2
2
 
3
- **20,000+ math standards across 75+ curriculum systems, accessible as a Claude MCP server.**
3
+ **157,000+ education standards across 298 curriculum systems, accessible as a Claude MCP server.**
4
4
 
5
- Covers the US (CCSS + all 50 states), Canada, Australia, UK, Singapore, Japan, New Zealand, Ireland, Hong Kong, India, Ghana, South Africa, Rwanda, Cambridge International, IB MYP/DP, and more all cross-referenced to CCSS via NLP semantic similarity.
5
+ Covers seven subjects — Mathematics, Science, ELA, Social Studies, Computer Science, Arts, and World Languages — across the US (CCSS + all 50 states), Canada, Australia, UK, Singapore, Japan, New Zealand, Ireland, Hong Kong, India, Ghana, South Africa, Rwanda, Cambridge International, IB MYP/DP, AP, and more. Standards are cross-referenced to subject hubs (CCSS for math, NGSS for science, etc.) via semantic similarity, with LLM quality scores on the strongest mappings.
6
6
 
7
7
  ## Install (macOS)
8
8
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "standardgraph"
3
- version = "1.1.2"
4
- description = "156,000+ education standards (math, science, ELA, social studies, CS, arts) across 298 curriculum systems, cross-referenced via NLP — accessible as a Claude MCP server"
3
+ version = "1.2.2"
4
+ description = "158,000+ education standards (math, science, ELA, social studies, CS, arts) across 300 curriculum systems, cross-referenced via NLP — accessible as a Claude MCP server"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  license = "MIT"
@@ -149,6 +149,19 @@ _AP_META = {"country": "United States", "country_code": "US", "region": "N
149
149
  _US_STATE_SUFFIXES = {"-sci", "-ela", "-ss", "-cs"}
150
150
 
151
151
 
152
+ # Quality scores come from two sources: LLM rubric scoring ("[LLM score N/5]") and
153
+ # deterministic exact-match scoring ("[exact-match N/5]", assigned when source and
154
+ # target standard text are byte-identical). Both are surfaced as quality_score.
155
+ _SCORE_RE = re.compile(r"\[(?:LLM score|exact-match) (\d)/5\]")
156
+
157
+
158
+ def _parse_quality(notes: str | None) -> int | None:
159
+ if not notes:
160
+ return None
161
+ m = _SCORE_RE.search(notes)
162
+ return int(m.group(1)) if m else None
163
+
164
+
152
165
  def _meta(system: str) -> dict:
153
166
  if system in SYSTEM_META:
154
167
  return SYSTEM_META[system]
@@ -215,8 +228,19 @@ def _embed_query(text: str) -> np.ndarray:
215
228
  return np.array(resp.json()["embeddings"][0], dtype=np.float32)
216
229
 
217
230
 
218
- def _cosine_scores(query_vec: np.ndarray, conn: sqlite3.Connection) -> list[tuple[float, str]]:
219
- rows = conn.execute("SELECT standard_id, vector, dimensions FROM embeddings").fetchall()
231
+ def _cosine_scores(
232
+ query_vec: np.ndarray,
233
+ conn: sqlite3.Connection,
234
+ system: str | None = None,
235
+ ) -> list[tuple[float, str]]:
236
+ if system:
237
+ rows = conn.execute(
238
+ "SELECT e.standard_id, e.vector, e.dimensions FROM embeddings e "
239
+ "JOIN standards s ON s.id = e.standard_id WHERE s.system = ?",
240
+ (system,),
241
+ ).fetchall()
242
+ else:
243
+ rows = conn.execute("SELECT standard_id, vector, dimensions FROM embeddings").fetchall()
220
244
  if not rows:
221
245
  return []
222
246
  dim = rows[0]["dimensions"]
@@ -440,14 +464,14 @@ def search_standards(
440
464
  "results": results,
441
465
  }, indent=2)
442
466
  conn = _db()
443
- scored = _cosine_scores(query_vec, conn)
467
+ scored = _cosine_scores(query_vec, conn, system=system)
444
468
 
445
469
  results = []
446
470
  for score, sid in scored:
447
471
  if len(results) >= limit:
448
472
  break
449
473
  row = conn.execute(
450
- "SELECT * FROM standards WHERE id=? AND system=?", (sid, system)
474
+ "SELECT * FROM standards WHERE id=?", (sid,)
451
475
  ).fetchone()
452
476
  if not row:
453
477
  continue
@@ -541,7 +565,7 @@ def get_progression(
541
565
  ],
542
566
  }, indent=2)
543
567
  conn = _db()
544
- scored = _cosine_scores(query_vec, conn)
568
+ scored = _cosine_scores(query_vec, conn, system=system)
545
569
 
546
570
  # Collect top standards per grade, filtered by grade range
547
571
  by_grade: dict[str, list[dict]] = {}
@@ -549,7 +573,7 @@ def get_progression(
549
573
  if score < 0.5:
550
574
  break
551
575
  row = conn.execute(
552
- "SELECT * FROM standards WHERE id=? AND system=?", (sid, system)
576
+ "SELECT * FROM standards WHERE id=?", (sid,)
553
577
  ).fetchone()
554
578
  if not row:
555
579
  continue
@@ -596,6 +620,7 @@ def map_standard(
596
620
  from_system: str,
597
621
  to_system: str,
598
622
  confidence_threshold: float = 0.7,
623
+ include_flagged: bool = False,
599
624
  ) -> str:
600
625
  """Find the closest equivalent to a standard in a different curriculum system.
601
626
 
@@ -613,8 +638,11 @@ def map_standard(
613
638
  from_system: system code of the source standard (e.g. 'tx', 'ca-on', 'sg-moe').
614
639
  to_system: target system code (any indexed system).
615
640
  confidence_threshold: minimum cosine similarity for primary results (default 0.7).
641
+ include_flagged: if True, include mappings flagged for review (LLM quality score 1-2).
642
+ Default False returns only verified-quality mappings.
616
643
 
617
- Returns matched standards with confidence score, grade alignment, and mapping method.
644
+ Returns matched standards with confidence score, grade alignment, quality_score (1-5),
645
+ flagged status, and mapping method.
618
646
  """
619
647
  sid = _expand_id(standard_id, from_system)
620
648
  conn = _db()
@@ -627,40 +655,53 @@ def map_standard(
627
655
  src_dict = dict(src)
628
656
 
629
657
  # ── 1. Precomputed crosswalk above threshold ───────────────────────────────
658
+ flagged_clause = "" if include_flagged else "AND cm.flagged_for_review = 0"
630
659
  mappings = conn.execute(
631
- """SELECT cm.*, s.standard_text AS target_text, s.grade AS target_grade,
660
+ f"""SELECT cm.*, s.standard_text AS target_text, s.grade AS target_grade,
632
661
  s.domain AS target_domain
633
662
  FROM crosswalk_mappings cm
634
663
  JOIN standards s ON s.id = cm.target_id
635
664
  WHERE cm.source_id = ?
636
665
  AND cm.target_system = ?
637
666
  AND cm.confidence_score >= ?
667
+ {flagged_clause}
638
668
  ORDER BY cm.confidence_score DESC""",
639
669
  (sid, to_system, confidence_threshold),
640
670
  ).fetchall()
641
671
 
642
672
  if mappings:
643
673
  conn.close()
674
+ result_list = [
675
+ {
676
+ "target_id": m["target_id"],
677
+ "target_standard_text": m["target_text"],
678
+ "relationship": m["relationship"],
679
+ "confidence": m["confidence_score"],
680
+ "quality_score": _parse_quality(m["notes"]),
681
+ "flagged": bool(m["flagged_for_review"]),
682
+ "grade_delta": m["grade_delta"],
683
+ "grade_alignment": "exact" if m["grade_delta"] == 0 else (
684
+ f"{abs(m['grade_delta'])} year{'s' if abs(m['grade_delta']) > 1 else ''} "
685
+ f"{'later' if m['grade_delta'] > 0 else 'earlier'} in target"
686
+ ),
687
+ "verified_by_human": bool(m["verified_by_human"]),
688
+ "notes": m["notes"],
689
+ }
690
+ for m in mappings
691
+ ]
692
+ # Rank by quality then confidence. Unscored rows (quality_score is None) are
693
+ # of *unknown* quality, not zero quality — treat them as a neutral midpoint so
694
+ # a high-cosine unscored match isn't buried beneath a mediocre scored one.
695
+ # (Score-1/2 rows are already filtered out by default via flagged_clause.)
696
+ result_list.sort(
697
+ key=lambda x: (x["quality_score"] if x["quality_score"] is not None else 3, x["confidence"]),
698
+ reverse=True,
699
+ )
644
700
  return json.dumps({
645
701
  "source_id": src_dict["id"],
646
702
  "target_curriculum": to_system,
647
703
  "mapping_method": "precomputed_crosswalk",
648
- "mappings": [
649
- {
650
- "target_id": m["target_id"],
651
- "target_standard_text": m["target_text"],
652
- "relationship": m["relationship"],
653
- "confidence": m["confidence_score"],
654
- "grade_delta": m["grade_delta"],
655
- "grade_alignment": "exact" if m["grade_delta"] == 0 else (
656
- f"{abs(m['grade_delta'])} year{'s' if abs(m['grade_delta']) > 1 else ''} "
657
- f"{'later' if m['grade_delta'] > 0 else 'earlier'} in target"
658
- ),
659
- "verified_by_human": bool(m["verified_by_human"]),
660
- "notes": m["notes"],
661
- }
662
- for m in mappings
663
- ],
704
+ "mappings": result_list,
664
705
  }, indent=2)
665
706
 
666
707
  # ── 2. Best precomputed result below threshold ─────────────────────────────
@@ -748,14 +789,14 @@ def map_standard(
748
789
  embedding_error: str | None = None
749
790
  try:
750
791
  qvec = _embed_query(src_dict["standard_text"])
751
- scored = _cosine_scores(qvec, conn)
792
+ scored = _cosine_scores(qvec, conn, system=to_system)
752
793
  for score, candidate_id in scored:
753
794
  if len(nearest_by_concept) >= 3:
754
795
  break
755
796
  if score < 0.35:
756
797
  break
757
798
  row = conn.execute(
758
- "SELECT * FROM standards WHERE id=? AND system=?", (candidate_id, to_system)
799
+ "SELECT * FROM standards WHERE id=?", (candidate_id,)
759
800
  ).fetchone()
760
801
  if row:
761
802
  nearest_by_concept.append({
@@ -782,6 +823,8 @@ def map_standard(
782
823
  "target_id": best_below["target_id"],
783
824
  "target_standard_text": best_below["target_text"],
784
825
  "confidence": round(best_below["confidence_score"], 4),
826
+ "quality_score": _parse_quality(best_below["notes"]),
827
+ "flagged": bool(best_below["flagged_for_review"]),
785
828
  "below_threshold": True,
786
829
  "threshold_used": confidence_threshold,
787
830
  }
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: standardgraph
3
- Version: 1.1.2
4
- Summary: 156,000+ education standards (math, science, ELA, social studies, CS, arts) across 298 curriculum systems, cross-referenced via NLP — accessible as a Claude MCP server
3
+ Version: 1.2.2
4
+ Summary: 158,000+ education standards (math, science, ELA, social studies, CS, arts) across 300 curriculum systems, cross-referenced via NLP — accessible as a Claude MCP server
5
5
  Author: StandardGraph
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/swoopeagle/standardgraph
@@ -22,9 +22,9 @@ Requires-Dist: numpy>=1.26.0
22
22
 
23
23
  # standardgraph
24
24
 
25
- **20,000+ math standards across 75+ curriculum systems, accessible as a Claude MCP server.**
25
+ **157,000+ education standards across 298 curriculum systems, accessible as a Claude MCP server.**
26
26
 
27
- Covers the US (CCSS + all 50 states), Canada, Australia, UK, Singapore, Japan, New Zealand, Ireland, Hong Kong, India, Ghana, South Africa, Rwanda, Cambridge International, IB MYP/DP, and more all cross-referenced to CCSS via NLP semantic similarity.
27
+ Covers seven subjects — Mathematics, Science, ELA, Social Studies, Computer Science, Arts, and World Languages — across the US (CCSS + all 50 states), Canada, Australia, UK, Singapore, Japan, New Zealand, Ireland, Hong Kong, India, Ghana, South Africa, Rwanda, Cambridge International, IB MYP/DP, AP, and more. Standards are cross-referenced to subject hubs (CCSS for math, NGSS for science, etc.) via semantic similarity, with LLM quality scores on the strongest mappings.
28
28
 
29
29
  ## Install (macOS)
30
30
 
File without changes