Skip to content

Repository files navigation

Almirath (الميراث) — Islamic inheritance for Android

A production Android app around a pure-Kotlin, exact-arithmetic inheritance engine supporting all four Sunni schools.

The engine is the product. The Android app is a way to reach it.

78 rules · 55 golden cases · 188 school-by-school assertions · 20,000 generated cases per test run

Play Console steps, listing copy, and the privacy policy: play/PLAY_CONSOLE.md.

iOS app and App Store steps: Almirath-iOS (security and publishing are in that README).


Status of this repository

Layer State
:core — exact Fraction, Money, allocator, domain model Verified
:engine — exclusion, prescribed shares, residuaries, ʿawl, radd, four-school policies Verified
:testing-fixtures — golden corpus Hand-computed from classical sources
:data — Room, DataStore, report export Shipping
:feature — Compose screens, ViewModels Shipping
:app — navigation, DI, Ledger theme Shipping · Play target API 36

Getting it running

1. Prerequisites

  • Android Studio, current stable
  • JDK 17
  • Android SDK Platform 36

2. Engine only (no Android SDK required)

./gradlew :core:test :engine:test

3. Debug on a device

./gradlew :app:installDebug

4. Release bundle for Play

Requires keystore.properties (see keystore.properties.example). Then:

./gradlew :app:bundleRelease

5. Everything else

./gradlew test                      # all JVM tests
./gradlew :engine:test --tests '*Golden*'   # just the corpus
./gradlew lint
./gradlew connectedCheck            # device tests

How the engine works

Nine stages, each a pure function of its input. No clock, no locale, no randomness — which is what lets the property tests assert byte-identical results across runs.

InheritanceCase (relatives + estate + school)
        │
  1  Validate ───────────────► InvalidInput
        │
  2  Derive facts once (CaseFacts)
        │
  3  Exclusion (ḥajb) ───────► every excluded relative keeps its blocker and rule code
        │
  4  Prescribed shares (farḍ)
        │
  4b Al-Mushtarakah, if that shape
  4c Grandfather with siblings ─► RequiresScholarReview when contested
        │
  5  Residuary selection (ʿaṣabah), by explicit priority chain
        │
  6  Settlement:  > 1 → ʿawl   ·   = 1 → exact   ·   < 1 → residue, radd, or treasury
        │
  7  Verify sum == 1 exactly ─► throws rather than showing a wrong distribution
        │
  8  Money, per individual, largest-remainder — every minor unit conserved
        │
  9  Explanation and audit trace
        ▼
  Completed | InvalidInput | RequiresScholarReview

Three decisions that carry the whole design

Exact fractions, never floating point. Shares are rational numbers. A Double engine eventually totals 0.9999999998 and misallocates money. Fraction is BigInteger-backed and always in lowest terms, so 2/4 == 1/2 structurally. CI greps the rule path for Double and Float and fails the build if either appears.

Exclusion is its own stage. That is what lets the results screen say "your brother receives nothing because your son survives" instead of quietly omitting him. Every excluded relative carries a blocker and a rule code, and a property test asserts no relative ever vanishes from a result.

Refusal is a supported outcome. RequiresScholarReview is returned for three configurations the schools genuinely do not settle. Producing a confident number there would be the most damaging thing this app could do.

Money

Allocated per individual, not per class, using largest-remainder. Three heirs dividing 100 cents receive 34, 33, 33 — and the UI explains why they differ. Currency exponents are respected: Kuwaiti dinar has three decimal places, yen has none. A property test asserts sum(allocated) == estate on every generated case.


Four schools without four engines

One shared rule set plus six policy flags. The schools agree on every prescribed fraction, the whole exclusion chain, ʿawl, and the two-to-one weighting.

Question Hanafi Maliki Shafi'i Hanbali
Grandfather with brothers Excludes them Shares Shares Shares
Surplus with no residuary Returns to heirs Treasury Treasury Returns to heirs
Surplus to a lone spouse Yes No No No
Al-Mushtarakah Brothers get nothing They share They share Brothers get nothing
Father excludes his own mother Yes Yes Yes No
Distant kindred inherit Yes No No Yes

Full reasoning, with the golden case for each row, in docs/madhhab-divergence.md.


Testing

Layer What it proves
FractionTest, MoneyTest Arithmetic is exact; every minor unit is conserved across 2,000 estate sizes
BlockingAndValidationTest Each exclusion rule gets a fires / does-not-fire / stronger-rule-wins triple
GoldenCorpusTest 55 hand-computed cases across 188 school combinations
PropertyInvariantTest 20,000 generated families: shares sum to one, money conserved, determinism, order invariance, scale invariance, nobody vanishes
CalculatorViewModelTest State mapping, validation, step skipping, save failure recovery

The golden corpus is the part that matters most. Every expected value was worked out from the classical rules by hand, so it is an independent check rather than a mirror of the code. If a resolver is rewritten and a case still passes, the rewrite preserved the ruling.

Changing an expected value in the corpus is changing a ruling, not fixing a test. The rules-review CI job prints the affected rule codes and case IDs on any pull request that touches them, so a domain reviewer can see what moved without reading Kotlin.


Before this ships

  1. Domain review. Give your reviewer docs/rule-catalog.md — 78 rules with sources, the refusal list, and all 55 golden cases with expected fractions. It requires no Kotlin. Nothing should be marked production-enabled before that review is complete.
  2. Confirm the two policy calls flagged at the end of docs/madhhab-divergence.md: surplus to a lone spouse, and the treasury outcome where no treasury exists.
  3. Compile and run the Android layers, then the accessibility pass at 200% font scale and one RTL smoke test.
  4. Room migrations — never add fallbackToDestructiveMigration(). Losing a family's saved calculations on an app update is not an acceptable failure mode.
  5. Privacy — the manifest has no INTERNET permission and backup is disabled. Keep it that way. Store listing copy and the public privacy policy are in play/. Store-signing notes: Almirath-iOS README.

Layout

core/                exact arithmetic, domain model, repository interfaces   (Kotlin/JVM)
engine/              rules, resolvers, calculator, trace                     (Kotlin/JVM)
testing-fixtures/    golden corpus                                          (Kotlin/JVM)
data/                Room, DataStore, report export                         (Android library)
feature/             Compose screens and ViewModels                         (Android library)
app/                 navigation, DI wiring, theme                           (Android application)
docs/                architecture, rule catalog, divergence, UX spec
tools/verify/        offline test harness — see below

tools/verify/ contains a JUnit shim and a reflective runner used to execute the real test sources without the JUnit platform, in an environment with no Maven access. It is not part of the Gradle build and should be deleted once your first ./gradlew test runs green.


Disclaimer

This software applies the rules of the school selected by the user. It is not a legal ruling and not a substitute for advice from a qualified scholar or from a lawyer in your jurisdiction. Civil probate law may distribute an estate differently from this calculation.

About

Almirath (الميراث) — Islamic inheritance calculator for Android. Four Sunni schools, on-device only.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages