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).
| 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 |
- Android Studio, current stable
- JDK 17
- Android SDK Platform 36
./gradlew :core:test :engine:test./gradlew :app:installDebugRequires keystore.properties (see keystore.properties.example). Then:
./gradlew :app:bundleRelease./gradlew test # all JVM tests
./gradlew :engine:test --tests '*Golden*' # just the corpus
./gradlew lint
./gradlew connectedCheck # device testsNine 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
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.
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.
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.
| 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.
- 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. - 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. - Compile and run the Android layers, then the accessibility pass at 200% font scale and one RTL smoke test.
- Room migrations — never add
fallbackToDestructiveMigration(). Losing a family's saved calculations on an app update is not an acceptable failure mode. - 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.
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.
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.