From 5101122fa8eb80ff6352a5aedfbd5a7859ddd24b Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Tue, 10 Feb 2026 20:10:00 -0800
Subject: [PATCH 01/16] Update CalSourceEnergyCalib table format to include
 ndf; add CalEnergyCalibInfo table

---
 DbTables/inc/CalEnergyCalibInfo.hh   | 106 +++++++++++++++++++++++++++
 DbTables/inc/CalSourceEnergyCalib.hh |  14 +++-
 DbTables/src/DbTableFactory.cc       |   3 +
 3 files changed, 119 insertions(+), 4 deletions(-)
 create mode 100755 DbTables/inc/CalEnergyCalibInfo.hh

diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
new file mode 100755
index 0000000000..198dc489c2
--- /dev/null
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -0,0 +1,106 @@
+#ifndef DbTables_CalEnergyCalibInfo_hh
+#define DbTables_CalEnergyCalibInfo_hh
+
+/*
+  Per-SiPM combined calibration metadata table.
+  Stores the combined ADC/MeV constants, uncertainties, and status flags
+  from the cosmic + source calibration combination algorithm.
+
+  Status codes:
+    0   - updated: cosmic + source, consistent
+    1   - fallback: methods inconsistent, kept old value
+    2   - fallback: all methods statistically invalid
+    101 - updated using cosmic only
+    102 - updated using source only
+
+  Author: W. Zhou 2025
+*/
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+#include "cetlib_except/exception.h"
+#include "Offline/DbTables/inc/DbTable.hh"
+#include "Offline/DataProducts/inc/CaloSiPMId.hh"
+#include "Offline/DataProducts/inc/CaloConst.hh"
+
+namespace mu2e {
+
+class CalEnergyCalibInfo : public DbTable {
+ public:
+  typedef std::shared_ptr<CalEnergyCalibInfo> ptr_t;
+  typedef std::shared_ptr<const CalEnergyCalibInfo> cptr_t;
+
+  class Row {
+   public:
+    Row(CaloSiPMId roid, float ADC2MeV, float ADC2MeV_err,
+        int status_code, std::string status_message)
+        : _roid(roid),
+          _ADC2MeV(ADC2MeV),
+          _ADC2MeV_err(ADC2MeV_err),
+          _status_code(status_code),
+          _status_message(status_message) {}
+
+    CaloSiPMId roid() const { return _roid; }
+    float ADC2MeV() const { return _ADC2MeV; }
+    float ADC2MeV_err() const { return _ADC2MeV_err; }
+    int status_code() const { return _status_code; }
+    std::string status_message() const { return _status_message; }
+
+   private:
+    CaloSiPMId _roid;
+    float _ADC2MeV;
+    float _ADC2MeV_err;
+    int _status_code;
+    std::string _status_message;
+  };
+
+  constexpr static const char* cxname = "CalEnergyCalibInfo";
+
+  CalEnergyCalibInfo()
+      : DbTable(cxname, "cal.energycalibinfo",
+                "roid,adc2mev,adc2mev_err,status_code,status_message") {}
+
+  const Row& row(CaloSiPMId roid) const { return _rows.at(roid.id()); }
+  std::vector<Row> const& rows() const { return _rows; }
+  std::size_t nrow() const override { return _rows.size(); }
+  size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
+  virtual std::size_t nrowFix() const override { return CaloConst::_nChannelDB; }
+  const std::string orderBy() const { return std::string("roid"); }
+
+  void addRow(const std::vector<std::string>& columns) override {
+    std::uint16_t index = std::stoul(columns[0]);
+    // enforce order, so channels can be looked up by index
+    if (index >= CaloConst::_nChannelDB || index != _rows.size()) {
+      throw cet::exception("CALENERGYCALIBINFO_BAD_INDEX")
+          << "CalEnergyCalibInfo::addRow found index out of order: " << index
+          << " != " << _rows.size() << "\n";
+    }
+    _rows.emplace_back(CaloSiPMId(index), std::stof(columns[1]),
+                       std::stof(columns[2]), std::stoi(columns[3]),
+                       columns[4]);
+  }
+
+  void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
+    Row const& r = _rows.at(irow);
+    sstream << std::fixed << std::setprecision(5);
+    sstream << r.roid() << ",";
+    sstream << r.ADC2MeV() << ",";
+    sstream << r.ADC2MeV_err() << ",";
+    sstream << r.status_code() << ",";
+    sstream << r.status_message();
+  }
+
+  virtual void clear() override {
+    baseClear();
+    _rows.clear();
+  }
+
+ private:
+  std::vector<Row> _rows;
+};
+
+}  // namespace mu2e
+
+#endif
diff --git a/DbTables/inc/CalSourceEnergyCalib.hh b/DbTables/inc/CalSourceEnergyCalib.hh
index 89211d298f..92e940a545 100644
--- a/DbTables/inc/CalSourceEnergyCalib.hh
+++ b/DbTables/inc/CalSourceEnergyCalib.hh
@@ -16,7 +16,7 @@ namespace mu2e {
 
     class Row {
     public:
-      Row(CaloSiPMId roid, float fullEPeak,float fullErrEPeak,float fullWidth,float fullErrWidth,float firstescEPeak,float firstescErrEPeak,float firstescWidth,float firstescErrWidth,float secescEPeak,float secescErrEPeak,float secescWidth,float secescErrWidth, float frFull, float frFirst, float frSecond, float chisq): _roid(roid), _fullEPeak(fullEPeak), _fullErrEPeak(fullErrEPeak), _fullWidth(fullWidth), _fullErrWidth(fullErrWidth),_firstescEPeak(firstescEPeak), _firstescErrEPeak(firstescErrEPeak), _firstescWidth(firstescWidth), _firstescErrWidth(firstescErrWidth),_secescEPeak(secescEPeak), _secescErrEPeak(secescErrEPeak), _secescWidth(secescWidth), _secescErrWidth(secescErrWidth), _frFull(frFull), _frFirst(frFirst), _frSecond(frSecond), _chisq(chisq){}
+      Row(CaloSiPMId roid, float fullEPeak,float fullErrEPeak,float fullWidth,float fullErrWidth,float firstescEPeak,float firstescErrEPeak,float firstescWidth,float firstescErrWidth,float secescEPeak,float secescErrEPeak,float secescWidth,float secescErrWidth, float frFull, float frFirst, float frSecond, float chisq, int ndf): _roid(roid), _fullEPeak(fullEPeak), _fullErrEPeak(fullErrEPeak), _fullWidth(fullWidth), _fullErrWidth(fullErrWidth),_firstescEPeak(firstescEPeak), _firstescErrEPeak(firstescErrEPeak), _firstescWidth(firstescWidth), _firstescErrWidth(firstescErrWidth),_secescEPeak(secescEPeak), _secescErrEPeak(secescErrEPeak), _secescWidth(secescWidth), _secescErrWidth(secescErrWidth), _frFull(frFull), _frFirst(frFirst), _frSecond(frSecond), _chisq(chisq), _ndf(ndf){}
 
       CaloSiPMId  roid() const { return _roid;}
       float fullEPeak() const { return _fullEPeak; }
@@ -39,6 +39,7 @@ namespace mu2e {
       float frSecond() const { return _frSecond; }
 
       float chisq() const { return _chisq; }
+      int ndf() const { return _ndf; }
 
     private:
       CaloSiPMId  _roid;
@@ -58,11 +59,12 @@ namespace mu2e {
       float _frFirst;
       float _frSecond;
       float _chisq;
+      int _ndf;
     };
 
     constexpr static const char* cxname = "CalSourceEnergyCalib";
 
-    CalSourceEnergyCalib():DbTable(cxname,"cal.sourceenergycalib","roid,fullepeak,fullerrepeak,fullwidth,fullerrwidth,firstescepeak,firstescerrepeak,firstescwidth,firstescerrwidth,secescepeak,secescerrepeak,secescwidth,secescerrwidth, frfull,frfirst,frsecond,chisq"){}
+    CalSourceEnergyCalib():DbTable(cxname,"cal.sourceenergycalib","roid,fullepeak,fullerrepeak,fullwidth,fullerrwidth,firstescepeak,firstescerrepeak,firstescwidth,firstescerrwidth,secescepeak,secescerrepeak,secescwidth,secescerrwidth,frfull,frfirst,frsecond,chisq,ndf"){}
 
     const Row& row(CaloSiPMId  roid) const {
                 return _rows.at(roid.id()); }
@@ -82,7 +84,7 @@ namespace mu2e {
        _rows.emplace_back(CaloSiPMId(index),std::stof(columns[1]),std::stof(columns[2]),std::stof(columns[3]),
        std::stof(columns[4]),std::stof(columns[5]),std::stof(columns[6]),std::stof(columns[7]),
        std::stof(columns[8]),std::stof(columns[9]),std::stof(columns[10]),std::stof(columns[11]),
-       std::stof(columns[12]),std::stof(columns[13]),std::stof(columns[14]),std::stof(columns[15]),std::stof(columns[16]));
+       std::stof(columns[12]),std::stof(columns[13]),std::stof(columns[14]),std::stof(columns[15]),std::stof(columns[16]),std::stoi(columns[17]));
 
     }
 
@@ -102,7 +104,11 @@ namespace mu2e {
       sstream << r.secescErrEPeak()<<",";
       sstream << r.secescWidth()<<",";
       sstream << r.secescErrWidth()<<",";
-      sstream << r.chisq();
+      sstream << r.frFull()<<",";
+      sstream << r.frFirst()<<",";
+      sstream << r.frSecond()<<",";
+      sstream << r.chisq()<<",";
+      sstream << r.ndf();
     }
 
     virtual void clear() override { baseClear(); _rows.clear();}
diff --git a/DbTables/src/DbTableFactory.cc b/DbTables/src/DbTableFactory.cc
index b8576e4d2b..e18b78b3c3 100644
--- a/DbTables/src/DbTableFactory.cc
+++ b/DbTables/src/DbTableFactory.cc
@@ -13,6 +13,7 @@
 #include "Offline/DbTables/inc/CalSourceEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalCosmicEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalCosmicEnergyCalibInfo.hh"
+#include "Offline/DbTables/inc/CalEnergyCalibInfo.hh"
 #include "Offline/DbTables/inc/CalLaserEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalLaserTimeCalib.hh"
 #include "Offline/DbTables/inc/CalLaserRuns.hh"
@@ -111,6 +112,8 @@ mu2e::DbTable::ptr_t mu2e::DbTableFactory::newTable(std::string const& name) {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalLaserRuns());
   } else if (name=="CalEnergyCalib") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalib());
+  } else if (name=="CalEnergyCalibInfo") {
+    return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalibInfo());
   } else if (name=="CalTimeCalib") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalTimeCalib());
   } else if (name=="CalCosmicT0Align") {

From 06247211c2ca2401fb0e296c0ad50929de884289 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Sun, 22 Feb 2026 22:47:32 -0800
Subject: [PATCH 02/16] Add utility header inclusion and optimize move
 semantics in calibration info classes

---
 DbTables/inc/CalCosmicEnergyCalibInfo.hh | 7 ++++---
 DbTables/inc/CalEnergyCalibInfo.hh       | 3 ++-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/DbTables/inc/CalCosmicEnergyCalibInfo.hh b/DbTables/inc/CalCosmicEnergyCalibInfo.hh
index 2df1741a6b..6dad9c88aa 100644
--- a/DbTables/inc/CalCosmicEnergyCalibInfo.hh
+++ b/DbTables/inc/CalCosmicEnergyCalibInfo.hh
@@ -6,6 +6,7 @@
 #include <iomanip>
 #include <sstream>
 #include <string>
+#include <utility>
 
 namespace mu2e {
 
@@ -17,9 +18,9 @@ class CalCosmicEnergyCalibInfo : public DbTable {
         _cID(cID),
         _FirstCalibRun(FirstCalibRun),
         _LastCalibRun(LastCalibRun),
-        _EnergyMethod(EnergyMethod),
-        _FitMethod(FitMethod),
-        _Comment(Comment) {}
+        _EnergyMethod(std::move(EnergyMethod)),
+        _FitMethod(std::move(FitMethod)),
+        _Comment(std::move(Comment)) {}
     int cID() const {return _cID; }
     int FirstCalibRun() const { return _FirstCalibRun; }
     int LastCalibRun() const { return _LastCalibRun; }
diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index 198dc489c2..577f105d13 100755
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -19,6 +19,7 @@
 #include <iomanip>
 #include <sstream>
 #include <string>
+#include <utility>
 #include <vector>
 #include "cetlib_except/exception.h"
 #include "Offline/DbTables/inc/DbTable.hh"
@@ -40,7 +41,7 @@ class CalEnergyCalibInfo : public DbTable {
           _ADC2MeV(ADC2MeV),
           _ADC2MeV_err(ADC2MeV_err),
           _status_code(status_code),
-          _status_message(status_message) {}
+          _status_message(std::move(status_message)) {}
 
     CaloSiPMId roid() const { return _roid; }
     float ADC2MeV() const { return _ADC2MeV; }

From 058b110667f2c783cd769fb520e5e23808b4078c Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Sun, 22 Feb 2026 22:53:25 -0800
Subject: [PATCH 03/16] Fix CSV output precision in rowToCsv method of
 CalEnergyCalibInfo class

---
 DbTables/inc/CalEnergyCalibInfo.hh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index 577f105d13..a385d4f86c 100755
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -85,8 +85,8 @@ class CalEnergyCalibInfo : public DbTable {
 
   void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
     Row const& r = _rows.at(irow);
-    sstream << std::fixed << std::setprecision(5);
     sstream << r.roid() << ",";
+    sstream << std::fixed << std::setprecision(5);
     sstream << r.ADC2MeV() << ",";
     sstream << r.ADC2MeV_err() << ",";
     sstream << r.status_code() << ",";

From 40b2ead0e2fb7e758e1509e34ff701dc3f7c395c Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Sun, 22 Feb 2026 23:04:33 -0800
Subject: [PATCH 04/16] Fix CalEnergyCalibInfo CSV handling for status_message

Quote/escape status_message in rowToCsv and unquote on read in addRow.
Also treat trailing columns as part of the last field so messages with commas
round-trip correctly instead of breaking CSV parsing.
---
 DbTables/inc/CalEnergyCalibInfo.hh | 43 ++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index a385d4f86c..2c3417f688 100755
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -78,9 +78,15 @@ class CalEnergyCalibInfo : public DbTable {
           << "CalEnergyCalibInfo::addRow found index out of order: " << index
           << " != " << _rows.size() << "\n";
     }
+    std::string statusMessage = columns[4];
+    for (std::size_t i = 5; i < columns.size(); ++i) {
+      statusMessage += ",";
+      statusMessage += columns[i];
+    }
+
     _rows.emplace_back(CaloSiPMId(index), std::stof(columns[1]),
                        std::stof(columns[2]), std::stoi(columns[3]),
-                       columns[4]);
+                       fromCsvText(statusMessage));
   }
 
   void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
@@ -90,7 +96,7 @@ class CalEnergyCalibInfo : public DbTable {
     sstream << r.ADC2MeV() << ",";
     sstream << r.ADC2MeV_err() << ",";
     sstream << r.status_code() << ",";
-    sstream << r.status_message();
+    sstream << toCsvText(r.status_message());
   }
 
   virtual void clear() override {
@@ -99,6 +105,39 @@ class CalEnergyCalibInfo : public DbTable {
   }
 
  private:
+  static std::string toCsvText(const std::string& text) {
+    if (text.find_first_of(",\"") == std::string::npos) return text;
+    std::string out;
+    out.reserve(text.size() + 2);
+    out.push_back('"');
+    for (char c : text) {
+      if (c == '"') out += "\"\"";
+      else out.push_back(c);
+    }
+    out.push_back('"');
+    return out;
+  }
+
+  static std::string fromCsvText(const std::string& text) {
+    if (text.size() < 2 || text.front() != '"' || text.back() != '"') {
+      return text;
+    }
+    std::string out;
+    out.reserve(text.size() - 2);
+    for (std::size_t i = 1; i + 1 < text.size(); ++i) {
+      if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
+        out.push_back('"');
+        ++i;
+      } else if (text[i] == '\\' && i + 2 < text.size() && text[i + 1] == '"') {
+        out.push_back('"');
+        ++i;
+      } else {
+        out.push_back(text[i]);
+      }
+    }
+    return out;
+  }
+
   std::vector<Row> _rows;
 };
 

From 71d148483ec7fbbb9bd89c2edc456f07d81847ad Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Sun, 22 Feb 2026 23:44:07 -0800
Subject: [PATCH 05/16] Flag CalEnergyCalibInfo table as an adhoc table.

---
 DbTables/inc/CalEnergyCalibInfo.hh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index 2c3417f688..d35625d62e 100755
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -67,6 +67,7 @@ class CalEnergyCalibInfo : public DbTable {
   std::vector<Row> const& rows() const { return _rows; }
   std::size_t nrow() const override { return _rows.size(); }
   size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
+  tableType type() const override { return Adhoc; }
   virtual std::size_t nrowFix() const override { return CaloConst::_nChannelDB; }
   const std::string orderBy() const { return std::string("roid"); }
 

From 2fe7db31d370ad2dd207ef3f35538e950d293352 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Sun, 1 Mar 2026 17:33:20 -0800
Subject: [PATCH 06/16] Remove CalEnergyCalibInfo table as an adhoc table

---
 DbTables/inc/CalEnergyCalibInfo.hh | 1 -
 1 file changed, 1 deletion(-)

diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index d35625d62e..2c3417f688 100755
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -67,7 +67,6 @@ class CalEnergyCalibInfo : public DbTable {
   std::vector<Row> const& rows() const { return _rows; }
   std::size_t nrow() const override { return _rows.size(); }
   size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
-  tableType type() const override { return Adhoc; }
   virtual std::size_t nrowFix() const override { return CaloConst::_nChannelDB; }
   const std::string orderBy() const { return std::string("roid"); }
 

From bc3a3eba28a9e8704bc04ca0658065fead14e9da Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Mon, 2 Mar 2026 16:24:25 -0800
Subject: [PATCH 07/16] Add CalEnergyCalibInfoLink adhoc table for CID mapping

Introduce a new adhoc DbTable (CalEnergyCalibInfoLink) to store
commit-level mapping between CalEnergyCalib and CalEnergyCalibInfo CIDs.

- Add DbTables/inc/CalEnergyCalibInfoLink.hh
- Register the new table in DbTableFactory
- Add cal.energycalibinfolink DDL and grants in DbService/data/create.sql
---
 DbService/data/create.sql              |  6 +++
 DbTables/inc/CalEnergyCalibInfoLink.hh | 68 ++++++++++++++++++++++++++
 DbTables/src/DbTableFactory.cc         |  3 ++
 3 files changed, 77 insertions(+)
 create mode 100644 DbTables/inc/CalEnergyCalibInfoLink.hh

diff --git a/DbService/data/create.sql b/DbService/data/create.sql
index 6af1ef1ad2..e74837de53 100644
--- a/DbService/data/create.sql
+++ b/DbService/data/create.sql
@@ -448,4 +448,10 @@ CREATE TABLE cal.cosmicenergycalibinfo
 GRANT SELECT ON cal.cosmicenergycalibinfo TO PUBLIC;
 GRANT INSERT ON cal.cosmicenergycalibinfo TO cal_role;
 
+CREATE TABLE cal.energycalibinfolink
+  (energycalibcid INTEGER, energycalibinfocid INTEGER, comment TEXT,
+   create_time TIMESTAMP WITH TIME ZONE NOT NULL,
+   create_user TEXT NOT NULL );
+GRANT SELECT ON cal.energycalibinfolink TO PUBLIC;
+GRANT INSERT ON cal.energycalibinfolink TO cal_role;
 
diff --git a/DbTables/inc/CalEnergyCalibInfoLink.hh b/DbTables/inc/CalEnergyCalibInfoLink.hh
new file mode 100644
index 0000000000..ef3c425bcb
--- /dev/null
+++ b/DbTables/inc/CalEnergyCalibInfoLink.hh
@@ -0,0 +1,68 @@
+#ifndef DbTables_CalEnergyCalibInfoLink_hh
+#define DbTables_CalEnergyCalibInfoLink_hh
+
+//
+// Ad-hoc table linking a CalEnergyCalib CID to the matching
+// CalEnergyCalibInfo CID produced by the same combination pass.
+//
+
+#include "Offline/DbTables/inc/DbTable.hh"
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace mu2e {
+
+class CalEnergyCalibInfoLink : public DbTable {
+ public:
+  class Row {
+   public:
+    Row(int energyCalibCid, int energyCalibInfoCid, std::string comment) :
+        _energyCalibCid(energyCalibCid),
+        _energyCalibInfoCid(energyCalibInfoCid),
+        _comment(std::move(comment)) {}
+
+    int energyCalibCid() const { return _energyCalibCid; }
+    int energyCalibInfoCid() const { return _energyCalibInfoCid; }
+    std::string comment() const { return _comment; }
+
+   private:
+    int _energyCalibCid;
+    int _energyCalibInfoCid;
+    std::string _comment;
+  };
+
+  constexpr static const char* cxname = "CalEnergyCalibInfoLink";
+
+  CalEnergyCalibInfoLink() :
+      DbTable(cxname, "cal.energycalibinfolink",
+              "energycalibcid,energycalibinfocid,comment") {}
+
+  const Row& rowAt(const std::size_t index) const { return _rows.at(index); }
+  std::vector<Row> const& rows() const { return _rows; }
+  std::size_t nrow() const override { return _rows.size(); }
+  size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
+  tableType type() const override { return Adhoc; }
+
+  void addRow(const std::vector<std::string>& columns) override {
+    _rows.emplace_back(std::stoi(columns[0]), std::stoi(columns[1]), columns[2]);
+  }
+
+  void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
+    Row const& r = _rows.at(irow);
+    sstream << r.energyCalibCid() << ",";
+    sstream << r.energyCalibInfoCid() << ",";
+    sstream << r.comment();
+  }
+
+  virtual void clear() override {
+    baseClear();
+    _rows.clear();
+  }
+
+ private:
+  std::vector<Row> _rows;
+};
+
+}  // namespace mu2e
+#endif
diff --git a/DbTables/src/DbTableFactory.cc b/DbTables/src/DbTableFactory.cc
index 65a7193eb6..ee39d11565 100644
--- a/DbTables/src/DbTableFactory.cc
+++ b/DbTables/src/DbTableFactory.cc
@@ -15,6 +15,7 @@
 #include "Offline/DbTables/inc/CalCosmicEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalCosmicEnergyCalibInfo.hh"
 #include "Offline/DbTables/inc/CalEnergyCalibInfo.hh"
+#include "Offline/DbTables/inc/CalEnergyCalibInfoLink.hh"
 #include "Offline/DbTables/inc/CalLaserEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalLaserTimeCalib.hh"
 #include "Offline/DbTables/inc/CalLaserRuns.hh"
@@ -117,6 +118,8 @@ mu2e::DbTable::ptr_t mu2e::DbTableFactory::newTable(std::string const& name) {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalib());
   } else if (name=="CalEnergyCalibInfo") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalibInfo());
+  } else if (name=="CalEnergyCalibInfoLink") {
+    return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalibInfoLink());
   } else if (name=="CalTimeCalib") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalTimeCalib());
   } else if (name=="CalCosmicT0Align") {

From bd8156f235579cc68a4bab649342358813663e60 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Mon, 2 Mar 2026 22:04:10 -0800
Subject: [PATCH 08/16] Add cal.energycalibinfo DDL to create.sql

Define cal.energycalibinfo with schema matching CalEnergyCalibInfo:
(cid, roid, adc2mev, adc2mev_err, status_code, status_message)
and add primary key and grants.
---
 DbService/data/create.sql | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/DbService/data/create.sql b/DbService/data/create.sql
index e74837de53..421e774db3 100644
--- a/DbService/data/create.sql
+++ b/DbService/data/create.sql
@@ -448,10 +448,17 @@ CREATE TABLE cal.cosmicenergycalibinfo
 GRANT SELECT ON cal.cosmicenergycalibinfo TO PUBLIC;
 GRANT INSERT ON cal.cosmicenergycalibinfo TO cal_role;
 
+CREATE TABLE cal.energycalibinfo
+  (cid INTEGER,
+   roid INTEGER, adc2mev NUMERIC, adc2mev_err NUMERIC,
+   status_code INTEGER, status_message TEXT,
+   CONSTRAINT cal_energycalibinfo_pk PRIMARY KEY (cid,roid) );
+GRANT SELECT ON cal.energycalibinfo TO PUBLIC;
+GRANT INSERT ON cal.energycalibinfo TO cal_role;
+
 CREATE TABLE cal.energycalibinfolink
   (energycalibcid INTEGER, energycalibinfocid INTEGER, comment TEXT,
    create_time TIMESTAMP WITH TIME ZONE NOT NULL,
    create_user TEXT NOT NULL );
 GRANT SELECT ON cal.energycalibinfolink TO PUBLIC;
 GRANT INSERT ON cal.energycalibinfolink TO cal_role;
-

From 1d3f66ea4c7f10115871c4f83aeaae26651eb7d6 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Mon, 2 Mar 2026 22:10:52 -0800
Subject: [PATCH 09/16] Quote and parse CalEnergyCalibInfoLink comment as CSV

Make CalEnergyCalibInfoLink comment field CSV-safe by quoting on output and
unquoting on input, and preserve compatibility by joining trailing parsed
columns when commas are present.
---
 DbTables/inc/CalEnergyCalibInfoLink.hh | 44 ++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/DbTables/inc/CalEnergyCalibInfoLink.hh b/DbTables/inc/CalEnergyCalibInfoLink.hh
index ef3c425bcb..564b8fc8e0 100644
--- a/DbTables/inc/CalEnergyCalibInfoLink.hh
+++ b/DbTables/inc/CalEnergyCalibInfoLink.hh
@@ -45,14 +45,20 @@ class CalEnergyCalibInfoLink : public DbTable {
   tableType type() const override { return Adhoc; }
 
   void addRow(const std::vector<std::string>& columns) override {
-    _rows.emplace_back(std::stoi(columns[0]), std::stoi(columns[1]), columns[2]);
+    std::string comment = columns[2];
+    for (std::size_t i = 3; i < columns.size(); ++i) {
+      comment += ",";
+      comment += columns[i];
+    }
+    _rows.emplace_back(std::stoi(columns[0]), std::stoi(columns[1]),
+                       fromCsvText(comment));
   }
 
   void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
     Row const& r = _rows.at(irow);
     sstream << r.energyCalibCid() << ",";
     sstream << r.energyCalibInfoCid() << ",";
-    sstream << r.comment();
+    sstream << toCsvText(r.comment());
   }
 
   virtual void clear() override {
@@ -61,6 +67,40 @@ class CalEnergyCalibInfoLink : public DbTable {
   }
 
  private:
+  static std::string toCsvText(const std::string& text) {
+    if (text.find_first_of(",\"") == std::string::npos) return text;
+    std::string out;
+    out.reserve(text.size() + 2);
+    out.push_back('"');
+    for (char c : text) {
+      if (c == '"') out += "\"\"";
+      else out.push_back(c);
+    }
+    out.push_back('"');
+    return out;
+  }
+
+  static std::string fromCsvText(const std::string& text) {
+    if (text.size() < 2 || text.front() != '"' || text.back() != '"') {
+      return text;
+    }
+    std::string out;
+    out.reserve(text.size() - 2);
+    for (std::size_t i = 1; i + 1 < text.size(); ++i) {
+      if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
+        out.push_back('"');
+        ++i;
+      } else if (text[i] == '\\' && i + 2 < text.size() &&
+                 text[i + 1] == '"') {
+        out.push_back('"');
+        ++i;
+      } else {
+        out.push_back(text[i]);
+      }
+    }
+    return out;
+  }
+
   std::vector<Row> _rows;
 };
 

From afc1f381f3d374af63f9c4734e6d5205d44505e6 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Mon, 2 Mar 2026 22:11:30 -0800
Subject: [PATCH 10/16] Validate CalEnergyCalibInfoLink input column count

Add a guard in CalEnergyCalibInfoLink::addRow to require at least 3
columns before parsing, and throw a clear cet::exception otherwise.
---
 DbTables/inc/CalEnergyCalibInfoLink.hh | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/DbTables/inc/CalEnergyCalibInfoLink.hh b/DbTables/inc/CalEnergyCalibInfoLink.hh
index 564b8fc8e0..44fd971f26 100644
--- a/DbTables/inc/CalEnergyCalibInfoLink.hh
+++ b/DbTables/inc/CalEnergyCalibInfoLink.hh
@@ -7,6 +7,7 @@
 //
 
 #include "Offline/DbTables/inc/DbTable.hh"
+#include "cetlib_except/exception.h"
 #include <sstream>
 #include <string>
 #include <utility>
@@ -45,6 +46,11 @@ class CalEnergyCalibInfoLink : public DbTable {
   tableType type() const override { return Adhoc; }
 
   void addRow(const std::vector<std::string>& columns) override {
+    if (columns.size() < 3) {
+      throw cet::exception("CALENERGYCALIBINFOLINK_BAD_COLUMNS")
+          << "CalEnergyCalibInfoLink::addRow expected at least 3 columns, got "
+          << columns.size() << "\n";
+    }
     std::string comment = columns[2];
     for (std::size_t i = 3; i < columns.size(); ++i) {
       comment += ",";

From 85e842084c30e3efa506e92463f40bb380ef856e Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Mon, 2 Mar 2026 22:13:04 -0800
Subject: [PATCH 11/16] Add cal.sourceenergycalib DDL with ndf

Define cal.sourceenergycalib in DbService/data/create.sql with column
layout matching CalSourceEnergyCalib, including fr* fields and ndf,
plus primary key and grants.
---
 DbService/data/create.sql | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/DbService/data/create.sql b/DbService/data/create.sql
index 421e774db3..ec14cd2f25 100644
--- a/DbService/data/create.sql
+++ b/DbService/data/create.sql
@@ -440,6 +440,20 @@ CREATE TABLE cal.cosmicenergycalib
 GRANT SELECT ON cal.cosmicenergycalib TO PUBLIC;
 GRANT INSERT ON cal.cosmicenergycalib TO cal_role;
 
+CREATE TABLE cal.sourceenergycalib
+  (cid INTEGER,
+   roid INTEGER, fullepeak NUMERIC, fullerrepeak NUMERIC,
+   fullwidth NUMERIC, fullerrwidth NUMERIC,
+   firstescepeak NUMERIC, firstescerrepeak NUMERIC,
+   firstescwidth NUMERIC, firstescerrwidth NUMERIC,
+   secescepeak NUMERIC, secescerrepeak NUMERIC,
+   secescwidth NUMERIC, secescerrwidth NUMERIC,
+   frfull NUMERIC, frfirst NUMERIC, frsecond NUMERIC,
+   chisq NUMERIC, ndf INTEGER,
+   CONSTRAINT cal_sourceenergycalib_pk PRIMARY KEY (cid,roid) );
+GRANT SELECT ON cal.sourceenergycalib TO PUBLIC;
+GRANT INSERT ON cal.sourceenergycalib TO cal_role;
+
 CREATE TABLE cal.cosmicenergycalibinfo
   (cid INTEGER, firstcalibrun INTEGER, lastcalibrun INTEGER,
    energymethod TEXT, fitmethod TEXT, comment TEXT,

From be816de3730e368ebb82c77fdcbe88ce3195d23d Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Tue, 3 Mar 2026 22:38:20 -0800
Subject: [PATCH 12/16] Remove create.sql changes from PR

---
 DbService/data/create.sql | 29 +----------------------------
 1 file changed, 1 insertion(+), 28 deletions(-)

diff --git a/DbService/data/create.sql b/DbService/data/create.sql
index ec14cd2f25..6af1ef1ad2 100644
--- a/DbService/data/create.sql
+++ b/DbService/data/create.sql
@@ -440,20 +440,6 @@ CREATE TABLE cal.cosmicenergycalib
 GRANT SELECT ON cal.cosmicenergycalib TO PUBLIC;
 GRANT INSERT ON cal.cosmicenergycalib TO cal_role;
 
-CREATE TABLE cal.sourceenergycalib
-  (cid INTEGER,
-   roid INTEGER, fullepeak NUMERIC, fullerrepeak NUMERIC,
-   fullwidth NUMERIC, fullerrwidth NUMERIC,
-   firstescepeak NUMERIC, firstescerrepeak NUMERIC,
-   firstescwidth NUMERIC, firstescerrwidth NUMERIC,
-   secescepeak NUMERIC, secescerrepeak NUMERIC,
-   secescwidth NUMERIC, secescerrwidth NUMERIC,
-   frfull NUMERIC, frfirst NUMERIC, frsecond NUMERIC,
-   chisq NUMERIC, ndf INTEGER,
-   CONSTRAINT cal_sourceenergycalib_pk PRIMARY KEY (cid,roid) );
-GRANT SELECT ON cal.sourceenergycalib TO PUBLIC;
-GRANT INSERT ON cal.sourceenergycalib TO cal_role;
-
 CREATE TABLE cal.cosmicenergycalibinfo
   (cid INTEGER, firstcalibrun INTEGER, lastcalibrun INTEGER,
    energymethod TEXT, fitmethod TEXT, comment TEXT,
@@ -462,17 +448,4 @@ CREATE TABLE cal.cosmicenergycalibinfo
 GRANT SELECT ON cal.cosmicenergycalibinfo TO PUBLIC;
 GRANT INSERT ON cal.cosmicenergycalibinfo TO cal_role;
 
-CREATE TABLE cal.energycalibinfo
-  (cid INTEGER,
-   roid INTEGER, adc2mev NUMERIC, adc2mev_err NUMERIC,
-   status_code INTEGER, status_message TEXT,
-   CONSTRAINT cal_energycalibinfo_pk PRIMARY KEY (cid,roid) );
-GRANT SELECT ON cal.energycalibinfo TO PUBLIC;
-GRANT INSERT ON cal.energycalibinfo TO cal_role;
-
-CREATE TABLE cal.energycalibinfolink
-  (energycalibcid INTEGER, energycalibinfocid INTEGER, comment TEXT,
-   create_time TIMESTAMP WITH TIME ZONE NOT NULL,
-   create_user TEXT NOT NULL );
-GRANT SELECT ON cal.energycalibinfolink TO PUBLIC;
-GRANT INSERT ON cal.energycalibinfolink TO cal_role;
+

From 6a529fc2d291d3158b6cad5a5a1db06186434d43 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Tue, 3 Mar 2026 22:41:42 -0800
Subject: [PATCH 13/16] Rename tables to restore Info naming pattern

---
 DbTables/inc/CalCombinedEnergyCalib.hh | 147 +++++++++++++++++++++++++
 DbTables/inc/CalEnergyCalibInfo.hh     | 108 +++++++-----------
 DbTables/inc/CalEnergyCalibInfoLink.hh | 114 -------------------
 DbTables/src/DbTableFactory.cc         |   6 +-
 4 files changed, 188 insertions(+), 187 deletions(-)
 create mode 100644 DbTables/inc/CalCombinedEnergyCalib.hh
 mode change 100755 => 100644 DbTables/inc/CalEnergyCalibInfo.hh
 delete mode 100644 DbTables/inc/CalEnergyCalibInfoLink.hh

diff --git a/DbTables/inc/CalCombinedEnergyCalib.hh b/DbTables/inc/CalCombinedEnergyCalib.hh
new file mode 100644
index 0000000000..585f5fb3aa
--- /dev/null
+++ b/DbTables/inc/CalCombinedEnergyCalib.hh
@@ -0,0 +1,147 @@
+#ifndef DbTables_CalCombinedEnergyCalib_hh
+#define DbTables_CalCombinedEnergyCalib_hh
+
+/*
+  Per-SiPM combined calibration metadata table.
+  Stores the combined ADC/MeV constants, uncertainties, and status flags
+  from the cosmic + source calibration combination algorithm.
+
+  Status codes:
+    0   - updated: cosmic + source, consistent
+    1   - fallback: methods inconsistent, kept old value
+    2   - fallback: all methods statistically invalid
+    101 - updated using cosmic only
+    102 - updated using source only
+
+  Author: W. Zhou 2025
+*/
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+#include "cetlib_except/exception.h"
+#include "Offline/DbTables/inc/DbTable.hh"
+#include "Offline/DataProducts/inc/CaloSiPMId.hh"
+#include "Offline/DataProducts/inc/CaloConst.hh"
+
+namespace mu2e {
+
+class CalCombinedEnergyCalib : public DbTable {
+ public:
+  typedef std::shared_ptr<CalCombinedEnergyCalib> ptr_t;
+  typedef std::shared_ptr<const CalCombinedEnergyCalib> cptr_t;
+
+  class Row {
+   public:
+    Row(CaloSiPMId roid, float ADC2MeV, float ADC2MeV_err,
+        int status_code, std::string status_message)
+        : _roid(roid),
+          _ADC2MeV(ADC2MeV),
+          _ADC2MeV_err(ADC2MeV_err),
+          _status_code(status_code),
+          _status_message(std::move(status_message)) {}
+
+    CaloSiPMId roid() const { return _roid; }
+    float ADC2MeV() const { return _ADC2MeV; }
+    float ADC2MeV_err() const { return _ADC2MeV_err; }
+    int status_code() const { return _status_code; }
+    std::string status_message() const { return _status_message; }
+
+   private:
+    CaloSiPMId _roid;
+    float _ADC2MeV;
+    float _ADC2MeV_err;
+    int _status_code;
+    std::string _status_message;
+  };
+
+  constexpr static const char* cxname = "CalCombinedEnergyCalib";
+
+  CalCombinedEnergyCalib()
+      : DbTable(cxname, "cal.combinedenergycalib",
+                "roid,adc2mev,adc2mev_err,status_code,status_message") {}
+
+  const Row& row(CaloSiPMId roid) const { return _rows.at(roid.id()); }
+  std::vector<Row> const& rows() const { return _rows; }
+  std::size_t nrow() const override { return _rows.size(); }
+  size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
+  virtual std::size_t nrowFix() const override { return CaloConst::_nChannelDB; }
+  const std::string orderBy() const { return std::string("roid"); }
+
+  void addRow(const std::vector<std::string>& columns) override {
+    std::uint16_t index = std::stoul(columns[0]);
+    // enforce order, so channels can be looked up by index
+    if (index >= CaloConst::_nChannelDB || index != _rows.size()) {
+      throw cet::exception("CALCOMBINEDENERGYCALIB_BAD_INDEX")
+          << "CalCombinedEnergyCalib::addRow found index out of order: "
+          << index
+          << " != " << _rows.size() << "\n";
+    }
+    std::string statusMessage = columns[4];
+    for (std::size_t i = 5; i < columns.size(); ++i) {
+      statusMessage += ",";
+      statusMessage += columns[i];
+    }
+
+    _rows.emplace_back(CaloSiPMId(index), std::stof(columns[1]),
+                       std::stof(columns[2]), std::stoi(columns[3]),
+                       fromCsvText(statusMessage));
+  }
+
+  void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
+    Row const& r = _rows.at(irow);
+    sstream << r.roid() << ",";
+    sstream << std::fixed << std::setprecision(5);
+    sstream << r.ADC2MeV() << ",";
+    sstream << r.ADC2MeV_err() << ",";
+    sstream << r.status_code() << ",";
+    sstream << toCsvText(r.status_message());
+  }
+
+  virtual void clear() override {
+    baseClear();
+    _rows.clear();
+  }
+
+ private:
+  static std::string toCsvText(const std::string& text) {
+    if (text.find_first_of(",\"") == std::string::npos) return text;
+    std::string out;
+    out.reserve(text.size() + 2);
+    out.push_back('"');
+    for (char c : text) {
+      if (c == '"') out += "\"\"";
+      else out.push_back(c);
+    }
+    out.push_back('"');
+    return out;
+  }
+
+  static std::string fromCsvText(const std::string& text) {
+    if (text.size() < 2 || text.front() != '"' || text.back() != '"') {
+      return text;
+    }
+    std::string out;
+    out.reserve(text.size() - 2);
+    for (std::size_t i = 1; i + 1 < text.size(); ++i) {
+      if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
+        out.push_back('"');
+        ++i;
+      } else if (text[i] == '\\' && i + 2 < text.size() && text[i + 1] == '"') {
+        out.push_back('"');
+        ++i;
+      } else {
+        out.push_back(text[i]);
+      }
+    }
+    return out;
+  }
+
+  std::vector<Row> _rows;
+};
+
+}  // namespace mu2e
+
+#endif
diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
old mode 100755
new mode 100644
index 2c3417f688..a559cd923c
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -1,102 +1,70 @@
 #ifndef DbTables_CalEnergyCalibInfo_hh
 #define DbTables_CalEnergyCalibInfo_hh
 
-/*
-  Per-SiPM combined calibration metadata table.
-  Stores the combined ADC/MeV constants, uncertainties, and status flags
-  from the cosmic + source calibration combination algorithm.
-
-  Status codes:
-    0   - updated: cosmic + source, consistent
-    1   - fallback: methods inconsistent, kept old value
-    2   - fallback: all methods statistically invalid
-    101 - updated using cosmic only
-    102 - updated using source only
-
-  Author: W. Zhou 2025
-*/
-
-#include <iomanip>
+//
+// Ad-hoc table linking a CalEnergyCalib CID to the matching
+// CalCombinedEnergyCalib CID produced by the same combination pass.
+//
+
+#include "Offline/DbTables/inc/DbTable.hh"
+#include "cetlib_except/exception.h"
 #include <sstream>
 #include <string>
 #include <utility>
-#include <vector>
-#include "cetlib_except/exception.h"
-#include "Offline/DbTables/inc/DbTable.hh"
-#include "Offline/DataProducts/inc/CaloSiPMId.hh"
-#include "Offline/DataProducts/inc/CaloConst.hh"
 
 namespace mu2e {
 
 class CalEnergyCalibInfo : public DbTable {
  public:
-  typedef std::shared_ptr<CalEnergyCalibInfo> ptr_t;
-  typedef std::shared_ptr<const CalEnergyCalibInfo> cptr_t;
-
   class Row {
    public:
-    Row(CaloSiPMId roid, float ADC2MeV, float ADC2MeV_err,
-        int status_code, std::string status_message)
-        : _roid(roid),
-          _ADC2MeV(ADC2MeV),
-          _ADC2MeV_err(ADC2MeV_err),
-          _status_code(status_code),
-          _status_message(std::move(status_message)) {}
-
-    CaloSiPMId roid() const { return _roid; }
-    float ADC2MeV() const { return _ADC2MeV; }
-    float ADC2MeV_err() const { return _ADC2MeV_err; }
-    int status_code() const { return _status_code; }
-    std::string status_message() const { return _status_message; }
+    Row(int energyCalibCid, int combinedEnergyCalibCid, std::string comment) :
+        _energyCalibCid(energyCalibCid),
+        _combinedEnergyCalibCid(combinedEnergyCalibCid),
+        _comment(std::move(comment)) {}
+
+    int energyCalibCid() const { return _energyCalibCid; }
+    int combinedEnergyCalibCid() const { return _combinedEnergyCalibCid; }
+    std::string comment() const { return _comment; }
 
    private:
-    CaloSiPMId _roid;
-    float _ADC2MeV;
-    float _ADC2MeV_err;
-    int _status_code;
-    std::string _status_message;
+    int _energyCalibCid;
+    int _combinedEnergyCalibCid;
+    std::string _comment;
   };
 
   constexpr static const char* cxname = "CalEnergyCalibInfo";
 
-  CalEnergyCalibInfo()
-      : DbTable(cxname, "cal.energycalibinfo",
-                "roid,adc2mev,adc2mev_err,status_code,status_message") {}
+  CalEnergyCalibInfo() :
+      DbTable(cxname, "cal.energycalibinfo",
+              "energycalibcid,combinedenergycalibcid,comment") {}
 
-  const Row& row(CaloSiPMId roid) const { return _rows.at(roid.id()); }
+  const Row& rowAt(const std::size_t index) const { return _rows.at(index); }
   std::vector<Row> const& rows() const { return _rows; }
   std::size_t nrow() const override { return _rows.size(); }
   size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
-  virtual std::size_t nrowFix() const override { return CaloConst::_nChannelDB; }
-  const std::string orderBy() const { return std::string("roid"); }
+  tableType type() const override { return Adhoc; }
 
   void addRow(const std::vector<std::string>& columns) override {
-    std::uint16_t index = std::stoul(columns[0]);
-    // enforce order, so channels can be looked up by index
-    if (index >= CaloConst::_nChannelDB || index != _rows.size()) {
-      throw cet::exception("CALENERGYCALIBINFO_BAD_INDEX")
-          << "CalEnergyCalibInfo::addRow found index out of order: " << index
-          << " != " << _rows.size() << "\n";
+    if (columns.size() < 3) {
+      throw cet::exception("CALENERGYCALIBINFO_BAD_COLUMNS")
+          << "CalEnergyCalibInfo::addRow expected at least 3 columns, got "
+          << columns.size() << "\n";
     }
-    std::string statusMessage = columns[4];
-    for (std::size_t i = 5; i < columns.size(); ++i) {
-      statusMessage += ",";
-      statusMessage += columns[i];
+    std::string comment = columns[2];
+    for (std::size_t i = 3; i < columns.size(); ++i) {
+      comment += ",";
+      comment += columns[i];
     }
-
-    _rows.emplace_back(CaloSiPMId(index), std::stof(columns[1]),
-                       std::stof(columns[2]), std::stoi(columns[3]),
-                       fromCsvText(statusMessage));
+    _rows.emplace_back(std::stoi(columns[0]), std::stoi(columns[1]),
+                       fromCsvText(comment));
   }
 
   void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
     Row const& r = _rows.at(irow);
-    sstream << r.roid() << ",";
-    sstream << std::fixed << std::setprecision(5);
-    sstream << r.ADC2MeV() << ",";
-    sstream << r.ADC2MeV_err() << ",";
-    sstream << r.status_code() << ",";
-    sstream << toCsvText(r.status_message());
+    sstream << r.energyCalibCid() << ",";
+    sstream << r.combinedEnergyCalibCid() << ",";
+    sstream << toCsvText(r.comment());
   }
 
   virtual void clear() override {
@@ -128,7 +96,8 @@ class CalEnergyCalibInfo : public DbTable {
       if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
         out.push_back('"');
         ++i;
-      } else if (text[i] == '\\' && i + 2 < text.size() && text[i + 1] == '"') {
+      } else if (text[i] == '\\' && i + 2 < text.size() &&
+                 text[i + 1] == '"') {
         out.push_back('"');
         ++i;
       } else {
@@ -142,5 +111,4 @@ class CalEnergyCalibInfo : public DbTable {
 };
 
 }  // namespace mu2e
-
 #endif
diff --git a/DbTables/inc/CalEnergyCalibInfoLink.hh b/DbTables/inc/CalEnergyCalibInfoLink.hh
deleted file mode 100644
index 44fd971f26..0000000000
--- a/DbTables/inc/CalEnergyCalibInfoLink.hh
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef DbTables_CalEnergyCalibInfoLink_hh
-#define DbTables_CalEnergyCalibInfoLink_hh
-
-//
-// Ad-hoc table linking a CalEnergyCalib CID to the matching
-// CalEnergyCalibInfo CID produced by the same combination pass.
-//
-
-#include "Offline/DbTables/inc/DbTable.hh"
-#include "cetlib_except/exception.h"
-#include <sstream>
-#include <string>
-#include <utility>
-
-namespace mu2e {
-
-class CalEnergyCalibInfoLink : public DbTable {
- public:
-  class Row {
-   public:
-    Row(int energyCalibCid, int energyCalibInfoCid, std::string comment) :
-        _energyCalibCid(energyCalibCid),
-        _energyCalibInfoCid(energyCalibInfoCid),
-        _comment(std::move(comment)) {}
-
-    int energyCalibCid() const { return _energyCalibCid; }
-    int energyCalibInfoCid() const { return _energyCalibInfoCid; }
-    std::string comment() const { return _comment; }
-
-   private:
-    int _energyCalibCid;
-    int _energyCalibInfoCid;
-    std::string _comment;
-  };
-
-  constexpr static const char* cxname = "CalEnergyCalibInfoLink";
-
-  CalEnergyCalibInfoLink() :
-      DbTable(cxname, "cal.energycalibinfolink",
-              "energycalibcid,energycalibinfocid,comment") {}
-
-  const Row& rowAt(const std::size_t index) const { return _rows.at(index); }
-  std::vector<Row> const& rows() const { return _rows; }
-  std::size_t nrow() const override { return _rows.size(); }
-  size_t size() const override { return baseSize() + nrow() * sizeof(Row); }
-  tableType type() const override { return Adhoc; }
-
-  void addRow(const std::vector<std::string>& columns) override {
-    if (columns.size() < 3) {
-      throw cet::exception("CALENERGYCALIBINFOLINK_BAD_COLUMNS")
-          << "CalEnergyCalibInfoLink::addRow expected at least 3 columns, got "
-          << columns.size() << "\n";
-    }
-    std::string comment = columns[2];
-    for (std::size_t i = 3; i < columns.size(); ++i) {
-      comment += ",";
-      comment += columns[i];
-    }
-    _rows.emplace_back(std::stoi(columns[0]), std::stoi(columns[1]),
-                       fromCsvText(comment));
-  }
-
-  void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
-    Row const& r = _rows.at(irow);
-    sstream << r.energyCalibCid() << ",";
-    sstream << r.energyCalibInfoCid() << ",";
-    sstream << toCsvText(r.comment());
-  }
-
-  virtual void clear() override {
-    baseClear();
-    _rows.clear();
-  }
-
- private:
-  static std::string toCsvText(const std::string& text) {
-    if (text.find_first_of(",\"") == std::string::npos) return text;
-    std::string out;
-    out.reserve(text.size() + 2);
-    out.push_back('"');
-    for (char c : text) {
-      if (c == '"') out += "\"\"";
-      else out.push_back(c);
-    }
-    out.push_back('"');
-    return out;
-  }
-
-  static std::string fromCsvText(const std::string& text) {
-    if (text.size() < 2 || text.front() != '"' || text.back() != '"') {
-      return text;
-    }
-    std::string out;
-    out.reserve(text.size() - 2);
-    for (std::size_t i = 1; i + 1 < text.size(); ++i) {
-      if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
-        out.push_back('"');
-        ++i;
-      } else if (text[i] == '\\' && i + 2 < text.size() &&
-                 text[i + 1] == '"') {
-        out.push_back('"');
-        ++i;
-      } else {
-        out.push_back(text[i]);
-      }
-    }
-    return out;
-  }
-
-  std::vector<Row> _rows;
-};
-
-}  // namespace mu2e
-#endif
diff --git a/DbTables/src/DbTableFactory.cc b/DbTables/src/DbTableFactory.cc
index ee39d11565..2e6bd545fe 100644
--- a/DbTables/src/DbTableFactory.cc
+++ b/DbTables/src/DbTableFactory.cc
@@ -14,8 +14,8 @@
 #include "Offline/DbTables/inc/CalSourceEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalCosmicEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalCosmicEnergyCalibInfo.hh"
+#include "Offline/DbTables/inc/CalCombinedEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalEnergyCalibInfo.hh"
-#include "Offline/DbTables/inc/CalEnergyCalibInfoLink.hh"
 #include "Offline/DbTables/inc/CalLaserEnergyCalib.hh"
 #include "Offline/DbTables/inc/CalLaserTimeCalib.hh"
 #include "Offline/DbTables/inc/CalLaserRuns.hh"
@@ -116,10 +116,10 @@ mu2e::DbTable::ptr_t mu2e::DbTableFactory::newTable(std::string const& name) {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalLaserRuns());
   } else if (name=="CalEnergyCalib") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalib());
+  } else if (name=="CalCombinedEnergyCalib") {
+    return std::shared_ptr<mu2e::DbTable>(new mu2e::CalCombinedEnergyCalib());
   } else if (name=="CalEnergyCalibInfo") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalibInfo());
-  } else if (name=="CalEnergyCalibInfoLink") {
-    return std::shared_ptr<mu2e::DbTable>(new mu2e::CalEnergyCalibInfoLink());
   } else if (name=="CalTimeCalib") {
     return std::shared_ptr<mu2e::DbTable>(new mu2e::CalTimeCalib());
   } else if (name=="CalCosmicT0Align") {

From 201fba9ce84951f19f22905419e5941e113072c0 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Tue, 3 Mar 2026 22:46:49 -0800
Subject: [PATCH 14/16] Add shared status code include for combined calib

---
 .../inc/CalCombinedEnergyCalibStatus.hh       | 45 +++++++++++++++++++
 DbTables/inc/CalCombinedEnergyCalib.hh        |  9 ++--
 2 files changed, 48 insertions(+), 6 deletions(-)
 create mode 100644 CaloConditions/inc/CalCombinedEnergyCalibStatus.hh

diff --git a/CaloConditions/inc/CalCombinedEnergyCalibStatus.hh b/CaloConditions/inc/CalCombinedEnergyCalibStatus.hh
new file mode 100644
index 0000000000..445a6610b4
--- /dev/null
+++ b/CaloConditions/inc/CalCombinedEnergyCalibStatus.hh
@@ -0,0 +1,45 @@
+#ifndef CaloConditions_CalCombinedEnergyCalibStatus_hh
+#define CaloConditions_CalCombinedEnergyCalibStatus_hh
+
+//
+// Status codes for combined calorimeter energy calibrations.
+//
+// 0   - updated: cosmic + source, consistent
+// 1   - fallback: methods inconsistent, kept old value
+// 2   - fallback: all methods statistically invalid
+// 101 - updated using cosmic only
+// 102 - updated using source only
+//
+
+namespace mu2e {
+
+namespace CalCombinedEnergyCalibStatus {
+
+constexpr int Updated = 0;
+constexpr int FallbackInconsistentMethods = 1;
+constexpr int FallbackAllMethodsInvalid = 2;
+constexpr int UpdatedUsingCosmicOnly = 101;
+constexpr int UpdatedUsingSourceOnly = 102;
+
+inline const char* description(int statusCode) {
+  switch (statusCode) {
+    case Updated:
+      return "updated: cosmic + source, consistent";
+    case FallbackInconsistentMethods:
+      return "fallback: methods inconsistent, kept old value";
+    case FallbackAllMethodsInvalid:
+      return "fallback: all methods statistically invalid";
+    case UpdatedUsingCosmicOnly:
+      return "updated using cosmic only";
+    case UpdatedUsingSourceOnly:
+      return "updated using source only";
+    default:
+      return "unknown status";
+  }
+}
+
+}  // namespace CalCombinedEnergyCalibStatus
+
+}  // namespace mu2e
+
+#endif
diff --git a/DbTables/inc/CalCombinedEnergyCalib.hh b/DbTables/inc/CalCombinedEnergyCalib.hh
index 585f5fb3aa..4754bf17b5 100644
--- a/DbTables/inc/CalCombinedEnergyCalib.hh
+++ b/DbTables/inc/CalCombinedEnergyCalib.hh
@@ -6,12 +6,8 @@
   Stores the combined ADC/MeV constants, uncertainties, and status flags
   from the cosmic + source calibration combination algorithm.
 
-  Status codes:
-    0   - updated: cosmic + source, consistent
-    1   - fallback: methods inconsistent, kept old value
-    2   - fallback: all methods statistically invalid
-    101 - updated using cosmic only
-    102 - updated using source only
+  Status-code values and descriptions are defined in:
+    Offline/CaloConditions/inc/CalCombinedEnergyCalibStatus.hh
 
   Author: W. Zhou 2025
 */
@@ -22,6 +18,7 @@
 #include <utility>
 #include <vector>
 #include "cetlib_except/exception.h"
+#include "Offline/CaloConditions/inc/CalCombinedEnergyCalibStatus.hh"
 #include "Offline/DbTables/inc/DbTable.hh"
 #include "Offline/DataProducts/inc/CaloSiPMId.hh"
 #include "Offline/DataProducts/inc/CaloConst.hh"

From 0888c5904f31e9fcb308a1a3cc9fdf8fe6c1f989 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Tue, 3 Mar 2026 22:47:08 -0800
Subject: [PATCH 15/16] Use const string refs instead of std::move in rows

---
 DbTables/inc/CalCombinedEnergyCalib.hh   |  5 ++---
 DbTables/inc/CalCosmicEnergyCalibInfo.hh | 11 ++++++-----
 DbTables/inc/CalEnergyCalibInfo.hh       |  6 +++---
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/DbTables/inc/CalCombinedEnergyCalib.hh b/DbTables/inc/CalCombinedEnergyCalib.hh
index 4754bf17b5..753fa7a586 100644
--- a/DbTables/inc/CalCombinedEnergyCalib.hh
+++ b/DbTables/inc/CalCombinedEnergyCalib.hh
@@ -15,7 +15,6 @@
 #include <iomanip>
 #include <sstream>
 #include <string>
-#include <utility>
 #include <vector>
 #include "cetlib_except/exception.h"
 #include "Offline/CaloConditions/inc/CalCombinedEnergyCalibStatus.hh"
@@ -33,12 +32,12 @@ class CalCombinedEnergyCalib : public DbTable {
   class Row {
    public:
     Row(CaloSiPMId roid, float ADC2MeV, float ADC2MeV_err,
-        int status_code, std::string status_message)
+        int status_code, const std::string& status_message)
         : _roid(roid),
           _ADC2MeV(ADC2MeV),
           _ADC2MeV_err(ADC2MeV_err),
           _status_code(status_code),
-          _status_message(std::move(status_message)) {}
+          _status_message(status_message) {}
 
     CaloSiPMId roid() const { return _roid; }
     float ADC2MeV() const { return _ADC2MeV; }
diff --git a/DbTables/inc/CalCosmicEnergyCalibInfo.hh b/DbTables/inc/CalCosmicEnergyCalibInfo.hh
index 6dad9c88aa..d97bea0d85 100644
--- a/DbTables/inc/CalCosmicEnergyCalibInfo.hh
+++ b/DbTables/inc/CalCosmicEnergyCalibInfo.hh
@@ -6,7 +6,6 @@
 #include <iomanip>
 #include <sstream>
 #include <string>
-#include <utility>
 
 namespace mu2e {
 
@@ -14,13 +13,15 @@ class CalCosmicEnergyCalibInfo : public DbTable {
  public:
   class Row {
    public:
-    Row(int cID, int FirstCalibRun, int LastCalibRun, std::string EnergyMethod, std::string FitMethod, std::string Comment) :
+    Row(int cID, int FirstCalibRun, int LastCalibRun,
+        const std::string& EnergyMethod, const std::string& FitMethod,
+        const std::string& Comment) :
         _cID(cID),
         _FirstCalibRun(FirstCalibRun),
         _LastCalibRun(LastCalibRun),
-        _EnergyMethod(std::move(EnergyMethod)),
-        _FitMethod(std::move(FitMethod)),
-        _Comment(std::move(Comment)) {}
+        _EnergyMethod(EnergyMethod),
+        _FitMethod(FitMethod),
+        _Comment(Comment) {}
     int cID() const {return _cID; }
     int FirstCalibRun() const { return _FirstCalibRun; }
     int LastCalibRun() const { return _LastCalibRun; }
diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index a559cd923c..d564f8b246 100644
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -10,7 +10,6 @@
 #include "cetlib_except/exception.h"
 #include <sstream>
 #include <string>
-#include <utility>
 
 namespace mu2e {
 
@@ -18,10 +17,11 @@ class CalEnergyCalibInfo : public DbTable {
  public:
   class Row {
    public:
-    Row(int energyCalibCid, int combinedEnergyCalibCid, std::string comment) :
+    Row(int energyCalibCid, int combinedEnergyCalibCid,
+        const std::string& comment) :
         _energyCalibCid(energyCalibCid),
         _combinedEnergyCalibCid(combinedEnergyCalibCid),
-        _comment(std::move(comment)) {}
+        _comment(comment) {}
 
     int energyCalibCid() const { return _energyCalibCid; }
     int combinedEnergyCalibCid() const { return _combinedEnergyCalibCid; }

From 0ed747822647459ea5e4fcd3948a58a1c47ae0b9 Mon Sep 17 00:00:00 2001
From: "Weilong (Sam) Zhou" <wzhou2@caltech.edu>
Date: Tue, 3 Mar 2026 22:47:36 -0800
Subject: [PATCH 16/16] Simplify CSV handling for combined calib info tables

---
 DbTables/inc/CalCombinedEnergyCalib.hh | 43 ++------------------------
 DbTables/inc/CalEnergyCalibInfo.hh     | 43 ++------------------------
 2 files changed, 4 insertions(+), 82 deletions(-)

diff --git a/DbTables/inc/CalCombinedEnergyCalib.hh b/DbTables/inc/CalCombinedEnergyCalib.hh
index 753fa7a586..794ceba211 100644
--- a/DbTables/inc/CalCombinedEnergyCalib.hh
+++ b/DbTables/inc/CalCombinedEnergyCalib.hh
@@ -75,15 +75,9 @@ class CalCombinedEnergyCalib : public DbTable {
           << index
           << " != " << _rows.size() << "\n";
     }
-    std::string statusMessage = columns[4];
-    for (std::size_t i = 5; i < columns.size(); ++i) {
-      statusMessage += ",";
-      statusMessage += columns[i];
-    }
-
     _rows.emplace_back(CaloSiPMId(index), std::stof(columns[1]),
                        std::stof(columns[2]), std::stoi(columns[3]),
-                       fromCsvText(statusMessage));
+                       columns[4]);
   }
 
   void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
@@ -93,7 +87,7 @@ class CalCombinedEnergyCalib : public DbTable {
     sstream << r.ADC2MeV() << ",";
     sstream << r.ADC2MeV_err() << ",";
     sstream << r.status_code() << ",";
-    sstream << toCsvText(r.status_message());
+    sstream << "\"" << r.status_message() << "\"";
   }
 
   virtual void clear() override {
@@ -102,39 +96,6 @@ class CalCombinedEnergyCalib : public DbTable {
   }
 
  private:
-  static std::string toCsvText(const std::string& text) {
-    if (text.find_first_of(",\"") == std::string::npos) return text;
-    std::string out;
-    out.reserve(text.size() + 2);
-    out.push_back('"');
-    for (char c : text) {
-      if (c == '"') out += "\"\"";
-      else out.push_back(c);
-    }
-    out.push_back('"');
-    return out;
-  }
-
-  static std::string fromCsvText(const std::string& text) {
-    if (text.size() < 2 || text.front() != '"' || text.back() != '"') {
-      return text;
-    }
-    std::string out;
-    out.reserve(text.size() - 2);
-    for (std::size_t i = 1; i + 1 < text.size(); ++i) {
-      if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
-        out.push_back('"');
-        ++i;
-      } else if (text[i] == '\\' && i + 2 < text.size() && text[i + 1] == '"') {
-        out.push_back('"');
-        ++i;
-      } else {
-        out.push_back(text[i]);
-      }
-    }
-    return out;
-  }
-
   std::vector<Row> _rows;
 };
 
diff --git a/DbTables/inc/CalEnergyCalibInfo.hh b/DbTables/inc/CalEnergyCalibInfo.hh
index d564f8b246..f89873c625 100644
--- a/DbTables/inc/CalEnergyCalibInfo.hh
+++ b/DbTables/inc/CalEnergyCalibInfo.hh
@@ -51,20 +51,15 @@ class CalEnergyCalibInfo : public DbTable {
           << "CalEnergyCalibInfo::addRow expected at least 3 columns, got "
           << columns.size() << "\n";
     }
-    std::string comment = columns[2];
-    for (std::size_t i = 3; i < columns.size(); ++i) {
-      comment += ",";
-      comment += columns[i];
-    }
     _rows.emplace_back(std::stoi(columns[0]), std::stoi(columns[1]),
-                       fromCsvText(comment));
+                       columns[2]);
   }
 
   void rowToCsv(std::ostringstream& sstream, std::size_t irow) const override {
     Row const& r = _rows.at(irow);
     sstream << r.energyCalibCid() << ",";
     sstream << r.combinedEnergyCalibCid() << ",";
-    sstream << toCsvText(r.comment());
+    sstream << "\"" << r.comment() << "\"";
   }
 
   virtual void clear() override {
@@ -73,40 +68,6 @@ class CalEnergyCalibInfo : public DbTable {
   }
 
  private:
-  static std::string toCsvText(const std::string& text) {
-    if (text.find_first_of(",\"") == std::string::npos) return text;
-    std::string out;
-    out.reserve(text.size() + 2);
-    out.push_back('"');
-    for (char c : text) {
-      if (c == '"') out += "\"\"";
-      else out.push_back(c);
-    }
-    out.push_back('"');
-    return out;
-  }
-
-  static std::string fromCsvText(const std::string& text) {
-    if (text.size() < 2 || text.front() != '"' || text.back() != '"') {
-      return text;
-    }
-    std::string out;
-    out.reserve(text.size() - 2);
-    for (std::size_t i = 1; i + 1 < text.size(); ++i) {
-      if (text[i] == '"' && i + 2 < text.size() && text[i + 1] == '"') {
-        out.push_back('"');
-        ++i;
-      } else if (text[i] == '\\' && i + 2 < text.size() &&
-                 text[i + 1] == '"') {
-        out.push_back('"');
-        ++i;
-      } else {
-        out.push_back(text[i]);
-      }
-    }
-    return out;
-  }
-
   std::vector<Row> _rows;
 };
 
