Files
Master-skill/scripts/validate-fidelity.py
T
xianren 9b2039e12a feat(v0.5): expand Tibetan + Theravāda each from 1 → 3 masters (15 total)
Second cross-tradition expansion. v0.4 introduced Milarepa + Ajahn
Chah; this release adds the major foundational figures of each
non-Chinese tradition that were missing.

藏传 (Tibetan): now 3 — Atiśa, Tsongkhapa, Milarepa
南传 (Theravāda): now 3 — Buddhaghosa, Mahasi Sayadaw, Ajahn Chah
汉传 (Chinese): unchanged at 8

New masters
-----------
* prebuilt/atisha/ — Atiśa Dīpaṃkara (982-1054). 噶当派 founder,
  Indo-Tibetan bridge. Sources: Toh 4465 Bodhipathapradīpa + Toh
  3948 self-commentary + 噶当口耳传承 Pha chos / Bu chos. Coverage:
  three scopes, bodhicitta (七因果 + 自他相换 from Suvarṇadvīpa
  Dharmakīrti), 戒律严持, 噶当六论, 依止善知识. HARD-GATE:
  NO_ESOTERIC_INSTRUCTION + NO_ANACHRONISTIC_ATTRIBUTION (don't
  project later Gelug analytical Madhyamaka onto Atiśa's era).

* prebuilt/tsongkhapa/ — Tsongkhapa Lobsang Drakpa (1357-1419).
  Gelug founder, basis of Dalai Lama / Panchen Lama lineages.
  Sources: 宗喀巴全集 gsung 'bum (BDRC searchable) — Lam rim chen
  mo, sNgags rim chen mo, Drang nges legs bshad snying po, 入中论
  善显密意疏, 三主要道. Coverage: 三主要道 (出离心 / 菩提心 / 清净
  见), lamrim, 应成中观, 三聚戒, 闻思修, 五部大论. HARD-GATE:
  NO_ESOTERIC_INSTRUCTION + NO_CROSS_SCHOOL_CONTAMINATION (don't
  blend Dzogchen / Mahāmudrā into Gelug positions) +
  NO_UNVERIFIED_BDRC_W_NUMBERS (descriptive guidance instead of
  fabricated W-IDs; lessons-learned from v0.4 fixup).

* prebuilt/buddhaghosa/ — Buddhaghosa (5th century). 上座部
  commentarial summit. Sources: PTS Vism + four Nikāya aṭṭhakathā
  + Samantapāsādikā (Vinaya) + Atthasālinī (Abhidhamma). Coverage:
  戒定慧三学, 四十种业处, 七清净十六观智, 缘起十二支 (three-life-
  two-causations interpretation), 阿毗达摩 paramattha vs paññatti,
  六义诠释 commentarial method. HARD-GATE:
  NO_MAHAYANA_CONTAMINATION + NO_MAHAVIHARA_PRIMACY_OVERSTATEMENT.

* prebuilt/mahasi-sayadaw/ — Mahāsi Sayādaw U Sobhana (1904-1982).
  Burmese Vipassanā tradition / Mahasi Method. Sources: Manual of
  Insight (Wisdom Publications 2016) + Progress of Insight (BPS
  Sri Lanka Wheel No. 280) + Practical Vipassanā Meditation
  Exercises (Mahasi Sasana Yeiktha) + SC + PTS Vism. Coverage:
  标记法 Noting Method, 腹部起伏 rising-falling primary object,
  七清净十六观智 progress, khaṇika-samādhi & vipassanā-jhāna,
  '初果可证' ethos, MN 10 Satipaṭṭhāna foundation. HARD-GATE:
  NO_FABRICATED_QUOTES + **NO_ATTAINMENT_JUDGMENT** (the strictest
  guardrail in this release — Mahasi's stages-of-insight framework
  is famous for inducing self-attainment delusions; AI is forbidden
  from confirming any individual's observed jhāna stage / fruition).

Each master ships the standard v0.3 progressive-disclosure shape:
SKILL.md (decision tree + HARD-GATE + Quick Reference) + meta.json +
references/{voice,teaching}.md + sources/INDEX.md + ≥1 excerpts file
+ tests/fidelity.jsonl with 12-13 cases each.

ETHICS updates
--------------
* Tier A grows from 9 → 12: Atiśa (>970yr), Tsongkhapa (>600yr),
  Buddhaghosa (>1500yr) all join based on age + open-canon sourcing.
* Tier B 特例 grows from 1 → 2: Mahasi Sayadaw codified under same
  Forest-Sangha-style rationale as Ajahn Chah, with explicit
  NO_ATTAINMENT_JUDGMENT addendum specific to his lineage's risks.
* Sectarian-judgment policy explicit extension: covers Theravāda
  intra-tradition meditation lineages (Mahasi vs Pa-Auk vs Goenka
  vs Thai Forest) — no superiority claims permitted.

compare-masters meta-skill
--------------------------
prebuilt/compare/SKILL.md updated:
* 可用祖师 table now lists all 15 masters by tradition.
* Topic mapping fallback table extended with rows pairing the new
  masters: 中观 (kumarajiva + tsongkhapa), 道次第 (atisha +
  tsongkhapa), 心识 (xuanzang + buddhaghosa + huineng), 戒律
  (xuyun + atisha + buddhaghosa), 禅修方法 (buddhaghosa + mahasi
  + ajahn-chah), 七清净 (buddhaghosa + mahasi), 论师风格 (xuanzang
  + tsongkhapa + buddhaghosa), 三大传统对比 (huineng + tsongkhapa
  + buddhaghosa).
* New cross-tradition guardrails: don't blend traditions (don't
  project Gelug positions onto Atiśa's era; don't put Mahāmudrā
  into Gelug; don't put Tathāgatagarbha into Theravāda).

Surface bumps
-------------
* All 4 plugin manifests + package.json + gemini-extension.json
  bumped 0.4.0 → 0.5.0 with description updated to "15 prebuilt
  masters".
* SKILL.md (project-level) preset list expanded to 8/3/3.
* README.md + README_EN.md: situational guidance table extended
  with cross-tradition rows for the 4 new entries; new master cards
  added with provenance notes; v0.5 release banner appended above
  v0.4 banner.

Validation
----------
* python scripts/validate.py --strict   →  15 masters pass
* python scripts/validate-fidelity.py   →  all valid
* python scripts/test-fidelity.py --all --dry-run  → 
* pytest tests/                          →  31 passed, 6 skipped

Notes
-----
* fojin_text_ids=[] for new masters — FoJin DB still hasn't imported
  BDRC Tibetan canon nor PTS Vism / SuttaCentral Pali full text;
  RAG falls back to the global corpus and each prompt explicitly
  notes this.
* The two Tibetan masters intentionally use descriptive BDRC
  guidance ("BDRC: 见宗喀巴 gsung 'bum") rather than fabricated
  W-numbers, applying lessons learned from the v0.4 fixup where
  W29193 was mistakenly assigned to two different works in early
  drafts. Toh (Tohoku) numbers are kept where they're well-attested
  in 藏学界 (Toh 4465 for Bodhipathapradīpa).
* CompanionPRs in xr843/fojin (#507 + #508) already synchronized
  the chat-mode subset of these 6 cross-tradition masters; v0.5 of
  this repo brings the Master-skill side to parity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 18:39:58 +08:00

148 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""Validate fidelity.jsonl structure for all masters.
Checks that every test case has required fields and valid structure.
No API calls needed — pure structural validation.
Usage:
python scripts/validate-fidelity.py
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
PREBUILT_DIR = Path(__file__).resolve().parent.parent / "prebuilt"
VALID_TEST_TYPES = {"fidelity", "boundary", "pressure"}
VALID_BOUNDARIES = {
"sectarian_judgment",
"no_prophecy",
"neutral_first_turn",
"no_fabricated_dialogue",
"no_esoteric_instruction",
"no_attainment_judgment",
}
VALID_PRESSURES = {
"citation_bypass",
"informality_bypass",
"meta_challenge",
"hostile_challenge",
"simplicity_bypass",
"terminology_bypass",
"relevance_challenge",
"misunderstanding_challenge",
}
def validate_master(master_dir: Path) -> list[str]:
"""Validate fidelity.jsonl for a single master. Returns list of errors."""
fidelity_path = master_dir / "tests" / "fidelity.jsonl"
if not fidelity_path.exists():
return [f"{master_dir.name}: no fidelity.jsonl found"]
errors = []
lines = fidelity_path.read_text(encoding="utf-8").strip().splitlines()
if len(lines) < 5:
errors.append(f"{master_dir.name}: fewer than 5 test cases ({len(lines)})")
for i, line in enumerate(lines, 1):
if not line.strip():
continue
try:
test = json.loads(line)
except json.JSONDecodeError as e:
errors.append(f"{master_dir.name}:{i}: invalid JSON — {e}")
continue
# Every test must have "q"
if "q" not in test:
errors.append(f"{master_dir.name}:{i}: missing 'q' field")
# Must have at least one assertion
has_assertion = any(
k in test
for k in [
"must_cite",
"must_mention",
"must_not_contain",
"must_not_contain_first_turn",
"must_select_masters",
"must_have_sections",
"must_cite_per_master",
]
)
if not has_assertion:
errors.append(f"{master_dir.name}:{i}: no assertion fields found")
# Validate test_type if present
test_type = test.get("test_type")
if test_type and test_type not in VALID_TEST_TYPES:
errors.append(
f"{master_dir.name}:{i}: invalid test_type '{test_type}' "
f"(valid: {VALID_TEST_TYPES})"
)
# Validate boundary/pressure subtypes
if test_type == "boundary":
boundary = test.get("boundary")
if not boundary:
errors.append(f"{master_dir.name}:{i}: boundary test missing 'boundary' field")
elif boundary not in VALID_BOUNDARIES:
errors.append(
f"{master_dir.name}:{i}: unknown boundary '{boundary}' "
f"(valid: {VALID_BOUNDARIES})"
)
if test_type == "pressure":
pressure = test.get("pressure")
if not pressure:
errors.append(f"{master_dir.name}:{i}: pressure test missing 'pressure' field")
# List fields must be lists
for field in ["must_cite", "must_mention", "must_not_contain", "must_not_contain_first_turn"]:
if field in test and not isinstance(test[field], list):
errors.append(f"{master_dir.name}:{i}: '{field}' must be a list")
# Check coverage: should have at least one boundary test
has_boundary = any(
json.loads(l).get("test_type") == "boundary"
for l in lines
if l.strip()
)
if not has_boundary:
errors.append(f"{master_dir.name}: no boundary tests found (need at least one)")
return errors
def main():
all_errors = []
masters = sorted(
d for d in PREBUILT_DIR.iterdir()
if d.is_dir() and (d / "tests" / "fidelity.jsonl").exists()
)
for master_dir in masters:
errors = validate_master(master_dir)
all_errors.extend(errors)
if not errors:
fidelity_path = master_dir / "tests" / "fidelity.jsonl"
count = len(fidelity_path.read_text().strip().splitlines()) if fidelity_path.exists() else 0
print(f" {master_dir.name}: {count} tests OK")
if all_errors:
print(f"\n{len(all_errors)} error(s) found:")
for err in all_errors:
print(f" ERROR: {err}")
sys.exit(1)
else:
print(f"\nAll {len(masters)} masters validated successfully.")
if __name__ == "__main__":
main()