chore(governance): add ETHICS.md, CHANGELOG.md, and PR fidelity smoke

Three governance-tier additions to convert Master-skill from a demo into a
defensible long-lived project:

**ETHICS.md** — mandatory governance document:
- AI transparency: outputs are AI-synthesized, not masters' own words
- Copyright tiers A (public domain, current 8), B (in-copyright, needs
  license), C (never admit: living masters, Buddhas/bodhisattvas, apocryphal
  figures), D (case-by-case)
- Religious boundary: AI must refuse precept transmission, awakening
  certification, karmic diagnosis, spirit-medium framing, etc.
- Dual-track content license: code MIT, master content CC BY-NC-SA 4.0,
  prompts CC BY 4.0
- Takedown + appeal channel with 48h / 7d SLAs

**CHANGELOG.md** — Keep a Changelog format:
- [Unreleased] captures the current governance + community + npm work
- [0.3.0] retroactively documents the architectural rebuild (provenance,
  fidelity, NPX, multi-platform, HARD-GATE, two-stage review)
- [0.2.0], [0.1.0] historical sections

**CI fidelity smoke** — make HARD-GATE a real gate, not just documentation:
- New `fidelity-smoke` job runs one basic-difficulty fixture against one
  master per PR; picks the master touched by the diff, else rotates by
  day-of-year for uniform coverage
- Cost cap ≈ $0.05/PR (~10k-token system prompt × 1 request × Sonnet 4.6
  pricing). Forks without ANTHROPIC_API_KEY get an advisory pass so
  external PRs can still land
- `scripts/test-fidelity.py` gains `--max-tests N` flag; when capping, it
  sorts by difficulty (basic → intermediate → advanced) so smoke runs hit
  the reliable floor, not stress cases
- Old `fidelity` job renamed to `fidelity-full` (still workflow_dispatch)

README 声明 section now links to ETHICS.md so every reader sees the AI
disclosure and boundary rules before copying master content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xianren
2026-04-16 13:45:56 +08:00
parent cfd18159e1
commit bd04ede817
5 changed files with 367 additions and 4 deletions
+25 -2
View File
@@ -110,7 +110,12 @@ def check_response(response: str, test_case: dict, is_first_turn: bool = True) -
}
def run_tests(master_name: str, dry_run: bool = False, model: str = "claude-sonnet-4-6") -> dict:
def run_tests(
master_name: str,
dry_run: bool = False,
model: str = "claude-sonnet-4-6",
max_tests: int | None = None,
) -> dict:
"""Run fidelity tests for a master. Returns summary."""
master_dir = PREBUILT_DIR / master_name
if not master_dir.exists():
@@ -120,6 +125,16 @@ def run_tests(master_name: str, dry_run: bool = False, model: str = "claude-sonn
if not tests:
return {"error": f"No fidelity.jsonl found for '{master_name}'"}
if max_tests is not None and max_tests > 0:
# Prefer easier/basic tests when capping — smoke suite should hit
# the reliable floor, not the advanced stress cases.
tests = sorted(
tests,
key=lambda t: {"basic": 0, "intermediate": 1, "advanced": 2}.get(
t.get("difficulty", "intermediate"), 1
),
)[:max_tests]
results: list[dict] = []
if dry_run:
@@ -218,6 +233,12 @@ def main():
parser.add_argument("--dry-run", action="store_true", help="Show test cases without calling API")
parser.add_argument("--model", type=str, default="claude-sonnet-4-6", help="Claude model to use")
parser.add_argument("--json", action="store_true", help="Output as JSON")
parser.add_argument(
"--max-tests",
type=int,
default=None,
help="Cap the number of fixtures per master (smoke runs in CI use 1)",
)
args = parser.parse_args()
if not args.master and not args.all:
@@ -236,7 +257,9 @@ def main():
print(f"\n{'='*50}")
print(f"Testing: {master}")
print(f"{'='*50}")
result = run_tests(master, dry_run=args.dry_run, model=args.model)
result = run_tests(
master, dry_run=args.dry_run, model=args.model, max_tests=args.max_tests
)
all_results.append(result)
if not args.json and "error" not in result: