Skip to content

Latest commit

 

History

History
86 lines (67 loc) · 2.72 KB

File metadata and controls

86 lines (67 loc) · 2.72 KB

Threshold Contract

Threshold is a small confidence-tiered human-in-the-loop routing primitive. Given caller-supplied signals and a policy, the pure core returns one of three verdicts:

  • auto_apply
  • route_to_human
  • auto_reject

When behavior is ambiguous, the safer and more supervised outcome wins.

Core Types

Verdict   = auto_apply | route_to_human | auto_reject
Band      = high | review | low
RiskLevel = low | medium | high | critical

Signals = {
  score?: number
  scores?: { [name: string]: number }
  flags?: string[]
  meta?: { [key: string]: unknown }
}

BandConfig = {
  highMin: number
  reviewMin: number
}

Rule = {
  id: string
  when: (signals: Signals) => boolean
  force: route_to_human | auto_reject
  reason: string
}

Policy = {
  bands?: { [scoreName: string]: BandConfig }
  combine?: (bands: { [scoreName: string]: Band }) => Verdict
  rules?: Rule[]
  enableAutoApply?: boolean
  enableAutoReject?: boolean
}

Reason = {
  code: string
  message: string
  source: band | rule | safety
}

Decision = {
  verdict: Verdict
  reasons: Reason[]
  risk?: RiskLevel
  bands?: { [scoreName: string]: Band }
}

Decision Algorithm

  1. Band each score named in policy.bands.
  2. Combine bands into a tentative verdict. The default combine uses the lowest band as the candidate: any low produces auto_reject, any review produces route_to_human, otherwise all-high produces auto_apply.
  3. Evaluate all rules.
  4. Resolve conflicts by the safest outcome: any route_to_human rule wins; otherwise any auto_reject rule produces an auto-reject candidate; otherwise keep the tentative verdict.
  5. Apply safety gates. auto_apply survives only when every configured band is high and enableAutoApply is true. auto_reject survives only when enableAutoReject is true. Blocked auto verdicts become route_to_human.
  6. Return the verdict with reasons for banding, fired rules, and safety gates that influenced the result.

Required Invariants

  • Rules cannot force auto_apply.
  • auto_apply is reachable only from an all-high band path with enableAutoApply: true.
  • Empty/default policies route to route_to_human.
  • decide() is pure and deterministic.
  • The queue module is additive; the core has no persistence or side effects.

Golden Vectors

The shared vectors/*.json corpus is the parity contract for language twins. Production policies use closures for Rule.when, but vectors use a small declarative fixture format so TypeScript and Swift can load the same files:

{ "flag": "needs_human" }
{ "metaNumberLessThan": { "key": "linkedCount", "value": 1 } }
{ "scoreBelow": { "name": "draft", "value": 0.8 } }

Vector runners translate those fixtures into native closures before calling decide().