Skip to content

The rules: policies as obligations and prohibitions#

Case study · Airline

A policy written for people reads like this: "A refundable fare that has not been flown is refunded to the original form of payment." A language model can repeat that sentence and still promise something it does not say. This page turns each sentence into a logical statement: a law the engine runs and the kernel can check. After that, the only thing that can commit the airline is a norm derived from those laws.

Source: Policy.hs · Policy.hp · data/policies.json

Reading a norm#

Deontic logic has three words, which you met in Duty:

Symbol Reads In Policy.hs
O(i) a party i is obliged to do a obliged(m, i, a, source)
F(i) a party i is forbidden to do a forbidden(m, i, a, source)
P(i) a party i is permitted to do a: nothing forbids it permitted(m, i, a)

Every norm carries four things, and each one closes a door a tricky question could use:

  • m, a moment. A norm holds at a time. Why that matters is the whole of time.md.
  • i, a party. The airline and the assistant are different parties with different norms.
  • a, an act. A closed vocabulary: refund, bereavement_fare, travel_credit.
  • source, a policy id. No norm exists without the policy that creates it, so every reply can say which policy it rests on.

The policies, one law each#

The facts a law reads come from two places. The booking record (bookings.json) says whether the trip was flown, the kind of fare, and whether the airline cancelled. The customer's message says what they ask for and whether a death in the family is the reason. The model never supplies a booking fact.

Bereavement fares#

BRV-1 A reduced bereavement fare is available for travel because of the death of an immediate family member. It must be requested before the trip.

BRV-2 A bereavement fare cannot be applied to travel that has already been completed.

law bereavementBefore = ∀ m, request(m, "bereavement_fare") ∧ bereavement(m) ∧ ¬ flown(m) ⇒ obliged(m, "airline", "bereavement_fare", "BRV-1")
law notABereavement   = ∀ m, request(m, "bereavement_fare") ∧ ¬ bereavement(m) ∧ ¬ flown(m) ⇒ forbidden(m, "airline", "bereavement_fare", "BRV-1")
law bereavementAfter  = ∀ m, request(m, "bereavement_fare") ∧ flown(m) ⇒ forbidden(m, "airline", "bereavement_fare", "BRV-2")

Read the first law aloud: at any moment m, if a bereavement fare is requested, there is a bereavement, and the trip is not flown, then the airline is obliged to give the bereavement fare, because of BRV-1. BRV-2 is the norm the Moffatt chatbot contradicted.

Note what a single policy sentence became. "Must be requested before the trip" turned into two laws: an obligation when the conditions hold, and a prohibition when there is no bereavement. A policy written for people leaves the "otherwise" implicit. A law has to say it, or the otherwise is simply unknown.

Refunds#

law refundable       = ∀ m, request(m, "refund") ∧ fare(m, "refundable") ∧ ¬ flown(m) ⇒ obliged(m, "airline", "refund", "REF-1")
law nonRefundable    = ∀ m, request(m, "refund") ∧ fare(m, "nonrefundable") ∧ ¬ flown(m) ∧ ¬ cancelledByAirline(m) ⇒ forbidden(m, "airline", "refund", "REF-2")
law keptAsCredit     = ∀ m, request(m, "refund") ∧ fare(m, "nonrefundable") ∧ ¬ flown(m) ∧ ¬ cancelledByAirline(m) ⇒ obliged(m, "airline", "travel_credit", "REF-2")
law airlineCancelled = ∀ m, request(m, "refund") ∧ cancelledByAirline(m) ⇒ obliged(m, "airline", "refund", "REF-3")
law alreadyFlown     = ∀ m, request(m, "refund") ∧ flown(m) ∧ ¬ cancelledByAirline(m) ⇒ forbidden(m, "airline", "refund", "REF-4")
Booking Asked Norms derived
RFD512 refundable, not flown refund O(airline) refund REF-1
FUT315 non-refundable, not flown refund F(airline) refund REF-2 and O(airline) travel_credit REF-2
CXL777 cancelled by the airline refund O(airline) refund REF-3
MOF240 flown refund F(airline) refund REF-4
MOF240 flown bereavement fare F(airline) bereavement_fare BRV-2

REF-2 shows why a norm is better than a yes/no answer. The same policy forbids one act and obliges another, and the reply says both: no refund, but you keep a travel credit.

CHAT-1: the rule the Moffatt chatbot lacked#

The policies above say what the airline owes. None of them says anything about what the chatbot may say. That gap is the Moffatt case. So the assistant is a party too, and its acts are promises:

law promiseOnlyWhatIsOwed = ∀ m a, moment(m) ∧ act(a) ∧ ¬ ought(m, "airline", a) ⇒ forbidden(m, "assistant", a, "CHAT-1")

law owes     = ∀ m i a _source, obliged(m, i, a, _source) ⇒ ought(m, i, a)
law mustNot  = ∀ m i a _source, forbidden(m, i, a, _source) ⇒ oughtNot(m, i, a)
law violates = ∀ m i a, oughtNot(m, i, a) ∧ did(m, i, a) ⇒ violation(m, i, a)

The assistant is forbidden to promise any act the airline is not obliged to perform. Promising is therefore forbidden by default and permitted only where an obligation exists. That default is the most important design choice in the file. The general rule "what is not forbidden is permitted" is fine for what a customer may do. It is dangerous for what a company commits to. For commitments the default is reversed.

Each model call returns a promise field saying what its text commits the airline to. The host asserts that as an act, did(m, "assistant", promise), and asks the engine for violations:

review  The model's draft promised a bereavement fare, which the airline is not obliged to give for
        booking MOF240 now; promising it violates CHAT-1. The draft was withheld.

A word the model invents, such as "full_refund_and_voucher", is not tidied into "nothing". It is asserted like any other promise. No policy obliges it, so it is a violation.

The agent: choosing the kind of reply#

Before any norm is asked for, Assistant.ha decides what kind of reply the message gets:

intend Answer  for Answered when B(self) topic("in") ∧ B(self) booking("yes")
intend Clarify for Answered when B(self) topic("in") ∧ B(self) booking("no")

impossible Answered when B(self) topic("out") because "That is not about a refund or a bereavement fare, and no written policy here covers it — please contact an agent"

A question the book does not cover (baggage, seats, anything else) is not answered from the model's general knowledge. It is impossible, and the reason in the source is what the customer reads. An honest refusal is a correct reply. Answering from general knowledge is how the Moffatt chatbot got into trouble.

The order of a reply is a plan, Reply.hk. It has no path to print that goes around review:

plan AnswerSteps(act: chan Word, done: chan Word) : Assistant ≔ "review" → act ; v ← done ; match v { … } ; "format" → act ; f ← done ; match f { when "formatted" ↦ SKIP  other ↦ "fallback" → act ; g ← done } ; "print" → act ; p ← done ; believe replied(1)

The frame, and what the kernel proves#

O is a real modality, not a label. ideal(i, m, u) means u is a situation in which party i does everything it ought to at m:

modality O(i) over ideal at holds

law serialO = ∀ i w u, idealSeed(i, w, u) ⇒ ideal(i, w, u)                 -- axiom D
law atIdeal = ∀ i a w u, ought(w, i, a) ∧ ideal(i, w, u) ⇒ holds(u, a)

Axiom D says every situation has an ideal. So nothing can be obliged and forbidden at once, since no ideal situation could satisfy both. The engine checks that too: conflict(m, i, a) must come back empty for every booking, and PolicyTests asks.

Policy.hp proves, and the build refuses to compile if any of these stop checking:

Theorem Says
every_seeded_situation_has_an_ideal axiom D
what_a_policy_obliges_holds_wherever_things_are_ideal the meaning of O
doing_what_a_policy_forbids_is_a_violation a forbidden act done is a violation, whoever says otherwise
two_steps_are_later, flying_leaves_the_trip_flown_two_moments_on time: see time.md
a_bereavement_fare_asked_for_after_flying_is_forbidden the Moffatt case, as a theorem
so_granting_it_anyway_is_a_violation and what granting it would be
a_cancellation_by_the_airline_obliges_a_refund REF-3

The laws with ¬ run in the engine and are tested rather than proved. That is how negation is handled throughout this repository, as on the Logic pages.

What every reply shows#

policy  REF-4   F(airline) refund     after you fly   Completed travel is not refunded
policy  REF-1   O(airline) refund     until you fly   Refundable fares are refunded

The customer sees the norm, the moment it holds, and the policy it comes from. A reply that cannot show a norm cannot commit the airline. That is the guarantee the Moffatt ruling says a company needs.