Skip to content

Research · Lean source

PeopleDevelopment.lean

The file exactly as Lean, a program that checks every step of a proof, checks it: 48 theorems in 455 lines.

What is proved, and what is not

import Std

/- Task-specific apprenticeship: finite public-policy verification and exact
   hidden-state witnesses. Lean 4.24.0 / Std only. Learning and observation
   kernels are premises; authorization is an organizational rule. The concrete
   witnesses evaluate fixed curricula, not a claim of general curriculum
   optimality or empirical calibration. -/
namespace PeopleDevelopment

variable {S A O D : Type}

def sumOver {α : Type} : List α → (α → Rat) → Rat
  | [], _ => 0
  | x :: xs, f => f x + sumOver xs f

theorem sumOver_mono {α : Type} (xs : List α) (f g : α → Rat)
    (h : ∀ x, x ∈ xs → f x ≤ g x) : sumOver xs f ≤ sumOver xs g := by
  induction xs with
  | nil => exact Rat.le_refl
  | cons x xs ih =>
    have hh := h x (by simp)
    have ht := ih (fun y hy => h y (by simp [hy]))
    simp only [sumOver]
    grind

structure Model (S A O D : Type) where
  outcomes : List O
  actions : S → A → Prop
  terminals : S → D → Prop
  payoff : S → D → Rat
  next : S → A → O → S
  charge : S → A → Rat

inductive Policy (A O D : Type) : Nat → Type where
  | stop {n : Nat} (decision : D) : Policy A O D n
  | step {n : Nat} (action : A) (next : O → Policy A O D n) : Policy A O D (n+1)

def evaluate (m : Model S A O D) : (n : Nat) → S → Policy A O D n → Rat
  | 0, s, .stop d => m.payoff s d
  | _n+1, s, .stop d => m.payoff s d
  | n+1, s, .step a k =>
      -m.charge s a + sumOver m.outcomes (fun o => evaluate m n (m.next s a o) (k o))

def Feasible (m : Model S A O D) : (n : Nat) → S → Policy A O D n → Prop
  | 0, s, .stop d => m.terminals s d
  | _n+1, s, .stop d => m.terminals s d
  | n+1, s, .step a k =>
      m.actions s a ∧ ∀ o, o ∈ m.outcomes → Feasible m n (m.next s a o) (k o)

/-- A local certificate covers every public-history policy, not just the
    policy used to propose the certificate. All branch masses live in S. -/
structure UpperCertificate (m : Model S A O D) (v : Nat → S → Rat) : Prop where
  terminal : ∀ n s d, m.terminals s d → m.payoff s d ≤ v n s
  step : ∀ n s a, m.actions s a →
    -m.charge s a + sumOver m.outcomes (fun o => v n (m.next s a o)) ≤ v (n+1) s

theorem certificate_bounds_every_policy (m : Model S A O D) (v : Nat → S → Rat)
    (cert : UpperCertificate m v) (n : Nat) (s : S) (p : Policy A O D n)
    (hp : Feasible m n s p) : evaluate m n s p ≤ v n s := by
  induction n generalizing s with
  | zero =>
    cases p with
    | stop d => exact cert.terminal 0 s d hp
  | succ n ih =>
    cases p with
    | stop d => exact cert.terminal (n+1) s d hp
    | step a k =>
      obtain ⟨ha, hk⟩ := hp
      have hs := sumOver_mono m.outcomes
        (fun o => evaluate m n (m.next s a o) (k o))
        (fun o => v n (m.next s a o))
        (fun o ho => ih (m.next s a o) (k o) (hk o ho))
      have hc := cert.step n s a ha
      simp only [evaluate]
      grind

theorem attained_certificate_is_optimal (m : Model S A O D) (v : Nat → S → Rat)
    (cert : UpperCertificate m v) (n : Nat) (s : S) (recommended : Policy A O D n)
    (hf : Feasible m n s recommended) (he : evaluate m n s recommended = v n s) :
    Feasible m n s recommended ∧ ∀ p, Feasible m n s p →
      evaluate m n s p ≤ evaluate m n s recommended := by
  refine ⟨hf, ?_⟩
  intro p hp
  rw [he]
  exact certificate_bounds_every_policy m v cert n s p hp

/-- An optional route preserves a feasible local policy without claiming that
    coordination itself changes its production technology. -/
theorem optional_route_preserves_local (localValue coordinated : Rat) :
    localValue ≤ (if localValue ≤ coordinated then coordinated else localValue) := by
  split <;> grind

/- Concrete four-world process. The exact witnesses use two actions, although
   the generic policy theorem above is valid for every finite horizon. -/
inductive Activity where
  | mentor | practice | scaffold | assess
  deriving DecidableEq, Repr
inductive Observation where
  | positive | negative | missing
  deriving DecidableEq, Repr
inductive Mode where
  | idle | independent | assisted
  deriving DecidableEq, Repr

abbrev World := Bool × Bool
abbrev Weights := World → Rat
abbrev Flags := Bool × Bool
abbrev Action := Activity × Bool

def worlds : List World := [(false,false),(true,false),(false,true),(true,true)]
def observations : List Observation := [.positive,.negative,.missing]
def skill (x : World) (second : Bool) : Bool := if second then x.2 else x.1
def change (x : World) (second value : Bool) : World :=
  if second then (x.1,value) else (value,x.2)

structure Environment where
  demand : Nat
  expert : Bool
  tool : Bool
  first : Bool
  second : Bool
  deriving DecidableEq, Repr
structure Assignment where
  expert : Bool
  first : Mode
  second : Mode
  deriving DecidableEq, Repr
abbrev Decision := Environment → Assignment

structure Configuration where
  mentorLearning : Rat := 3/4
  scaffoldLearning : Rat := 1/4
  sensitivity : Rat := 3/4
  falsePositive : Rat := 1/4
  retention : Rat := 1
  gate : Bool := true
  budget : Nat := 3
  environments : List (Rat × Environment)

structure State where
  weights : Weights
  authorization : Flags
  budget : Nat

def learning (c : Configuration) : Activity → Rat
  | .mentor => c.mentorLearning
  | .practice => 1/2
  | .scaffold => c.scaffoldLearning
  | .assess => 0

def units : Activity → Nat
  | .mentor => 2
  | .assess => 1
  | _ => 0

def cost : Activity → Rat
  | .mentor => 1
  | .practice => 1/2
  | .scaffold => 1/4
  | .assess => 1/4

/-- Concrete learning retains existing skill; the JS interface additionally
    supports activity-specific negative-transfer probabilities. -/
def targetCompetence (c : Configuration) (a : Activity) (old : Bool) : Rat :=
  if old then 1 else learning c a

def transition (c : Configuration) (a : Action) (x y : World) : Rat :=
  if change x a.2 (skill y a.2) = y then
    if skill y a.2 then targetCompetence c a.1 (skill x a.2)
    else 1 - targetCompetence c a.1 (skill x a.2)
  else 0

def likelihood (c : Configuration) (a : Activity) (competent : Bool) : Observation → Rat
  | .missing => 0
  | .positive => if a = .assess then (if competent then c.sensitivity else c.falsePositive) else 1
  | .negative => if a = .assess then 1 - (if competent then c.sensitivity else c.falsePositive) else 0

def childWeights (c : Configuration) (w : Weights) (a : Action) (o : Observation) : Weights :=
  fun y => likelihood c a.1 (skill y a.2) o * sumOver worlds (fun x => w x * transition c a x y)

def childFlags (g : Flags) (a : Action) (o : Observation) : Flags :=
  change g a.2 (decide (a.1 = .assess ∧ o = .positive))

def initial (c : Configuration) : State :=
  { weights := fun x => if x = (false,false) then 1 else 0
    authorization := (false,false), budget := c.budget }

def next (c : Configuration) (s : State) (a : Action) (o : Observation) : State :=
  { weights := childWeights c s.weights a o
    authorization := childFlags s.authorization a o
    budget := s.budget - units a.1 }

def jobs (a : Assignment) : Nat :=
  (if a.expert then 1 else 0) + (if a.first = .idle then 0 else 1) + (if a.second = .idle then 0 else 1)

def learnerAllowed (c : Configuration) (authorized available tool : Bool) (m : Mode) : Prop :=
  m = .idle ∨ (available = true ∧ (m = .independent → c.gate = false ∨ authorized = true) ∧
    (m = .assisted → tool = true))
instance (c : Configuration) (authorized available tool : Bool) (m : Mode) :
    Decidable (learnerAllowed c authorized available tool m) := by unfold learnerAllowed; infer_instance

def allowed (c : Configuration) (g : Flags) (e : Environment) (a : Assignment) : Prop :=
  jobs a ≤ e.demand ∧ (a.expert = true → e.expert = true) ∧
  learnerAllowed c g.1 e.first e.tool a.first ∧ learnerAllowed c g.2 e.second e.tool a.second
instance (c : Configuration) (g : Flags) (e : Environment) (a : Assignment) :
    Decidable (allowed c g e a) := by unfold allowed; infer_instance

def learnerReward (c : Configuration) (competent : Bool) : Mode → Rat
  | .idle => 0
  | .assisted => 4
  | .independent => if competent then c.retention * 8 + (1-c.retention) * (-24) else -24

def reward (c : Configuration) (x : World) (a : Assignment) : Rat :=
  (if a.expert then 8 else 0) + learnerReward c x.1 a.first + learnerReward c x.2 a.second

def terminalValue (c : Configuration) (s : State) (d : Decision) : Rat :=
  sumOver c.environments (fun pe => pe.1 * sumOver worlds (fun x => s.weights x * reward c x (d pe.2)))

def concreteModel (c : Configuration) : Model State Action Observation Decision where
  outcomes := observations
  actions := fun s a => units a.1 ≤ s.budget
  terminals := fun s d => ∀ pe ∈ c.environments, allowed c s.authorization pe.2 (d pe.2)
  payoff := terminalValue c
  next := next c
  charge := fun s a => sumOver worlds s.weights * cost a.1

/-- These are conditional structural properties, not a claim that tests have
    no false positives. They hold independently of the learning probabilities. -/
theorem authorized_target_iff_assessment_pass (g : Flags) (a : Action) (o : Observation) :
    skill (childFlags g a o) a.2 = true ↔ a.1 = .assess ∧ o = .positive := by
  rcases a with ⟨a, second⟩
  cases second <;> simp [childFlags, change, skill]

theorem missing_revokes (g : Flags) (a : Action) :
    skill (childFlags g a .missing) a.2 = false := by
  rcases a with ⟨a, second⟩
  cases a <;> cases second <;> simp [childFlags, change, skill]

theorem capacity_of_allowed (c : Configuration) (g : Flags) (e : Environment) (a : Assignment)
    (h : allowed c g e a) : jobs a ≤ e.demand := h.1

theorem budget_conservation (c : Configuration) (s : State) (a : Action) (o : Observation)
    (h : (concreteModel c).actions s a) : units a.1 + (next c s a o).budget = s.budget := by
  change units a.1 ≤ s.budget at h
  simp only [next]
  omega

/-- No observation about the other learner is discarded: this kernel sums
    full joint-world weights, permitting correlated priors. -/
theorem uninformative_completion (c : Configuration) (w : Weights) (a : Action)
    (ha : a.1 ≠ .assess) (y : World) :
    childWeights c w a .positive y = sumOver worlds (fun x => w x * transition c a x y) := by
  simp [childWeights, likelihood, ha]


/-- Both concrete kernels have total mass one before multiplying parent mass. -/
theorem observation_rows_normalized (c : Configuration) (a : Activity) (s : Bool) :
    sumOver observations (likelihood c a s) = 1 := by
  cases a <;> cases s <;> simp [observations, sumOver, likelihood] <;> grind

theorem transition_rows_normalized (c : Configuration) (a : Action) (x : World) :
    sumOver worlds (transition c a x) = 1 := by
  rcases a with ⟨a, i⟩
  rcases x with ⟨f, s⟩
  cases a <;> cases i <;> cases f <;> cases s <;>
    simp [worlds, sumOver, transition, targetCompetence, learning, skill, change] <;> grind

/-- The complete joint transition-and-observation filter conserves mass.
    This identity does not replace the separate nonnegativity assumptions
    required when interpreting the weights as probabilities. -/
theorem joint_filter_mass_conservation (c : Configuration) (w : Weights) (a : Action) :
    sumOver observations (fun o => sumOver worlds (childWeights c w a o)) = sumOver worlds w := by
  rcases a with ⟨a, i⟩
  cases a <;> cases i <;>
    simp [observations, worlds, sumOver, childWeights, likelihood, transition,
      targetCompetence, learning, change, skill] <;> grind

def normal : Environment := ⟨2,true,false,true,true⟩
def base : Configuration := { environments := [(1,normal)] }

def dispatch (deploy : Bool) (e : Environment) : Assignment :=
  let useExpert := e.expert && decide (0 < e.demand)
  let room := decide ((if useExpert then 1 else 0) < e.demand)
  { expert := useExpert
    first := if e.first && room then (if deploy then .independent else if e.tool then .assisted else .idle) else .idle
    second := .idle }

def mentorAssessment (deploy : Bool) : Policy Action Observation Decision 2 :=
  .step (.mentor,false) (fun o => match o with
    | .positive => .step (.assess,false) (fun q =>
        .stop (dispatch (deploy && decide (q = .positive))))
    | _ => .stop (dispatch false))

def scaffoldAssessment : Policy Action Observation Decision 2 :=
  .step (.scaffold,false) (fun o => match o with
    | .positive => .step (.assess,false) (fun q => .stop (dispatch (decide (q = .positive))))
    | _ => .stop (dispatch false))

def mentorPractice : Policy Action Observation Decision 2 :=
  .step (.mentor,false) (fun o => match o with
    | .positive => .step (.practice,false) (fun q => .stop (dispatch (decide (q = .positive))))
    | _ => .stop (dispatch false))

def fixedValue (c : Configuration) (p : Policy Action Observation Decision 2) : Rat :=
  evaluate (concreteModel c) 2 (initial c) p

def stopValue (c : Configuration) : Rat := fixedValue c (.stop (dispatch false))

def passState (c : Configuration) : State :=
  next c (next c (initial c) (.mentor,false) .positive) (.assess,false) .positive

theorem favorable_true_positive_mass : (passState base).weights (true,false) = 9/16 := by decide +kernel
theorem favorable_false_positive_mass : (passState base).weights (false,false) = 1/16 := by decide +kernel
theorem favorable_pass_mass : sumOver worlds (passState base).weights = 5/8 := by decide +kernel
theorem favorable_fixed_curriculum : fixedValue base (mentorAssessment true) = 39/4 := by decide +kernel
theorem favorable_stop : stopValue base = 8 := by decide +kernel
theorem favorable_gain : stopValue base < fixedValue base (mentorAssessment true) := by decide +kernel

def oneJob : Configuration := { base with environments := [(1,{ normal with demand := 1 })] }
theorem one_job_fixed_curriculum_loss : fixedValue oneJob (mentorAssessment true) = 27/4 := by decide +kernel
theorem one_job_stop : stopValue oneJob = 8 := by decide +kernel

def independentAbsence : Configuration := { base with environments :=
  [(1/2,{normal with demand := 1}),(1/2,{normal with demand := 1, expert := false})] }
theorem independent_absence_value : fixedValue independentAbsence (mentorAssessment true) = 17/4 := by decide +kernel

def commonAbsence : Configuration := { base with environments :=
  [(1/2,{normal with demand := 1}),(1/2,⟨1,false,false,false,false⟩)] }
theorem common_absence_fixed_loss : fixedValue commonAbsence (mentorAssessment true) = 11/4 := by decide +kernel
theorem common_absence_stop : stopValue commonAbsence = 4 := by decide +kernel

def scarce : Configuration := { base with budget := 2 }
theorem mentor_then_assessment_exceeds_scarce_budget :
    ¬ (concreteModel scarce).actions (next scarce (initial scarce) (.mentor,false) .positive) (.assess,false) := by
  change ¬ (1 ≤ (0 : Nat))
  decide +kernel

def guardedScaffold : Configuration := { scarce with scaffoldLearning := 3/4 }
theorem guarded_scaffold_value : fixedValue guardedScaffold scaffoldAssessment = 21/2 := by decide +kernel

def reliableAI : Configuration := { base with environments := [(1,{normal with tool := true})] }
theorem reliable_AI_stop : stopValue reliableAI = 12 := by decide +kernel
theorem reliable_AI_curriculum_loss : fixedValue reliableAI (mentorAssessment true) = 45/4 := by decide +kernel

def AIOutages : Configuration := { base with environments := [(1/2,normal),(1/2,{normal with tool := true})] }
theorem AI_outages_curriculum : fixedValue AIOutages (mentorAssessment true) = 21/2 := by decide +kernel
theorem AI_outages_stop : stopValue AIOutages = 10 := by decide +kernel

def weakMentor : Configuration := { base with mentorLearning := 1/2 }
theorem weak_mentor_refused_deployment : fixedValue weakMentor (mentorAssessment false) = 27/4 := by decide +kernel

def forgetting : Configuration := { base with retention := 2/3 }
theorem forgetting_refused_deployment : fixedValue forgetting (mentorAssessment false) = 27/4 := by decide +kernel
theorem forgetting_frozen_policy_loss : fixedValue forgetting (mentorAssessment true) = 15/4 := by decide +kernel
theorem forgetting_stop_beats_frozen_policy : fixedValue forgetting (mentorAssessment true) < stopValue forgetting := by decide +kernel

def noisyAssessment : Configuration := { base with falsePositive := 1/2 }
theorem noisy_assessment_value : fixedValue noisyAssessment (mentorAssessment true) = 33/4 := by decide +kernel
theorem noisy_assessment_false_positive_mass : (passState noisyAssessment).weights (false,false) = 1/8 := by decide +kernel

def uninformativeAssessment : Configuration := { base with falsePositive := 3/4 }
theorem uninformative_assessment_refused_deployment : fixedValue uninformativeAssessment (mentorAssessment false) = 27/4 := by decide +kernel

def noGate : Configuration := { base with gate := false }
theorem ungated_practice_value : fixedValue noGate mentorPractice = 21/2 := by decide +kernel
theorem ungated_practice_exceeds_gated_witness : fixedValue base (mentorAssessment true) < fixedValue noGate mentorPractice := by decide +kernel

def afterMentorPractice (c : Configuration) : State :=
  next c (next c (initial c) (.mentor,false) .positive) (.practice,false) .positive

theorem ungated_bad_assignment_mass : (afterMentorPractice noGate).weights (false,false) = 1/8 := by decide +kernel

theorem identical_local_value : fixedValue base (mentorAssessment true) = 39/4 := favorable_fixed_curriculum

def mandatoryValue (c : Configuration) (fee : Rat) (p : Policy Action Observation Decision 2) : Rat := fixedValue c p - fee

theorem mandatory_fee_loss : mandatoryValue base 2 (mentorAssessment true) = 31/4 := by decide +kernel
theorem mandatory_fee_below_untrained_local : mandatoryValue base 2 (mentorAssessment true) < stopValue base := by decide +kernel


/-- The favorable numerical witness is a feasible complete policy, including
    all missing and zero-probability branches. -/
theorem favorable_policy_feasible :
    Feasible (concreteModel base) 2 (initial base) (mentorAssessment true) := by
  constructor
  · change (2 : Nat) ≤ 3
    decide +kernel
  · intro o _ho
    cases o with
    | positive =>
      constructor
      · change (1 : Nat) ≤ 1
        decide +kernel
      · intro q _hq
        cases q <;> simp [Feasible, concreteModel, base, normal, initial, next,
          childFlags, change, dispatch, allowed, learnerAllowed, jobs]
    | negative =>
      simp [Feasible, concreteModel, base, normal, initial, next,
        childFlags, change, dispatch, allowed, learnerAllowed, jobs]
    | missing =>
      simp [Feasible, concreteModel, base, normal, initial, next,
        childFlags, change, dispatch, allowed, learnerAllowed, jobs]

/-- The ungated opportunity-cost witness obeys the same physical budget. -/
theorem ungated_policy_feasible :
    Feasible (concreteModel noGate) 2 (initial noGate) mentorPractice := by
  constructor
  · change (2 : Nat) ≤ 3
    decide +kernel
  · intro o _ho
    cases o with
    | positive =>
      constructor
      · change (0 : Nat) ≤ 1
        decide +kernel
      · intro q _hq
        cases q <;> simp [Feasible, concreteModel, noGate, base, normal, initial, next,
          childFlags, change, dispatch, allowed, learnerAllowed, jobs]
    | negative =>
      simp [Feasible, concreteModel, noGate, base, normal, initial, next,
        childFlags, change, dispatch, allowed, learnerAllowed, jobs]
    | missing =>
      simp [Feasible, concreteModel, noGate, base, normal, initial, next,
        childFlags, change, dispatch, allowed, learnerAllowed, jobs]

/-- Symbolic identities are linked to the actual transition/filter/assignment
    evaluator. Valid probability inputs are required for their economic use. -/
theorem concrete_learning_value (l : Rat) :
    fixedValue {base with mentorLearning := l} (mentorAssessment true) = 3/4 + 12*l := by
  simp [fixedValue, evaluate, concreteModel, mentorAssessment, base, initial, next,
    terminalValue, sumOver, worlds, observations, childWeights, likelihood,
    transition, targetCompetence, learning, change, skill, dispatch, normal, cost, learnerReward, reward]
  <;> grind

theorem concrete_learning_threshold (l : Rat) :
    8 < fixedValue {base with mentorLearning := l} (mentorAssessment true) ↔ 29/48 < l := by
  rw [concrete_learning_value]
  have hc : (3/4 : Rat) + 12*(29/48) = 8 := by decide +kernel
  grind

theorem concrete_retention_value (r : Rat) :
    fixedValue {base with retention := r} (mentorAssessment true) = 18*r-33/4 := by
  simp [fixedValue, evaluate, concreteModel, mentorAssessment, base, initial, next,
    terminalValue, sumOver, worlds, observations, childWeights, likelihood,
    transition, targetCompetence, learning, change, skill, dispatch, normal, cost, learnerReward, reward]
  <;> grind

theorem concrete_retention_threshold (r : Rat) :
    8 < fixedValue {base with retention := r} (mentorAssessment true) ↔ 65/72 < r := by
  rw [concrete_retention_value]
  have hc : 18*(65/72 : Rat)-33/4 = 8 := by decide +kernel
  grind

end PeopleDevelopment