From 84c8ceb172afe90634a587afe499f69bb4743478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Sat, 1 Aug 2026 21:51:13 +0300 Subject: [PATCH] documentation: AI specs, data format docs, Russian README --- .ai-specs/DATA_MODEL_SPEC.md | 246 +++++++++ .ai-specs/ENRICHMENT_WORKFLOW.md | 257 ++++++++++ .ai-specs/PROJECT_CONTEXT.md | 124 +++++ .ai-specs/WORKING_POLICIES.md | 235 +++++++++ DATA_EN.md | 837 +++++++++++++++++++++++++++++++ DATA_RUS.md | 837 +++++++++++++++++++++++++++++++ README.md | 32 +- README_RUS.md | 101 ++++ 8 files changed, 2662 insertions(+), 7 deletions(-) create mode 100644 .ai-specs/DATA_MODEL_SPEC.md create mode 100644 .ai-specs/ENRICHMENT_WORKFLOW.md create mode 100644 .ai-specs/PROJECT_CONTEXT.md create mode 100644 .ai-specs/WORKING_POLICIES.md create mode 100644 DATA_EN.md create mode 100644 DATA_RUS.md create mode 100644 README_RUS.md diff --git a/.ai-specs/DATA_MODEL_SPEC.md b/.ai-specs/DATA_MODEL_SPEC.md new file mode 100644 index 0000000..33b5296 --- /dev/null +++ b/.ai-specs/DATA_MODEL_SPEC.md @@ -0,0 +1,246 @@ +# Data Model Specification + +## CId (Canonical Identifier) System + +### Format Rules + +CIds are identifiers for saints, feasts, and liturgical elements. They follow these routing rules: + +| CId Pattern | Target File | Examples | Notes | +|-------------|-------------|----------|-------| +| `01XX-01ZZ` | `01.json` | `010101`, `014567` | January saints | +| `02XX-02ZZ` | `02.json` | `023456`, `027890` | February saints | +| ... | ... | ... | ... | +| `12XX-12ZZ` | `12.json` | `123456`, `127890` | December saints | +| Other CIds | `misc.json` | `772426`, `373`, `868` | Non-month-prefixed | + +### Routing Logic +```typescript +function bundleFileForCid(cid: string): string { + return /^(0[1-9]|1[0-2])\d+/.test(cid) + ? `${cid.substring(0, 2)}.json` + : 'misc.json'; +} +``` + +## Menaion Bundle Structure + +### Format Definition +```json +{ + "MM-DD": [ + { "id": "CId" }, + { "id": "CId" } + ] +} +``` + +**Key Points**: +- Each date key: "MM-DD" format (Julian calendar) +- Array of objects with only "id" field +- CIds correspond to actual commemorations on that date +- One per language: `menaion-bundle.json`, `{lang}-menaion-bundle.json` + +### Example +```json +{ + "01-01": [ + { "id": "010101" }, + { "id": "772426" }, + { "id": "010102" } + ] +} +``` + +## Life Entry Structure + +### Format Definition +```json +{ + "CId": { + "name": { + "nominative": "Прп. Сильвестра Печерского (XII)", + "short": "Прп. Сильвестра Печерского", + "genitive": "Прп. Сильвестра Печерского" + }, + "life": { + "id": "minei-0101-772426", + "copyright": "Четьи-Минеи свт. Димитрия Ростовского", + "text": "

Complete life text in HTML...

" + } + } +} +``` + +### Required Fields +- **`CId`**: String key (the canonical identifier) +- **`name.nominative`**: Required field (validated by validate-data.ts) + +### Optional Fields +- **`name.short`**: Short name variant +- **`life.text`**: HTML content (only written when empty) +- **`life.id`**: Source identifier (e.g., "minei-0101-772426") +- **`life.copyright`**: Copyright string + +## Service Template Structure + +### Hierarchical JSON Format +```json +{ + "ROYALHOURS": { + "0": { + "text": "In the name of the Father...", + "type": "0" + } + }, + "MATINS": { + "kathisma": { + "text": "Kathisma content..." + } + } +} +``` + +### Conditional Logic Markers +- **P-prefix nodes**: Optional content that may be included +- **Var/I-prefix nodes**: Conditional selection logic +- **Plain nodes**: Required content always included + +## Chetyi-Minei Source Format + +### Format Definition +```json +{ + "MM-DD": [ + { + "title": "Память святого X", + "html": "

Content paragraphs...

" + } + ] +} +``` + +### Key Characteristics +- Generated by `convert-mines.ts` from EPUB source +- Stored in `scripts/output/minei.json` (gitignored, 33MB) +- Titles and HTML are carefully extracted and parsed +- Footnotes collected and appended as "Примечания:" blocks + +## File Organization Rules + +### Lives Files +- **Location**: `static/data/{lang}/lives/` +- **Files**: + - `01.json` through `12.json` (month-prefixed CIds) + - `misc.json` (non-month-prefixed CIds) +- **Routing**: Based on first two digits of CId + +### Menaion Files +- **Location**: `static/data/{lang}/menaion/` +- **Files**: `01-01.json` through `12-31.json` (daily entries) +- **Purpose**: Daily liturgical readings by date + +### Service Templates +- **Location**: `static/data/{lang}/services/` +- **Shared**: `static/data/shared/services/templates/` + +### Calendar Data +- **Location**: `static/data/{lang}/calendar/` and `static/data/shared/calendar/` +- **Purpose**: Movable feast calculations and metadata + +## Data Invariants + +### CId Consistency Rules +- Same CId must have consistent name across all languages +- Bundle CIds must have corresponding lives entries +- CIds that exist in bundle must have lives entries +- CIds with lives entries must exist in bundle for their date + +### File Organization Invariants +- No month file contains CIds with different month prefix +- `misc.json` contains all CIds outside the 01-12 prefix range +- All data files are tracked in `static/data/` + +### Content Validation Invariants +- All lives entries must have `name.nominative` field +- HTML content in `life.text` must be properly escaped +- JSON files must be parseable (no syntax errors) +- File routing must match CId prefixes consistently + +## Common Data Mistakes to Avoid + +### CId Pattern Errors +- ⚠️ Don't create CIds with invalid prefixes +- ⚠️ Don't put CIds in wrong month files +- ⚠️ Don't create duplicate CIds with different meanings + +### JSON Structure Errors +- ⚠️ Don't omit required fields (`name.nominative`) +- ⚠️ Don't nest structures incorrectly (service templates) +- ⚠️ Don't mix CId numbers and strings inconsistently +- ⚠️ Don't leave trailing commas in JSON + +### File Organization Mistakes +- ⚠️ Don't place month-prefixed CIds in misc.json +- ⚠️ Don't create inconsistent JSON indentation +- ⚠️ Don't mix languages in incorrect directories + +## Examples + +### Valid CId Examples +- `010101` → `01.json` (January saint) +- `1253` → `12.json` (December saint) +- `772426` → `misc.json` (non-prefixed saint) + +### Invalid CId Examples +- `00501` → Should not exist (prefix `00` → misc) +- `13xxx` → Should not exist (prefix `13` → misc) + +### File Routing Examples +- CId `1253` routes to `12.json` +- CId `772426` routes to `misc.json` +- CId `010101` routes to `01.json` + +### Bundle Entry Examples +```json +{ + "01-15": [ + { "id": "010201" }, + { "id": "772455" } + ] +} +``` + +### Life Entry Examples +```json +{ + "772426": { + "name": { + "nominative": "Прп. Сильвестра Печерского (XII)", + "short": "Прп. Сильвестра Печерского" + }, + "life": { + "id": "minei-0101-772426", + "copyright": "Четьи-Минеи свт. Димитрия Ростовского", + "text": "

Complete life content...

" + } + } +} +``` + +## Current Project State + +### Coverage Statistics +- Total CIds: 3046 +- Lives with text: 1190 (39% coverage) +- Empty lives: 1856 (61% remain) + +### Data Files +- Total validated files: 274 +- Main source files: 6 Lives bundle files (misc, 01-12) +- Service template files: Multiple per language + +### Recent Changes +- Bundle fix: 868 Иаков Боровицký moved from 05-22 to 10-23 +- Enrichment: 64 manual fixes added to enrich-lives.ts +- Coverage increase: 1009→1190 lives with text (191 new) \ No newline at end of file diff --git a/.ai-specs/ENRICHMENT_WORKFLOW.md b/.ai-specs/ENRICHMENT_WORKFLOW.md new file mode 100644 index 0000000..27d46d5 --- /dev/null +++ b/.ai-specs/ENRICHMENT_WORKFLOW.md @@ -0,0 +1,257 @@ +# Enrichment Workflow for AI Agents + +## Quick Start Guide + +Run enrichment in safe mode first: +```bash +# Dry run to see matches +npx tsx scripts/enrich-lives.ts + +# Write changes when confident +npx tsx scripts/enrich-lates.ts --write +``` + +## Common Enrichment Mistakes + +### Auto-Matching Pitfalls +- ⚠️ Don't ignore low scores when a clear match exists +- ⚠️ Don't skip review phase entirely — need to examine unmatched entries carefully +- ⚠️ Don't assume auto means "correct" — scores ≥0.6 can still be wrong-saint +- ⚠️ Don't overlook `already-filled` status — some matches hit CIds already filled + +### Manual Fixes Errors +- ⚠️ Don't create substrings that match multiple source titles on same date +- ⚠️ Don't use substrings with spaces that appear in multiple contexts +- ⚠️ Don't forget about OCR artifacts in source titles (Latin `a`, `[1]` markers) +- ⚠️ Don't mismatch case forms: account for case differences in substrings + +### Collision Issues +- ⚠️ Don't expect first chapter to have a heading (this is by design) +- ⚠️ Don't count chapters by counting `` tags alone (verify by checking content) +- ⚠️ Don't append to CIds that already have life.text without checking collision behavior +- ⚠️ Don't assume all multi-source CIds follow same pattern + +### Validation Skipping +- ⚠️ Don't skip `npx tsx scripts/validate-data.ts` — it catches real errors +- ⚠️ Don't skip `npx tsc --noEmit` — type errors indicate real problems +- ⚠️ Don't skip `npm run build` — build failures need investigation +- ⚠️ Don't assume "all files valid" without actually running it + +## Decision Points for AI Agents + +### When to Add MANUAL_FIXES +- When score is 0.35-0.6 and you can identify the correct target +- When source title contains distinctive substring not in other titles on same date +- When auto-matcher picks wrong saint (e.g., different homonym on same date) +- When target CId exists but is listed on wrong calendar date (bundle bug) +- When narrative maps to known CId but has empty life (can be enriched) + +### When to Leave Unmatched +- When source is a narrative or homily without saint association +- When no appropriate CId exists in the bundle for that saint +- When target CId already has life (no data improvement possible) +- When cross-date narratives have no clear target CId + +### When to Use `--month` Flag +- When working on enrichment for a specific period only +- When testing changes without affecting entire dataset +- When troubleshooting issues in a particular month + +## Quality Checkpoints + +### After Manual Fixes Addition +- Verify substring uniqueness per date (use verification script) +- Check that target CIds exist and are empty +- Re-run dry run to verify improvement +- Check for potential new conflicts with existing fixes + +### After Writing Changes +- Verify coverage increased appropriately +- Check that collision targets have correct chapter count +- Confirm only intended files were written +- Verify no unintended side effects on other files + +### Before Committing +- Run full validation: `npx tsx scripts/validate-data.ts` +- Type check: `npx tsc --noEmit` +- Build verify: `npm run build` +- Check git status to confirm intended files staged + +## Troubleshooting Common Issues + +### Unexpected Unmatched Entries +**Problem**: Good match exists but score < 0.35 +- **Solution**: Add MANUAL_FIX with distinctive substring +- **Check**: Verify target CId exists and is empty +- **Alternative**: Check if bundle has correct CIds on that date + +### No Auto Matches on Date +**Problem**: All entries on a date show unmatched +- **Solution**: Check menaion-bundle.json for correct CIds on that date +- **Alternative**: May be narrative without target CId → leave unmatched + +### Target Already Filled +**Problem**: Manual fix shows `already-filled` in report +- **Solution**: Fix targeting or remove fix (no data change) +- **Check**: Verify CId already has life.text (no improvement possible) + +### Wrong Match Applied +**Problem**: Good score applied to wrong CId +- **Solution**: Add MANUAL_FIX with more distinctive substring +- **Verify**: Check score distribution for potential collisions + +### Collision Issues +- ⚠️ **First chapter unheaded**: This is expected behavior by design +- ⚠️ **Expected behavior**: First source writes without heading, subsequent sources append +- **Check**: Verify total chapters match expected count for CId + +### Strange JSON Syntax Errors +- **Problem**: Parse errors in data files after modification +- **Solution**: Check JSON syntax, fix trailing commas, quote issues +- **Verify**: Run `validate-data.ts` to get specific error location + +### Build Size Changes +- **Problem**: Unexpected file size increases/decreases +- **Solution**: Check for malformed content, duplicate data, formatting changes +- **Check**: Compare before/after file sizes in git diff + +## Verification Commands + +### Coverage Tracking +```bash +# Check coverage statistics +python3 -c " +import json, glob, os +total=has=0 +for fp in glob.glob('static/data/ru/lives/*.json'): + data=json.load(open(fp)) + for cid,entry in data.items(): + total+=1 + if isinstance(entry.get('life'), dict) and entry.get('life',{}).get('text'): + has+=1 +print(f'Coverage: {has}/{total} ({has*100//total}%) lives with text') +" +``` + +### Collision Chapter Count Check +```bash +# Check collision targets have correct chapter counts +python3 -c " +import json, re +misc = json.load(open('static/data/ru/lives/misc.json')) +for cid in ['493', '1674', '257401']: # Known collision targets + text = misc[cid]['life']['text'] + headings = re.findall(r'([^<]+)', text) + print(f'{cid}: {len(headings)} chapters') +" +``` + +### Find Specific Pattern in Data +```bash +npx tsx scripts/tools/search-texts.ts "Захарии" --lang cu --type menaion +``` + +### Get Statistics by Language +```bash +npx tsx scripts/tools/stats.ts --lang ru +``` + +## Recent Context Updates + +### Known Fixed Issues +- 868 Иаков Боровицký moved from 05-22 to 10-23 (bundle mis-mapping correction) +- Сретение→373 added (02-02 Сказание about Presentation) +- Захарий Печерский→822 added (03-24 miracle story) +- Анна пророчица→2396 added (08-28 prophetess Anna) + +### Current Unmatched Floor +- 27 entries remain unmatched (all narratives/homilies or already-filled targets) +- These are at the floor for Chetyi-Minei source — no recoverable matches available + +## File Routing Quick Reference + +### Lives File Routing +- Files: `static/data/ru/lives/01.json` through `12.json` for month-prefixed CIds +- File: `misc.json` for non-month-prefixed CIds +- Route: `bundleFileForCid(cid: string):` checks `/^(0[1-9]|1[0-2])\d+/.test(cid)` + +### Bundle File Organization +- Main bundle: `static/data/cu/menaion-bundle.json` (authoritative calendar) +- Language overrides: `{lang}-menaion-bundle.json` +- Format: Date keys (MM-DD) with arrays of CId objects + +## Next Steps After Completing Enrichment + +### Quality Assurance +- Verify collision targets have correct chapter counts +- Check that file sizes are reasonable after writing +- Confirm coverage increased as expected + +### Documentation Updates +- Update DATA_FORMAT.md or DATA_RUS.md if schema changed +- Update coverage statistics in relevant documentation +- Add new manual fixes to enrichment documentation if needed + +### Commit Sequence +```bash +# 1. Validate, typecheck, build all passing +npx tsx scripts/validate-data.ts && npx tsc --noEmit && npm run build + +# 2. Stage all changes +git add scripts/enrich-lives.ts scripts/output/lives-match-report.json static/data/ru/lives/ + +# 3. Commit with description +git commit -m "enrich [N] more ru lives: [description]" +``` + +## Coverage Tracking + +### Current Status +- Total CIds: 3046 +- Lives with text: 1190 (enriched from Chetyi-Minei) +- Unmatched minei chapters: 27 (floor: narratives, no-target, already-filled) +- Files validated: 274 files (all passing) + +### Recent Enrichment Work +- Baseline: 1009 lives with text (from prior work) +- Latest commits added 181 lives (121 + 57 + 3) +- Manual fixes added: 214 total in enrich-lives.ts +- Bundle corrections applied: 868 date fix + +### Progress Tracking +- Review band: 127 entries resolved, 0 remaining +- Unmatched band: 94 → 30 → 27 (final floor) +- Coverage: 1009→1130→1190 lives (181 net increase) + +## Example Workflow for Adding Manual Fixes + +### Step 1: Identify Problematic Match +``` +Date: 03-24 +Source: "Воспоминание о чуде в Печерском monastery" → score 0.12 +Candidate: 722 (Прп. Евстратий Печерский, LIFE) - wrong saint +Target: 822 (Прп. Захарий Печерский, EMPTY) - correct saint +``` + +### Step 2: Create Fix +```typescript +'03-24|воспоминание о чуде': '822' +``` + +### Step 3: Verify Uniqueness +```bash +# Check if substring is unique on date 03-24 +python3 -c " +import json, re +m=json.load(open('scripts/output/minei.json')) +titles=[t['title'] for t in m['03-24']] +cnt=sum(1 for t in titles if 'воспоминание о чуде' in re.sub(r'\s+',' ',t['title']).lower()) +print(f'Count: {cnt}') +" +``` + +### Step 4: Apply and Verify +```bash +npx tsx scripts/enrich-lives.ts # Check new counts +npx tsx scripts/validate-data.ts # Validate all files +``` \ No newline at end of file diff --git a/.ai-specs/PROJECT_CONTEXT.md b/.ai-specs/PROJECT_CONTEXT.md new file mode 100644 index 0000000..07f4b42 --- /dev/null +++ b/.ai-specs/PROJECT_CONTEXT.md @@ -0,0 +1,124 @@ +# Project Context for AI Agents + +## Quick Project Overview + +**Ponomar** is a Progressive Web App for Orthodox Church calendar, liturgical services, and Bible readings. + +- **Technology**: TypeScript + Vite + Tailwind CSS v4 +- **Data**: JSON-based liturgical data organized by language (en, cu, el, fr, zh, ru) +- **Architecture**: Client-side PWA with static JSON data, no backend database +- **Core Functionality**: Calendar display, service assembly, Bible reading, saint lives + +## Key Architectural Patterns + +### Data Organization +- **Language-based structure**: `static/data/{lang}/` (en, cu, el, fr, zh, ru) +- **Bundle system**: menaion-bundles, lives bundles, service templates +- **File routing**: CIds with `01`-`12` prefix → month files, else `misc.json` + +### Core Scripts +- `convert-all.ts` — Master conversion script +- `enrich-lives.ts` — Fuzzy matching and enrichment pipeline +- `validate-data.ts` — Main validator (checks 274 files) +- `convert-minei.ts` — Chetyi-Minei EPUB to JSON conversion +- `migrate-data.ts` — Data normalization + +## Recent Work Context + +### Completed Enrichment +- **Chetyi-Minei import**: 1154 chapters processed, 1190/3046 lives enriched +- **Manual fixes**: 214 manual corrections in `enrich-lives.ts` +- **Bundle fixes**: 868 Иаков Боровицký corrected from 05-22 to 10-23 +- **Coverage**: 39% of lives have texts (source from Chetyi-Minei) + +### Validation Status +- All data files validated: 274 files checked +- TypeScript compiles cleanly +- Build succeeds without errors + +## Critical Invariants + +- **Never overwrite existing `life.text`** — enrichment only fills empty entries +- **File routing is strict**: CId prefix determines file location +- **Bundle CIds must exist**: Menaion CIds require corresponding lives entries +- **Static data is tracked**: `static/data/` in git (except `scripts/output/minei.json`) +- **Validation must pass**: Changes must pass `validate-data.ts`, `tsc --noEemit`, `npm run build` + +## Key Script Quick Reference + +```bash +# Development +npm run dev # Start dev server +npm run build # Production build + +# Data operations +npm run convert # Convert XML to JSON +npm run migrate # Normalize data format + +# Validation +npx tsx scripts/validate-data.ts # Main validator +npx tsc --noEmit # Type checking +npm run build # Build verification + +# Enrichment +npx tsx scripts/enrich-lives.ts # Dry run enrichment +npx tsx scripts/enrich-lives.ts --write # Apply enrichment +``` + +## File Structure Highlights + +``` +src/ +├── core/ # Domain logic (calendar, paschalion, service assembly) +├── ui/ # View components +└── main.ts # Entry point + +scripts/ +├── convert-*.ts # XML→JSON conversion pipeline +├── validate-*.ts # Comprehensive validation suite +└── enrich-lives.ts # Enrichment with manual fixes + +static/data/ +├── cu/ # Church Slavonic (authoritative calendar) +├── ru/ # Russian (enriched lives) +├── en/ # English +└── shared/ # Cross-language resources +``` + +## Important Notes + +### Pipeline Dependencies +- **Chetyi-Minei source**: EPUB conversion requires `convert-minei.ts` +- **Enrichment workflow**: Requires minei.json output + menaion-bundle.json +- **Validation chain**: Each commit must pass validation → typecheck → build + +### File System Constraints +- `scripts/output/minei.json` is gitignored (33MB source file) +- `static/data/` is fully tracked in git +- Lives files are written by month (01.json-12.json) or misc.json + +## Common Tools Reference + +- **Search**: `npx tsx scripts/tools/search-texts.ts ` +- **Stats**: `npx tsx scripts/tools/stats.ts [--lang en]` +- **Validate**: `npx tsx scripts/validate-data.ts` + +## Documentation Reference + +- **DATA_FORMAT.md** — Detailed technical specifications (English) +- **DATA_RUS.md** — Complete documentation in Russian +- **README.md** — Project overview and getting started + +## Working Reminders + +- Always run validation before committing data changes +- Check coverage statistics when working with enrichment +- Test builds after any modifications to static data +- Review the match report after dry runs + +## Current State + +- Total CIds: 3046 +- Lives with text: 1190 (enriched from Chetyi-Minei) +- Unmatched minei chapters: 27 (floor: narratives, no-target, already-filled) +- Latest enrichment commits: `ec3f593` (3 more lives), `08950cd` (57 more lives), `381a494` (121 more lives), `7dde216` (baseline enrichment) \ No newline at end of file diff --git a/.ai-specs/WORKING_POLICIES.md b/.ai-specs/WORKING_POLICIES.md new file mode 100644 index 0000000..6b8104b --- /dev/null +++ b/.ai-specs/WORKING_POLICIES.md @@ -0,0 +1,235 @@ +# Working Policies for AI Agents + +## Data Modification Rules + +### Never Overwrite Existing Content +- **CRITICAL**: Never overwrite existing `life.text` fields in lives entries +- Enrichment pipeline only fills empty entries +- If a target already has content, classify as `already-filled` and skip + +### File Modification Permissions +- **Allowed**: Adding new life.text to empty entries +- **Allowed**: Adding manual fixes to `enrich-lives.ts` MANUAl_FIXES +- **Allowed**: Correcting menaion-bundle.json for CId date corrections +- **Forbidden**: Modifying existing life.text content +- **Forbidden**: Deleting or renaming CIds without proper validation +- **Forbidden**: Changing JSON structure without updating related code + +## Validation Requirements + +### Pre-Commit Checklist +All changes must pass all three checks: + +```bash +# 1. Data validation +npx tsx scripts/validate-data.ts +# Expected: "All files valid!" or specific error count + +# 2. Type safety +npx tsc --noEmit +# Expected: No TypeScript errors + +# 3. Build verification +npm run build +# Expected: Successful build with reasonable bundle sizes +``` + +### When to Stop +- Stop immediately if any validation fails +- Fix errors before proceeding +- Address TypeScript compilation issues +- Check build output for unexpected size changes + +## Commit Message Standards + +### Format Conventions + +**Enrichment commits**: +``` +enrich [N] more ru lives: [brief description] +``` + +**Bundle fix commits**: +``` +fix bundle: move [saint] from [date1] to [date2] +``` + +**Script updates**: +``` +update [script name]: [brief description] +``` + +**General guidance**: +- Be specific about what changed +- Reference specific CIds or dates when applicable +- Keep messages concise but descriptive +- Reference recent commits for style + +## File Change Guidelines + +### Static Data Files +- **Tracked**: `static/data/` directory (all JSON files tracked) +- **Not tracked**: `scripts/output/minei.json` (33MB generated file) +- **Validate**: Always run validation after data changes + +### Script Files +- Maintain existing code patterns +- Use existing helper functions when available +- Update documentation in relevant markdown files + +### Output Files +- Generated files (`dist/`, `scripts/output/`) should not be committed +- Only commit source code and data files + +## Code Quality Standards + +### TypeScript Requirements +- Maintain strict typing +- Follow existing code conventions +- Add type annotations where appropriate +- Use proper error handling + +### Data Structure Integrity +- Maintain CId naming conventions +- Preserve JSON structure consistency +- Ensure required fields are present (`name.nominative` in lives entries) + +## Error Handling Protocols + +### When Validation Fails +1. Review error messages carefully +2. Identify root cause (JSON syntax, missing fields, type issues) +3. Fix the underlying problem +4. Re-run validation until it passes +5. Then proceed to type checking + +### When TypeScript Fails +1. Check for type mismatches in modified code +2. Verify imports and exports +3. Ensure all dependencies are properly declared +4. Fix type errors +5. Re-run tsc --noEmit + +### When Build Fails +1. Check console output for specific errors +2. Verify data file integrity +3. Check for import/export issues +4. Resolve build errors before proceeding + +## Documentation Requirements + +### When Modifying Data Schemas +- Update relevant documentation files (DATA_FORMAT.md, DATA_RUS.md) +- Note any breaking changes or invariants +- Update project README if structural changes + +### When Adding New Scripts +- Document the script's purpose and usage +- Add NPM script entry if needed +- Update project documentation as appropriate + +## Common Operational Pitfalls + +### Data Modification Risks +- ⚠️ **Don't accidentally overwrite existing life.text** — Always check before writing +- ⚠️ **Don't skip validation** — Always validate before committing +- ⚠️ **Don't ignore build errors** — Build failures indicate real problems +- ⚠️ **Don't commit generated files** — Avoid committing dist/ or output files + +### Code Change Risks +- ⚠️ **Don't break existing patterns** — Follow established code conventions +- ⚠️ **Don't duplicate logic** — Use existing helper functions +- ⚠️ **Don't ignore type safety** — Maintain TypeScript strict typing +- ⚠️ **Don't make undocumented changes** — Update relevant documentation + +### Commit Risks +- ⚠️ **Don't commit without validation** — Ensure all checks pass +- ⚠️ **Don't write vague commit messages** — Be specific about what changed +- ⚠️ **Don't assume `static/data/` is excluded** — It's tracked, commit your changes + +## Workflow for New Enrichment Work + +### Before Starting +1. Review existing MANUAL_FIXES in `enrich-lives.ts` +2. Understand the current coverage status +3. Identify which dates/cases you're targeting + +### During Work +1. Use dry runs first: `npx tsx scripts/enrich-lives.ts` +2. Review the match report carefully +3. Add MANUAL_FIXES only for problematic matches +4. Re-run dry run until satisfied with results +5. Only use `--write` when confident + +### After Completion +1. Verify file sizes are reasonable +2. Check that collision appends are correct +3. Run full validation suite +4. Commit with descriptive message + +## Quality Assurance Standards + +### Coverage Tracking +- Monitor coverage statistics: `1190/3046 lives with text` +- Track unmatched count: currently 27 (floor for this data source) +- Report changes in coverage when adding MANUAL_FIXES + +### Content Verification +- For collision targets, verify chapter counts +- Check that first chapter being unheaded is expected behavior +- Verify that life.text contains expected content for known CIds + +### Consistency Checks +- Ensure similar fixes follow the same pattern +- Maintain consistency with existing MANUAL_FIXES format +- Keep naming conventions consistent across all entries + +## Quick Reference for Common Operations + +### Adding a MANUAL_FIX +```typescript +const MANUAL_FIXES: Record = { + 'MM-DD|distinctive-substring': 'CId', +}; +``` +- Key format: `${date}|${substring}` → CId +- Substring must be unique within that date +- CId must be empty for the fix to have effect + +### Running Enrichment +```bash +# Dry run +npx tsx scripts/enrich-lives.ts + +# Write changes +npx tsx scripts/enrich-lives.ts --write + +# Single month +npx tsx scripts/enrich-lives.ts --month 01 +npx tsx scripts/enrich-lives.ts --write --month 01 +``` + +### Validating Data +```bash +# Main validator +npx tsx scripts/validate-data.ts + +# Period-specific validators +npx tsx scripts/validate-menaion.ts +npx tsx scripts/validate-triodion.ts +``` + +### Quick Coverage Check +```bash +python3 -c " +import json,glob,os +total=has=0 +for fp in glob.glob('static/data/ru/lives/*.json'): + data=json.load(open(fp)) + for cid,entry in data.items(): + total+=1 + if isinstance(entry.get('life'),dict) and entry.get('life',{}).get('text'): + has+=1 +print(f'Coverage: {has}/{total} ({has*100//total}%) lives with text') +" +``` \ No newline at end of file diff --git a/DATA_EN.md b/DATA_EN.md new file mode 100644 index 0000000..adec06b --- /dev/null +++ b/DATA_EN.md @@ -0,0 +1,837 @@ +# Static Data Format Documentation + +## Table of Contents +1. [Static Data Format Overview](#static-data-format-overview) +2. [Directory Structure & Organization](#directory-structure--organization) +3. [Data Models & Schemas](#data-models--schemas) +4. [File Routing Rules](#file-routing-rules) +5. [Data Components Breakdown](#data-components-breakdown) +6. [Data Management Tools](#data-management-tools) +7. [Enrichment Process](#enrichment-process) +8. [Quality Assurance Workflow](#quality-assurance-workflow) +9. [Common Issues & Solutions](#common-issues--solutions) +10. [Quick Reference](#quick-reference) + +--- + +## Static Data Format Overview + +The Ponomar PWA uses a JSON-based static data system organized by language. All liturgical data is pre-converted from XML sources and structured for efficient serving and client-side rendering. + +### Core Principles +- **Language-based organization**: Each language has its own directory under `static/data/` +- **JSON storage**: All data stored as JSON files for easy parsing +- **Date-based routing**: Calendar data organized by Julian calendar dates (MM-DD format) +- **CId-based identification**: Canonical Identifiers (CIds) uniquely identify saints and feasts +- **Prefix-based file routing**: Lives files routed by CId prefix (01-12 → month files) + +### Supported Languages +- `en` — English +- `cu` — Church Slavonic +- `ru` — Russian +- `el` — Greek (includes `el/mono` for monochord) +- `fr` — French +- `zh` — Chinese (includes `zh/Hans` and `zh/Hant` for Simplified/Traditional) +- `shared` — Cross-language resources + +--- + +## Directory Structure & Organization + +``` +static/data/ +├── en/ +│ ├── menaion-bundle.json # Date → CId mapping (authoritative) +│ ├── en-menaion-bundle.json # Language-specific overrides +│ ├── lives/ # Saint lives by month +│ │ ├── 01.json through 12.json # Month-prefixed CIds (01XX-12XX) +│ │ └── misc.json # Non-month-prefixed CIds +│ ├── menaion/ # Daily menaion entries (366 days) +│ ├── calendar/ # Calendar metadata +│ └── services/ # Service templates +├── cu/ # Church Slavonic (similar structure) +├── ru/ # Russian (lives, services) +├── el/ # Greek (includes mono/) +├── fr/ # French +├── zh/ # Chinese (includes Hans/, Hant/) +└── shared/ # Cross-language resources + ├── calendar/ # Movable feast calendar + ├── services/ # Shared service templates + └── lives-index.json # CId → scripture lookup index +``` + +### File Types +- `*-bundle.json` — Calendar mapping files +- `lives/*.json` — Saint lives bundles +- `menaion/*.json` — Daily liturgical entries +- `services/*.json` — Service templates and logic +- `calendar/*.json` — Calendar calculations and metadata + +--- + +## Data Models & Schemas + +### Bundle Entry (menaion-bundle.json) +```json +{ + "01-01": [ + { "id": "010101" }, + { "id": "772426" }, + { "id": "010102" } + ] +} +``` +**Structure**: Object keyed by date `MM-DD` with array of entries, each containing only `"id"` field with CId value. + +### Life Entry (lives/*.json) +```json +{ + "772426": { + "name": { + "nominative": "Прп. Сильвестра Печерского (XII)", + "short": "Прп. Сильвестра Печерского" + }, + "life": { + "id": "minei-0101-772426", + "copyright": "Четьи-Минеи свт. Димитрия Ростовского", + "text": "

Преподобный отец наш Сильвестр...

" + } + } +} +``` +**Structure**: Object keyed by CId (string), each containing: +- `name` object with case variants (`nominative`, `short`, `genitive`, etc.) +- `life` object (optional) with `id`, `copyright`, and `text` fields + +### Calendar Entry +```json +{ + "pascha": { "year": 2025, "date": "04-20" }, + "fixed": [ + { "date": "01-01", "rank": 5, "celebration": "Circumcision" } + ] +} +``` +**Structure**: Contains movable feast calculations and fixed calendar data. + +### Service Template Entry +```json +{ + "ROYALHOURS": { + "0": { + "text": "In the name of the Father...", + "type": "0" + } + } +} +``` +**Structure**: Hierarchical service structure with text nodes and conditional logic. + +--- + +## File Routing Rules + +### Lives File Routing +Lives bundles are routed based on CId prefix: + +| CId Pattern | Target File | Examples | +|-------------|--------------|----------| +| `01XX-01ZZ` | `01.json` | `010101`, `014567` | +| `02XX-02ZZ` | `02.json` | `023456`, `027890` | +| ... | ... | ... | +| `12XX-12ZZ` | `12.json` | `123456`, `127890` | +| Other CIds | `misc.json` | `772426`, `373`, `2396` | + +**Examples:** +- `010101` → `01.json` +- `1253` → `12.json` +- `772426` → `misc.json` +- `373` → `misc.json` + +### Bundle File Naming +- Main bundle: `menaion-bundle.json` (per language) +- Language overrides: `{lang}-menaion-bundle.json` +- No prefix-based routing for bundles (single file per language) + +--- + +## Data Components Breakdown + +### Menaion Bundles +**Purpose**: Authoritative date → CId mapping for calendar rendering + +**Structure**: Date-keyed JSON with arrays of CIds +```json +{ + "01-01": [{ "id": "010101" }, { "id": "772426" }], + "01-02": [{ "id": "010201" }, { "id": "772455" }] +} +``` + +**Coverage**: 366 Julian calendar days × multiple entries per day +**File Size**: ~50-100KB per language +**Usage**: Calendar view determines which saints to display on each day + +### Lives Bundles +**Purpose**: Saint biographies and lives for enrichment + +**Structure**: CId-keyed JSON with name variants and optional life text +```json +{ + "772426": { + "name": { + "nominative": "Прп. Сильвестра Печерского (XII)", + "short": "Прп. Сильвестра Печерского" + }, + "life": { + "id": "minei-0101-772426", + "copyright": "Четьи-Минеи свт. Димитрия Ростовского", + "text": "

Complete life text in HTML...

" + } + } +} +``` + +**Coverage**: 3046 total CIds, 1190 with life.text enriched +**Routing**: Prefix-based (01.json-12.json + misc.json) +**Usage**: Lives display on saint detail pages + +### Calendar Data +**Purpose**: Movable feast calculations and calendar metadata + +**Components**: +- `shared/calendar/triodion.json` — Pre-Lent through Holy Week +- `shared/calendar/pentecostarion.json` — Pascha through All Saints +- `{lang}/calendar/` — Language-specific calendar data + +**Key Features**: +- Paschalion calculations +- Movable feast dating +- Fasting period definitions +- Holiday and commemoration metadata + +### Service Templates +**Purpose**: Structured liturgical service data with conditional logic + +**Organization**: +``` +services/ +├── octoecheos/ # Eight tones × days +├── triodion/ # 37 Lenten sections +├── pentecostarion/ # 50 Paschal days +├── menaion/ # 366 daily entries + 34 feasts +├── canons/ # Paraclete, Octoechos, Great Canon +└── shared/templates/ # Reusable service components +``` + +**Structure**: Hierarchical JSON with text nodes and conditional prefixes +- **P-prefix nodes**: Optional content that may be included +- **Var/I-prefix nodes**: Conditional selection logic +- **Plain nodes**: Required content always included + +### Bible Metadata +**Purpose**: Bible version mappings and reading pericopes + +**Structure**: Version identifiers and pericope mappings across 13 Bible versions +- Church Slavonic +- Russian Synodal +- KJV +- Brenton (Septuagint) +- Vulgate +- Other versions + +### Prayer Rules & Commands +**Purpose**: Daily cycle structures and prayer rule definitions + +**Components**: +- **Prayer Rules**: Daily reading schedules +- **Commands**: Service command structures +- **Horologion**: Hours, Kathismata, Compline, etc. + +### Fasting Rules +**Purpose**: Period definitions and fasting exceptions + +**Structure**: JSON with fasting periods, exceptions, and detailed rules +- Pre-Lent periods +- Great Lent +- Fast-free periods +- Fish/strict fasting days + +--- + +## Data Management Tools + +### Conversion Pipeline (`scripts/convert-*.ts`) + +#### Master Script +**`convert-all.ts`** — Orchestrates all conversion steps +```bash +npm run convert +``` + +Converts XML data from Java Ponomar sources to JSON format. + +#### Individual Converters + +**`convert-lives.ts`** — Saint lives XML → JSON conversion +- Input: `ponomar/Ponomar/languages/{lang}/xml/lives/*.xml` +- Output: `{lang}/lives/{01.json|misc.json}` bundles +- Features: + - XML parsing with attribute extraction + - Name case normalization + - Grammar data extraction + - Service data extraction + - Scripture reference extraction + - Bundle generation by month prefix + +**`convert-calendar.ts`** — Calendar metadata conversion +- Input: XML calendar data +- Output: JSON calendar structures +- Features: + - Movable feast calculations + - Fixed feast mappings + - Period definitions + +**`convert-services.ts`** — Service template conversion +- Input: XML service definitions +- Output: JSON service templates +- Features: + - Hierarchical structure preservation + - Conditional logic extraction + - Text node normalization + +**`convert-bible-meta.ts`** — Bible metadata extraction +- Input: XML bible metadata +- Output: JSON version mappings and pericopes + +**`convert-fasting.ts`** — Fasting rules conversion +- Input: XML fasting definitions +- Output: JSON fasting rules and periods + +**`convert-commands.ts`** — Command structure conversion +- Input: XML command definitions +- Output: JSON command structures + +**`convert-service-rules.ts`** — Service rule extraction +- Input: XML service rule definitions +- Output: JSON service rules + +### Migration Tools (`scripts/migrate-data.ts`) + +**Purpose**: Normalize data format across versions and languages + +**Operations:** +1. Strip `@_` prefixes from lives name keys (all languages) +2. Remove `SId` from menaion entries (keep id = CId) (all languages) +3. Rename service directories to lowercase (cu, el, fr, zh/Hans, zh/Hant, ru) +4. Flatten Octoecheos structure (cu, fr, zh/Hans, zh/Hant) +5. Convert `TEXT` → `text` in command files +6. Move shared services into `templates/` subdirectory +7. Normalize name key casing (Nominative → nominative, Short → short) +8. Migrate merged calendar files (triodion.json, pentecostarion.json) + +**Usage:** +```bash +npm run migrate # Apply migrations +npm run migrate:dry # Preview changes +``` + +### Validation Suite (`scripts/validate-*.ts`) + +#### Main Validator +**`validate-data.ts`** — Comprehensive data validation +```bash +npx tsx scripts/validate-data.ts +``` +**Validates:** +- Life entry structure (required fields) +- Lives bundle format (CId keys, name objects) +- Calendar data integrity +- Service template structure +- Prayer format compliance +- Command node structure +- Commemoration entries +- Fasting rule definitions + +**Output:** File count, errors, warnings + +#### Specialized Validators +**`validate-i18n.ts`** — Internationalization completeness +```bash +npx tsx scripts/validate-i18n.ts +``` +Checks coverage across languages (en/ru/cu). + +**`validate-tabs.ts`** — Service tab/template consistency +```bash +npx tsx scripts/validate-tabs.ts +``` +Validates that service tabs match template structures. + +**`validate-menaion.ts`** — Menaion data validation +```bash +npx tsx scripts/validate-menaion.ts +``` +Validates menaion entries against calendar rules. + +**`validate-prayer-rule.ts`** — Prayer rule structure validation +```bash +npx tsx scripts/validate-prayer-rule.ts +``` +Validates prayer rule format and completeness. + +**Period-specific Validators:** +- `validate-triodion.ts` — Triodion period validation +- `validate-pentecostarion.ts` — Pentecostarion validation +- `validate-holy-week.ts` — Holy Week validation +- `validate-great-canon.ts` — Great Canon validation +- `validate-great-compline.ts` — Great Compline validation +- `validate-libcs.ts` — Library content validation + +### Utility Tools (`scripts/tools/`) + +**`search-texts.ts`** — Full-text search across data files +```bash +npx tsx scripts/tools/search-texts.ts [--lang en] [--type prayers] +``` + +**`stats.ts`** — Data statistics and size analysis +```bash +npx tsx scripts/tools/stats.ts [--lang en] +``` + +Provides file counts, sizes, and category breakdowns. + +--- + +## Enrichment Process + +### Overview +The enrichment process fills empty `life.text` fields in ru/lives bundles using Chetyi-Minei (St. Dimitri of Rostov) hagiographic texts. + +### Source Preparation: Chetyi-Minei Import + +**`convert-minei.ts`** — Converts Chetyi-Minei EPUB to date-keyed JSON + +**Input Layout (extracted EPUB):** +``` +extracted-epub/ +├── index_split_000.xhtml through index_split_9999.xhtml +├── toc.ncx +└── content.opf +``` + +**Process:** +1. Parse day files sequentially +2. Extract headings: `h2` for dates (`"Память 1 января"`), `h3` for chapter titles +3. Extract paragraphs: `

` for content +4. Collect footnotes from `` anchors +5. Append notes as "Примечания:" block +6. Apply heading date corrections (e.g., `calibre_toc_10023` → `01-27`) +7. Build output structure: `{ "MM-DD": [{ title, html }] }` + +**Usage:** +```bash +npx tsx scripts/convert-minei.ts [output.json] +``` + +**Output:** `scripts/output/minei.json` (gitignored, ~33MB) + +### Enrichment Pipeline + +**`enrich-lives.ts`** — Fuzzy-matches minei titles to CId names and fills empty lives + +**Inputs:** +- `scripts/output/minei.json` — Source lives by date (MM-DD) +- `static/data/cu/menaion-bundle.json` — Authoritative date→CId map +- `static/data/ru/lives/*.json` — Target bundles for enrichment + +**Matching Strategy:** +1. **Tokenization**: Split titles into tokens, filter ROLE_WORDS +2. **Dice Coefficient**: Calculate similarity over token sets +3. **Status Classification**: + - `already-filled` — Target already has `life.text` → skip + - `auto` — Score ≥ 0.6, empty target → write + - `review` — Score 0.35–0.6 → manual review + - `unmatched` — Score < 0.35 or no candidates → unmatched + +**Manual Overrides:** +```typescript +const MANUAL_FIXES: Record = { + '02-02|сказание о сретении': '373', + '03-24|воспоминание о чуде': '822', + // 214 entries total +} +``` +Key format: `{date}|{distinctive substring}` → CId + +**Collision Handling:** Multiple sources map to same CId +- First source: writes `life.html` directly (no heading) +- Subsequent sources: append `

{title}

{html}` + +**File Routing:** +```typescript +function bundleFileForCid(cid: string): string { + return /^(0[1-9]|1[0-2])\d+/.test(cid) + ? `${cid.substring(0, 2)}.json` + : 'misc.json'; +} +``` + +**Usage:** +```bash +# Dry run: report only +npx tsx scripts/enrich-lives.ts + +# Limit to one month +npx tsx scripts/enrich-lives.ts --month 01 + +# Apply changes +npx tsx scripts/enrich-lives.ts --write + +# Apply changes for specific month +npx tsx scripts/enrich-lives.ts --write --month 01 +``` + +**Output:** `scripts/output/lives-match-report.json` with match status per source + +### Workflow Example + +**Phase 1: Source Preparation** +```bash +npx tsx scripts/convert-minei.ts ~/Downloads/chetyi-minei-epub/ +# Output: scripts/output/minei.json +``` + +**Phase 2: Dry Run Analysis** +```bash +npx tsx scripts/enrich-lives.ts +# Shows: Auto-applied: 184, needs review: 127, unmatched: 94 +# Review: scripts/output/lives-match-report.json +``` + +**Phase 3: Manual Review & Fixes** +- Analyze `review` entries in report +- Add MANUAL_FIXES for problematic matches +- Re-run until `review` count acceptable + +**Phase 4: Write & Validate** +```bash +npx tsx scripts/enrich-lives.ts --write +# Shows: Wrote 7 updated bundle(s) +npx tsx scripts/validate-data.ts +npx tsc --noEmit +npm run build +``` + +**Phase 5: Commit** +```bash +git add scripts/enrich-lives.ts scripts/output/lives-match-report.json static/data/ru/lives/ +git commit -m "enrich 121 more ru lives with Chetyi-Minei texts" +``` + +### Quality Controls + +**Collision Verification:** Check multi-chapter entries have correct headings +```bash +python3 -c " +import json, re +misc = json.load(open('static/data/ru/lives/misc.json')) +for cid in ['493', '1674', '257401']: # Known collision targets + text = misc[cid]['life']['text'] + headings = re.findall(r'([^<]+)', text) + print(f'{cid}: {len(headings)} chapters - {headings}') +" +``` + +**Coverage Tracking:** Monitor enrichment progress +```bash +python3 -c " +import json, glob, os +total = has = 0 +for fp in glob.glob('static/data/ru/lives/*.json'): + data = json.load(open(fp)) + for cid, entry in data.items(): + total += 1 + if isinstance(entry.get('life'), dict) and entry.get('life', {}).get('text'): + has += 1 +print(f'Coverage: {has}/{total} ({has*100//total}%) lives with text') +" +``` + +--- + +## Quality Assurance Workflow + +### Pre-Commit Checklist + +1. **Data Validation** +```bash +npx tsx scripts/validate-data.ts +# Expected: "All files valid!" or specific error count +``` + +2. **Type Safety** +```bash +npm run check # or npx tsc --noEmit +# Expected: No TypeScript errors +``` + +3. **Build Verification** +```bash +npm run build +# Expected: Successful build with bundle sizes +``` + +4. **Functional Testing** +```bash +npm run dev +# Manual test: Calendar view, saint detail pages, lives display +``` + +### Continuous Monitoring + +**Automated Checks:** +- File count validation (should be 274 files) +- JSON parseability (all data files) +- Required field presence (nominative, life.text for enriched entries) +- CId consistency (same CId should have same name across languages) + +**Issue Detection:** +- Corrupted JSON files → parse errors in validate-data.ts +- Missing required fields → validation warnings +- Type mismatches → TypeScript errors +- Build failures → invalid data structures + +### Issue Resolution + +**Common Validation Errors:** +1. **"Missing nominative"** — Name object lacks nominative case + - **Solution**: Add `name.nominative` field to affected entries + +2. **"Failed to parse"** — Corrupted JSON file + - **Solution**: Re-run conversion or fix JSON syntax + +3. **"Rank should be 0-8"** — Invalid rank value + - **Solution**: Normalize rank to range 0-8 + +4. **Build bundle size changes** — Unexpected file size increases + - **Solution**: Check for duplicate or malformed content + +--- + +## Common Issues & Solutions + +### OCR Artifacts in Minei Texts + +**Problem:** Chetyi-Minei conversion produces OCR issues like: +- Latin characters in Russian text (`Taиcии` instead of `Таисии`) +- Footnote markers `[1]` in body text +- Erratic punctuation `[1]` in titles + +**Solution:** +- Keep OCR artifacts as-is (part of source text) +- Manual fixes use exact OCR substrings for matching +- Examples: `'02-15|onissima, odnogo iz lika'` → `'450'` + +### Homonym Resolution on Same Date + +**Problem:** Multiple saints share similar names on same date + +**Examples:** +- 03-24: Иаков исповедник (68501) vs other Иаков entries +- 02-22: Варадат vs Фалассий (both map to 493) +- 09-03: Анфим, Аристион, Василиса on same date + +**Solution:** +- Use distinctive substrings in MANUAL_FIXES +- Ensure uniqueness per date (verify with verification script) +- For collisions: both sources map to same CId (append behavior) + +### Cross-Date Narratives + +**Problem:** Some minei chapters are narratives not tied to a specific feast + +**Examples:** +- 02-02: "Сказание о Сретении Господнем" (presentation narrative) +- 03-24: "Воспоминание о чуде в Печерском монастыре" (miracle story) +- 08-28: "Память святой праведной Анны" (prophetess Anna) + +**Solution:** +- Identify appropriate CId for the saint/event +- Map with MANUAL_FIXES even if not on same date (though current pipeline is date-based) +- For entries with no appropriate CId: remain unmatched + +### Bundle Mis-Mappings + +**Problem:** Some CIds are listed on wrong calendar dates + +**Example:** +- 868 Иаков Боровицкий listed under 05-22, actual feast 10-23 + +**Solution:** +- Manually correct menaion-bundle.json +- Move CIds from incorrect date to correct date +- Verify with calendar sources and tradition + +### File Routing Edge Cases + +**Problem:** Ambiguous routing for CIds at boundaries + +**Edge Cases:** +- `00` prefixes → misc.json (not 00.json) +- `99` prefixes → misc.json (not 09.json) +- Non-numeric CIds → misc.json + +**Solution:** +```typescript +/^(0[1-9]|1[0-2])\d+/.test(cid) // Match only 01-12 followed by digits +``` + +### Multi-Chapter Collision Display + +**Problem:** When multiple sources append to same CId, first chapter lacks heading + +**Behavior:** +- First source: writes `life.html` directly (no title) +- Subsequent sources: append `

{title}

{html}` +- Result: First chapter unheaded, others clearly marked + +**Acceptable Trade-off:** Consistent with all single-chapter lives (which have no heading) + +--- + +## Quick Reference + +### NPM Scripts Summary + +```bash +# Development +npm run dev # Start development server +npm run build # Production build +npm run preview # Preview production build + +# Data Conversion +npm run convert # Convert all XML sources to JSON +npm run migrate # Normalize to current format +npm run migrate:dry # Preview migration changes + +# Validation +npm run check # Type check (tsc --noEmit) +npx tsx scripts/validate-data.ts # Main validator +npx tsx scripts/validate-i18n.ts # i18n completeness +npx tsx scripts/validate-tabs.ts # Service consistency + +# Tools +npx tsx scripts/tools/search-texts.ts # Search data files +npx tsx scripts/tools/stats.ts # Data statistics + +# Enrichment +npx tsx scripts/convert-minei.ts # Import Chetyi-Minei +npx tsx scripts/enrich-lives.ts # Dry run enrichment +npx tsx scripts/enrich-lives.ts --write # Apply enrichment +``` + +### File Extensions + +| Extension | Purpose | Format | +|-----------|---------|--------| +| `.json` | All static data files | JSON | +| `.text` | Plain text resources | Plain text | +| `.xml` | Source data (not in repo) | XML | + +### Git Strategy + +**Tracked:** `static/data/` (except output files) +**Ignored:** +- `scripts/output/minei.json` (33MB, generated) +- `node_modules/` +- `dist/` + +### Important File Paths + +```bash +# Data directories +static/data/cu/menaion-bundle.json # Calendar authority +static/data/ru/lives/ # Target for enrichment +static/data/shared/services/ # Shared service templates + +# Scripts +scripts/enrich-lives.ts # Enrichment pipeline +scripts/convert-minei.ts # Minei import +scripts/validate-data.ts # Main validator + +# Output files +scripts/output/minei.json # Minei source (gitignored) +scripts/output/lives-match-report.json # Match report +``` + +### Coverage Statistics + +**Current Status:** +- Total CIds: 3046 +- Lives with text: 1190 (39%) +- Empty lives: 1856 (61%) + +**Enrichment Progress:** +- Chetyi-Minei chapters: 1154 total +- Matched: 1127 (auto 64 + already-filled 1063) +- Unmatched: 27 (floor: narratives, no-target, already-filled) + +### Status Classifications + +| Status | Meaning | Action | +|--------|---------|--------| +| `auto` | Score ≥ 0.6, empty target | Automatically written | +| `already-filled` | Target already has life.text | Skip (redundant) | +| `review` | Score 0.35–0.6 | Manual review required | +| `unmatched` | Score < 0.35 or no candidates | No suitable target | + +### Key Constants + +**File Paths:** +```typescript +const MINEI_PATH = 'scripts/output/minei.json'; +const MENAION_BUNDLE_PATH = 'static/data/cu/menaion-bundle.json'; +const LIVES_DIR = 'static/data/ru/lives'; +const REPORT_PATH = 'scripts/output/lives-match-report.json'; +``` + +**Matching Thresholds:** +```typescript +const AUTO_THRESHOLD = 0.6; // Automatic write +const REVIEW_THRESHOLD = 0.35; // Manual review +``` + +**Copyright String:** +```typescript +const COPYRIGHT = 'Четьи-Минеи свт. Димитрия Ростовского'; +``` + +--- + +## Version History + +- **Initial release** — Complete data format and enrichment process documentation +- **Updated** — Added bundle mis-mapping section, cross-date narrative handling, QA workflow + +--- + +## Contributing + +When contributing to the data format or enrichment pipeline: + +1. **Test thoroughly:** Run validation, typecheck, and build before committing +2. **Document changes:** Update this documentation for any schema changes +3. **Preserve compatibility:** Maintain existing file routing rules and naming conventions +4. **Validate data:** Run `validate-data.ts` and fix any errors + +--- + +## Support + +For questions or issues with the static data format: +- Review this documentation +- Check existing issues in the repository +- Run validation tools for error diagnosis +- Examine the enrichment pipeline for matching problems \ No newline at end of file diff --git a/DATA_RUS.md b/DATA_RUS.md new file mode 100644 index 0000000..2ad9773 --- /dev/null +++ b/DATA_RUS.md @@ -0,0 +1,837 @@ +# Документация по формату статических данных + +## Оглавление +1. [Обзор формата статических данных](#обзор-формата-статических-данных) +2. [Структура директорий и организация](#структура-директорий-и-организация) +3. [Модели данных и схемы](#модели-данных-и-схемы) +4. [Правила маршрутизации файлов](#правила-маршрутизации-файлов) +5. [Разбор компонентов данных](#разбор-компонентов-данных) +6. [Инструменты управления данными](#инструменты-управления-данными) +7. [Процесс обогащения](#процесс-обогащения) +8. [Рабочий процесс контроля качества](#рабочий-процесс-контроля-качества) +9. [Распространённые проблемы и решения](#распространённые-проблемы-и-решения) +10. [Краткий справочник](#краткий-справочник) + +--- + +## Обзор формата статических данных + +Ponomar PWA использует систему статических данных на основе JSON, организованную по языкам. Все литургические данные предварительно конвертированы из XML-источников и структурированы для эффективной отдачи и рендеринга на стороне клиента. + +### Основные принципы +- **Организация по языкам**: Каждый язык имеет свою директорию в `static/data/` +- **Хранение в JSON**: Все данные хранятся в виде JSON-файлов для простого парсинга +- **Маршрутизация по датам**: Календарные данные организованы по датам юлианского календаря (формата ММ-ДД) +- **Идентификация по CId**: Канонические идентификаторы (CId) уникально идентифицируют святых и праздники +- **Маршрутизация по префиксу файлов**: Файлы житий маршрутизируются по префиксу CId (01-12 → файлы месяцев) + +### Поддерживаемые языки +- `en` — английский +- `cu` — церковнославянский +- `ru` — русский +- `el` — греческий (включает `el/mono` для монохорда) +- `fr` — французский +- `zh` — китайский (включает `zh/Hans` и `zh/Hant` для упрощённого и традиционного) +- `shared` — межязыковые ресурсы + +--- + +## Структура директорий и организация + +``` +static/data/ +├── en/ +│ ├── menaion-bundle.json # Отображение дата → CId (авторитетно) +│ ├── en-menaion-bundle.json # Переопределения для конкретного языка +│ ├── lives/ # Жития святых по месяцам +│ │ ├── 01.json through 12.json # Файлы месяцев с CId по префиксу (01XX-12XX) +│ │ └── misc.json # CId без месячного префикса +│ ├── menaion/ # Ежедневные записи минеи (366 дней) +│ ├── calendar/ # Метаданные календаря +│ └── services/ # Шаблоны богослужений +├── cu/ # Церковнославянский (аналогичная структура) +├── ru/ # Русский (жития, богослужения) +├── el/ # Греческий (включает mono/) +├── fr/ # Французский +├── zh/ # Китайский (включает Hans/, Hant/) +└── shared/ # Межязыковые ресурсы + ├── calendar/ # Календарь подвижных праздников + ├── services/ # Общие шаблоны богослужений + └── lives-index.json # Индекс поиска CId → чтения Писания +``` + +### Типы файлов +- `*-bundle.json` — файлы отображения календаря +- `lives/*.json` — пачки (bundles) житий святых +- `menaion/*.json` — ежедневные записи минеи +- `services/*.json` — шаблоны и логика богослужений +- `calendar/*.json` — вычисления календаря и метаданные + +--- + +## Модели данных и схемы + +### Запись пачки (bundle entry) (menaion-bundle.json) +```json +{ + "01-01": [ + { "id": "010101" }, + { "id": "772426" }, + { "id": "010102" } + ] +} +``` +**Структура**: Объект с ключами по дате `ММ-ДД`, содержащий массив записей, каждая из которых содержит только поле `"id"` со значением CId. + +### Запись жития (life entry) (lives/*.json) +```json +{ + "772426": { + "name": { + "nominative": "Прп. Сильвестра Печерского (XII)", + "short": "Прп. Сильвестра Печерского" + }, + "life": { + "id": "minei-0101-772426", + "copyright": "Четьи-Минеи свт. Димитрия Ростовского", + "text": "

Преподобный отец наш Сильвестр...

" + } + } +} +``` +**Структура**: Объект с ключами по CId (строка), каждый содержит: +- `name` (объект) с падежными вариантами (`nominative`, `short`, `genitive` и т.д.) +- `life` (объект, необязательный) с полями `id`, `copyright` и `text` + +### Запись календаря +```json +{ + "pascha": { "year": 2025, "date": "04-20" }, + "fixed": [ + { "date": "01-01", "rank": 5, "celebration": "Circumcision" } + ] +} +``` +**Структура**: Содержит вычисления подвижных праздников и данные неподвижного календаря. + +### Запись шаблона богослужения +```json +{ + "ROYALHOURS": { + "0": { + "text": "Во имя Отца...", + "type": "0" + } + } +} +``` +**Структура**: Иерархическая структура богослужения с текстовыми узлами и условной логикой. + +--- + +## Правила маршрутизации файлов + +### Маршрутизация файлов житий +Пачки (bundles) житий маршрутизируются на основе префикса CId: + +| Шаблон CId | Целевой файл | Примеры | +|-------------|--------------|----------| +| `01XX-01ZZ` | `01.json` | `010101`, `014567` | +| `02XX-02ZZ` | `02.json` | `023456`, `027890` | +| ... | ... | ... | +| `12XX-12ZZ` | `12.json` | `123456`, `127890` | +| Прочие CId | `misc.json` | `772426`, `373`, `2396` | + +**Примеры:** +- `010101` → `01.json` +- `1253` → `12.json` +- `772426` → `misc.json` +- `373` → `misc.json` + +### Нейминг файлов пачек +- Основная пачка: `menaion-bundle.json` (для каждого языка) +- Переопределения языка: `{lang}-menaion-bundle.json` +- Маршрутизация по префиксу для пачек отсутствует (один файл на язык) + +--- + +## Разбор компонентов данных + +### Пачки минеи (Menaion Bundles) +**Назначение**: Авторитетное отображение дата → CId для рендеринга календаря + +**Структура**: JSON с ключами по дате и массивами CId +```json +{ + "01-01": [{ "id": "010101" }, { "id": "772426" }], + "01-02": [{ "id": "010201" }, { "id": "772455" }] +} +``` + +**Покрытие**: 366 дней юлианского календаря × несколько записей на день +**Размер файла**: ~50-100KB на язык +**Использование**: Представление календаря определяет, каких святых отображать в каждый день + +### Пачки житий (Lives Bundles) +**Назначение**: Биографии и жития святых для обогащения + +**Структура**: JSON с ключами по CId, вариантами имён и необязательным текстом жития +```json +{ + "772426": { + "name": { + "nominative": "Прп. Сильвестра Печерского (XII)", + "short": "Прп. Сильвестра Печерского" + }, + "life": { + "id": "minei-0101-772426", + "copyright": "Четьи-Минеи свт. Димитрия Ростовского", + "text": "

Полный текст жития в HTML...

" + } + } +} +``` + +**Покрытие**: 3046 CId всего, 1190 с обогащённым life.text +**Маршрутизация**: по префиксу (01.json-12.json + misc.json) +**Использование**: Отображение житий на страницах подробностей о святых + +### Данные календаря +**Назначение**: Вычисления подвижных праздников и метаданные календаря + +**Компоненты**: +- `shared/calendar/triodion.json` — Масленица до Великой седмицы +- `shared/calendar/pentecostarion.json` — Пасха до всех святых +- `{lang}/calendar/` — данные календаря для конкретного языка + +**Ключевые особенности:** +- Вычисления Пасхалии +- Определение дат подвижных праздников +- Определения постных периодов +- Метаданные праздников и commemorations + +### Шаблоны богослужений +**Назначение**: Структурированные литургические данные с условной логикой + +**Организация:** +``` +services/ +├── octoecheos/ # Восемь гласов × дни +├── triodion/ # 37 постных разделов +├── pentecostarion/ # 50 дней Пасхи +├── menaion/ # 366 ежедневных записей + 34 праздника +├── canons/ # Пареклит, Осмогласник, Великий канон +└── shared/templates/ # Переиспользуемые компоненты богослужений +``` + +**Структура**: Иерархический JSON с текстовыми узлами и условными префиксами +- **P-узлы**: Необязательный контент, который может быть включён +- **Var/I-узлы**: Логика условного выбора +- **Обычные узлы**: Обязательный контент, всегда включён + +### Метаданные Библии +**Назначение**: Отображения версий Библии и перикоп чтений + +**Структура**: Идентификаторы версий и отображения перикоп для 13 версий Библии +- Церковнославянский +- Русский синодальный +- KJV +- Брентон (Септуагинта) +- Вульгата +- Другие версии + +### Правила молитв и команды (Prayer Rules & Commands) +**Назначение**: Структуры суточного круга и определения правила молитвы + +**Компоненты:** +- **Правила молитвы**: Расписания ежедневных чтений +- **Команды**: Структуры команд богослужений +- **Часослов**: Часы, кафисмы, повечерие и т.д. + +### Правила поста +**Назначение**: Определения периодов и исключений поста + +**Структура**: JSON с правилами поста, периодами и детальными правилами +- Предпостные периоды +- Великий пост +- Безпостные периоды +- Рыбные и строгие постные дни + +--- + +## Инструменты управления данными + +### Конвейер конвертации (`scripts/convert-*.ts`) + +#### Главный скрипт +**`convert-all.ts`** — Оркестрирует все этапы конвертации +```bash +npm run convert +``` + +Конвертирует данные XML из источников Java Ponomar в формат JSON. + +#### Индивидуальные конвертеры + +**`convert-lives.ts`** — Конвертация житий святых из XML в JSON +- Вход: `ponomar/Ponomar/languages/{lang}/xml/lives/*.xml` +- Выход: `{lang}/lives/{01.json|misc.json}` пачки +- Особенности: + - Парсинг XML с извлечением атрибутов + - Нормализация падежей имён + - Извлечение грамматических данных + - Извлечение данных богослужений + - Извлечение ссылок на Писание + - Генерация пачек по месячному префиксу + +**`convert-calendar.ts`** — Конвертация метаданных календаря +- Вход: данные календаря XML +- Выход: структуры календаря JSON +- Особенности: + - Вычисления подвижных праздников + - Отображения неподвижных праздников + - Определения периодов + +**`convert-services.ts`** — Конвертация шаблонов богослужений +- Вход: определения богослужений XML +- Выход: шаблоны богослужений JSON +- Особенности: + - Сохранение иерархической структуры + - Извлечение условной логики + - Нормализация текстовых узлов + +**`convert-bible-meta.ts`** — Извлечение метаданных Библии +- Вход: метаданные Библии XML +- Выход: отображения версий и перикоп JSON + +**`convert-fasting.ts`** — Конвертация правил поста +- Вход: определения поста XML +- Выход: правила и периоды поста JSON + +**`convert-commands.ts`** — Конвертация структур команд +- Вход: определения команд XML +- Выход: структуры команд JSON + +**`convert-service-rules.ts`** — Извлечение правил богослужений +- Вход: определения правил богослужений XML +- Выход: правила богослужений JSON + +### Инструменты миграции (`scripts/migrate-data.ts`) + +**Назначение**: Нормализация формата данных между версиями и языками + +**Операции:** +1. Удаление префиксов `@_` из ключей имён житий (все языки) +2. Удаление `SId` из записей минеи (сохранение id = CId) (все языки) +3. Переименование директорий богослужений в нижний регистр (cu, el, fr, zh/Hans, zh/Hant, ru) +4. Выравнивание структуры Осмогласника (cu, fr, zh/Hans, zh/Hant) +5. Преобразование `TEXT` → `text` в файлах команд +6. Перемещение общих богослужений в подкаталог `templates/` +7. Нормализация регистра ключей имён (Nominative → nominative, Short → short) +8. Миграция объединённых файлов календаря (triodion.json, pentecostarion.json) + +**Использование:** +```bash +npm run migrate # Применение миграций +npm run migrate:dry # Предпросмотр изменений +``` + +### Набор валидации (`scripts/validate-*.ts`) + +#### Главный валидатор +**`validate-data.ts`** — Комплексная валидация данных +```bash +npx tsx scripts/validate-data.ts +``` +**Валидирует:** +- Структуру записей житий (обязательные поля) +- Формат пачек житий (ключи CId, объекты name) +- Целостность данных календаря +- Структуру шаблонов богослужений +- Соответствие формату молитв +- Структуру узлов команд +- Записи commemorations +- Определения правил поста + +**Вывод:** Количество файлов, ошибки, предупреждения + +#### Специализированные валидаторы +**`validate-i18n.ts`** — Полнота международной локализации +```bash +npx tsx scripts/validate-i18n.ts +``` +Проверяет покрытие по языкам (en/ru/cu). + +**`validate-tabs.ts`** — Согласованность вкладок/шаблонов богослужений +```bash +npx tsx scripts/validate-tabs.ts +``` +Валидирует, что вкладки богослужений соответствуют структурам шаблонов. + +**`validate-menaion.ts`** — Валидация данных минеи +```bash +npx tsx scripts/validate-menaion.ts +``` +Валидирует записи минеи против правил календаря. + +**`validate-prayer-rule.ts`** — Валидация структуры правила молитвы +```bash +npx tsx scripts/validate-prayer-rule.ts +``` +Валидирует формат и полноту правила молитвы. + +**Периодические валидаторы:** +- `validate-triodion.ts` — Валидация периода Триоди +- `validate-pentecostarion.ts` — Валидация Пятидесятницы +- `validate-holy-week.ts` — Валидация Страстной седмицы +- `validate-great-canon.ts` — Валидация Великого канона +- `validate-great-compline.ts` — Валидация великого повечерия +- `validate-libcs.ts` — Валидация содержания библиотеки + +### Утилиты (`scripts/tools/`) + +**`search-texts.ts`** — Полно-текстовый поиск по файлам данных +```bash +npx tsx scripts/tools/search-texts.ts [--lang en] [--type prayers] +``` + +**`stats.ts`** — Статистика данных и анализ размеров +```bash +npx tsx scripts/tools/stats.ts [--lang en] +``` + +Предоставляет количество файлов, размеры и разбивку по категориям. + +--- + +## Процесс обогащения + +### Обзор +Процесс обогащения заполняет пустые поля `life.text` в пачках ru/lives, используя агиографические тексты Четьи-Миней (свт. Димитрия Ростовского). + +### Подготовка источника: Импорт Четьи-Миней + +**`convert-minei.ts`** — Конвертирует EPUB Четьи-Миней в JSON с ключами по датам + +**Структура входа (извлечённый EPUB):** +``` +extracted-epub/ +├── index_split_000.xhtml through index_split_9999.xhtml +├── toc.ncx +└── content.opf +``` + +**Процесс:** +1. Последовательный парсинг дневных файлов +2. Извлечение заголовков: `h2` для дат (`"Память 1 января"`), `h3` для заголовков глав +3. Извлечение абзацев: `

` для содержания +4. Сбор сносок из якорей `` +5. Добавление сносок в виде блока "Примечания:" +6. Применение исправлений дат заголовков (например, `calibre_toc_10023` → `01-27`) +7. Построение выходной структуры: `{ "ММ-ДД": [{ title, html }] }` + +**Использование:** +```bash +npx tsx scripts/convert-minei.ts [output.json] +``` + +**Вывод:** `scripts/output/minei.json` (игнорируется в git, ~33МБ) + +### Конвейер обогащения + +**`enrich-lives.ts`** — Нечёткое сопоставление названий minei с именами CId и заполнение пустых житий + +**Входные данные:** +- `scripts/output/minei.json` — источники житий по дате (ММ-ДД) +- `static/data/cu/menaion-bundle.json` — Авторитетное отображение дата→CId +- `static/data/ru/lives/*.json` — целевые пачки для обогащения + +**Стратегия сопоставления:** +1. **Токенизация**: Разбиение названий на токены, фильтрация ROLE_WORDS +2. **Коэффициент Dice**: Вычисление сходства по наборам токенов +3. **Классификация статусов**: + - `already-filled` — Целевой объект уже имеет `life.text` → пропускается + - `auto` — Оценка ≥ 0.6, пустой целевой объект → записывается + - `review` — Оценка 0.35–0.6 → требуется ручной обзор + - `unmatched` — Оценка < 0.35 или нет кандидатов → без совпадения + +**Ручные переопределения:** +```typescript +const MANUAL_FIXES: Record = { + '02-02|сказание о сретении': '373', + '03-24|воспоминание о чуде': '822', + // 214 записей всего +} +``` +Формат ключа: `{дата}|{характерная подстрока}` → CId + +**Обработка коллизий:** Несколько источников отображаются на один CId +- Первый источник: записывает `life.html` напрямую (без заголовка) +- Последующие источники: добавляют `

{title}

{html}` + +**Маршрутизация файлов:** +```typescript +function bundleFileForCid(cid: string): string { + return /^(0[1-9]|1[0-2])\d+/.test(cid) + ? `${cid.substring(0, 2)}.json` + : 'misc.json'; +} +``` + +**Использование:** +```bash +# Тестовый прогон: только отчёт +npx tsx scripts/enrich-lives.ts + +# Ограничение одним месяцем +npx tsx scripts/enrich-lives.ts --month 01 + +# Применение изменений +npx tsx scripts/enrich-lives.ts --write + +# Применение изменений для конкретного месяца +npx tsx scripts/enrich-lives.ts --write --month 01 +``` + +**Вывод:** `scripts/output/lives-match-report.json` со статусом совпадения для каждого источника + +### Пример рабочего процесса + +**Этап 1: Подготовка источника** +```bash +npx tsx scripts/convert-minei.ts ~/Downloads/chetyi-minei-epub/ +# Вывод: scripts/output/minei.json +``` + +**Этап 2: Тестовый анализ** +```bash +npx tsx scripts/enrich-lives.ts +# Показывает: Auto-applied: 184, needs review: 127, unmatched: 94 +# Обзор: scripts/output/lives-match-report.json +``` + +**Этап 3: Ручной обзор и исправления** +- Анализ записей `review` в отчёте +- Добавление MANUAL_FIXES для проблемных совпадений +- Повторный запуск, пока количество `review` не станет приемлемым + +**Этап 4: Запись и валидация** +```bash +npx tsx scripts/enrich-lives.ts --write +# Показывает: Wrote 7 updated bundle(s) +npx tsx scripts/validate-data.ts +npx tsc --noEmit +npm run build +``` + +**Этап 5: Коммит** +```bash +git add scripts/enrich-lives.ts scripts/output/lives-match-report.json static/data/ru/lives/ +git commit -m "enrich 121 more ru lives with Chetyi-Minei texts" +``` + +### Контроль качества + +**Проверка коллизий:** Проверка много-главных записей на правильность заголовков +```bash +python3 -c " +import json, re +misc = json.load(open('static/data/ru/lives/misc.json')) +for cid in ['493', '1674', '257401']: # Известные цели коллизий + text = misc[cid]['life']['text'] + headings = re.findall(r'([^<]+)', text) + print(f'{cid}: {len(headings)} глав - {headings}') +" +``` + +**Отслеживание покрытия:** Мониторинг прогресса обогащения +```bash +python3 -c " +import json, glob, os +total = has = 0 +for fp in glob.glob('static/data/ru/lives/*.json'): + data = json.load(open(fp)) + for cid, entry in data.items(): + total += 1 + if isinstance(entry.get('life'), dict) and entry.get('life', {}).get('text'): + has += 1 +print(f'Покрытие: {has}/{total} ({has*100//total}%) житий с текстом') +" +``` + +--- + +## Рабочий процесс контроля качества + +### Чек-лист перед коммитом + +1. **Валидация данных** +```bash +npx tsx scripts/validate-data.ts +# Ожидается: "All files valid!" или конкретное количество ошибок +``` + +2. **Безопасность типов** +```bash +npm run check # или npx tsc --noEmit +# Ожидается: Нет ошибок TypeScript +``` + +3. **Проверка сборки** +```bash +npm run build +# Ожидается: Успешная сборка с размерами пакетов +``` + +4. **Функциональное тестирование** +```bash +npm run dev +# Ручной тест: Представление календаря, страницы подробностей святых, отображение житий +``` + +### Непрерывный мониторинг + +**Автоматические проверки:** +- Проверка количества файлов (должно быть 274 файла) +- Возможность парсинга JSON (все файлы данных) +- Наличие обязательных полей (nominative, life.text для обогащённых записей) +- Согласованность CId (один и тот же CId должен иметь одинаковое имя на разных языках) + +**Обнаружение проблем:** +- Повреждённые JSON-файлы → ошибки парсинга в validate-data.ts +- Отсутствие обязательных полей → предупреждения валидации +- Несоответствие типов → ошибки TypeScript +- Ошибки сборки → недопустимые структуры данных + +### Решение проблем + +**Распространённые ошибки валидации:** +1. **"Missing nominative"** — Объект name отсутствует именительный падеж + - **Решение**: Добавить поле `name.nominative` к затронутым записям + +2. **"Failed to parse"** — Повреждённый JSON-файл + - **Решение**: Повторно запустить конвертацию или исправить синтаксис JSON + +3. **"Rank should be 0-8"** — Недопустимое значение rank + - **Решение**: Нормализовать rank в диапазон 0-8 + +4. **Изменения размеров пакетов сборки** — Неожиданное увеличение размера файла + - **Решение**: Проверить на наличие дубликатов или искажённого содержимого + +--- + +## Распространённые проблемы и решения + +### Артефакты OCR в текстах Четьи-Миней + +**Проблема:** Конвертация Четьи-Миней создаёт проблемы OCR, такие как: +- Латинские символы в русском тексте (`Taиcии` вместо `Таисии`) +- Маркеры сносок `[1]` в тексте тела +- Нестабильная пунктуация `[1]` в названиях + +**Решение:** +- Оставлять артефакты OCR как есть (часть исходного текста) +- Ручные исправления используют точные подстроки OCR для сопоставления +- Примеры: `'02-15|onissima, odnogo iz lika'` → `'450'` + +### Разрешение омонимов в одну дату + +**Проблема:** Несколько святых имеют схожие имена в одну дату + +**Примеры:** +- 03-24: Иаков исповедник (68501) против других записей Иаков +- 02-22: Варадат против Фалассия (оба отображаются на 493) +- 09-03: Анфим, Аристион, Василиса в одну дату + +**Решение:** +- Использовать характерные подстроки в MANUAL_FIXES +- Обеспечить уникальность по дате (проверить с помощью скрипта верификации) +- Для коллизий: оба источника отображаются на один CId (поведение добавления) + +### Нарративы на пересекающихся датах + +**Проблема:** Некоторые главы minei являются повествованиями, не привязанными к конкретному празднику + +**Примеры:** +- 02-02: "Сказание о Сретении Господнем" (повествование о сретении) +- 03-24: "Воспоминание о чуде в Печерском монастыре" (история чуда) +- 08-28: "Память святой праведной Анны" (пророчица Анна) + +**Решение:** +- Определить соответствующий CId для святого/события +- Отобразить с MANUAL_FIXES, даже если не в ту же дату (хотя текущий конвейер основан на дате) +- Для записей без подходящего CId: остаться без совпадения + +### Неверные отображения в пачке (bundle) + +**Проблема:** Некоторые CId указаны в неправильных календарных датах + +**Пример:** +- 868 Иаков Боровицкий указан под 05-22, фактический праздник 10-23 + +**Решение:** +- Вручную исправить menaion-bundle.json +- Переместить CId с неверной даты на правильную дату +- Проверить по источникам календаря и традиции + +### Пограничные случаи маршрутизации файлов + +**Проблема:** Неоднозначная маршрутизация для CId на границах + +**Пограничные случаи:** +- Префиксы `00` → misc.json (не 00.json) +- Префиксы `99` → misc.json (не 09.json) +- Нецифровые CId → misc.json + +**Решение:** +```typescript +/^(0[1-9]|1[0-2])\d+/.test(cid) // Совпадает только с 01-12, за которыми следуют цифры +``` + +### Отображение много-главных коллизий + +**Проблема:** Когда несколько источников добавляются к одному CId, первая глава не имеет заголовка + +**Поведение:** +- Первый источник: записывает `life.html` напрямую (без заголовка) +- Последующие источники: добавляют `

{title}

{html}` +- Результат: Первая глава без заголовка, другие чётко отмечены + +**Приемлемый компромисс:** Соответствует всем одно-главным житиям (которые не имеют заголовка) + +--- + +## Краткий справочник + +### Сводка npm-скриптов + +```bash +# Разработка +npm run dev # Запуск сервера разработки +npm run build # Продуктивная сборка +npm run preview # Предпросмотр продуктивной сборки + +# Конвертация данных +npm run convert # Конвертация всех источников XML в JSON +npm run migrate # Нормализация к текущему формату +npm run migrate:dry # Предпросмотр изменений миграции + +# Валидация +npm run check # Проверка типов (tsc --noEmit) +npx tsx scripts/validate-data.ts # Главный валидатор +npx tsx scripts/validate-i18n.ts # Полнота i18n +npx tsx scripts/validate-tabs.ts # Согласованность богослужений + +# Инструменты +npx tsx scripts/tools/search-texts.ts # Поиск по файлам данных +npx tsx scripts/tools/stats.ts # Статистика данных + +# Обогащение +npx tsx scripts/convert-minei.ts # Импорт Четьи-Миней +npx tsx scripts/enrich-lives.ts # Тестовый прогон обогащения +npx tsx scripts/enrich-lives.ts --write # Применение обогащения +``` + +### Расширения файлов + +| Расширение | Назначение | Формат | +|-----------|-------------|--------| +| `.json` | Все файлы статических данных | JSON | +| `.text` | Ресурсы простого текста | Простой текст | +| `.xml` | Исходные данные (не в репо) | XML | + +### Стратегия Git + +**Отслеживается:** `static/data/` (за исключением выходных файлов) +**Игнорируется:** +- `scripts/output/minei.json` (33МБ, генерируемый) +- `node_modules/` +- `dist/` + +### Важные пути к файлам + +```bash +# Директории данных +static/data/cu/menaion-bundle.json # Авторитет календаря +static/data/ru/lives/ # Цель для обогащения +static/data/shared/services/ # Общие шаблоны богослужений + +# Скрипты +scripts/enrich-lives.ts # Конвейер обогащения +scripts/convert-minei.ts # Импорт minei +scripts/validate-data.ts # Главный валидатор + +# Выходные файлы +scripts/output/minei.json # Источник minei (игнорируется в git) +scripts/output/lives-match-report.json # Отчёт о совпадениях +``` + +### Статистика покрытия + +**Текущий статус:** +- Всего CId: 3046 +- Жития с текстом: 1190 (39%) +- Пустые жития: 1856 (61%) + +**Прогресс обогащения:** +- Главы Четьи-Миней: 1154 всего +- Совпавшие: 1127 (auto 64 + already-filled 1063) +- Без совпадений: 27 (минимум: повествования, нет цели, уже заполнено) + +### Классификация статусов + +| Статус | Значение | Действие | +|--------|----------|----------| +| `auto` | Оценка ≥ 0.6, пустая цель | Автоматически записывается | +| `already-filled` | Цель уже имеет life.text | Пропускается (избыточно) | +| `review` | Оценка 0.35–0.6 | Требуется ручной обзор | +| `unmatched` | Оценка < 0.35 или нет кандидатов | Нет подходящей цели | + +### Ключевые константы + +**Пути к файлам:** +```typescript +const MINEI_PATH = 'scripts/output/minei.json'; +const MENAION_BUNDLE_PATH = 'static/data/cu/menaion-bundle.json'; +const LIVES_DIR = 'static/data/ru/lives'; +const REPORT_PATH = 'scripts/output/lives-match-report.json'; +``` + +**Пороги сопоставления:** +```typescript +const AUTO_THRESHOLD = 0.6; // Автоматическая запись +const REVIEW_THRESHOLD = 0.35; // Ручной обзор +``` + +**Строка авторских прав:** +```typescript +const COPYRIGHT = 'Четьи-Минеи свт. Димитрия Ростовского'; +``` + +--- + +## История версий + +- **Первоначальный выпуск** — Полная документация формата данных и процесса обогащения +- **Обновлено** — Добавлен раздел о неверных отображениях пачки, обработка повествований на пересекающихся датах, рабочий процесс QA + +--- + +## Вклад + +При вкладе в формат данных или конвейер обогащения: + +1. **Тщательно тестируйте:** Запускайте валидацию, проверку типов и сборку перед коммитом +2. **Документируйте изменения:** Обновляйте эту документацию при любых изменениях схемы +3. **Сохраняйте совместимость:** Поддерживайте существующие правила маршрутизации файлов и соглашения об именовании +4. **Валидируйте данные:** Запускайте `validate-data.ts` и исправляйте любые ошибки + +--- + +## Поддержка + +По вопросам или проблемам с форматом статических данных: +- Ознакомьтесь с этой документацией +- Проверьте существующие проблемы в репозитории +- Запустите инструменты валидации для диагностики ошибок +- Изучите конвейер обогащения для проблем сопоставления \ No newline at end of file diff --git a/README.md b/README.md index 7fa4254..cfced8c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ npm install npm run dev ``` -Data files in `static/data/` are pre-converted JSON (not committed). To regenerate from the Java XML sources, run: +Data files in `static/data/` are tracked in git. The only gitignored output is `scripts/output/minei.json` (33MB Chetyi-Minei source). ```bash npm run convert # re-convert all data from XML @@ -46,9 +46,16 @@ npm run preview # preview production build ## QA / Validation ```bash -npx tsx scripts/validate-i18n.ts # i18n completeness (en/ru/cu) -npx tsx scripts/validate-tabs.ts # service tab/template consistency -npx tsx scripts/assembler-test.ts # service assembler integration tests +npx tsx scripts/validate-data.ts # Main validator (274 files checked) +npx tsx scripts/validate-i18n.ts # i18n completeness (en/ru/cu) +npx tsx scripts/validate-tabs.ts # service tab/template consistency +npx tsx scripts/validate-menaion.ts # menaion data validation +npx tsx scripts/validate-prayer-rule.ts # prayer rule structure validation +npx tsx scripts/validate-triodion.ts # Triodion period validation +npx tsx scripts/validate-pentecostarion.ts # Pentecostarion validation +npx tsx scripts/validate-holy-week.ts # Holy Week validation +npx tsx scripts/validate-great-canon.ts # Great Canon validation +npx tsx scripts/assembler-test.ts # service assembler integration tests ``` ## Liturgical Text Categories (static/data/shared/services/) @@ -60,7 +67,7 @@ npx tsx scripts/assembler-test.ts # service assembler integration tests - **Canons** — Paraclete (weekday, 8 tones × 6 days = 48), Octoechos (Sunday, 8 tones), Great Canon - **Services** — 78 data-backed services with full.json (Pascha, Paralytic, Sergius, Pokrov, etc.; Var/I-prefix + bare P-prefix varNodes now intercepted) - **Horologion / Sbornik / Prayer Rule / Akathists / Parimii / Paraclete / Irmologion** — daily-cycle collections -- **Lives** — Saint lives (en/cu, name.nominative validated by `validate-data.ts`) +- **Lives** — Saint lives (en/cu/ru, 1190/3046 with life.text enriched from Chetyi-Minei) ## Project Structure @@ -69,9 +76,9 @@ src/ core/ — Domain logic (calendar, paschalion, service assembly, i18n) ui/ — View components (app, calendar, bible, service, settings) main.ts — Entry point -scripts/ — Data conversion, migration, validation, and CLI tools +scripts/ — Data conversion, migration, validation, enrichment, and CLI tools static/ - data/ — Liturgical data as JSON (not committed, generated from Java XML via npm run convert) + data/ — Liturgical data as JSON (tracked in git, generated from Java XML via npm run convert) fonts/ — Church Slavonic fonts icons/ — PWA icons ``` @@ -79,3 +86,14 @@ static/ ## License Same as the original Java project. + +## Documentation + +- **[DATA_FORMAT.md](DATA_FORMAT.md)** — Comprehensive static data format documentation in English +- **[DATA_RUS.md](DATA_RUS.md)** — Complete Russian documentation of data format and enrichment process + +Covers: +- Static data models, routing rules, and component breakdown +- Complete tool inventory for conversion, migration, and validation +- Chetyi-Minei enrichment pipeline and quality assurance workflow +- Quick reference for all available NPM scripts and commands diff --git a/README_RUS.md b/README_RUS.md new file mode 100644 index 0000000..0c396e0 --- /dev/null +++ b/README_RUS.md @@ -0,0 +1,101 @@ +# Ponomar — Православный календарь PWA + +Прогрессивное веб-приложение для православного церковного календаря, богослужебных текстов и чтений Писания. + +Произведено из оригинального Java-приложения Ponomar от Александра Андреева, Юрия Шардта и Сергея Ф. + +**Демо:** + +## Возможности + +- **Calendar** — Просмотр сеток месяцев с литургическими днями, периодами поста, чинами и празднованиями. Поддерживает юлианский календарь с григорианскими эквивалентами. +- **Service Reader** — Сборка богослужебных текстов (часов, кафизм) из структурированных шаблонов с условной логикой. +- **Bible Reader** — Чтение Писания на 13 языках (церковнославянский, русский синодальный, KJV, Брентон, Вульгата и др.). Позиция чтения для каждой версии сохраняется между сессиями. +- **Многоязычный интерфейс** — Английский, русский, церковнославянский (со специальными шрифтами для церковнославянского). +- **PWA** — Устанавливается на настольные и мобильные устройства. +- **Навигация** — 3 элемента верхнего уровня (Calendar, Library, Settings) с выпадающим меню Library: Библия, Service (Часослов, Сборник, Молитвенное правило, Каноны и акафисты, Паримии, Пареклит, Ирмологий), Праздники (Минея, Постная Триодь). + +## Технологический стек + +- [TypeScript](https://www.typescriptlang.org/) — полностью типизированный +- [Vite](https://vitejs.dev/) — инструмент сборки +- [Tailwind CSS v4](https://tailwindcss.com/) — CSS с утилитарными классами +- [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) — конвертация устаревшего XML (только ручной режим) + +## Начало работы + +```bash +npm install +npm run dev +``` + +Файлы данных в `static/data/` отслеживаются в git. Единственный игнорируемый файл вывода — `scripts/output/minei.json` (33МБ источник Четьи-Миней). + +Для повторного создания из XML-источников Java Ponomar запустите: + +```bash +npm run convert # повторная конвертация всех данных из XML +npm run migrate # нормализация к текущему формату +``` + +Установите `PONOMAR_JAVA_HOME` для указания на локальный клон репозитория Java Ponomar (по умолчанию `../ponomar`). + +```bash +npm run build # продуктивная сборка +npm run preview # предпросмотр продуктивной сборки +``` + +## QA / Валидация + +```bash +npx tsx scripts/validate-data.ts # Главный валидатор (274 файлов проверено) +npx tsx scripts/validate-i18n.ts # Полнота i18n (en/ru/cu) +npx tsx scripts/validate-tabs.ts # Согласованность вкладок/шаблонов богослужений +npx tsx scripts/validate-menaion.ts # Валидация данных минеи +npx tsx scripts/validate-prayer-rule.ts # Валидация структуры правила молитвы +npx tsx scripts/validate-triodion.ts # Валидация периода Триоди +npx tsx scripts/validate-pentecostarion.ts # Валидация Пятидесятницы +npx tsx scripts/validate-holy-week.ts # Валидация Страстной седмицы +npx tsx scripts/validate-great-canon.ts # Валидация Великого канона +npx tsx scripts/assembler-test.ts # Интеграционные тесты сборщика богослужений +``` + +## Категории литургических текстов (static/data/shared/services/) + +- **Triodion** — 37 разделов (Масленица → Великий пост → Страстная седмица) +- **Pentecostarion** — 50 дней (Пасха → Все святые) +- **Menaion (daily)** — 367 ежедневных записей (одна на каждый день юлианского календаря) +- **Menaion (feasts)** — 34 неподвижных праздника с отдельными богослужениями +- **Canons** — Пареклит (будние дни, 8 гласов × 6 дней = 48), Осмогласник (воскресенье, 8 гласов), Великий канон +- **Services** — 78 богослужений с полными данными (Пасха, расслабленный, Сергий, Покров и др.; Var/I-префикс + простые P-узлы varNodes теперь перехватываются) +- **Horologion / Sbornik / Prayer Rule / Akathists / Parimii / Paraclete / Irmologion** — коллекции суточного круга +- **Lives** — Жития святых (en/cu/ru, 1190/3046 с обогащённым life.text из Четьи-Миней) + +## Структура проекта + +``` +src/ + core/ — Логика предметной области (календарь, пасхалия, сборка богослужений, i18n) + ui/ — Компоненты представления (приложение, календарь, библия, богослужения, настройки) + main.ts — Точка входа +scripts/ — Конвертация данных, миграция, валидация, обогащение и инструменты CLI +static/ + data/ — Литургические данные в формате JSON (отслеживаются в git) + fonts/ — Шрифты для церковнославянского языка + icons/ — Иконки PWA +``` + +## Лицензия + +Такая же, как у оригинального Java-проекта. + +## Документация + +- **[DATA_FORMAT.md](DATA_FORMAT.md)** — Комплексная документация формата статических данных на английском языке +- **[DATA_RUS.md](DATA_RUS.md)** — Полная русская документация формата данных и процесса обогащения + +Охватывает: +- Модели статических данных, правила маршрутизации и разбор компонентов +- Полный набор инструментов для конвертации, миграции и валидации +- Конвейер обогащения Четьи-Миней и рабочий процесс контроля качества +- Краткий справочник по всем доступным npm-скриптам и командам \ No newline at end of file