Modular Moral Reasoning

Turn philosophy into math, then test it, compare it & explain it.

We’re building a small, transparent engine where ethical theories become modular programs evaluated on shared scenarios. Facts live in causal models. Values live in normative modules. Disagreement is handled by explicit moral uncertainty, no hand-waving.

Why

Clarity over rhetoric

Debates drift, math commits. We expose assumptions, score actions, & show where theories truly diverge.

How

Modular ethics

Consequentialism, deontology, virtue & more become plug-in evaluators with shared inputs & comparable outputs.

What

Auditable results

Each recommendation ships with a minimal explanation set: the few premises that did the real work.

Purpose

Build a reproducible testbed for ethics that (1) separates facts from values, (2) lets multiple theories run side-by-side on the same scenario, & (3) aggregates disagreement under explicit credences with safeguard constraints.

Framework (small but honest)

World models carry the facts. Normative modules carry the values. Aggregation handles pluralism. Constraints protect rights.

Formal core (plain math)
// Consequentialism
CW_cons(a) = E[ Σ_i w_i · v(U_i(O)) | a, M ]

// Deontology (admissibility)
Admissible(a) iff ∀k: g_k(a, M) ≤ 0

// Virtue (trait distance)
CW_virtue(a) = - || T_after(a) - T* ||

// Moral uncertainty (normalized to [0,1])
CW(a) = Σ_j p_j · f_j( CW_j(a) )  over admissible actions
Scenario schema (JSON)
{
  "id": "string",
  "context": {"domain": "triage|evacuation|policy", "tags": ["emergency"]},
  "agents": [{"id": "A", "baseline": {"wellbeing": 0.55, "years_left": 35}, "consent": true}],
  "actions": ["a1","a2"],
  "outcomes": {"a1": [{"p":0.8,"A":{"alive":true,"years_gain":35}}], "a2": []},
  "constraints": {"no_intentional_harm_innocent": true, "treat_like_cases_alike": true}
}

Example Scenarios

Two simple dilemmas we’ll use for first runs. Transparent, parameterized, & easy to audit.

Scenario 1: Clinical triage - one ventilator, two patients

ID: triage-vent-v1

{
  "agents": [
    {"id":"A","baseline":{"wellbeing":0.55,"years_left":35},"consent":true,"survival":{"vent":0.80,"no_vent":0.10}},
    {"id":"B","baseline":{"wellbeing":0.55,"years_left":35},"consent":true,"survival":{"vent":0.60,"no_vent":0.55}}
  ],
  "actions":["a1_allocate_A","a2_allocate_B","a3_lottery"],
  "notes":"Prognosis differences count as relevant; lottery allowed when differences are small."
}
Scenario 2: Flood evacuation - promise vs numbers

ID: evac-promise-v1

{
  "context":{"tags":["flood","resource-scarce"]},
  "agents":["D1(elderly)","D2","D3","D4","D5","R(rescuer_with_promise_to_D1)"],
  "boat_capacity":3,
  "prob_survive_if_rescued":0.95,
  "prob_if_delayed":{"east":0.40,"west":0.60},
  "actions":["b1_east_now","b2_west_plus_one_east","b3_mixed_break_promise"]
}

Axiom Ledger v0.1

  • A1. Persons have equal moral worth.
  • A2. Comparable goods are explicitly scaled within each scenario.
  • A3. Uncertainty is modeled; guesses are distributions.
  • A4. Rights/duties act as side-constraints (lexicographic priority).
  • A5. Doing vs allowing matters but is not decisive alone.
  • A6. Consent changes scores & constraint triggers.
  • A7. Priority to the worse-off via concavity/priority.
  • A8. Like cases alike; only prognosis-relevant differences justify unequal treatment.
  • A9. Minimal explanations: identify the few premises that did the work.
  • A10. Pluralism is explicit; red lines are not aggregative.
  • A11. Culture tunes parameters, not personhood.
  • A12. Reversibility check flags unstable rules.

Project Log

Weekly, concise, reproducible. Each entry links to code, parameters, & results.

Week 0 - Scaffold

Drafted axiom ledger, scenario schema, & two seed dilemmas. Next: implement three modules (consequentialist, deontic constraints, virtue distance) & run sensitivity on credences.

Week 1 - First Runs

Baseline results for triage & evacuation. Interactive dashboard at interactive results.