SilverSight/formal/BindingSite/BindingSiteCodec.lean
allaun 1794299a6c chore(quality): native_decide migration, docs, and phi pipeline cleanup
Systematic native_decide → dec_trivial/rfl migration across all Lean modules
to comply with AGENTS.md rule 5 (no native_decide unless only option):
- CoreFormalism: BraidEigensolid, BraidField, ChentsovFinite, HachimojiBase,
  HachimojiBridging, HachimojiCodec, HachimojiLUT, HachimojiManifoldAxiom,
  Q16_16Numerics
- BindingSite: BindingSiteCodec, BindingSiteEntropy, BindingSiteHachimoji
- SilverSight: ProductSchema, ProductWireFormat, PolyFactorIdentity, Schema, WireFormat
- PVGS_DQ_Bridge: all three files (native_decide->dec_trivial)
- UniversalEncoding/ChiralitySpace

Additional changes:
- gemma4_mcp.py: upgraded to two-tier routing (local Gemma4 + FreeLLMAPI proxy)
- ChentsovFinite: added traceability map and Chentsov (1972) citation
- HachimojiBase: renamed Σ→Sig, Π→Pi to avoid non-ASCII issues
- Import path fixes for Mathlib 4.30.0-rc2 compatibility
- Doc updates: PURE_FORMULAS, SOS_CERTIFICATE, fundamental math derivations
- Build log: 2026-06-26 session findings
- BRKGLASS_NR_BRACKET_PROPOSAL: updated to REAL-DATA VALIDATED status
- New docs: FOUNDATIONAL_GUIDANCE, PURE_EQUATION_MAP, CHENTSOV_FINITE_MATH,
  BREAKGLASS_FUSION_REVIEW_SPEC, COLD_REVIEWER_FORMULA
- New python: phi pipeline (equation_dna_encoder, ast_parse, charclass,
  consistency, embed, output), nr_bracket_validation with receipt

Build: lake build SilverSightRRC — passes on all committed modules.
  Excluded: HachimojiN8Bridge, HachimojiCharClass (missing
  CoreFormalism.HachimojiManifoldAxiom olean — WIP)
2026-06-27 01:56:54 -05:00

161 lines
8.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
BindingSiteCodec.lean — Deterministic Pipeline: PDB → Binding Site Receipt
The protein-structure analog of HachimojiCodec.lean.
Takes raw PDB residue data (residueName, modification, bFactor, neighborBFactors),
computes the entropy profile, classifies residues via the 8-state Hachimoji system,
and emits a typed BindingSiteReceipt.
Design constraints:
- No Float, no Real in compute path — all arithmetic is Q16_16
- No PVGS_DQ_Bridge dependency (avoids Bridge Q16_16 / Core Q16_16 type collision)
- dqEnergy and stellarRank are computed directly from the entropy profile
- Delegates to BindingSiteHachimoji.buildProfile and BindingSiteEntropy functions
Pipeline:
(residueName, mod, bFactor, neighborBFs)
→ bindingSiteEntropyProfile (BindingSiteEntropy §3)
→ buildProfile (BindingSiteHachimoji §4)
→ stellarRank, dqEnergy
→ BindingSiteReceipt
-/
import BindingSite.BindingSiteHachimoji
import BindingSite.BindingSiteEntropy
namespace BindingSiteCodec
open BindingSite SilverSight.FixedPoint
-- ═══════════════════════════════════════════════════════════════════════════
-- §1 PDB data interface (IO layer, placeholder for RCSB API)
-- ═══════════════════════════════════════════════════════════════════════════
-- PDB residue record type — matches bindingSiteEntropyProfile's input signature.
-- bFactor and neighborBFactors are Nat (PDB stores as integers scaled ×100; caller
-- should pass the integer value, e.g., B=35.12 → 35).
abbrev PDBResidue := String × String × Nat × List Nat
-- resName mod bFac neighborBFacs
/-- Placeholder: in production calls RCSB REST API and parses mmCIF.
Returns empty list; actual data is injected by the IO layer. -/
def fetchPDB (pdbId : String) : IO (List PDBResidue) := do
IO.println s!"[BindingSiteCodec] fetchPDB {pdbId} (placeholder)"
pure []
/-- Placeholder: fetches sequence cluster membership from RCSB.
Returns (entityId, clusterId) or none. -/
def fetchClusterMembership (pdbId : String) : IO (Option (Nat × Nat)) := do
IO.println s!"[BindingSiteCodec] fetchCluster {pdbId} (placeholder)"
pure none
-- ═══════════════════════════════════════════════════════════════════════════
-- §2 Stellar rank and DQ energy (pure Q16_16, no PVGS Bridge)
-- ═══════════════════════════════════════════════════════════════════════════
/-- Stellar rank = number of distinct BindingSiteStates present in the profile.
Maps to photon variation count in the PVGS-DQ formalism. -/
def stellarRank (residues : List BindingSiteResidue) : Nat :=
let states : List BindingSiteState :=
[ .Phi, .Lambda, .Rho, .Kappa, .Omega, .Sigma, .Pi, .Zeta ]
states.countP (fun s => residues.any (fun r => r.state == s))
/-- DQ energy proxy: sum of entropy.val over all residues (Int).
Tracks total disorder; lower = more ordered = stronger pocket signal.
This is an entropy-only proxy; the full dual-quaternion energy requires
spatial coordinates (not available in the B-factor-only pipeline). -/
def dqEnergyFromProfile (profile : BindingSiteProfile) : Int :=
profile.residues.foldl (fun acc r => acc + r.entropy.val) 0
/-- Helstrom bound placeholder (Q16_16).
Full computation requires pairwise quantum state discrimination across residue
pairs — research-level; left as zero pending the quantum sensing module. -/
def helstromBoundPlaceholder : Q16_16 := Q16_16.zero
-- ═══════════════════════════════════════════════════════════════════════════
-- §3 Pipeline stages
-- ═══════════════════════════════════════════════════════════════════════════
/-- Stage 1: PDB residues → entropy-classified list.
Delegates to BindingSiteEntropy.bindingSiteEntropyProfile. -/
def classifyResidues
(pdbData : List PDBResidue)
: List (AminoAcidToken × Q16_16 × BindingSiteState) :=
bindingSiteEntropyProfile pdbData
/-- Stage 2: classified list → BindingSiteProfile.
Delegates to BindingSiteHachimoji.buildProfile. -/
def profileFromClassified
(classified : List (AminoAcidToken × Q16_16 × BindingSiteState))
: BindingSiteProfile :=
buildProfile classified
/-- Stage 3: profile → BindingSiteReceipt. -/
def emitReceipt (pdbId : String) (entityId clusterId : Nat)
(profile : BindingSiteProfile) : BindingSiteReceipt :=
{ version := "BindingSite:v1"
, pdbId := pdbId
, entityId := entityId
, clusterId := clusterId
, profile := profile
, dqEnergy := dqEnergyFromProfile profile
, stellarRank := stellarRank profile.residues
, helstromBound := helstromBoundPlaceholder
, sha256 := "PENDING" }
-- ═══════════════════════════════════════════════════════════════════════════
-- §4 One-function API
-- ═══════════════════════════════════════════════════════════════════════════
/-- `pdbToReceipt : PDB ID → IO BindingSiteReceipt`
Complete pipeline in one call. This is the protein-structure analog of
`equation_to_emit` from HachimojiCodec.lean.
Usage:
let receipt ← pdbToReceipt "1YY9"
IO.println s!"{receipt.profile.siteState}" -- Pi or Lambda → druggable
The receipt is compatible with the PVGS-DQ receipt system:
- receipt.dqEnergy → entropy-sum proxy (full DQ requires coordinates)
- receipt.stellarRank → photon variation count
- receipt.sha256 → hash chain anchor (populated by caller) -/
def pdbToReceipt (pdbId : String) : IO BindingSiteReceipt := do
let pdbData ← fetchPDB pdbId
let classified := classifyResidues pdbData
let profile := profileFromClassified classified
let clusterInfo ← fetchClusterMembership pdbId
let (entity, cluster) := clusterInfo.getD (0, 0)
pure (emitReceipt pdbId entity cluster profile)
-- ═══════════════════════════════════════════════════════════════════════════
-- §5 Batch screening API
-- ═══════════════════════════════════════════════════════════════════════════
/-- Screen a library of PDB IDs, returning only druggable sites. -/
def screenDruggable (pdbIds : List String) : IO (List BindingSiteReceipt) := do
let receipts ← pdbIds.mapM pdbToReceipt
pure (receipts.filter (fun r => r.profile.druggable))
/-- Rank receipts by DQ energy (lower = more ordered = stronger pocket). -/
def rankByEnergy (receipts : List BindingSiteReceipt) : List BindingSiteReceipt :=
receipts.insertionSort (fun r1 r2 => r1.dqEnergy < r2.dqEnergy)
-- ═══════════════════════════════════════════════════════════════════════════
-- §6 Sanity checks (no IO, pure, decidable)
-- ═══════════════════════════════════════════════════════════════════════════
/-- stellarRank is bounded by the 8 Hachimoji states. -/
theorem stellarRank_le_8 (residues : List BindingSiteResidue) :
stellarRank residues ≤ 8 := by
simp only [stellarRank]
apply List.countP_le_length
/-- An empty profile has dqEnergy = 0. -/
theorem dqEnergy_empty :
dqEnergyFromProfile (show BindingSiteProfile from
{ residues := [], totalEntropy := Q16_16.zero,
maxEntropy := Q16_16.zero, minEntropy := Q16_16.zero,
siteState := .Phi, druggable := false, receiptHash := "" }) = 0 := by
simp [dqEnergyFromProfile]
end BindingSiteCodec