Pre-publication review draft
日常訳NICHIJOYAKU日本語 ↗

SOURCE EXPLORER / EVIDENCE BROWSER

verify_aligned_release.py

Inspect the implementation and evidence, line by line.

Nichijoyaku was created using AI. A complete review by human biblical-language and biblical-studies specialists has not been established. Read alongside established translations and original-language resources.

verify_aligned_release.py89 linesDownload raw ↓

verbatim snapshot · cli/translate-bible/scripts/verify_aligned_release.py

Provenance & checksum

Captured: 2026-10-03. See the evidence index for source-specific provenance.

SHA-256 424762bc2aad3fcc2ca4b47c21e979e3f5f182adf82dc92aac98e51e4adab948

index.json ↗

Jump to a function or class (4)

Line numbers link directly to each line. Find in this file with ⌘F / Ctrl+F.

1#!/usr/bin/env python32"""Verify exported reference coverage, repair texts and provenance offline."""3import argparse4import hashlib5import json6from pathlib import Path7import re8import sys910ROOT = Path(__file__).resolve().parents[1]11sys.path.insert(0, str(ROOT))12from src.output.originals import load_site13from src.output.alignment import read_output141516def unique_object(pairs):17    result = {}18    for key, value in pairs:19        if key in result:20            raise ValueError(f'Duplicate JSON key: {key}')21        result[key] = value22    return result232425def read(path):26    return json.loads(path.read_text(), object_pairs_hook=unique_object)272829def sha(path):30    return hashlib.sha256(path.read_bytes()).hexdigest()313233def verify(release, audit_path, bundle_path, source):34    manifest, audit, bundle = map(read, (release / 'manifest.json', audit_path, bundle_path))35    assert manifest['audit_sha256'] == sha(audit_path), 'Audit hash mismatch'36    assert audit['numbering_ready'], 'Unresolved numbering audit'37    assert not any(audit[k] for k in ('missing_passages', 'conflicts', 'held_records'))38    raw, files = read_output(source)39    assert files == audit['input_files'], 'Raw source changed'40    site, codes = load_site()41    reverse = {code: book for book, code in codes.items()}42    actual, headings = {}, 043    assert set(manifest['files']) == {code + '.json' for code in codes.values()}44    assert {p.name for p in release.iterdir()} == set(manifest['files']) | {'manifest.json'}45    for filename, expected in manifest['files'].items():46        path = release / filename47        assert sha(path) == expected, f'Asset hash mismatch: {filename}'48        book = read(path)49        assert book['translation'] == '日常訳第1版' and book['schema'] == 150        assert book['book'] == path.stem51        for ch, chapter in book['chapters'].items():52            headings += bool(chapter['heading'])53            for verse, text in chapter['verses'].items():54                key = (reverse[book['book']], int(ch), int(verse))55                assert int(verse) > 0 and key not in actual56                assert text.strip() and not re.search(r'[\x00-\x1f\x7f<>\ufffd\u0370-\u03ff\u0590-\u05ff]|```', text), key57                actual[key] = text58    assert actual.keys() == site.keys(), 'Missing or extra release references'59    for key, text in actual.items():60        ref = ':'.join(map(str, key))61        expected = audit['aligned_changes'].get(ref, {}).get('text', raw.get(ref))62        assert text == expected, f'Export differs from approved alignment: {ref}'63    for decision in bundle['decisions']:64        book, ch, verse = decision['target'].split(':')65        assert actual[(book, int(ch), int(verse))] == decision['text'], decision['target']66    counts = {'books': len({k[0] for k in actual}), 'chapters': len({k[:2] for k in actual}), 'verses': len(actual)}67    assert all(manifest[k] == value for k, value in counts.items())68    return {'status': 'pass', **counts, 'heading_blocks': headings, 'verified_repairs': len(bundle['decisions']),69            'audit_sha256': sha(audit_path), 'bundle_sha256': sha(bundle_path), 'manifest_sha256': sha(release / 'manifest.json')}707172if __name__ == '__main__':73    parser = argparse.ArgumentParser(description=__doc__)74    parser.add_argument('--release', type=Path, default=ROOT / 'reports/releases/nichijo-v1')75    parser.add_argument('--audit', type=Path, default=ROOT / 'reports/nichijo-v1-numbering-alignment.json')76    parser.add_argument('--bundle', type=Path, default=ROOT / 'reports/numbering-repairs/repair-bundle.json')77    parser.add_argument('--source', type=Path, default=ROOT / 'data/output')78    parser.add_argument('--report', type=Path)79    args = parser.parse_args()80    try:81        result = verify(args.release, args.audit, args.bundle, args.source)82    except (AssertionError, ValueError, KeyError, OSError) as exc:83        print(f'Release verification failed: {exc}', file=sys.stderr)84        sys.exit(1)85    output = json.dumps(result, ensure_ascii=False, indent=2) + '\n'86    if args.report:87        args.report.write_text(output)88    print(output, end='')89