"""Prepare a public source distribution from an explicit, inspected allowlist. Never copy the monorepo's .git, .env files, credentials or private run archives. This deliberately leaves gaps in historical input/output rather than publishing unrelated private conversations or pretending they have been recovered. """ import argparse import hashlib import json from pathlib import Path import shutil import subprocess SITE=Path(__file__).resolve().parents[1] ROOT=SITE.parents[1] def package(out): if out.exists() and any(out.iterdir()): raise ValueError('Use an empty destination') out.mkdir(parents=True, exist_ok=True) corpus=SITE/'public/downloads/nichijo-v1' shutil.copytree(corpus,out/'edition-1') shutil.copytree(SITE/'public/evidence',out/'evidence') shutil.copytree(SITE/'public/downloads/provenance-v1',out/'provenance-v1') translator=ROOT/'cli/translate-bible' for name in ['main.py','pyproject.toml','uv.lock','README.md','LICENSE']: dest=out/'software'/name;dest.parent.mkdir(exist_ok=True);shutil.copyfile(translator/name,dest) # Python source and package data only. No caches, .env or local databases. for p in sorted((translator/'src').rglob('*')): if p.is_file() and p.suffix in ('.py','.json','.yaml','.yml') and '__pycache__' not in p.parts: dest=out/'software'/p.relative_to(translator);dest.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(p,dest) for folder in ['scripts', 'tests']: for source in sorted((translator/folder).rglob('*.py')): dest=out/'software'/source.relative_to(translator);dest.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(source,dest) for source in sorted((translator/'data/config').glob('*.json')): dest=out/'software'/source.relative_to(translator);dest.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(source,dest) for name in ['export-release.py','package-source.py','package-site-source.py','collect-provenance.py']: dest=out/'tools'/name;dest.parent.mkdir(exist_ok=True);shutil.copyfile(SITE/'scripts'/name,dest) audit_path=translator/'reports/nichijo-v1-numbering-alignment.json' audit=json.loads(audit_path.read_text()) # Only translation decisions, Japanese alternatives and reference routing. decisions={ 'source_sha256':hashlib.sha256(audit_path.read_bytes()).hexdigest(), 'aligned_changes':{key:{'text':v['text'],'sources':v['sources']} for key,v in audit['aligned_changes'].items()}, 'resolutions':{key:{'reason':v['reason'],'selected':v.get('selected',[]), 'all_candidates':[{'source':c['source'],'text':c['text']} for c in v.get('all_candidates',[])]} for key,v in audit['resolutions'].items()} } (out/'evidence/numbering-decisions.json').write_text(json.dumps(decisions,ensure_ascii=False,indent=2)+'\n') (out/'LICENSE').write_text((corpus/'LICENSE.txt').read_text()) (out/'.gitignore').write_text('.env\n.env.*\n.venv/\n__pycache__/\nsoftware/data/corpus/\nsoftware/data/output/\nsoftware/data/jobs/\nsoftware/data/request-archive/\n*.log\n') (out/'README.md').write_text('''# 日常訳 / Nichijoyaku An open Japanese Bible translation, maintained and stewarded by **Conor Livingston**. The Japanese text is **CC BY 4.0**; project software is **MIT**. See LICENSE and software/LICENSE. The Bible was generated with AI and has not received comprehensive human expert review. File verification does not prove accuracy. ## Read, reuse, contribute - [Read edition 1](https://japanbible.net/?translation=nichijo-v1). - [Project, method and evidence](https://nichijoyaku.pages.dev/). - `edition-1/`: verified book JSON, JSONL, CSV, text, USFM, furigana and printable academic study layout. The study layout uses the same edition. - `edition-1/checksums.json`: SHA-256 for every distribution file. - Download the complete source archive from the project website; no GitHub account is needed to inspect, verify or reuse it. - [Suggest a correction without an account](https://nichijoyaku.pages.dev/contribute/). Identify edition, passage, current wording or reading, proposed change and reason. Do not include private data. ## What can be inspected `software/` contains the translation pipeline's source, not its private runtime environment. `evidence/` includes pinned prompts/configuration, release evidence, usage summaries, and surviving numbering decisions with Japanese alternatives. `provenance-v1/` publishes 28,602 saved parsed outputs from 1,096 release-matched chapter files. 6,446 include retained-input hashes, reference labels and timing; one project-authored system prompt is available in full. Historical prompts include Kougo and KJV, so a claim of no reference inputs is contradicted. Exact user prompts remain private because they embed separately licensed text. 94 missing/changed chapter inputs are explicitly listed. Two Joel chapters were recovered from Git history and verified against the original audit. Original-language corpora and reference Bible translations are not redistributed. Download prerequisites using the software's documented source importers. The prompt builder supports reference translations. We do **not** claim that no other translations were input, that all model training data was copyright free, or that every historical LLM input/output survives. Existing evidence is published as evidence; missing records are not reconstructed and relabeled as original logs. Model labels in saved records are not independent vendor checks. ## Reproduce and verify From the extracted source directory: `python3 tools/verify-package.py` checks every distributed file against its checksum manifest. No network or model calls are required. The release-generation tools in `tools/` document the export from the source monorepo; they need that original layout and are not standalone translators. Use `software/README.md` for pipeline requirements. Private runtime state is not included and running a translation may incur provider charges. ## Changes and stewardship Submissions do not rewrite a published edition automatically. A change records the old text, proposed text, reference, reason, reviewer role and decision. Keep edition 1 immutable; publish accepted translation changes as a new edition with its own manifest. AI review and human review must remain distinguishable. Why open source? Reuse should not depend on one website, device or maintainer. People should be able to inspect the work, correct mistakes and build new reading, teaching and accessibility tools around it. ''') (out/'CONTRIBUTING.md').write_text('''# Contributing Report a word, verse or furigana issue with the edition, book/chapter/verse, exact current wording/reading, proposed replacement, and the reason. An account is not needed: use https://nichijoyaku.pages.dev/contribute/ on the project website. Do not paste private correspondence or long copyrighted commentary excerpts. Translation changes need review. Preserve before/after text and supporting references. Mark AI-generated suggestions clearly; never label them human review. Contributions to text use CC BY 4.0; software changes use MIT. ''') (out/'tools/verify-package.py').write_text('''import hashlib, json from pathlib import Path root=Path(__file__).resolve().parents[1]/'edition-1' package=json.loads((root.parent/'PROVENANCE.json').read_text()) for name, expected in package['files'].items(): if hashlib.sha256((root.parent/name).read_bytes()).hexdigest()!=expected: raise SystemExit('Source hash mismatch: '+name) manifest=json.loads((root/'checksums.json').read_text()) for name, expected in manifest['files'].items(): actual=hashlib.sha256((root/name).read_bytes()).hexdigest() if actual!=expected: raise SystemExit('Hash mismatch: '+name) provenance=root.parent/'provenance-v1' record=json.loads((provenance/'index.json').read_text()) for name, expected in record['files'].items(): if hashlib.sha256((provenance/name).read_bytes()).hexdigest()!=expected: raise SystemExit('Provenance hash mismatch: '+name) print('Verified',len(package['files']),'source files,',len(manifest['files']),'edition files and historical provenance') ''') # Record exactly which source revision was inspected without leaking paths. revision=subprocess.check_output(['git','rev-parse','HEAD'],cwd=ROOT,text=True).strip() (out/'PROVENANCE.json').write_text(json.dumps({'source_repository':'jtcm-io/monorepo','base_revision':revision, 'packaged_at':'2026-10-05','edition':'nichijo-v1','source_scope':'Explicit source allowlist; local additions for the October 5 open release.', 'missing':'Complete historical LLM inputs/outputs, private session bodies, unpreserved correction reports.', 'files':{p.relative_to(out).as_posix():hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted(out.rglob('*')) if p.is_file()}},indent=2)+'\n') print(f'Prepared {out}') if __name__=='__main__': parser=argparse.ArgumentParser();parser.add_argument('destination',type=Path) package(parser.parse_args().destination)