Branch: main (merged from feat/rc-hardening-p0 via PR #66 + 4 post-merge fixes)
Latest stable commit: v1.1.0 tag points to the head after final doc updates
Test status: 174/174 tests pass (163 unit + 11 AppImage smoke) in <3s
- P0: 95 tests (scanner_tab + decision_log + translation + hf_dataset_staging + lazy_ocr_service)
- P1: 66 tests (field_extractor + benchmark_reporter + decision_instrumentation)
- P2: 11 AppImage smoke tests (now run with
MEDICAL_DOC_APPIMAGEenv var pointing to v1.1.0 AppImage) - Additional: 28 P0-extra tests (field_extractor_core + other)
P0 status: 7/7 complete (deploy source of truth, scanner integration, lazy loading, translation service, HF staging, decision log, pytest unification) P1 status: 4/4 complete (field extractor, benchmark reporter, decision instrumentation, Git LFS audit) P2 status: 4/4 complete (AppImage hardening, CI matrix, RC checklist + release notes, LFS migration plan) Stable promotion: ✅ rc1 → stable after 4 AppImage build fixes (desktop file at AppDir root, ARCH env var, icon naming, README direct-download link)
-
bash scripts/sync-hf-space.sh --force— clean, 5 directories synced -
bash scripts/sync-hf-space.sh --verify— ✅ in sync - 163/163 P0+P1+P0-extra tests pass in 1.92s
- 11/11 AppImage smoke tests pass in 1.28s (using v1.1.0-rc1 AppImage artifact)
- No real tokens leaked in git history (filter-repo placeholders only)
- Remote URL cleaned (no embedded PAT)
- Credential helper uses
$GH_TOKENenv var (not hardcoded) - Backup branch
backup/before-v1.1.0-stablepushed - All 4 AppImage build fixes verified in CI (run 29681501968 ✅ green)
- HF Space drift intentionally documented in STATE_OF_TRUTH.md
- Tag:
v1.1.0(annotated) - GitHub Release: https://github.com/DrAbdulmalek/omni-medical-suite/releases/tag/v1.1.0
- AppImage asset (177 MB):
MedicalDocProcessor-v1.1.0-x86_64.AppImage - SHA256 asset:
MedicalDocProcessor-v1.1.0-x86_64.AppImage.sha256 - Release Notes:
RELEASE_NOTES_v1.1.0.md
-
scripts/sync-hf-space.shenhanced with--verifyand--forcemodes -
docs/DEPLOYMENT.mdadds "🎯 Source of Truth" section at top -
STATE_OF_TRUTH.mdalready documents runtime state matrix - Sync mapping documented:
src/ocr,packages/{vision,nlp,core},config→hf-space/ - HF-specific overrides (
app.py,Dockerfile,requirements.txt) marked as not-synced
-
app/scanner_tab.pycreated — 397 LOC, pure functions, no Gradio imports at module level - Manual crop via 4 number inputs (x/y/w/h) —
apply_manual_crop()supports dict/tuple/list formats - Advanced edge detection: Canny + Adaptive Threshold + Morphology + Hough Lines
-
apply_advanced_edges()composable composition with metadata dict -
save_processed_image()with path-traversal sanitization -
build_zip_from_dir()for "save all as ZIP" - Tab 1 in
advanced_review_app.pyupgraded: manual crop accordion + edge options accordion + save button -
requirements-scanner.txtdocumenting optional deps - 40 unit tests in
tests/test_scanner_tab.py(all pass)
-
app/services/ocr_service.py—get_paddle_ocr(),get_image_preprocessor(),has_tesseract(),get_spell_checker() -
app/services/review_service.py—get_proofreader(),get_ner() - PEP 562
__getattr__preserves backward-compat module-level names - Thread-safe singleton + failure caching
-
app/services/translation_service.pycreated (~130 LOC extracted) -
transformers + torchimported lazily insideload_translator() -
app/gradio_full_hitl.pyslimmed 585 → 466 LOC - Public API:
translate_text,correct_translation,load_translator,get_translation_corrector,reset_lazy_cache
-
save_to_hf()now appends to local JSONL (~/.omni/hf_dataset_queue/pending.jsonl) -
flush_queue()does dedup (via content_hash) + single batched push -
count_pending()for monitoring - Append-only staging — no correction ever lost
- Pre-P0 O(N) per save → post-P0 O(1) per save + O(N) per flush (amortized)
-
app/core/decision_log.py—log_decision()emits JSON line per decision - Logger:
app.decision_log(separate from root) - Schema:
{ts, decision, outcome, reasons, inputs, skipped, duration_ms, session_id} - 12 unit tests in
tests/test_decision_log.py
- Duplicate
pytest.iniremoved; config consolidated inpyproject.toml - All 4 P0 test files run cleanly: 55 new tests, 0 regressions
-
✅ P1-1: Field extractor hardening (
src/ocr/field_extractor.py)- Multi-line value support for diagnosis/medications (lookahead pattern)
- Bilingual labels: Arabic + English shorthand (Pt Name, File No, DOB, Dr, Dx, Rx)
- Per-field confidence scoring in [0.0, 1.0] via
_confidence_for() - Safe
build_template_signature():re.escape()+ placeholder + length-desc sort - Tests:
tests/test_field_extractor_p1.py(29 tests, all pass) - Commit:
5b70816
-
✅ P1-2: Benchmark reporter (
omni_medical_suite/preprocessing/compare_raw_vs_printed.py)to_csv(results, path, *, flatten_field_aware=True)— CSV export with field-aware flatteningto_json(results, path, *, indent=2)— JSON export preserving Arabic Unicodeaggregate_metrics(results, *, percentiles=(0.5, 0.9, 0.95))— min/max/mean/median/stdev/percentiles- Convenience rollups:
improvement_mean,processed_better_count,processed_better_ratio - Tests:
tests/test_benchmark_reporter_p1.py(25 tests, all pass) - Commit:
e9ffdde
-
✅ P1-3: RTL/dedup/field_extractor decision logging
src/ocr/rtl_utils.py—analyze_and_fix()emitsdecision='rtl_fix'src/ocr/deduplication.py—deduplicate()emitsdecision='dedup_batch'src/ocr/field_extractor.py—extract_fields()emitsdecision='field_extraction'- All instrumentation wrapped in
try/except ImportError(graceful degradation) - Bug fix in
app/core/decision_log.py:_coerce_outcome()now handles dicts (previously stringified them);_safe_jsonable()handles nested lists/dicts with circular-reference protection - Tests:
tests/test_decision_instrumentation_p1.py(12 tests, all pass) - Commit:
e8ea063
-
✅ P1-4: Git LFS audit + .gitattributes cleanup
- Expanded
.gitattributesfrom 11 → 50+ patterns across 10 categories - Added:
*.ipynb, ML weights (.h5/.pt/.safetensors/.onnx/...), media (.mp4/.mp3/...), archives (.zip/.tar/.7z/...), office docs (.docx/.xlsx/.pptx), path-specific patterns fortectonicbinary andtokenizer.json - New
scripts/audit-lfs-coverage.sh— verifies coverage,--strictmode for CI - Audit result: 32/32 large files covered, 0 uncovered
- Commit:
bcd5c73
- Expanded
P1 test total: 66 new tests (29 + 25 + 12), all pass. Combined with P0's 95 tests: 161/161 pass in 3.02s.
-
packages/desktop/build_appimage.shenhanced with:- Auto-detect distro (Manjaro/Arch pacman, Debian apt, Fedora dnf)
--version-from-gitflag: derives version fromgit describe --tags--smoke-testflag: verifies AppImage launches offscreen- SHA256 checksum file generation (
.AppImage.sha256) - AppStream metainfo with build date + git commit
- Optional signing via
APPIMAGETOOL_SIGN_KEYenv var - Qt platform abstraction in AppRun (Wayland/X11/offscreen auto-detect)
-
docs/APPIIMAGE_MANJARO.md— comprehensive Manjaro build guide (pacman deps, yay install, Wayland/KDE Plasma 6 notes, troubleshooting, system-wide install) -
.github/workflows/appimage-build.yml— CI workflow builds AppImage on push + tags, uploads as artifact (30-day retention) -
packages/desktop/test_appimage_smoke.py— standalone smoke test (CLI) -
packages/desktop/test_appimage_smoke_pytest.py— pytest wrapper (11 tests, skipped withoutMEDICAL_DOC_APPIMAGEenv var)
-
.github/workflows/ci-matrix.ymlwith 5 jobs:- matrix-test: Python 3.10/3.11/3.12 on Ubuntu 22.04 — runs P0+P1 hardening tests
- manjaro-smoke:
archlinux:latestcontainer — verifies imports (PySide6, cv2, scanner_fixer) + decision_log + lazy_ocr tests - hf-space-smoke: builds
hf-space/Dockerfile+ verifiesapp.pyimports inside container + runssync-hf-space.sh --verify(drift check, non-blocking) - colab-smoke: validates all
notebooks/*.ipynbvianbformat - summary: aggregates results for branch protection (matrix-test blocks merge)
-
scripts/validate_notebooks.py— reusable notebook validator - Weekly schedule trigger (Sun 03:00 UTC) for proactive regression detection
- All three deploy surfaces covered: Manjaro (desktop AppImage), HF Space (Dockerfile build), Colab (notebook JSON validation)
- This file updated to reflect P2 completion
-
RELEASE_NOTES_v1.1.0-rc1.mdcreated with full feature breakdown, migration notes, download links, and known issues
-
docs/LFS_MIGRATION_PLAN.mdcreated — staged migration approach (no forced history rewrite on main; LFS applied to new files going forward, with opt-ingit lfs migrate importfor legacy blobs) -
.gitattributesaudited — 50+ patterns across 10 categories already in place from P1-4 -
scripts/audit-lfs-coverage.sh(existing) verifies coverage; CI integration via--strictmode documented
- Engine router instrumentation — emit
decision='engine_selection'inpackages/core/engine_router.py(only remaining uninstrumented decision site) - LFS migration of existing tracked files —
git lfs migrate importfor files now covered by new patterns (rewrites history, coordinate with collaborators) - HF Space live URL smoke — extend
hf-space-smokejob to hit the live Space URL after deploy (currently only verifies Dockerfile build) - Performance regression baseline — capture P95 latency for OCR + field extraction; alert on >10% regression
Direct URL: https://huggingface.co/spaces/DrAbdulmalek/omni-medical-ocr
# Sync monorepo → hf-space/ (idempotent)
./scripts/sync-hf-space.sh --force
./scripts/sync-hf-space.sh --verify
# Push to trigger deploy-to-hf.yml workflow
git add hf-space/
git commit -m "chore(hf-space): sync from monorepo"
git push origin main# 1. Install scanner_fixer (editable)
pip install -e packages/scanner_fixer
# 2. Install scanner-specific deps
pip install -r requirements-scanner.txt
# 3. Install tesseract binary (system package)
# Debian/Ubuntu:
sudo apt install tesseract-ocr tesseract-ocr-ara
# Arch/Manjaro:
sudo pacman -S tesseract tesseract-data-ara
# macOS:
brew install tesseract tesseract-lang
# 4. Run advanced review app (Tab 1 has new scanner features)
python app/advanced_review_app.py
# → Open http://localhost:7860
# → Tab "🔬 معالج الصور" → expand "✂️ قص يدوي" + "⚙️ كشف الحواف المتقدم"# In a Colab cell:
!git clone https://github.com/DrAbdulmalek/omni-medical-suite.git
%cd omni-medical-suite
!git checkout v1.1.0 # stable release
!pip install -e packages/scanner_fixer
!pip install -r requirements-scanner.txt
!apt-get install -y tesseract-ocr tesseract-ocr-ara
# Run Gradio (use share=True for public URL)
import sys; sys.path.insert(0, '.')
from app.advanced_review_app import build_app, demo
build_app().launch(share=True, debug=True)# Pre-built binary (recommended) — direct from GitHub Release
wget https://github.com/DrAbdulmalek/omni-medical-suite/releases/download/v1.1.0/MedicalDocProcessor-v1.1.0-x86_64.AppImage
wget https://github.com/DrAbdulmalek/omni-medical-suite/releases/download/v1.1.0/MedicalDocProcessor-v1.1.0-x86_64.AppImage.sha256
sha256sum -c MedicalDocProcessor-v1.1.0-x86_64.AppImage.sha256
chmod +x MedicalDocProcessor-v1.1.0-x86_64.AppImage
./MedicalDocProcessor-v1.1.0-x86_64.AppImage
# Build from source (advanced)
cd packages/desktop
bash build_appimage.sh --version-from-git --smoke-testFor full Manjaro prerequisites (pacman packages, yay, Wayland notes, troubleshooting), see docs/APPIIMAGE_MANJARO.md.
# Mobile uses the HF Space backend — no separate deployment
# Just point your mobile app/PWA to:
# https://DrAbdulmalek-omni-medical-ocr.hf.spaceNone. All P0 changes are backward-compatible:
app/services/ocr_service.pykeepspaddle_ocr,HAS_TESSERACT,spell_checker,proofreader,ner,HAS_LLMas module-level attributes via PEP 562__getattr__. Existing call sites work unchanged.app/gradio_full_hitl.pystill importstranslate_textfrom its old location (re-exported fromtranslation_service).app/services/hf_dataset_service.pykeepssave_to_hf()signature unchanged; new functionsflush_queue()andcount_pending()are additive.app/advanced_review_app.pyprocess_single_image()adds 5 new optional parameters with defaults — existing call sites work unchanged.
-
HF dataset writes are now batched. A
save_to_hf()call appends to a local JSONL and only pushes whenOMNI_HF_FLUSH_THRESHOLD(default 25) rows accumulate. To flush manually:from app.services.hf_dataset_service import flush_queue flush_queue()
Or set
OMNI_HF_FLUSH_THRESHOLD=1for legacy per-save behavior (useful for debugging). -
OCR engines are constructed on first use, not at import. First call to
get_paddle_ocr()etc. will take longer (model loading); subsequent calls are cached. Failures are cached too — a missing dependency is not retried. -
Decision log emits to stderr by default. In production, attach a JSON-lines file handler to the
app.decision_loglogger to ship decisions to your log aggregator.
| Variable | Default | Purpose |
|---|---|---|
OMNI_HF_QUEUE_DIR |
~/.omni/hf_dataset_queue |
Directory for staging JSONL files |
OMNI_HF_FLUSH_THRESHOLD |
25 |
Number of staged rows that trigger a batched push |
The verification step in scripts/sync-hf-space.sh --verify revealed:
hf-space/packages/nlp/translation_corrector/was deleted in the monorepo but the snapshot still has ithf-space/packages/core/mobile/was added in the monorepo but missing from the snapshothf-space/packages/core/engine_router.pyhas minor drift
Fix: Run ./scripts/sync-hf-space.sh (default mode) and commit the result. This will bring the snapshot in sync.
If v1.1.0 stable introduces a regression, roll back by checking out the previous main:
git checkout main
git reset --hard v1.0.0 # legacy stable
git push --force-with-lease origin mainOr revert individual P0/P1/P2 commits:
# Post-rc1 AppImage fixes (latest first)
git revert 25a6198 # docs(readme): direct download link
git revert a121b8c # fix(appimage): root icon naming
git revert 9225884 # fix(appimage): ARCH env var
git revert bf34b84 # fix(appimage): .desktop + icon at AppDir root
# P2 reverts
git revert ecb150c # P2-3 + P2-4: RC Checklist + LFS migration plan
git revert 5e2e45f # P2-2: CI matrix
git revert 63c58cd # P2-1: AppImage hardening
# P1 reverts
git revert bcd5c73 # P1-4: Git LFS audit
git revert e8ea063 # P1-3: decision instrumentation
git revert e9ffdde # P1-2: benchmark reporter
git revert 5b70816 # P1-1: field extractor hardening
# P0 reverts
git revert 4321b31 # P0-2: scanner tab
git revert e2e1d1b # P0-1: deploy source of truth
git revert 6a23c52 # P0: lazy loading + translation + HF staging + decision logBackup branches available:
backup/before-p0-1-p0-2-work→ points at6a23c52(post-P0 patch, pre-P0-1/P0-2)backup/before-p1-work→ points atd4a170f(post-P0, pre-P1)backup/before-p2-work→ points at22d0aff(post-P1, pre-P2)backup/before-v1.1.0-stable→ points at098e9b9(post-rc1, pre-stable promotion)